153 Commits
Author SHA1 Message Date
Tianyi Cui c2f8af30da Merge branch 'feat/acp-1-max-tokens-turn-end' into feat/acp-2-bridge
# Conflicts:
#	AGENTS.md
#	docs/cookbook/extension-cookbook.md
#	yarn.lock
2026-06-16 23:40:23 +08:00
Tianyi Cui b3ea13749c feat(acp): multiplex N concurrent ACP sessions + bash task ownership (RFC 011)
Lifts the RFC 010 single-session-per-connection cap: the bridge now runs N
concurrent sessions over one connection, each mapped to its own LoopAgent.

- packages/acp: live sessions held in a Map<sessionId, SessionRecord> with an
  agent→sessionId reverse WeakMap so agent/* events (which carry only the
  Agent) demux in O(1). Every session/event and agent/status is routed strictly
  to its owning record — concurrent sessions never cross-settle or interleave
  their session/update notifications. Per-session state: one in-flight prompt
  each, session/cancel aborts+settles only its own agent/prompt, session/load
  reserves a per-id load slot (distinct ids load concurrently; re-loading a live
  id is rejected), and disposal drains every live session in parallel to
  quiescence.
- packages/tool-bash: record each background task's owning agent at spawn and
  keep it for the executor's lifetime (NOT cleared on completion).
  bash_output/bash_kill reject a task owned by a different agent (a task with no
  owner is open; a no-agent caller can't access an owned task). Task ids are
  global and predictable, so this is the fence that stops one session's agent
  from reading/killing another session's background task.
- Per-session permission ownership and a per-agent disposer seam stay deferred
  (depend on the deferred permission gate); the reverse map the gate will route
  through is in place. RFC 011 stays `proposed`.
- Tests: two sessions stream concurrently without interleave; cross-session
  cancel isolation; per-session in-flight enforcement; dispose-all-to-quiescence;
  bash cross-session read/kill rejected (+ no-agent and unowned-task cases).
- Docs: RFC 011 implementation-status note; acp + tool-bash READMEs; example
  MVP-limitations updated. 100% per-file coverage maintained.
2026-06-16 19:47:13 +08:00
Tianyi Cui fb9636db44 feat(acp): ACP bridge — drive the coding agent from an editor over JSON-RPC stdio
Implements the RFC 010 MVP: a new `@deepseek-ai/dsh-acp` package bridges the
harness agent to the Agent Client Protocol (JSON-RPC 2.0 over newline-delimited
stdio), so Zed and other ACP editors can drive the coding agent — streaming
render, tool-call display, and resumable sessions via `session/load`.

- packages/acp: AgentSideConnection wiring; initialize/newSession/loadSession/
  prompt/cancel; a total TurnEndReason→StopReason codec; settle-once with a
  fallback chain (agent/turn-end → logged turn/end → idle); single-session
  guard; cwd-must-equal-launch-dir validation; load replays from the persisted
  event log (assistant/chunk→agent_message_chunk, tool/call/result→tool_call*).
- agent: add Agent.whenIdle() quiescence signal to the interface; LoopAgent
  implements it (resolves on the first running→idle/disposed transition). The
  bridge awaits it on disposal so teardown reaches quiescence, not just abort.
- examples: extract the shared provider/tool core into examples/base.yml;
  coding-agent nest-includes it; new examples/acp-agent serves the agent over
  ACP with JSONL persistence and no stdout logger (stdout is the protocol).
- Permission gate deferred (TODO(rfc010-permission-gate)): tools run with the
  executor's full authority; only the Agent→sessionId ownership seam is laid
  down. Cancel is best-effort for a not-yet-started queued turn
  (TODO(rfc010-cancel-prestep)). RFC 010 stays `proposed`.
- Docs: package README + Zed snippet; client-driver cookbook section; root and
  packages layout/commands; RFC 010 implementation-status note.

48 bridge tests + whenIdle coverage; 100% per-file coverage; e2e boots the
example as a subprocess and verifies a written file on disk (key-gated, with a
no-key stdout-purity check).
2026-06-16 18:44:31 +08:00