Agent host: a Claude session shows nothing more once the parent resumes after a background subagent
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
When a Claude agent-host turn spawns a background subagent, the parent finishes its own turn. Once the subagent settles and the parent resumes producing output, every SDK message is discarded, so the chat shows nothing further for the rest of the work. The transcript on disk records all of it, so restarting the agent host makes the whole response appear at once.
## Steps to reproduce
1. In a Claude agent-host session, send a prompt that makes the agent spawn background subagents, for example "use subagents to audit these two directories in parallel, read-only".
2. Watch the chat while it works.
**Expected:** the parent's output keeps appearing as the subagents report back.
**Actual:** the response stops at whatever the parent said before spawning, typically one or two lines, and nothing more ever renders. No error appears in any log, at any log level.
Restart the agent host and reopen the session: the complete response appears, rebuilt from the transcript.
## Root cause
`ClaudeSdkPipeline._processMessages` derives the turn from the prompt queue head:
```ts
const parent = this._queue.peekParent();
const turnId = parent?.turnId;
```
A parent that spawns background subagents ends its own turn, so the queue drains and `turnId` becomes `undefined` for everything that follows.
`ClaudeSdkMessageRouter.handle` then drops the message outright:
```ts
if (turnId === undefined) {
return;
}
```
That early return is silent at every log level, which is why the failure leaves no trace anywhere.
## Evidence
Captured on a live host with `AgentHostStateManager`'s envelope logging temporarily raised to `info`:
| | |
|---|---|
| Host's last emitted envelope | 9:15:13 p.m. |
| Parent produced 4 assistant messages | transcript, 9:15:17 to 9:15:21 p.m. |
| Envelopes emitted for those messages | none |
The three `AgentSideEffects` drop paths (`Dropping stale ...`, `Dropping completion for cancelled turn ...`) were also raised to `info` for the same run and never fired, confirming the message dies earlier, in the router.
Replaying that session's transcript offline through `mapSessionMessagesToTurns` produces the turn with all 35 response parts (3 markdown, 23 tool calls, 9 reasoning). The data is intact; only the live path loses it.
## Related
PR #331872 hooks this same early return for `system` / `task_notification`, so a background subagent's chip completes. That is a narrower case of the same gap: once a turn id is available, `claudeSubagentSignals` already maps `task_notification` normally, so a general fix here supersedes it.
## Version
Visual Studio Code 1.1.3 (stable), server commit `110a328ea54b42367b803ec53ee0bf52ef26b419`, dev container on linux-arm64. Root cause confirmed against `main`.
*AI disclosure: this issue and the related code were written with the assistance of AI.*
### Public patches and patcher scripts
[Public patch catalog and patcher scripts](https://github.com/RyanEwen/vscode-patches/blob/main/CATALOG.md) · [Source patch index](https://github.com/RyanEwen/vscode-patches/blob/main/SOURCE-PATCHES.md). The [public collection](https://github.com/RyanEwen/vscode-patches) includes the maintained patchers, rollback instructions, regression scripts, and historical snapshots. Build restrictions and exact installer coverage are documented there.
Contributor guide
Assessment
This issue has not been assessed yet.