fix(server): task_status reports how long a running delegated task has been silent#23898

open1
main
GitHub fork: fix/delegated-task-idle-signal
opened1d agobyOomar7550
View on GitHubTwo-way sync enabledPR last imported 1d ago

Problem

A delegated Codex child can sit in Working with no provider events at all. Neither the parent agent (task_status) nor the user can tell it apart from a turn that is doing work. This is the silent post-tool case in #17503. Below is the notification sequence @juliusmarminge asked for, from the last tool result through the end of each silence.

Versions: T3 Code Nightly 0.1.1-nightly.20261020.3411 (macOS), codex-cli 0.163.0 over codex app-server, model gpt-6.1-sol via a Responses-compatible CLIProxyAPI on loopback. Codex stream settings are defaults.

Silence 1: a hung request after a tool result (15m35s, never answered)

UTCDirMethodKey fields
21:39:28.953initem/startedcommandExecution
21:39:28.960initem/completedcommandExecution failed, exitCode 1 (the command's real exit)
21:39:29.008inthread/tokenUsage/updatedlast notification
21:39:29 – 21:55:04silenceno thread/status/changed, error, willRetry, deltas, or turn/completed. The Codex rollout is also empty.
21:55:04.228outturn/interruptmanual restart by the parent agent
21:55:04.376inthread/status/changed / turn/completedidle / interrupted, error: null

Silence 2: the same thread after the restart (5m13s before first output, then normal)

UTCDirMethodKey fields
21:55:04.767inthread/status/changed / turn/startedactive
21:55:04.782initem/completeduserMessage
21:55:04 – 22:00:18silencethe same: no status change, error, retry, or reasoning
22:00:18.085initem/startedagentMessage (first model output)

The proxy logged 499 | 15m35s for the first request when the client closed it, and 200 | 5m15s for the second. It logged no retries. These are slow or hung upstream requests that never return response headers, not a 429 retry sequence. Codex's stream idle timeout never fires, so it emits nothing and T3 has no signal to act on. A 5-minute silence can also be healthy, as the second one was, so this PR reports idleness and does not time anything out.

Change

  • task_status (contract, server, tool description, docs) now returns three fields for running tasks:

    • lastActivityAt: the last recorded change to the child thread.
    • idleForMs: time since then.
    • hasRunningItem: whether an open item belongs to the run's active attempt. Items left open by an attempt that a restart superseded don't count.

    A long idleForMs with workState: working, hasRunningItem: false and no pending request points to a stalled provider. The parent can then restart or cancel the task. All three are null/false for queued and finished tasks.

  • Web Working row: after 3 minutes without item activity, with nothing in progress and no pending request, the row adds a quiet "· No activity for N" hint. A pure helper in TimelineWorkGroupRows.logic.ts derives this from data the client already has.

  • Not included:

    • Timeouts and auto-fail.
    • Adapter changes.
    • Mobile. Its working indicator is separate and would be a follow-up.
    • Streaming items with no output. An open text or reasoning item still counts as in progress, because reasoning can legitimately be silent. Codex's stream idle timeout covers a hang in the middle of a stream.

Scope and approval

This addresses #17503, specifically its "no no-progress signal on an active turn" gap. The reporter also asked for that state to be "visible … to parent agents through task_status for delegated tasks". The PR stays informational (no new timeouts or retries) so that it fits the problem the issue already establishes. It does not address the issue's systemError recovery or 429 backoff parts.

Before / after

MessagesTimeline rendered on its own with a running turn whose last activity was 15 minutes ago. Upstream ignores the idle input, and the two "before" captures are byte-identical.

Before (upstream)After
External imageExternal image

Fixture-driven component captures, not a live stuck provider. The desktop and mobile shells were not exercised. Full sanitized notification sequence.

Verification

  • OrchestratorMcpService.activity.test.ts (using TestClock) covers:
    • idleForMs growing as time advances;
    • open items from a superseded attempt vs. the active attempt;
    • an open item with no provider turn (workspace preparation);
    • completed items and items from inactive runs;
    • finished tasks returning nulls.
  • TimelineWorkGroupRows.logic.test.ts covers:
    • the 3-minute threshold;
    • suppression while an item is in progress;
    • the restart baseline;
    • ignoring items from other runs;
    • missing attempt or start returning null;
    • formatting.
  • The new tests fail on upstream, where the fields and helper don't exist.
  • vp test run on the MCP service, activity and toolkit integration tests (44 passed) and the web logic tests (6 passed).
  • vp run check:changed upstream/main passed: format, lint, knip, typecheck for 29 packages, and 191 tests.
  • Three independent review rounds, none blocking. Their wording, query-cost, item-filter, render-flash and test-gap findings were fixed, including tests that fail when the lazy-loading guard is removed.
  • Not checked: a live stalled provider end to end, Electron, mobile.

Done by Claude Opus 5.5 in Claude Code, running in T3 Code.

🤖 Generated with Claude Code

Checks

All checks passed

Added 1 commit

  • fix(server): task_status reports how long a running delegated task has been silent50acc35
Synced from GitHub

Approvability

Verdict: Approved at 50acc35

Macroscope's review found this PR approvable — This is a focused observability fix that adds backward-compatible task liveness fields and a minor desktop idle-status hint. It does not add timeouts, retries, workflow gating, breaking schema changes, or other material side effects.

You can add or adjust custom eligibility rules. Learn more.

Synced from GitHub

Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
📥 Commits

Reviewing files that changed from the base of the PR and between e78297d89133eb69a375750974c88aa744dae7c7 and 50acc3565a7462fb943ec9cb13863496330f8075.

📒 Files selected for processing: 13
  • apps/server/src/mcp/OrchestratorMcpService.activity.test.ts
  • apps/server/src/mcp/OrchestratorMcpService.test.ts
  • apps/server/src/mcp/OrchestratorMcpService.ts
  • apps/server/src/mcp/toolkits/orchestrator/tools.ts
  • apps/web/src/components/ChatView.tsx
  • apps/web/src/components/chat/MessagesTimeline.tsx
  • apps/web/src/components/chat/TimelineWorkGroupRows.logic.test.ts
  • apps/web/src/components/chat/TimelineWorkGroupRows.logic.ts
  • apps/web/src/components/chat/TimelineWorkGroupRows.tsx
  • apps/web/src/components/chat/timelineRowContext.ts
  • docs/orchestration-v2/orchestrator-mcp-server.md
  • packages/contracts/src/orchestratorMcp.test.ts
  • packages/contracts/src/orchestratorMcp.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

📝 Walkthrough

Delegated-task status now includes child-thread activity time, elapsed idle time, and active-attempt item state. The chat timeline derives activity for active work and displays an idle hint after three minutes.

Changes: Delegated task activity

Layer / File(s)Summary
Task activity status and contract
packages/contracts/src/orchestratorMcp.ts, apps/server/src/mcp/OrchestratorMcpService.ts, apps/server/src/mcp/toolkits/orchestrator/tools.ts, docs/orchestration-v2/orchestrator-mcp-server.md, packages/contracts/src/orchestratorMcp.test.ts, apps/server/src/mcp/OrchestratorMcpService.test.ts, apps/server/src/mcp/OrchestratorMcpService.activity.test.ts
Task status reports the child thread’s last activity, elapsed idle time, and whether an in-progress item belongs to an active run attempt. The service queries activity for running or waiting tasks. Tests cover attempt filtering, query conditions, and terminal-task values.
Timeline activity and idle hint
apps/web/src/components/chat/TimelineWorkGroupRows.logic.ts, apps/web/src/components/chat/timelineRowContext.ts, apps/web/src/components/ChatView.tsx, apps/web/src/components/chat/MessagesTimeline.tsx, apps/web/src/components/chat/TimelineWorkGroupRows.tsx, apps/web/src/components/chat/TimelineWorkGroupRows.logic.test.ts
The timeline derives the latest eligible activity for the active attempt and returns no timestamp when an item remains in progress. It displays a formatted idle hint after three minutes when the row is not awaiting input or shimmering.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Possibly related issues

  • pingdotgg/t3code issue 18877: The change filters items from superseded attempts when determining active work and reports activity for delegated tasks.
  • pingdotgg/t3code issue 22651: The added idle and running-item status fields expose delegated tasks that remain running without active work; the change does not complete or time out those tasks.

Suggested reviewers: juliusmarminge, t3dotgg

Merge Risk: ⚪ Minimal · up to 50acc

The delegated-task activity fields and idle hint have no identified merge-blocking issue. The change is ready for normal merge checks.

Pre-merge checks: Passed 4
Check nameStatusExplanation
Description checkPassedThe description includes all required sections. It clearly explains the problem, implementation, scope and approval basis, verification results, screenshots, limitations, and agent attribution.
Title checkPassedThe title is concise and accurately describes the main change: reporting the idle duration of a running delegated task through task_status.
Linked Issues checkPassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes checkPassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.