feat(acp-adapter): forward subagent lifecycle and streams over ACP - #2484
feat(acp-adapter): forward subagent lifecycle and streams over ACP#2484esempe wants to merge 2 commits into
Conversation
subagent.spawned/started/suspended/completed/failed now emit ordinary tool_call/tool_call_update frames with a _meta.kimiCode.subagent payload (parentToolCallId linkage, resultSummary/usage on completion), and the subagent's own assistant/thinking/tool frames are forwarded tagged with _meta.kimiCode.subagentId instead of being dropped at the main-agent guard. Standard frames keep every client compatible; capability is advertised via agentCapabilities._meta.kimiCode.subagentEvents.
Changeset bumps the publishable @moonshot-ai/kimi-code (acp-adapter is private); the kimi-acp reference documents the kimiCode subagent _meta payload (en + zh).
🦋 Changeset detectedLatest commit: 6774cce The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6774cced4f
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| conn | ||
| .sessionUpdate(toolCallStartToSessionUpdate(sessionId, event)) | ||
| .sessionUpdate( | ||
| withSubagentMeta(toolCallStartToSessionUpdate(sessionId, event), event), |
There was a problem hiding this comment.
Namespace subagent tool-call ids
When this branch now forwards non-main tool.call.started events, toolCallStartToSessionUpdate still builds toolCallId from only ${turnId}:${rawToolCallId} and withSubagentMeta only adds metadata. Turn ids are per agent and the adjacent comment says tool ids are only unique per agent, so a main agent and a subagent (or two subagents) can both emit the same wire id such as 0:call_1; ACP clients key tool cards and updates by toolCallId, so a nested tool can update or complete the wrong card. Include the agentId in the wire id (and matching accumulator keys) for non-main agent events.
Useful? React with 👍 / 👎.
| if (event.type === 'subagent.spawned') { | ||
| conn | ||
| .sessionUpdate(subagentSpawnedToSessionUpdate(sessionId, event)) |
There was a problem hiding this comment.
Keep background subagents subscribed
This emits a subagent card for every subagent.spawned, including runInBackground: true, but the listener lives only inside runTurnBody and is unsubscribed as soon as the main agent's turn.ended settles the prompt. For background Agent calls, the parent turn can finish while the child keeps running, so the later subagent.completed/failed and stream frames are dropped and the ACP client is left with a permanently pending/in-progress subagent card. Background subagent lifecycle needs a session-level subscription or another path that outlives the parent prompt.
Useful? React with 👍 / 👎.
Related Issue
Resolve #2482
Problem
See linked issue. In short: over ACP, subagent work is invisible — the adapter drops every non-main-agent event at the
isFromMainAgentguard, so a client sees the parentAgenttool call and nothing until it completes.What changed
All additive; no existing frame changes.
subagent.spawned/started/suspended/completed/failedare emitted as ordinarytool_call/tool_call_updateupdates with a_meta.kimiCode.subagentpayload (subagentId, parentToolCallId, description/swarm/background on spawn; resultSummary/usage/contextTokens on completion; reason on suspend; error on fail). One card per subagent,toolCallId: subagent:<subagentId>.assistant.delta/thinking.delta/tool.call.started/.delta/tool.progress/tool.resultframes are forwarded (guard relaxed inrunTurnBody) tagged with_meta.kimiCode.subagentIdso clients can nest them. Turn-scoped bookkeeping (currentTurnId,turn.started/turn.endedsettling, error handling) stays main-agent-only, so a subagent finishing can never resolve the parent's prompt — the existing test for that was extended, not weakened.plan(plan emission is main-agent-only now).agentCapabilities._meta.kimiCode.subagentEventsper the spec's SHOULD._metarather than a customsessionUpdatekind because v1 SDKs drop unknown kinds (closed zod union); this is the same extension pattern claude-agent-acp uses for subagent progress, and it aligns with the direction of docs(RFD): Subagent Discovery, Delegation and Child Sesssions agentclientprotocol/agent-client-protocol#855.Verified end-to-end against a live
kimi acpserver (spawn → started → nested Bash tool call → completed with summary/usage), plus unit tests for every mapper and the dispatch.Checklist
gen-changesetsskill, or this PR needs no changeset.gen-docsskill, or this PR needs no doc update.