Problem
When a subagent (sessions_spawn with mode: "run") completes its work, the completion announcement is delivered to the requester session via a direct in-process dispatch that requires the requester session to be available and responsive.
If the requester session is busy (streaming a response, compacting, waiting for tools), the direct announce call times out after 120 seconds. The announce system retries 3 times, but each attempt hits the same busy-session condition, eventually giving up with:
[warn] Subagent completion direct announce failed for run X: gateway request timeout for agent
[warn] Subagent announce give up (retry-limit) run=X child=... retries=3 deliveryError="completion agent handoff is still pending"
The subagent itself has completed its work (all tool calls finished, report generated). The announcement is permanently lost.
Key observations
Proposed Design
Persist the completion announcement so the requester can fetch it on its next available turn, instead of pushing directly to a busy session.
Option A: Session entry annotation
- On subagent completion, write metadata to the requester session entry (e.g.
metadata.subagentCompletions[])
- Before the requester starts its next LLM turn, scan and process pending announcements
- Durable (written to disk), survives restarts, decouples timing completely
Option B: Message queue event
- Subagent completion emits an internal event to a shared message queue
- Requester consumes from the queue on its next available turn
- More architecturally clean but requires queue infrastructure
Option C: Session file message injection
- Write a system event into the requester session file
- The requester picks it up on the next read cycle
Workarounds
- Increasing the announce timeout only delays the failure — does not fix the race
- Manually checking subagent session output — not practical
Related
Problem
When a subagent (
sessions_spawnwithmode: "run") completes its work, the completion announcement is delivered to the requester session via a direct in-process dispatch that requires the requester session to be available and responsive.If the requester session is busy (streaming a response, compacting, waiting for tools), the direct announce call times out after 120 seconds. The announce system retries 3 times, but each attempt hits the same busy-session condition, eventually giving up with:
The subagent itself has completed its work (all tool calls finished, report generated). The announcement is permanently lost.
Key observations
Proposed Design
Persist the completion announcement so the requester can fetch it on its next available turn, instead of pushing directly to a busy session.
Option A: Session entry annotation
metadata.subagentCompletions[])Option B: Message queue event
Option C: Session file message injection
Workarounds
Related