Skip to content

Fix subagent activity, opening, and completion state - #334986

Draft
Justin Chen (justschen) wants to merge 4 commits into
mainfrom
justschen/fix-subagent-activity-lifecycle
Draft

Fix subagent activity, opening, and completion state#334986
Justin Chen (justschen) wants to merge 4 commits into
mainfrom
justschen/fix-subagent-activity-lifecycle

Conversation

@justschen

@justschen Justin Chen (justschen) commented Sep 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fix subagent pills losing their connection to the child chat: tool activity remains stuck at "Working on it...", completed background agents still look busy, and opening a subagent can either do nothing or produce an empty editable chat.

The pill and the "Background agent ... is complete" notification represent the same delegated agent. The notification was arriving through the parent chat while the pill's child-chat subscription had already failed. This is a client-side lifecycle and presentation problem, not evidence that the agent had stopped doing work.

Findings from the debug exports

Two locally inspected debug bundles covered the missing-activity, blank-editor, and stale-completion cases. Raw logs, transcripts, machine paths, and session identifiers are intentionally not attached.

Delayed startup strands the parent pill

The reviewer session showed the following sequence on September 7, 2026 (times below are UTC):

Time Event
21:29:26 Five background task calls returned their launch acknowledgments; the parent began subscribing to their prospective child-chat URIs.
21:29:41 All five subscriptions failed with AHP_NOT_FOUND after the 15-second pre-spawn wait.
21:30:07 The actual subagent chats were registered, approximately 41 seconds after launch.
21:40:41 One reviewer emitted SDK completion after 142 tool calls; its child chat received chat/turnComplete immediately afterward.
21:40:42 The parent received the separate background-completion notification, but its pill remained visually busy.

Four reviewers completed in the captured interval; the fifth was still active. Opening a child could establish a fresh, working subscription, explaining why its transcript contained real tool calls while the parent pill remained stale.

There were two holes in recovery:

  1. A failed subscription stores an Error value asynchronously. _observeSubagentSession only had a synchronous try/catch, so it left the failed observation registered and the pill marked active.
  2. Background launch tools can complete before their children start. The protocol ignores ChatToolCallContentChanged for completed tools, so the later discovery block cannot wake a tool-only observer. The session's chat catalog does publish the real child, but the observer was not using that catalog for discovery.

Other presentation and restore gaps

  • Restored parent state was disconnected. A completed launch tool in an active-turn snapshot was rendered as a serialized part, while child observation updated a separate, unrendered live invocation.
  • The latest tool was missing or incorrectly worded. The subagent activity renderer skipped serialized child tools and always used the invocation message rather than the completed tool's past-tense message.
  • Unavailable actions looked clickable. Readiness was conflated with rich presentation visibility; navigation needs to be disabled without hiding the pill and its activity.
  • A prospective URI was treated as an openable chat. The rich editor action could become enabled before the provider had resolved a child chat.
  • Missing chats became blank editable editors. The load path awaited child subscription hydration without checking its Error value. Not-found suppression was also broad enough to hide missing-child failures, and missing child state could fall back to editable interactivity.

Relevant history

This is a combination of lifecycle assumptions rather than a single rendering-only change:

Change Relationship to the failure
#326169 (9603ef1ea5f) Introduced the bounded 15-second wait for a prospective subagent chat. The client did not recover when that wait expired before a slow/background child was published.
#328651 (d5dd3ab6966) Shared the rich subagent presentation with editor chats and enabled opening based on a prospective URI.
#331045 (dcfc4269938) Avoided duplicate restored task cards, but left the rendered serialized parent separate from the live invocation receiving child state.
#332456 (908ab0dc0b8) Suppressed not-found load errors generally, including missing child chats rather than only root sessions that the host might not know yet.

Fixes

Recover and track the actual child chat

  • Await child subscription hydration and route Error values through the existing logging and observation cleanup.
  • Observe subagent resource membership in the session chat catalog, including discovery after the launch tool has completed.
  • Prefer the catalog's child URI and replace an observation when the real resource differs from the provisional one.
  • Project only resource/launch-tool identity with equality checking so unrelated catalog status updates do not repeatedly drive discovery.
  • Preserve the existing bounded timeout; no timeout increase or polling loop is introduced.

Keep opening and completion tied to real state

  • Add optional isChatAvailable metadata for provider-resolved availability, separately from the prospective resource URI.
  • Preserve availability through tool updates and history hydration; enable the open action only once the provider has resolved the child chat.
  • Restore observable parent invocations for completed subagent launch tools in active turns so the visible pill receives child activity and completion without creating a duplicate card or splitting streamed markdown.
  • Keep a completed delegated tool's inline result accessible when no separate child chat materializes.
  • Keep the rich header and activity visible while navigation is disabled. Explain unavailability in the hover instead of showing a clickable cursor, and retain a separate output disclosure when no child chat is available.

Show accurate activity and load failures

  • Include serialized child tools in activity presentation and prefer completed past-tense messages such as "Searched...".
  • Check child subscription errors before constructing history or synthesizing a draft.
  • Restrict not-found suppression to root sessions and show a normal load error for missing child chats.
  • Keep unresolved subagent editors read-only rather than falling back to an editable empty chat.

No SDK dependency bump, generated protocol change, new setting, or telemetry change is included.

Review follow-up

Commit 042e0ebd701 addresses the three PR review threads and the two findings from the additional three-agent review:

  • Scope both live and historical child discovery to (origin.chat, origin.toolCallId) so reused tool IDs cannot redirect a pill to a sibling's child.
  • Preserve subagent metadata and observe child state for other-client launches.
  • Reuse completed same-client snapshots rather than emitting duplicate parent invocations.
  • Restore nested subagent resources and availability from the correctly scoped catalog entries.
  • Do not use success-worded past-tense labels for denied or skipped tools.
  • Keep resolved availability on the child observation so local tool preparation cannot overwrite it, and preserve synchronous setup when child state is already hydrated so nested client tools retain their grouping.

Commit 892e443ecd7 corrects a follow-up regression where the availability guard hid the entire rich pill and a completed background launch fell back to the legacy text header. Presentation now remains rich while child navigation is pending. Tests use the real toolbar/action view together, and new dark/light component fixtures cover pending, running, and unavailable states.

Commit 0ae69d43141 handles child subscription errors throughout the observation lifetime, not only during initial hydration. A later error clears availability and activity, freezes timing, releases the failed observer, and permits catalog-driven recovery. The metadata contract now explicitly distinguishes prospective resources from readiness and documents legacy behavior when availability is undefined.

Validation

  • 705 affected unit tests passed using the existing Electron test runner.
  • npm run typecheck-client passed.
  • Targeted ESLint for changed TypeScript files passed.
  • Targeted CSS lint passed.
  • git diff --check passed.

Regression coverage includes:

  • The observed 15-second subscription failure followed by chat-catalog discovery at 41 seconds, after the background launch tool has completed.
  • Initially failed and pending-then-failed child subscriptions, and provisional-to-discovered resource replacement.
  • Child completion updating restored parent pills.
  • Completed and serialized tool labels.
  • Actual computed CSS visibility before and after action readiness.
  • Clearing the spinner/activity row, publishing completed ARIA state, freezing duration, and retaining a working open action after completion.
  • Missing-child load errors and read-only state.
  • Existing reconnect behavior that must not duplicate the task card or split the streamed response.
  • Reused tool-call IDs across parent chats, nested restored availability, and server/same-client/other-client reconnect parity.
  • Denied/skipped tool labels for live and serialized invocations.
  • Existing client-tool execution and nested grouping behavior.
  • The real rich-header toolbar remains visible across pending navigation and completed background launches.
  • Browser validation of all six pending/running/unavailable fixtures in dark and light themes, including the resolved open action and keyboard-accessible output disclosure.
  • Post-hydration errors on active and completed children, including error-only events without a state-change event, published unavailability, subscription cleanup, and recovery.

The affected suites cover AgentHostChatContribution, AgentHostClientTools, stateToProgressAdapter, ChatSubagentContentPart, OpenSubagentChatActionViewItem, and the collapsed subagent history renderer.

Manual follow-up

The exact reported sequence has been reproduced in automated regression tests, and the rich-header components have been validated in the integrated browser. The changes have not been manually replayed against a live SDK session in the reporter's installed Insiders window. Keeping this PR in draft for review and real-window confirmation.

Suggested verification: start background subagents with delayed startup; confirm pills become openable when the child chats resolve, show tool activity without opening the child first, stop showing busy state when the corresponding background-completion notification arrives, and remain correct after reopening the parent chat.

Recover failed child subscriptions through chat catalog discovery, keep restored subagent pills observable, and gate opening on resolved child chats. Preserve completed tool labels and surface missing-chat errors instead of blank editable editors.

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

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.

Copilot review overview

🟡 Changes recommended

Catalog correlation and restored nested/cross-client subagent availability remain incorrect in supported scenarios.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review tier: Balanced
Findings: 1 High severity · 2 Medium severity

New issues introduced by this change (3)
Severity Finding
High severity src/​vs/​workbench/​contrib/​chat/​browser/​agentSessions/​agentHost/​agentHostSessionHandler.ts — The catalog projection drops origin.chat and later matches only toolCallId. Tool-call ids are…
Medium severity src/​vs/​workbench/​contrib/​chat/​browser/​agentSessions/​agentHost/​stateToProgressAdapter.ts — This new live-invocation path does not recover restored subagents contributed by another client.…
Medium severity src/​vs/​workbench/​contrib/​chat/​browser/​agentSessions/​agentHost/​stateToProgressAdapter.ts — Hard-coding serialized subagents as unavailable leaves restored nested subagents permanently hidden…
What changed in this PR

Fixes subagent lifecycle synchronization, availability, activity labels, and missing-chat handling.

Changes:

  • Recovers child chats through catalog discovery and subscription retries.
  • Gates opening on resolved availability and improves completion/activity UI.
  • Adds regression coverage for restore, failure, and delayed-start scenarios.
File Description
chatSubagentContentPart.test.ts Tests pill state, visibility, and labels.
stateToProgressAdapter.test.ts Tests initial availability metadata.
agentHostChatContribution.test.ts Tests recovery, restoration, and load errors.
chatService.ts Adds subagent chat availability metadata.
chatSubagentOpenChat.css Hides unavailable pill actions.
chatSubagentOpenChat.ts Gates opening on chat availability.
chatSubagentContentPart.ts Improves completed and serialized activity rendering.
stateToProgressAdapter.ts Preserves observable subagent invocations and availability.
agentHostSessionHandler.ts Adds catalog recovery and subscription-error handling.

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

Scope child discovery to the spawning chat, restore cross-client and nested subagent availability, and adopt completed client snapshots without duplicate pills. Keep cancelled tools from showing success labels and preserve synchronous setup for already-hydrated child chats.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Separate rich pill visibility from chat navigation readiness, preserve activity after the launch tool completes, and keep unavailable output accessible. Cover the actual toolbar lifecycle and add dark/light fixtures for pending, running, and unavailable child chats.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

Screenshot Changes

Base: abb16775 Current: b2c8d5f8

1 insignificant change(s) omitted (≤20 px, Δ≤2). See CI logs for details.

Added (6)

chat/chatSubagentContent/Pending/Dark

current

chat/chatSubagentContent/Pending/Light

current

chat/chatSubagentContent/Running/Dark

current

chat/chatSubagentContent/Running/Light

current

chat/chatSubagentContent/Unavailable/Dark

current

chat/chatSubagentContent/Unavailable/Light

current

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.

Copilot review overview

🟡 Changes recommended

Post-hydration child subscription failures can leave subagent pills stale and incorrectly openable.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review tier: Balanced
Findings: 1 Medium severity · 1 Low severity

New issues introduced by this change (2)
Severity Finding
Medium severity src/​vs/​workbench/​contrib/​chat/​browser/​agentSessions/​agentHost/​agentHostSessionHandler.ts — This marks the child permanently available after the first snapshot, but the subscription can enter…
Low severity src/​vs/​workbench/​contrib/​chat/​common/​chatService/​chatService.ts — The existing chatResource contract still says the URI is present only for a separately openable…
Issues resolved since last review (3)
Severity Finding
Medium severity src/​vs/​workbench/​contrib/​chat/​browser/​agentSessions/​agentHost/​stateToProgressAdapter.ts — Hard-coding serialized subagents as unavailable leaves restored nested subagents permanently hidden… View resolved comment
Medium severity src/​vs/​workbench/​contrib/​chat/​browser/​agentSessions/​agentHost/​stateToProgressAdapter.ts — This new live-invocation path does not recover restored subagents contributed by another client.… View resolved comment
High severity src/​vs/​workbench/​contrib/​chat/​browser/​agentSessions/​agentHost/​agentHostSessionHandler.ts — The catalog projection drops origin.chat and later matches only toolCallId. Tool-call ids are… View resolved comment

Comment thread src/vs/workbench/contrib/chat/common/chatService/chatService.ts Outdated
Observe child subscription failures throughout the observation lifetime, clear stale activity and availability, release the failed observer, and allow subsequent catalog recovery. Clarify prospective chat resources and legacy undefined availability semantics.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

2 participants