Skip to content

agentHost: don't subscribe to subagent chats that never spawn - #330558

Merged
roblourens merged 1 commit into
mainfrom
roblou/agents/log-analysis-error-fix-prioritization-b008581c
Aug 13, 2026
Merged

agentHost: don't subscribe to subagent chats that never spawn#330558
roblourens merged 1 commit into
mainfrom
roblou/agents/log-analysis-error-fix-prioritization-b008581c

Conversation

@roblourens

Copy link
Copy Markdown
Member

Found while scanning recent Insiders logs for actionable errors.

Issue

A task tool call that fails without spawning a subagent left the workbench subscribed to a child chat URI the host never created. The host waited out its pending-subagent window (15s) and then failed the subscription:

12:52:30.201 [trace] [AgentService] subscribe: ahp-chat://subagent/.../toolu_01FE...
12:52:30.223 [info] [Copilot:...] Tool completed: toolu_01FE...
12:52:30.226 [info] [AgentSideEffects] ... success=false
12:52:45.263 [error] [ProtocolServer] Request 'subscribe' failed Resource not found: ahp-chat://subagent/.../toolu_01FE...

The client saw the matching failure:

[RemoteAgentHostProtocol] Request 2891 failed: {"code":-32001,"message":"Resource not found: ahp-chat://subagent/.../toolu_01FE..."}

The underlying tool failure was legitimate and self-describing — the SDK rejected the nested delegation:

Maximum sub-agent depth of 4 reached. Complete this task without spawning further sub-agents.

So the agent behaved correctly; the client just kept observing a child chat that was never going to exist, producing a misleading Resource not found error.

Root cause

AgentHostSessionHandler._tryObserveSubagentToolCall began observing any recognized subagent tool once it reached Running or Completed, and never reconsidered that decision. A subagent-spawning tool briefly passes through Running, so the observation started before the depth-limit failure arrived and was never released.

Fix

  • Added shouldObserveSubagentChat in stateToProgressAdapter.ts: observe while the tool is Running, and after completion only when it actually has a subagent content block or succeeded (preserving legacy/restored snapshots that carry no content).
  • AgentHostSessionHandler now releases the child-chat observation when a subagent tool completes unsuccessfully without a subagent content block, instead of holding a subscription to a chat that will never exist.
  • Per-observation disposables moved into a DisposableMap keyed by tool call, so releasing an observation also tears down its autoruns and chat subscription.

Live and nested subagents are unaffected: they keep their subscription from the moment the tool starts running.

Tests

Two regressions, both at the layer that owns the behavior (no E2E fixture needed — this is a workbench-side decision, not host/AHP behavior):

  • stateToProgressAdapter.test.ts — the predicate observes running/successful tools and a failed tool that produced a child, but not a failed tool without one.
  • agentHostChatContribution.test.ts — end-to-end through the handler: the child chat subscription is live while the tool runs, and released after the failed completion. This one fails without the handler change.

Validation

  • ./scripts/test.sh --grep "subagent" over both files: 21 passing
  • Full stateToProgressAdapter.test.ts: 131 passing
  • npm run typecheck-client: clean

(Written by Copilot)

A `task` tool call that fails without spawning a subagent (for example when
the SDK rejects it with "Maximum sub-agent depth of 4 reached") left the
workbench observing a child chat URI the host never created. The host waited
out its pending-subagent window and then failed the subscription:

  [ProtocolServer] Request 'subscribe' failed Resource not found:
  ahp-chat://subagent/<session>/<toolCallId>

`AgentHostSessionHandler` now observes a subagent chat only while the tool can
still produce one, and releases the child-chat subscription when the tool
completes unsuccessfully without a subagent content block. Per-observation
disposables move into a `DisposableMap` keyed by tool call so a released
observation also tears down its autoruns and subscriptions.

(Written by Copilot)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI balanced review requested due to automatic review settings August 12, 2026 22:29

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Prevents stale subscriptions when subagent tool calls fail without creating child chats.

Changes:

  • Adds a predicate for determining whether a subagent chat should remain observed.
  • Tracks observations with disposable maps for immediate cleanup.
  • Adds predicate and subscription-lifecycle regression tests.
Show a summary per file
File Description
stateToProgressAdapter.ts Adds the observation predicate.
agentHostSessionHandler.ts Releases invalid child-chat observations.
stateToProgressAdapter.test.ts Tests predicate outcomes.
agentHostChatContribution.test.ts Tests subscription cleanup after failure.

Review details

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

  • Files reviewed: 4/4 changed files
  • Comments generated: 0
  • Review effort level: Balanced

@roblourens
roblourens marked this pull request as ready for review August 12, 2026 22:56
@roblourens
roblourens enabled auto-merge (squash) August 12, 2026 22:56
@roblourens
roblourens merged commit f1e7808 into main Aug 13, 2026
45 of 46 checks passed
@roblourens
roblourens deleted the roblou/agents/log-analysis-error-fix-prioritization-b008581c branch August 13, 2026 01:47
@vs-code-engineering vs-code-engineering Bot added this to the 1.134.0 milestone Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants