Files
claude-agent-acp/src/tests/acp-scenarios/__snapshots__/v2/compaction-legacy.jsonl
Ben Brandt 23b8ebf8c2 refactor: report tool calls on the experimental ACP v2 surface (#1231)
First part of step 4 of opt-in ACP v2 support (#1217, #1219, #1226,
#1230): the v2 surface now sends the agent's tool calls. Nothing changes
on ACP v1.

## Change

`src/v2/tool-call.ts` maps the agent's v1 tool call reports to v2:
- **One message.** v1 reports a new tool call with `tool_call` and
changes it with `tool_call_update`. v2 has one `tool_call_update` that
upserts by `toolCallId`, so both become that.
- **`null` is left out.** Both versions leave an omitted field unchanged
and replace `content` and `locations` as whole arrays. They differ on
`null`: in v1 it leaves a field unchanged (v1's `name` docs say so
explicitly), in v2 it clears it. The agent doesn't send `null` fields
today; a unit test pins the rule.
- **Content blocks pass through.** v2's content blocks are a superset of
v1's.
- **Diff and terminal content still throw**, until their own parts of
step 4.

## Scenario suite

Of the 30 scenarios that stopped at their first `tool_call`:

| Status now | Scenarios |
|---|---|
| passes | 17: `read`, `grep-and-glob`, `bash-error`, `bash-background`,
`skill`, `ask-user-question`, `memory-recall`, `permission-denied`,
`tool-progress`, `task-output-and-stop`, four subagent scenarios, the
three compaction scenarios |
| stops at a permission request (step 5) | 9 |
| stops at diff content (next part of step 4) | 4 |

The 17 new golden files are in
`src/tests/acp-scenarios/__snapshots__/v2/`.

**One new check.** In v1, a `tool_call_update` for an id the client
hasn't seen is an orphan, and clients drop it. In v2 the same message
creates a tool call. A stray update would show up as a blank tool call,
and the schema can't catch that. So every scenario recording, including
those that stop, must give each tool call a title in its first report.
It passes everywhere; making the first report lose its title fails it in
30 scenarios.

## Noted for later, not changed here

- **`_meta` becomes stored state.** In v1, a report's `_meta` belongs to
that report. In v2 it's stored on the tool call, and a concrete value
replaces it. So a v2 client keeps only the last report's
`_meta.claudeCode`: in `permission-denied`, the denial's `toolResponse`
is replaced by the result's `{ toolName }`. No v2 client reads these
keys yet.
- **v2 has a `cancelled` tool status.** v1 reports an interrupted tool
as `failed` with `_meta.claudeCode.nonExecutionKind`. Mapping it to
`cancelled` means deciding where that fact lives.

## Verification

Build, lint and all 2353 tests pass.
2026-10-02 17:20:13 +02:00

13 lines
3.6 KiB
JSON
Generated

{"kind":"response","method":"initialize","payload":{"_meta":{"steering":{"supported":true}},"authMethods":[],"capabilities":{"_meta":{"authStatus":{},"claudeCode":{"promptQueueing":true}}},"info":{"name":"@agentclientprotocol/claude-agent-acp","title":"Claude Agent","version":"<version>"},"protocolVersion":2}}
{"kind":"response","method":"session/new","payload":{"configOptions":[{"category":"mode","configId":"mode","currentValue":"default","description":"Session permission mode","name":"Mode","options":[{"description":"Always ask before making changes","name":"Manual","value":"default"},{"description":"Automatically accept all file edits","name":"Accept edits","value":"acceptEdits"},{"description":"Create a plan before making changes","name":"Plan","value":"plan"},{"description":"Claude handles permission decisions","name":"Auto","value":"auto"},{"description":"Accepts all permissions","name":"Bypass permissions","value":"bypassPermissions"}],"type":"select"},{"category":"model","configId":"model","currentValue":"claude-sonnet-4-6","description":"AI model to use","name":"Model","options":[{"description":"Fast","name":"Claude Sonnet 4.6","value":"claude-sonnet-4-6"}],"type":"select"}],"sessionId":"<session>"}}
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"availableCommands":[{"description":"Show the MCP servers and their status, or reconnect, enable, or disable a server","input":{"hint":"[reconnect|enable|disable [<server>|all]]","type":"text"},"name":"mcp"}],"sessionUpdate":"available_commands_update"}}}
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"content":[{"text":"prompt 1","type":"text"}],"messageId":"<id-1>","sessionUpdate":"user_message"}}}
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"state_update","state":"running"}}}
{"kind":"response","method":"session/prompt","payload":{"messageId":"<id-1>"}}
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"claudeCode":{"toolName":"compact"}},"kind":"think","sessionUpdate":"tool_call_update","status":"in_progress","title":"Compact conversation","toolCallId":"00000000-0000-4000-8000-000000000001"}}}
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"claudeCode":{"toolName":"compact"}},"sessionUpdate":"tool_call_update","status":"in_progress","toolCallId":"00000000-0000-4000-8000-000000000001"}}}
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"claudeCode":{"toolName":"compact"}},"rawOutput":{"durationMs":7,"postTokens":100,"preTokens":1000,"trigger":"automatic"},"sessionUpdate":"tool_call_update","status":"completed","toolCallId":"00000000-0000-4000-8000-000000000001"}}}
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"sessionUpdate":"usage_update","size":200000,"used":100}}}
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"cost":{"amount":0,"currency":"USD"},"sessionUpdate":"usage_update","size":200000,"used":100}}}
{"kind":"notification","method":"session/update","payload":{"sessionId":"<session>","update":{"_meta":{"quota":{"model_usage":[],"token_count":{"cachedInputTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"reasoningOutputTokens":0,"totalTokens":0}}},"sessionUpdate":"state_update","state":"idle","stopReason":"end_turn","usage":{"cachedReadTokens":0,"cachedWriteTokens":0,"inputTokens":0,"outputTokens":0,"totalTokens":0}}}}