fix: announce ad-hoc spawned subagents so their output is not dropped - #482
Open
gurungabit wants to merge 1 commit into
Open
fix: announce ad-hoc spawned subagents so their output is not dropped#482gurungabit wants to merge 1 commit into
gurungabit wants to merge 1 commit into
Conversation
A spawn is registered as pending and only announced when a subAgentActivity item supplies its agent path. Codex sends that item for subagents it names, but not for an ad-hoc `spawn_agent`, so the child's notifications buffer against a materialization that never comes: the buffer reaches MAX_PENDING_NOTIFICATIONS, the oldest updates are dropped, and the client is never told the subagent exists. Announce from the spawn's own `item/completed` instead, which carries receiverThreadIds and lands before any child output. An activity item that arrives first still wins, since materializing a known child is a no-op, so named subagents keep the identity their path gives them.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A spawn is registered as pending in
CodexSubagentEventRouter.handle()and is only announced when asubAgentActivityitem later supplies its agent path:Codex sends that item for subagents it names, but not for an ad-hoc
spawn_agent. Every notification from the child then matches the pending-spawn branch and is buffered against a materialization that never arrives — untilMAX_PENDING_NOTIFICATIONS, after which its oldest updates are dropped. The client is never told the subagent exists, and the transcript it produced is lost.Because the spawn's
item/completedis reported as represented, it is also swallowed, so the client is left with theitem/startedcopy — which leaks through only because itsreceiverThreadIdsis still empty — stuck atin_progressfor the rest of the session.Evidence
Codex 0.153.4, adapter 1.7.0, native subagent sessions negotiated, prompt "use subagents to analyze this repo" (
APP_SERVER_LOGS):subAgentActivityitems in the whole log: 0Pending subagent 01a07280-e18f-… exceeded the notification buffer; dropping oldest updatesFound while integrating an ACP client; the same shape is described in manaflow-ai/cmux#5698, and #238 mapped
spawn_agentonto tool calls with nested sessions left optional.Fix
Announce from the spawn's own
item/completed, which carriesreceiverThreadIdsand lands before any child output — the point wheresubagent_spawnedis supposed to go.materialize()takes the agent path as optional, since an ad-hoc spawn has none, and falls back to the identity helper that already existed for exactly that case.Named subagents are unaffected: an activity item that arrives first still wins, because materializing a known child is a no-op, so they keep the name their path gives them. That ordering is what the existing tests assert, and they pass unmodified — including
emits native lifecycle and routes child output after capability negotiation, which is the case where child output precedes the announcement.Terminal states are skipped, so a spawn that completes already-terminal still finishes as pending rather than being announced, per
waits for a pending spawn without publishing fallback identity and suppresses late activity.Testing
announces an unannounced spawn so its output is not lost— assertssubagent_spawnedagainst the parent under the fallback identity with the spawn prompt as its task, the child's own tool call routed to the child session, and no barespawnAgenttool call in the thread.npm run typecheckandnpm test: 542 passed, 26 skipped, 0 failed, no existing test modified.🤖 Generated with Claude Code