Files
deepseek-harness/docs/acp-feature-support.md
T
Tianyi Cui bcf255fc57 docs: fix review findings in ACP checklist
- session/close: ⚠️ (no handler; SDK dispatch returns method_not_found —
  disconnect/disposal teardown is not the per-session method)
- Codex plan: ⚠️ (CodexEventHandler.updatePlan emits the stable `plan`
  update; the plan-as-text note was stale)
- Codex elicitation: ⚠️ (maps onto session/request_permission; does not
  call elicitation/create|complete)
- Overview: qualify the "both adapters ship" clause — neither drives the
  client terminal/* family and only Claude uses fs/*
- Remove a stray </content> sentinel that rendered literally at EOF
2026-06-20 17:50:58 +08:00

15 KiB

ACP feature support checklist

A structured inventory of Agent Client Protocol (ACP) features and where the harness's ACP bridge (@deepseek-ai/dsh-acp) stands on each. The bridge exposes the harness agent as an ACP server (the agent side of an editor↔agent connection), so "supported" below means the bridge implements the agent's half — answering an agent method, advertising a capability, or calling a client method.

Scope

This tracks the stable ACP v1 surface (schema 1.14.0, schema/v1/schema.json) PLUS the unstable/draft features that the two reference adapters — claude-agent-acp (Claude Code) and codex-acp (OpenAI Codex) — actually ship. A purely-unstable feature that neither reference adapter uses is omitted (see Out of scope).

Legend: supported · ⚠️ partial / fallback · not yet · — n/a. The Stable column marks whether the feature is in the released v1 schema (S) or only the unstable schema (U). The Claude / Codex columns record whether each reference adapter ships it, as a maturity signal.

At a glance

The bridge implements the core prompt-turn loop for N concurrent sessions: initialize, session new/load, prompt, cancel, streamed assistant/thought chunks, tool-call rendering (including Zed terminal cards), and resumable session replay. The largest unbuilt areas are the permission gate (session/request_permission), MCP passthrough, session modes / config options / model selection, slash commands, and agent plans — all of which both reference adapters ship — plus the client filesystem and terminal method families (which the adapters mostly do NOT drive either — see rows 43-49). See Gap summary.

1. Agent methods (client → agent)

Method Stable Bridge Claude Codex Notes
initialize S Negotiates PROTOCOL_VERSION; advertises loadSession + baseline prompt caps. Snapshots the Zed _meta.terminal_output client cap.
authenticate S ⚠️ No-op stub; the bridge advertises no authMethods, so there is nothing to authenticate.
logout S Gated by agentCapabilities.auth.logout; not advertised.
session/new S Maps to agents.create; requires an absolute cwd (becomes the session workspace); rejects non-empty additionalDirectories / mcpServers.
session/load S Maps to agents.resume + full event-log replay; validates persisted cwd before constructing the agent.
session/resume S Reconnect WITHOUT replay; gated by sessionCapabilities.resume. Not advertised.
session/close S No session/close handler — the SDK dispatch returns method_not_found. The bridge tears sessions down on client disconnect / Cordis disposal (cross-cutting, see §8), but that is not the on-demand per-session method.
session/prompt S Maps to agent.send; one in-flight prompt per session; settles on the owning turn's end.
session/cancel S Queue-aware agent.cancel; settles the in-flight prompt cancelled, scoped to the one session.
session/set_mode S Session modes not modeled (see §6 Modes).
session/set_config_option S Config options not modeled.
model selection S No distinct stable session/set_model — model is the model-category session/set_config_option. The bridge fixes the model per-bridge via config; no runtime switch. Codex still uses the legacy unstable_setSessionModel ext method.
session/list S Gated by sessionCapabilities.list. The harness HAS sessionPersistence.list() (used internally for load-cwd validation) but does not expose it over ACP.
session/delete S Gated by sessionCapabilities.delete.
session/fork U Claude ships unstable_forkSession; Codex does not.

2. Client methods the agent CALLS (agent → client)

These are capabilities the bridge would drive on the editor. The harness runs tools in-process (its own dsh-bash executor, direct file I/O), so it does not yet delegate to the editor for any of these.

Method Stable Bridge Claude Codex Notes
session/update S The bridge's primary output channel (see §4).
session/request_permission S The biggest gap. Tools run with the executor's full authority; no user authorization round-trip. The agent→sessionId reverse map is already in place to route a future permission request. Tracked TODO(rfc010-permission-gate).
fs/read_text_file S The harness reads files directly (it does not see the editor's unsaved buffer state). Claude delegates; Codex does not.
fs/write_text_file S Same — direct writes, no editor delegation.
terminal/create S Neither reference adapter drives the client terminal API either — both, like the bridge, render shell output as tool-call content + a _meta channel (see §5 Terminal).
terminal/output S As above.
terminal/wait_for_exit S As above.
terminal/kill S As above.
terminal/release S As above.
elicitation/create · elicitation/complete U ⚠️ Structured user-input forms. Claude calls the unstable_* elicitation methods (to surface MCP server elicitations); Codex does NOT — its CodexElicitationHandler maps elicitations onto session/request_permission instead.

3. Capabilities

3a. agentCapabilities (advertised by the bridge)

Capability Stable Bridge Claude Codex Notes
loadSession S Advertised true; backs session/load.
promptCapabilities.image S Bridge advertises image: false; image prompt blocks are rejected.
promptCapabilities.audio S audio: false; neither adapter accepts audio either.
promptCapabilities.embeddedContext S embeddedContext: false; embedded resource blocks rejected.
mcpCapabilities.{http,sse} S ⚠️ No MCP passthrough; mcpServers is rejected. Claude advertises http+sse, Codex http only.
sessionCapabilities.* S None advertised (list/delete/resume/close/additionalDirectories/fork all off).
auth.logout S Not advertised.
authMethods[] S ⚠️ Advertised as empty (no auth required to reach the model).
agentInfo (name/version) S From agentName / agentVersion config.
_meta custom caps S E.g. Claude's claudeCode.promptQueueing. The bridge advertises no custom _meta.

3b. clientCapabilities (consumed by the bridge)

Capability Stable Bridge Notes
fs.{readTextFile,writeTextFile} S Not consulted (the bridge never calls fs/*).
terminal S Not consulted; the bridge keys terminal rendering off the Zed _meta.terminal_output cap instead.
_meta.terminal_output (Zed) S (_meta) Snapshotted per session at create/load; gates terminal-card rendering.

4. session/update variants

sessionUpdate Stable Bridge Claude Codex Notes
agent_message_chunk S From assistant/chunk text-delta.
agent_thought_chunk S From assistant/chunk reasoning-delta.
user_message_chunk S Emitted during session/load replay to reconstruct the user side.
tool_call S Tool-owned presentation (presentCall); see §5.
tool_call_update S From tool/result via presentResult.
plan S No agent plan emitted. Both adapters emit real plan entries (Codex's CodexEventHandler.updatePlan maps turn/plan/updated{ sessionUpdate: 'plan', entries }).
available_commands_update S No slash commands advertised.
current_mode_update S No session modes.
config_option_update S No config options.
usage_update S Token/cost reporting not surfaced (the harness HAS usage events internally).
session_info_update S ⚠️ ⚠️ Session title/metadata not pushed.

5. Tool-call rendering

Tool-call presentation is owned by each tool (presentCall / presentResult on the dsh-tools definition), not special-cased in the bridge — see the terminal-and-tool-rendering RFC.

Feature Stable Bridge Claude Codex Notes
ToolCallKind mapping S execute/read/edit/other inferred from the tool; richer mapping possible.
ToolCallStatus S in_progresscompleted/failed.
content blocks S Text content; the description renders above the card.
diff content S No structured diff rendering for edits (would need a diffing edit tool + presenter).
terminal content S Via the Zed _meta terminal convention (see below), not the spec terminal/* sub-protocol.
locations (follow-along) S No file-location hints emitted.
rawInput S ⚠️ Parsed tool args surfaced as rawInput.
rawOutput S ⚠️ Not emitted.

Terminal rendering

⚠️ Implemented via the Zed _meta convention (terminal_info / terminal_output / terminal_exit), gated on the client advertising _meta.terminal_output — NOT the spec's terminal/create sub-protocol (which would make the editor execute the command, bypassing dsh-bash's sandbox / env-scrub / ownership / cwd). Both reference adapters take the same _meta approach. Live incremental streaming (terminal_output_delta, which Codex negotiates) is a follow-up — the bridge currently sends the full captured output once on the result.

6. Session modes / config options / models

None modeled. Both reference adapters ship modes (Claude: a "plan" auto-mode; Codex: read-only / agent / agent-full-access mapping to its approval+sandbox policy), the newer config-option surface, and runtime model selection. The harness fixes the model per-bridge via AcpConfig.model. These are coupled to the unbuilt permission gate (a mode often selects an approval policy), so they are natural follow-ups to it.

7. Content blocks

Block Stable In prompts In updates Notes
text S Baseline.
resource_link S ⚠️ Accepted in prompts and rendered into text (acpPromptToText); not emitted as a structured update block.
image S Rejected in prompts (promptCapabilities.image: false).
audio S Rejected.
resource (embedded) S Rejected (embeddedContext: false).

The bridge rejects unsupported prompt blocks rather than silently dropping them (promptHasUnsupportedContent), per the "explicit over implicit" convention.

8. Cross-cutting

Feature Stable Bridge Notes
StopReason mapping S turnEndToStopReason is total over harness turn-end reasons → end_turn/max_tokens/cancelled.
Multi-session (N per connection) S Strict per-session demux; concurrent streams never interleave. See the multi-session RFC.
Disconnect / disposal teardown S Quiesces every live session on client disconnect or Cordis disposal.
_meta extensibility S ⚠️ Consumed (Zed terminal cap) and emitted (terminal _meta); no other custom extensions.
Background-task ownership isolation bash_output/bash_kill reject another session's task via an opaque owner token.
stdout-is-the-protocol guarantee S The bridge runs in an example with no stdout logger.

Gap summary

Ranked by how commonly the reference adapters ship them and how much UX they unlock:

  1. Permission gatesession/request_permission + permission options. Tracked TODO(rfc010-permission-gate); the reverse map is already wired. Foundational, and a prerequisite for modes.
  2. Session lifecyclesession/list + session/delete (the persistence layer already lists), then session/resume / session/close.
  3. Modes / config options / model selection — coupled to the permission gate.
  4. Agent plan (sessionUpdate: 'plan') — surface the loop's plan as structured entries.
  5. Slash commands (available_commands_update).
  6. MCP passthrough (mcpServers on session/new + mcpCapabilities).
  7. Richer prompt content — image / embedded resource blocks (needs a multimodal model path).
  8. Diff + location tool renderingdiff content and locations for edit tools.
  9. Usage reporting (usage_update) — the harness already has the internal usage events.
  10. Editor filesystem delegation (fs/read_text_file / fs/write_text_file) — lets the agent see unsaved buffers; lower priority since the harness has direct disk access.

Out of scope

Unstable/draft ACP features that neither reference adapter ships are not tracked above: providers/* (LLM provider selection), mcp/connect·mcp/message·mcp/disconnect (client-side MCP passthrough), nes/* (Next Edit Suggestion), document/did* (LSP-style document sync), the v2 plan model (plan_update / plan_removed), boolean config options, $/cancel_request, and the draft Streamable-HTTP transport. They can be added if a target editor adopts them.

Sources