Heartbeat beats reach the bridge under a derived `<tool_use_id>-heartbeat-<n>` id that no `tool_call` was ever emitted for, and the handler forwarded it verbatim. Clients that expect a `tool_call_update` to reference a tool call they have been told about saw a reference they could not resolve, and since the counter makes every beat a fresh id, nothing deduplicated them: a ten-minute Bash call produced roughly twenty phantom entries. Zed renders each as a failed "Tool call not found" card; compozy/compozy#257 and agent-of-empires/agent-of-empires#3084 report the same shape. Strip the derived suffix so the beat is reported against the call it describes, and drop it when that call is not in `emittedToolCalls`. Ids enter that set at `tool_use` and leave it at `tool_result`, so the guard covers both an id that was never announced and a straggling beat that races past completion, which would otherwise flip a call the client has seen finish back to `in_progress`. The SDK sets `heartbeat: true` on these messages, but that flag alone cannot recover the original id, and `parent_tool_use_id` is the subagent parent rather than the call being reported on, so the suffix still has to be stripped. `tool_progress` had no test coverage. Add cases for the retarget across a climbing counter, the not-in-flight drop, meta pass-through, and an unsuffixed id being left alone. Fixes #913 --------- Signed-off-by: Daan De Meyer <daan@amutable.com> Co-authored-by: Ben Brandt <benjamin.j.brandt@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
ACP adapter for the Claude Agent SDK
Use Claude Agent SDK from ACP-compatible clients!
This tool implements an ACP agent by using the official Claude Agent SDK, supporting:
- Context @-mentions
- Images
- Tool calls (with permission requests)
- Following
- Edit review
- TODO lists
- Nested subagent transcripts
- Interactive (and background) terminals
- Custom Slash commands
- Client MCP servers
Learn more about the Agent Client Protocol.
Nested subagent transcripts
ACP 1.2 has no standard subagent tool kind or nested-message relationship. Clients that can render
nested transcripts can opt in with clientCapabilities._meta["subagent-transcript"] = true.
The agent then forwards subagent text, thinking, and tool calls, relating nested updates to the
launching Agent/Task call through _meta.claudeCode.parentToolUseId. Agent/Task calls are marked
with _meta.claudeCode.subagent = true.
Clients that do not advertise the capability retain the legacy flattened behavior. In both modes, the normal Agent/Task tool result is preserved as the protocol-compatible fallback.
Contribution Policy
This project does not require a Contributor License Agreement (CLA). Instead, contributions are accepted under the following terms:
By contributing to this project, you agree that your contributions will be licensed under the Apache License, Version 2.0. You affirm that you have the legal right to submit your work, that you are not including code you do not have rights to, and that you understand contributions are made without requiring a Contributor License Agreement (CLA).