Skip to content

fix(server): route Copilot ACP subagent output into subagent threads - #17714

Merged
maria-rcks merged 1 commit into
pingdotgg:mainfrom
maria-rcks:fix/copilot-acp-subagent-routing
Oct 10, 2026
Merged

maria-rcks merged 1 commit into
pingdotgg:mainfrom
maria-rcks:fix/copilot-acp-subagent-routing

Conversation

@maria-rcks

Copy link
Copy Markdown
Collaborator

Closes #17267

Copilot CLI over ACP streams subagent text as plain agent_message_chunks on the parent session, with nothing on them to say which subagent wrote them. With parallel subagents, the parent assistant message became interleaved word salad, and no subagent rows or child threads were created.

Copilot can attribute that text, but only after the client opts into its raw event feed through initialize clientCapabilities._meta["github.com/copilot"].events. Then every chunk is preceded inline by an assistant.*_delta that carries the spawning task tool call id. Verified against Copilot CLI 1.0.95: 78 of 78 chunks paired with their delta across three parallel subagents, with no mismatches.

  • copilotAcp.ts subscribes to the deltas and subagent.* lifecycle events. It routes each chunk whose text matches the preceding delta, and each child tool call tagged with _meta["github.com/copilot"].agentId, onto a per-task child session. A chunk with no matching delta stays on the parent, so the fallback is today's behavior.
  • The task tool becomes a subagent with its own child thread through the existing extractSubagentUpdate path. Background (mode: "background") subagents finish on subagent.completed.
  • This is a per-agent exception in the registry adapter, enabled for github-copilot-cli and for local agents whose command is copilot. The maintainer approved it on the same terms as the Devin hooks.

Before: three parallel subagents' text and thoughts are shredded into the parent turn.

Before: subagent text interleaved into the parent assistant message

After: same prompt, same Copilot build. The parent reply is clean and each subagent has its own row and result.

After: parent reply with three separate subagent rows

After: a subagent child thread holding its own table

https://uploads-production-47e4.up.railway.app/files/559fe07b-373b-470c-8e76-800a6ee9643a/after-subagents-trim.mp4

Verification

  • Real app (web dev server, local Copilot 1.0.95 instance): reproduced the bug, then confirmed the fix with three parallel sync subagents and with one background subagent waited on via read_agent.
  • Added a replay test in AcpAdapterV2.test.ts using wire shapes captured from Copilot. It covers interleaved chunks from two sync subagents plus a background one, child tool routing, and the parent text staying intact. AcpAdapterV2 and AcpRegistryAdapterV2 tests pass (122/122), and typecheck passes for server, provider-acp, and provider-acp-registry.
  • Not run live: the registry-installed Copilot path. It uses the same hooks, keyed on the registry id.

🤖 Generated with Claude Code

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:L 100-499 changed lines (additions + deletions). labels Oct 10, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 10, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR adds substantial stateful ACP event routing and automatically changes existing Copilot sessions so output and tool calls are projected into child subagent threads. The replay test covers representative interleaving, but the behavior spans shared orchestration hooks and introduces a new provider-specific runtime path.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 10, 2026

Copy link
Copy Markdown

Review in Change Stack →Review in Change Stack →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Path: .coderabbit.config.ts
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: f51280ff-029a-49e2-afbd-9e35c9493629

📥 Commits

Reviewing files that changed from the base of the PR and between 4ea7356 and 84e06cc.


📒 Files selected for processing (5)
  • apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.test.ts
  • packages/provider-acp-registry/src/server/adapter.ts
  • packages/provider-acp-registry/src/server/copilotAcp.ts
  • packages/provider-acp-registry/src/testing.ts
  • packages/provider-acp/src/server/adapter.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 2 remain after this review.



📝 Walkthrough

Walkthrough

The ACP registry adapter now detects Copilot agents and configures Copilot-specific capabilities and subagent routing. Copilot subagent messages and tool calls are mapped to child sessions. An adapter test covers interleaved output from synchronous and background subagents.

Changes

Copilot ACP subagent routing

Layer / File(s) Summary
Copilot event and task routing
packages/provider-acp-registry/src/server/copilotAcp.ts
Tracks Copilot subagent lifecycle and task attribution. Routes matching message, reasoning, and tool updates to child sessions, and extracts task status and output.
ACP registry adapter wiring
packages/provider-acp/src/server/adapter.ts, packages/provider-acp-registry/src/server/adapter.ts
Types client capability metadata from the ACP schema. Detects Copilot registry agents and matching local commands, then supplies Copilot capabilities and routing hooks.
Adapter routing validation
packages/provider-acp-registry/src/testing.ts, apps/server/src/orchestration-v2/Adapters/AcpAdapterV2.test.ts
Exports Copilot routing helpers for tests. Tests interleaved synchronous and background subagent output, child tool projection, and parent-thread output.

Priority: ⬆️ High

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: High

Suggested reviewers: juliusmarminge


Merge Risk | ⚪ Minimal · up to 84e06

Merge Risk: ⚪ Minimal · up to 84e06

This change routes Copilot subagent output into child threads and keeps it out of the parent message. It applies only to Copilot agents, and no concrete merge-blocking risk was identified.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 84e06

The change does not grant additional tool permissions. The main risk is incorrect conversation or tool attribution between sessions sharing a configuration, because routing state is shared and depends on provider-supplied identifiers. Cancellation and background completion also depend on event details that remain unverified.

Retained concerns

  • Low · security · inferred: Attribution state is shared across opened runtimes, but the new event handler keys mutations only by provider-supplied sessionId. If a stream can supply another session's identifier, or identifiers collide, it can overwrite that session's pending delta or agent-to-task mapping. Upstream rejection of foreign identifiers was not established. Receiving controls restrict projection to the current parent and known child lineage, limiting the supported concern to attribution integrity rather than additional execution authority or demonstrated data disclosure.
Security review details

Security Blast Radius

  • inferred — The conditional attribution concern reaches sessions sharing the same adapter instance, not independently configured instances. A successful poisoning would additionally require a matching victim chunk or mapped tool update and usable child lineage. No inspected change grants filesystem, terminal, credential, or tenant authority.

Security Findings and Attack Paths

  • inferred — The conditional attack path starts with control of a raw ACP event stream, supplies a foreign session identifier to mutate shared attribution, and influences how a subsequent notification in that session is projected. Ordinary prompt text was not shown to control these protocol fields, and upstream foreign-session filtering remains unresolved; this is not a verified exploit.

Trust Boundaries and Controls

  • observed — Completion callbacks require the active root session, a current runtime generation, and no direct-stop quarantine, then resolve known active or carryover children. Permission requests remain on a separate policy-and-approval path; notification attribution does not select approval outcomes.

Resilience and Maintainability Implications

  • observed — Routing entries release only when no delta and no agent mapping remain; the returned hooks expose no reset for interruption or runtime teardown. Existing direct-stop handling terminalizes visible children and clears carryover state separately. Missing terminal toolCallId causes the new handler to return without finishing a background child, but whether supported providers emit that shape is unverified.

Hardening Proposals

  • proposed — Bind attribution mutations to their delivering runtime or validated root-session owner. Define reset and reconciliation behavior for interruption and missing terminal identity while preserving intentionally live background children. Establish the provider's identifier and terminal-event guarantees before relying on them for isolation and recovery.

Pre-merge checks | Passed 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check Passed The title clearly and concisely describes the main change: routing Copilot ACP subagent output into subagent threads.
Description check Passed The description covers the problem, implementation, scope, linked issue, screenshots, recording, verification results, and known limitations. It is sufficiently complete despite not using every templa…
Linked Issues check Passed Issue #17267 requires Copilot ACP subagent output to stay out of the parent message and to create child projections when possible. copilotAcp.ts opts into Copilot raw events, matches each delta to t…
Out of Scope Changes check Passed The changes stay within issue #17267. Copilot event capability metadata, registry detection, routing and subagent extraction implement the required fix. The adapter type update supports the metadata s…

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@maria-rcks
maria-rcks merged commit 818e2be into pingdotgg:main Oct 10, 2026
29 checks passed
github-actions Bot added a commit to omarcresp/t3code-flake that referenced this pull request Oct 11, 2026
## What's Changed
* fix(pi): preserve tool images and structured results by @StiensWout in pingdotgg/t3code#17851
* fix(server): Claude 5 task lists reach the tasks drawer by @Mnigos in pingdotgg/t3code#14964
* fix(web): find bar and thread details panel stop covering each other by @MatthewFeroz in pingdotgg/t3code#17858
* fix(web): use server metadata for file chip icons by @Yash-Singh1 in pingdotgg/t3code#17923
* fix(desktop): copy images from HTML previews by @Bil0000 in pingdotgg/t3code#17555
* docs(pi): update installation and remote login guidance by @StiensWout in pingdotgg/t3code#17836
* fix(pi): preserve native abort outcomes by @StiensWout in pingdotgg/t3code#17853
* fix(pi): keep thinking defaults specific to each model by @StiensWout in pingdotgg/t3code#17835
* fix(pi): preserve shell command exit codes by @StiensWout in pingdotgg/t3code#17834
* fix(pi): expire and cancel extension approvals by @StiensWout in pingdotgg/t3code#17840
* feat(pi): include native sessions in usage reports by @StiensWout in pingdotgg/t3code#17848
* fix(server): route Copilot ACP subagent output into subagent threads by @maria-rcks in pingdotgg/t3code#17714
* fix(web): composer banner titles truncate beside their icon instead of wrapping by @maria-rcks in pingdotgg/t3code#17699
* fix(server): Muse turns no longer fail on Windows by @ntindle in pingdotgg/t3code#17163
* fix(pi): allow known read-only T3 tools without approval by @StiensWout in pingdotgg/t3code#17852
* fix: worktree threads keep their worktree when the agent starts, and messages sent during setup queue by @maria-rcks in pingdotgg/t3code#17654
* fix(server): keep Claude workflows alive while they report progress by @maria-rcks in pingdotgg/t3code#17715
* fix(web): media preview centers its content and pins the close button by @maria-rcks in pingdotgg/t3code#17951
* fix(server): threads without a project no longer need Git installed by @t3dotgg in pingdotgg/t3code#17959
* fix(web): toggling tools and thinking at the bottom keeps you at the bottom by @t3dotgg in pingdotgg/t3code#17954
* fix(web): Compact chip follows Claude's real prompt cache TTL by @t3dotgg in pingdotgg/t3code#17945
* fix(usage): bound OpenCode history reads to prevent backend OOM by @Yash-Singh1 in pingdotgg/t3code#17961
* refactor: format diff line counts through one shared helper by @maria-rcks in pingdotgg/t3code#17948
* fix: new projects start their first thread in the project folder, not a worktree by @t3dotgg in pingdotgg/t3code#17371

## New Contributors
* @ntindle made their first contribution in pingdotgg/t3code#17163

**Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261010.2948...v0.0.46-nightly.20261011.2955

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261011.2955
github-actions Bot added a commit to davidvanderklay/t3code-flake that referenced this pull request Oct 11, 2026
## What's Changed
* fix(pi): preserve tool images and structured results by @StiensWout in pingdotgg/t3code#17851
* fix(server): Claude 5 task lists reach the tasks drawer by @Mnigos in pingdotgg/t3code#14964
* fix(web): find bar and thread details panel stop covering each other by @MatthewFeroz in pingdotgg/t3code#17858
* fix(web): use server metadata for file chip icons by @Yash-Singh1 in pingdotgg/t3code#17923
* fix(desktop): copy images from HTML previews by @Bil0000 in pingdotgg/t3code#17555
* docs(pi): update installation and remote login guidance by @StiensWout in pingdotgg/t3code#17836
* fix(pi): preserve native abort outcomes by @StiensWout in pingdotgg/t3code#17853
* fix(pi): keep thinking defaults specific to each model by @StiensWout in pingdotgg/t3code#17835
* fix(pi): preserve shell command exit codes by @StiensWout in pingdotgg/t3code#17834
* fix(pi): expire and cancel extension approvals by @StiensWout in pingdotgg/t3code#17840
* feat(pi): include native sessions in usage reports by @StiensWout in pingdotgg/t3code#17848
* fix(server): route Copilot ACP subagent output into subagent threads by @maria-rcks in pingdotgg/t3code#17714
* fix(web): composer banner titles truncate beside their icon instead of wrapping by @maria-rcks in pingdotgg/t3code#17699
* fix(server): Muse turns no longer fail on Windows by @ntindle in pingdotgg/t3code#17163
* fix(pi): allow known read-only T3 tools without approval by @StiensWout in pingdotgg/t3code#17852
* fix: worktree threads keep their worktree when the agent starts, and messages sent during setup queue by @maria-rcks in pingdotgg/t3code#17654
* fix(server): keep Claude workflows alive while they report progress by @maria-rcks in pingdotgg/t3code#17715
* fix(web): media preview centers its content and pins the close button by @maria-rcks in pingdotgg/t3code#17951
* fix(server): threads without a project no longer need Git installed by @t3dotgg in pingdotgg/t3code#17959
* fix(web): toggling tools and thinking at the bottom keeps you at the bottom by @t3dotgg in pingdotgg/t3code#17954
* fix(web): Compact chip follows Claude's real prompt cache TTL by @t3dotgg in pingdotgg/t3code#17945
* fix(usage): bound OpenCode history reads to prevent backend OOM by @Yash-Singh1 in pingdotgg/t3code#17961
* refactor: format diff line counts through one shared helper by @maria-rcks in pingdotgg/t3code#17948
* fix: new projects start their first thread in the project folder, not a worktree by @t3dotgg in pingdotgg/t3code#17371

## New Contributors
* @ntindle made their first contribution in pingdotgg/t3code#17163

**Full Changelog**: pingdotgg/t3code@v0.0.46-nightly.20261010.2948...v0.0.46-nightly.20261011.2955

Upstream release: https://github.com/pingdotgg/t3code/releases/tag/v0.0.46-nightly.20261011.2955
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Copilot ACP subagent output is interleaved into the parent assistant message (garbled text, laggy timeline)

1 participant