Files
deepseek-harness/examples/acp-agent
Tianyi Cui 46e31d8481 feat(tool-todo): add the model-facing todo_write tool
Add @deepseek-ai/dsh-tool-todo (a new packages/todo/ group): a model-facing
todo_write(todos: [{content, status}]) tool with whole-list-replace semantics.
Each call appends the full list as a todo/write event to the calling agent's
session log; the current list is the most recent such event (last-write-wins).
Single-owner — a non-agent caller is rejected. Beyond the schema's
type/required/enum checks, execute rejects empty/duplicate content and more than
one in_progress task, narrowing the loosely-typed args into a real TodoItem[].

Both UIs render off the existing session/event: the stdio UI prints a glyphed
checklist; the ACP bridge maps the list to a `plan` sessionUpdate (todosToPlan
synthesizes the priority ACP requires; status maps 1:1). Wired into the
coding-agent, acp-agent, and snapshot example configs with a system-prompt nudge.

Tests: unit (schema, validation, append/replace, no-agent rejection, presentCall,
HMR-safety, Loader export-shape guard), full-loop integration through the agent
loop, the ACP todosToPlan mapping + stream-update arm, the stdio render arm, and
a session/load replay that re-emits the plan. New-group TS wiring added to
tsconfig.base/json/build. RFC + a doc-inventory sweep (architecture, packages
README, AGENTS layout, cookbook group list, example READMEs) ship with it.

The todo-plan ACP snapshot scenario is recorded separately (needs an API key).
2026-06-29 10:30:52 +08:00
..

acp-agent example

The DeepSeek Harness coding agent exposed as an Agent Client Protocol (ACP) server over JSON-RPC stdio — drive it from Zed or any other ACP client.

pnpm run demo:acp          # needs DEEPSEEK_API_KEY (repo-root .env or env)

This example is just a leaf cordis.yml: it loads the @deepseek-ai/dsh-acp-agent app (which bundles the @deepseek-ai/dsh-agent-core spine, JSONL session persistence, and the @deepseek-ai/dsh-acp bridge — with no pre-created agents, since ACP session/new creates them on demand) plus the two swappable backends (llm-deepseek, bash-local). The app package bakes in the no-stdout-logger cluster, so a leaf has no logger entry to get wrong by default — keeping stdout pure for JSON-RPC.

stdout is the protocol

This example loads no stdout loggerstdout carries the JSON-RPC frames, and any other write corrupts them. @deepseek-ai/dsh-acp-agent includes no logger entry, so this leaf has none to get wrong by default; do not add one (use a stderr exporter if you need logs).

Zed configuration

Add to your Zed settings.json under agent_servers:

{
  "agent_servers": {
    "DeepSeek Harness": {
      "command": "pnpm",
      "args": ["--dir", "/path/to/deepseek-harness", "run", "demo:acp"],
      "env": { "DEEPSEEK_API_KEY": "sk-…" }
    }
  }
}

The editor sets each session's cwd to the project it opens; the agent's bash tools run there (see the per-session cwd note in packages/ui/acp), so launch the server from the harness repo with pnpm --dir … and let ACP carry the workspace path per session.

Snapshot tests (record-once / replay-deterministic)

This example is the home of the harness's snapshot tests — they boot this server as a real subprocess, drive it with a deterministic input script, and diff its normalized output against committed golden files. The model is made deterministic by @deepseek-ai/dsh-llm-replay, a function/namespace plugin that installs an llm/stream waterfall listener and short-circuits it, serving model streams reconstructed from a recorded session JSONL fixture (<scenario>/session.jsonl) — so replay needs no API key. The fixture IS the persisted session log: its assistant/chunk events carry every StreamChunk, so grouping them by (turn, step) reconstructs each stream() call (one model call per loop step). Recording is therefore "run the real agent once and harvest the .jsonl". The two failure modes not expressible as logged chunks — a pure throw before any chunk, and cancel/hang — use an optional <scenario>/replay.override.json sidecar (a ReplayEntry[] that replaces the derived script). A scenario that needs the agent to operate on existing files ships an optional <scenario>/workspace/ directory — the harness copies its contents into the temp cwd before the run (see workspace-edit). See docs/rfc/implemented/2026-06-19-acp-snapshot-tests.md for the full design.

MVP limitations

The bridge supports N concurrent sessions per connection, each in its own workspace cwd (RFC 011). Remaining limits: prompts support ACP's baseline text and resource_link blocks only, additionalDirectories and mcpServers are rejected, and the tool-permission gate is deferred (TODO(rfc010-permission-gate) — tools run with the executor's full authority). See packages/ui/acp/README.md for the full contract.