Skip to content

feat(acp-adapter): forward subagent lifecycle and streams over ACP - #2484

Open
esempe wants to merge 2 commits into
MoonshotAI:mainfrom
esempe:acp-subagent-events
Open

feat(acp-adapter): forward subagent lifecycle and streams over ACP#2484
esempe wants to merge 2 commits into
MoonshotAI:mainfrom
esempe:acp-subagent-events

Conversation

@esempe

@esempe esempe commented Jul 31, 2026

Copy link
Copy Markdown

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 isFromMainAgent guard, so a client sees the parent Agent tool call and nothing until it completes.

What changed

All additive; no existing frame changes.

  • subagent.spawned/started/suspended/completed/failed are emitted as ordinary tool_call / tool_call_update updates with a _meta.kimiCode.subagent payload (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>.
  • The subagent's own assistant.delta / thinking.delta / tool.call.started / .delta / tool.progress / tool.result frames are forwarded (guard relaxed in runTurnBody) tagged with _meta.kimiCode.subagentId so clients can nest them. Turn-scoped bookkeeping (currentTurnId, turn.started/turn.ended settling, 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.
  • A subagent's TodoList display no longer leaks into the session plan (plan emission is main-agent-only now).
  • Capability advertised as agentCapabilities._meta.kimiCode.subagentEvents per the spec's SHOULD.
  • Standard frames + _meta rather than a custom sessionUpdate kind 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 acp server (spawn → started → nested Bash tool call → completed with summary/usage), plus unit tests for every mapper and the dispatch.

Checklist

  • I have read the CONTRIBUTING document.
  • I have linked a related issue, or explained the problem above.
  • I have added tests that prove my feature works.
  • Ran gen-changesets skill, or this PR needs no changeset.
  • Ran gen-docs skill, or this PR needs no doc update.

esempe added 2 commits July 31, 2026 17:22
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-bot

changeset-bot Bot commented Jul 31, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 6774cce

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@moonshot-ai/kimi-code Patch

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 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),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 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 👍 / 👎.

Comment on lines +1056 to +1058
if (event.type === 'subagent.spawned') {
conn
.sessionUpdate(subagentSpawnedToSessionUpdate(sessionId, event))

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge 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 👍 / 👎.

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.

ACP: subagent work is invisible — forward subagent lifecycle and streams over session updates

1 participant