microsoft / microsoft/vscode

Agent host: a subagent's tool call is never executed and its turn is never closed, so the chat spins forever

Open
#333,931 2 comments 0 reactions 1 assignee Claimed by @roblourens View on GitHub
Dominant language
TypeScript
Stars
193k
Forks
42.4k
PR merge metrics
PR metrics pending

Description

In a dev container, a subagent's tool call is announced and then never executed. Nothing runs it, nothing fails it, and nothing times out, so the subagent's turn stays open and the chat spins indefinitely.

I reproduced this six times, on both a patched and a completely stock build, driving a real window through a scripted scenario rather than by hand.

## What happens

A prompt that launches a subagent (`Agent` / `Task`) produces, on the subagent's own chat channel:

```
chat/toolCallStart turn=3fcf1cc0-… Bash
chat/toolCallReady turn=3fcf1cc0-…
(nothing further, ever)
```

At that point, measured inside the container:

- **No process is executing.** `ps` shows no shell, no `find`, no `grep`, nothing but the container's own keep-alive processes.
- **The agent host log is silent.** Its last line is the tool completion that preceded the hang.
- **The UI still reports the turn as running**, and did so for the full 10 minute observation window.
- The parent's spawning `Agent` tool call also never completes.

So the call is announced to the client, never executed by anything, and never reaped.

## It scales with the number of subagents

A prompt that spawns several subagents leaves several turns open. One run, driven the same way:

```
chat/turnStarted x10
chat/turnComplete x4
```

Seven subagent turns were opened and two completed; five were left open, along with the parent's follow-up turn. The chat shows nothing further for any of them and no amount of waiting changes it.

That ratio matches what #332073 reports from a different trigger, which is why I think the missing terminal path is worth treating as its own defect rather than only as a consequence of whatever stalls the tool call.

## Why the turn never closes

`AgentSideEffects.completeSubagentSession` is the only thing that completes a subagent chat's turn, and it is reachable from exactly one place: a `subagent_completed` signal.

```
node/agentSideEffects.ts
590: if (signal.kind === 'subagent_completed') {
591: this.completeSubagentSession(signal.chat.toString(), signal.toolCallId);
```

That signal has two producers, and both are downstream of the spawning tool finishing:

- `claudeMapSessionEvents.ts:406` fires it on the `tool_result` for the spawning `Task`/`Agent` `tool_use`, and only when the spawn is not flagged background.
- `claudeSubagentSignals.ts:129` fires it on a `task_notification` with a terminal status.

Because the spawning tool call never completes, neither producer fires. `subagent_completed` was emitted **zero times in every run**. The subagent turn is therefore never completed, cancelled or errored.

Nothing else closes it. The only thing resembling a watchdog is `agentHostTurnTracker`, which derives a hang reason for telemetry and dispatches no action, so there is no path by which an abandoned turn is ever terminated.

## Reproducing it

Drive a window, send a prompt that spawns a subagent, and wait. The scenario I used, with all prompts read-only:

> Without changing anything, launch a subagent to inventory the top-level directories of this repository, then report what it found.

Then assert that every `chat/turnStarted` eventually reaches a terminal action. The run never satisfies it.

Two measurements make the diagnosis unambiguous and are worth repeating if anyone tries this:

- check `ps` inside the container, to distinguish "the command is slow" from "nothing is running"
- check whether the agent host log is still growing, rather than judging from the UI: the Stop control disappears transiently during tool execution, so the UI is not a reliable indicator of progress

## Scope

Reproduced on **1.135.0** (`08d4889f9ec4a1685d257b9b95de036c8e1ce1e5`), dev container on Docker, agent host in the container, Claude harness, Windows client and Linux container on arm64.

I run a set of local patches against the shipped bundle, so I re-ran this against a **completely stock, reverted bundle** to be sure they were not the cause. It reproduces identically: the turn is still open after 10 minutes with nothing executing. As a control in the same comparison, the stock build produced 2 `ENOPRO` errors where the patched build produced none, which confirms the revert genuinely took effect.

## What I have not established

I have not identified why the announced call is never executed. Two candidates in the existing set look most likely, and I would rather not guess between them:

- [#330899](https://github.com/microsoft/vscode/issues/330899), where a client tool is admitted to execution off the stream-mapper ready rather than the runtime invocation
- [#331595](https://github.com/microsoft/vscode/issues/331595), where a subagent's tool call is handled on the parent chat

Whichever it is, the missing reaper is separable and worth having on its own: a turn whose producing work is gone should not remain open forever, and today nothing can end it but the user.

Related: [#332073](https://github.com/microsoft/vscode/issues/332073) reports the same visible outcome from a different cause (closing the window mid-flight). The grouping is in [#333174](https://github.com/microsoft/vscode/issues/333174).

*AI disclosure: this issue and the related investigation 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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.