Parent thread shows "Awaiting Input" for delegated-task questions that the parent agent is answering#24096

opened5d agobyKkosovojs

What happened

When a sub-agent (a delegate_task child) asks a question, the parent thread shows it as input required from me. But the main agent answers it. In these cases I don't think the user needs to be shown that there is a question.

Diagnosis

Two features overlap without accounting for each other:

  1. Client, from #16634: packages/client-runtime/src/state/threadShell.ts
    • subagentRequest() returns "user_input" for any non-native subagent thread with a pending request while its run is live.
    • pendingSubagentRequestsByThread() passes this up to every ancestor.
    • On the parent this produces:
      • "Awaiting Input" in the sidebar (apps/web/src/components/Sidebar.logic.ts, resolveSidebarThreadStatus / status pill)
      • an "Input needed" toast/OS notification (ThreadNotificationCoordinator.tsx)
      • a "Subagent needs input" banner (ThreadActivityBanners.tsx)
  2. Server, from #19521: apps/server/src/orchestration-v2/DelegatedTaskQuestionReactor.ts sends the same question to the parent agent. It queues a message telling it to read the question (t3_pending_request_read) and answer it (t3_pending_request_respond), or ask the user if needed. If the parent is blocked in a delegate_task wait, the wait returns the question directly.

The client only skips provider-native subagents (isProviderNativeSubagentThread). It does not skip app-owned delegated tasks, which are exactly the threads the reactor sends to the parent agent. The user gets told to act on something the agent is already handling.

A narrower bug in the same function: subagentRequest() ignores pendingRuntimeRequest.blocking. #15258 made a thread's own status ignore non-blocking (async) questions while its run keeps working (models.ts: blocking !== false || !runtimeIsWorking). The parent path was never updated. A codex async question (request_user_input with responseCapability: { type: "message" }) therefore does not show "Awaiting Input" on the child itself, but does on the parent.

UX is open. Fully hiding the flag risks bringing back #15082 (a child stuck unnoticed) if the parent agent ignores the question or its run fails. One option:

  • Don't flag the parent while it has a queued or running turn handling the question.
  • Flag it again if that turn ends and the question is still pending.
  • If the parent agent decides to ask the user, that already appears as the parent's own question.

Steps to reproduce

  1. Web app (nightly) connected to a local server run by the desktop app (nightly). Start a parent thread that delegates work with delegate_task to a Codex child.
  2. Have the child ask a question with request_user_input. Async questions reproduce this most reliably.
  3. The parent thread shows "Awaiting Input", the "Subagent needs input" banner, and fires an "Input needed" notification.
  4. Shortly after, the parent agent answers the question with t3_pending_request_respond, without any user action.

Version

Server: 0.1.3-nightly.20261023.3566 (desktop app). Client: nightly web app, exact build unknown. The client code above is unchanged on main as of b2377db9.

Environment

macOS 26.3 (Darwin 25.3.0, arm64), Node v26.12.1, codex-cli 0.164.0

Evidence

shell
1# orchestration_v2_projection_runtime_requests, child thread
2# thread:delegated-task:command%3Amcp%3A<id>%3Adelegate-task%3Afix-all-retry-generations-20261023-r1
3kind=user_input responseCapability={"type":"message"} created=11:27:49Z resolved=11:28:27Z
4kind=user_input responseCapability={"type":"message"} created=11:29:28Z resolved=11:30:08Z
5kind=user_input responseCapability={"type":"message"} created=11:31:55Z resolved=11:34:28Z
6# a sibling delegated task: created=11:15:50Z resolved=11:17:28Z
7# none were answered by the user (confirmed with the user)

Related issues

  • #15082: the parent was never told about child questions. Fixed by #19521, which this issue builds on.
  • #15258: the async-question fix for the thread itself, not carried over to the parent path.
  • #18978 / #19165: a stale "Subagent needs input" after the child run ended (fixed in #18996). This issue happens while the child run is live.

None of these covers the parent being flagged while its agent is answering.

Fix applied or workaround

None.

Filed by

Claude Code (claude-opus-5-5) via t3 triage

Synced from GitHub

Title: Keep parent question wakeups while distinguishing agent handling, human escalation, and stale requests

Problem: A retained audit found 198 delegated user-input requests across 156 child threads: 113 resolved and 85 pending. Of the pending requests, 84 belonged to children whose latest recorded lifecycle was completed and 1 to an interrupted child, so these are not 85 currently blocked workers. There were also 97 question-notification messages across 8 parent threads; notification messages and distinct unresolved requests are different counts. These observations support reconciling request ownership and terminal state, but do not establish a current regression in the question-wakeup fix. The live report in #24096 shows the parent can answer a child's question while the UI simultaneously asks the human to act.

Reproduction or observation: Delegate an asynchronous child that asks an ordinary user-input question after the parent ends its turn. Observe the request-open event, queued/running parent handling, answer receipt, and request resolution. Repeat with a nonblocking question, then interruption/cancellation. Verify both provider delivery and UI state. This is a proposed focused verification sequence; no new provider run was performed for this draft.

Proposed behavior: Preserve the existing event-driven parent wake and answer route, deduplicated per live request. While the parent has queued or running handling work, show that the agent is handling the question rather than immediately demanding human input. Escalate if handling fails or ends with an unresolved blocking question, or if the parent explicitly asks the human. Reconcile cancelled/resolved requests with the provider; terminal children must not look currently blocked solely because of retained stale rows. Keep approval/sign-in authority separate from answerable questions.

Why native: The request reactor and client state already own these transitions. Polling or telling children to bypass the question tool creates a second coordination channel and cannot repair stale projection state.