From c8dbe6567afecc85524e9a71253783e09c99ca27 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Thu, 18 Jun 2026 17:34:50 +0800 Subject: [PATCH] docs(acp): clarify _meta is a spec extensibility point; the terminal keys are the Zed convention --- .../implemented/2026-06-18-acp-terminal-and-tool-rendering.md | 4 ++-- packages/acp/README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/rfc/implemented/2026-06-18-acp-terminal-and-tool-rendering.md b/docs/rfc/implemented/2026-06-18-acp-terminal-and-tool-rendering.md index 7817b1e441..db0f744c1f 100644 --- a/docs/rfc/implemented/2026-06-18-acp-terminal-and-tool-rendering.md +++ b/docs/rfc/implemented/2026-06-18-acp-terminal-and-tool-rendering.md @@ -17,7 +17,7 @@ Studying the two reference agents (2026-06-18) shows neither uses `terminal/crea - **`claude-agent-acp`** (`tools.ts`, `acp-agent.ts`): gated on `clientCapabilities._meta.terminal_output`. The `tool_call` carries `content: [{ type: 'terminal', terminalId }]` and `_meta.terminal_info.{ terminal_id, cwd }`; output/exit arrive on the `tool_call_update`'s `_meta.terminal_output.{ terminal_id, data }` and `_meta.terminal_exit.{ terminal_id, exit_code, signal }`. - **`codex-acp`** (`CodexToolCallMapper.ts`, `TerminalOutputMode.ts`): same `terminal_info` on the call; output via `_meta.terminal_output` (full) or `_meta.terminal_output_delta` (incremental), selected from the same `_meta.terminal_output` capability. -Zed's side (`crates/agent_servers/src/acp.rs`, verified): on a `ToolCall` whose `_meta.terminal_info.terminal_id` is set, it registers a **display-only** terminal (header = `terminal_info.cwd`, label = `tool_call.title`); on a `ToolCallUpdate`, `_meta.terminal_output.data` writes to that terminal and `_meta.terminal_exit.{exit_code,signal}` sets the status. It advertises the capability as `clientCapabilities._meta.terminal_output = true`. This is an off-spec `_meta` extension, but it is the de-facto contract for the Zed integration and the only way to get the terminal card while keeping execution agent-side. +Zed's side (`crates/agent_servers/src/acp.rs`, verified): on a `ToolCall` whose `_meta.terminal_info.terminal_id` is set, it registers a **display-only** terminal (header = `terminal_info.cwd`, label = `tool_call.title`); on a `ToolCallUpdate`, `_meta.terminal_output.data` writes to that terminal and `_meta.terminal_exit.{exit_code,signal}` sets the status. It advertises the capability as `clientCapabilities._meta.terminal_output = true`. `_meta` itself is a spec-blessed ACP extensibility point (typed `{[k]: unknown} | null` on `ToolCall`/`ToolCallUpdate`); the *specific keys* here (`terminal_info`/`terminal_output`/`terminal_exit`) are a Zed convention, not part of the ACP spec — but they are the de-facto contract for the Zed integration and the only way to get the terminal card while keeping execution agent-side. ## Decision @@ -30,7 +30,7 @@ Keep `dsh-bash` agent-side execution; render the terminal card via the `_meta` c ## Risks / trade-offs -- **Off-spec `_meta`.** The terminal card rides on a Zed-specific `_meta` extension, not the ACP terminal sub-protocol. A client that doesn't recognize it still gets the text fallback (the capability gate ensures we only emit it when the client opted in via `_meta.terminal_output`), so a non-Zed client is never worse off. If ACP later standardizes agent-executed terminals, migrate to that and drop the `_meta`. +- **Zed-convention `_meta` keys.** The terminal card rides on Zed-specific keys (`terminal_info`/`terminal_output`) inside ACP's spec-blessed `_meta` extensibility point, NOT on the ACP terminal sub-protocol. A client that doesn't recognize the keys still gets the text fallback (the capability gate ensures we only emit them when the client opted in via `_meta.terminal_output`), so a non-Zed client is never worse off. If ACP later standardizes agent-executed terminals, migrate to that and drop the convention keys. - **Capability honesty.** Emit terminal metadata ONLY when the client advertised `_meta.terminal_output`; the text fallback is the contract for everyone else and must never regress. Covered by a no-capability test asserting the ` ```console ` path. - **terminalId collisions.** Deriving it from the per-call `callId` keeps it unique within a session and stable across the call/result pair; never reuse one across calls. - **Provider-neutral vocabulary creep.** The terminal presentation widens the `dsh-tools` surface; keep it neutral (no ACP types leak into `dsh-tools`) and only as rich as a second UI consumer would also want. diff --git a/packages/acp/README.md b/packages/acp/README.md index 3cb311a43e..4b6d81dae5 100644 --- a/packages/acp/README.md +++ b/packages/acp/README.md @@ -53,7 +53,7 @@ A tool whose call IS a shell command (`bash`) can render as a real **terminal ca - `tool_call`: `content:[{type:'terminal', terminalId}]` + `_meta.terminal_info.{terminal_id, cwd}` — the terminal id is the harness `callId`; the cwd is the tool's explicit `terminal.cwd` if it has one, else the session's workspace cwd (the bridge fills that, since the pure tool presenter can't see it). - `tool_call_update`: `_meta.terminal_output.{terminal_id, data}` — the captured output, attached at completion. -When the client does NOT advertise the capability, none of the `_meta`/terminal content is emitted and the ` ```console ` text block (above) is the rendering — so a non-Zed client is never worse off. This is an off-spec Zed `_meta` extension, not the ACP `terminal/create` sub-protocol: that would make the editor execute the command, bypassing `dsh-bash`'s sandbox/env-scrub/ownership/cwd. The exit-status pill, live streaming, and command classification are follow-ups. See [the terminal-rendering RFC](../../docs/rfc/implemented/2026-06-18-acp-terminal-and-tool-rendering.md). +When the client does NOT advertise the capability, none of the `_meta`/terminal content is emitted and the ` ```console ` text block (above) is the rendering — so a non-Zed client is never worse off. The `_meta` object is ACP's spec-blessed extensibility point; the specific `terminal_info`/`terminal_output` keys are a Zed convention, not the ACP `terminal/create` sub-protocol (which would make the editor execute the command, bypassing `dsh-bash`'s sandbox/env-scrub/ownership/cwd). The exit-status pill, live streaming, and command classification are follow-ups. See [the terminal-rendering RFC](../../docs/rfc/implemented/2026-06-18-acp-terminal-and-tool-rendering.md). ## Settle-exactly-once