编者按

dushaobindoudou/dsh-acp

Agent Client Protocol (ACP) server plugin for the DeepSeek Harness (dsh) - drive dsh agents from Zed, any ACP v1 client, or the built-in web UI over stdio / HTTP+SSE, with sessions, jobs, goals, skills and the agent tree on the wire

这是一个 DeepSeek Harness(DSH)插件。本站汇总其 GitHub README、安装信息、维护状态与公开安全信号。

dsh-acp-server

npm CI License: MIT

DeepSeek Harnessdsh)的 Agent Client Protocol(ACP)服务端。

Zed 或任意 ACP v1 客户端完整驱动 dsh 编程 agent——流式输出、工具调用、权限确认、持久会话——体验与 opencode / Gemini CLI 一致。

English | 中文

它做什么

一个 dsh profile bundle:启动完整的 DeepSeek Harness(agent 循环、工具、沙箱、会话持久化),以 ACP v1 JSON-RPC 服务替代——或伴随——Web UI 运行。

ACP 方法状态
initialize✅ 完整能力声明(loadSessionpromptCapabilities.imagesessionCapabilities.list/resume/close
session/new✅ 持久 dsh agent + 模式 + 斜杠命令广播
session/prompt✅ 流式 agent_message_chunk / agent_thought_chunk(推理)、plan 更新、完整工具调用生命周期、{stopReason};失败的 turn 以携带原因的 JSON-RPC 错误拒绝;图片块经 dsh attachments 持久化;单条 /命令 文本路由到 dsh 命令注册表
session/list✅ 全部持久 + 活跃会话(id、cwd、标题)
session/resume✅ 不回放地重开持久会话(vendor 方法的标准形态)
session/load✅ 重开并以 user_message_chunk / agent_message_chunk 回放记录
session/set_modedefaultplan,桥接 dsh plan mode,推送 current_mode_update
available_commands_update✅ dsh 命令注册表,按会话广播、每 turn 刷新
session/request_permission✅ dsh 审批桥接到客户端(允许/拒绝 一次/总是)
session/cancel✅ 中止 turn,prompt 返回 cancelled
session/close✅ 取消、落盘、释放 agent

路线图:session/fork 与 elicitation(两者在 ACP SDK 中仍为 UNSTABLE)、configOptions、音频、文档同步;dsh↔dsh 客户端半边、发现与身份规划为独立包,保持本服务端单一职责——见设计文档

最终形态:两条命令

dsh-acp-server       # 1) 单独启动:stdio 接编辑器,`serve` 子命令开远程 HTTP
dsh web              # 2) 同时启动:GUI 与 ACP 同进程同端口

形态 1 —— 单独启动(dsh-acp-server

npm i -g dsh-acp-server 后全局可用(或 npx 直接跑)。该命令以当前 stdio 启动 dsh --profile acp,所有 launcher 参数透传(serve --port 7800--patch extra.yml)。DSH home 里还没有 acp profile 时,首次运行会用官方 dsh plugin 命令自动引导——引导输出全部走 stderr,编辑器读到的 stdout 永远只有 ACP 帧。

Zed → 设置 → agent_servers(完整样例见 examples/zed-settings.json):

{
  "agent_servers": {
    "dsh": { "type": "custom", "command": "dsh-acp-server", "args": [] }
  }
}

形态 2 —— 同时启动(dsh web

web profile 装一次,之后每次 dsh web 都同端口服务 GUI 和 ACP:

node bin/setup-webacp.mjs        # 内部执行官方 `dsh plugin --profile web add` + 写入挂载行
dsh web                          # http://127.0.0.1:3080 = GUI,/acp = ACP
node bin/acp-chat.mjs --url http://127.0.0.1:3080

不想动 web 本体?node bin/setup-webacp.mjs --clone webacp 换成 dsh --profile webacp 同样效果。

脚本写入的行级 inject: [agents, agentDefaultModel, webServer] 让 Cordis 等共享 webServer 服务就绪后才挂 acp-server 行——stdio 传输永远不可能与 web 启动竞争。手动裸安装(没写这行)也安全:插件通过服务供给事件晚到挂载(终端启动直接跳过 stdio;守护式启动有 EOF 宽限期兜底)。完整行说明见 examples/patches/web-mounted.yml

为什么是独立命令而不是字面的 dsh acp-server:dsh launcher 的应用子命令(webplugin)是写死的,且在任何插件加载前就解析 argv,bundle 无法注册新子命令;这个包装器就是同形态的单命令。

安装

需要 Node.js ≥ 22 和 dsh CLI(npm i -g @deepseek-ai/dsh)。dsh-acp-server 命令会自行处理 profile;需要显式管理时:

# npm 预构建包(推荐——无需构建授权)
dsh plugin --profile acp add dsh-acp-server

# 或从 tarball
dsh plugin --profile acp add ./dsh-acp-server-0.7.0.tgz

# 或从 GitHub(源码安装,见下方说明)
dsh plugin --profile acp add github:dushaobindoudou/dsh-acp

GitHub 安装拉的是源码而非构建产物。 包的 prepare 脚本在安装时构建 lib/;pnpm ≥ 10 会拒绝执行,直到你在 profile 的 pnpm-workspace.yaml 里放行:

allowBuilds:
  dsh-acp-server: true

然后重新执行 add。建议锁定 commit(github:…/dsh-acp#<sha>),或直接用 npm 包/tarball 免去授权。随时可用 dsh --profile acp --dump-config 验证(应出现 dsh-acp-server 层)。node bin/setup-profile.mjs --pkg <spec> 是同一命令的薄封装。

远程接入(serve

编辑器走 stdio;serve 起常驻 HTTP+SSE 端点——用于远程机器、共享 agent 或 curl,形态跟随 ACP streamable-HTTP 草案

dsh --profile acp serve --port 7800            # 默认只绑 127.0.0.1
dsh --profile acp serve --host 0.0.0.0 --port 7800 --token s3cret

serve 端口还在 GET / 内置了一个单文件 web 客户端--浏览器打开 http://127.0.0.1:7800 就是完整聊天界面(流式、思考、工具卡片、计划、授权弹窗), 全部由上述 ACP 路由驱动--即"这套接口撑得起 web 界面"的参照实证。web 挂载模式 (形态 2)在 GUI 端口上提供相同的路由。

HTTP 传输规范

方法 + 路径用途
POST /acp每次请求体一条 JSON-RPC 消息(单个 JSON 对象或 NDJSON 行);initialize200 + JSON 体 + Acp-Connection-Id 头;其余 → 202,响应走 SSE 流
GET /acp/stream该连接的长连 SSE 流(头 Acp-Connection-Id?connection=);每 15 秒 : ping 心跳
DELETE /acp关闭连接 → 204
GET /acp/healthz存活探针(免鉴权;serve 模式同时应答 /healthz

错误码:401 Bearer token 缺失/错误 · 404 未知连接 ID 或路由 · 400 请求体无法解析。一个进程可挂多个客户端(每个一条 ACP 连接)。

dsh/* vendor 扩展(宿主平面)

ACP v1 标准化的是"一段对话",不是它周围的宿主。会话历史、任务、目标、技能、 实时代理树以只读 vendor 方法暴露在 dsh/ 命名空间下--内置 web UI 在用,任何客户端可用:

方法返回
dsh/sessions/list全部持久+活跃会话(id、标题、创建时间、cwd、父会话、acp 标记)
dsh/sessions/read单个会话的记录文本({seq, type, text}
dsh/sessions/resume把持久会话重开为活跃 ACP 会话(带完整上下文)
dsh/jobs/list后台任务(id、kind、label、状态、属主)
dsh/goals/list每个活跃代理的当前目标(objective、phase、轮次)
dsh/skills/list已安装技能(name、description、provider)
dsh/agents/tree活跃代理及其父/模型/cwd(子代理树)
dsh/sessions/watch / unwatch订阅任意会话的翻译实时流——dsh/session/update 帧与属主收到的 SessionUpdate 同构(编排、仪表盘、审计)

推送:turn 结束、会话生命周期、任务变化、代理状态迁移(节流)时发 dsh/changed {topics} 通知。 互操作性天然安全--只发给通过 schema 官方扩展位 clientCapabilities._meta['dsh/extensions'] 声明启用的连接(_meta 记录是 ACP 官方 schema 的一部分);Zed 等标准客户端看到的是一个完全标准的服务端, 永远不会收到 vendor 流量。缺少底层服务的组合里,各方法干净地返回 -32601

只用 curl 跑完整对话的可执行示例:examples/curl-conversation.sh

./examples/curl-conversation.sh http://127.0.0.1:7800 [bearer-token]

配置

所有配置项都有 schema 默认值;只需在 profile 层($DSH_HOME/profiles/<name>/cordis.patch.yml)覆盖想改的键。完整样例见 examples/patches/

类型默认说明
agentNamestringdsh客户端看到的 initialize.agentInfo.name
providerstring-钉死 ACP 会话的模型供应商(必须 model 同设)
modelstring-钉死 ACP 会话的模型(必须 provider 同设)
tokenstring-HTTP 传输要求 authorization: Bearer <token>(web 挂载模式;独立 serve 用命令行 --token
offerAlwaysPermissionsbooleantrue权限请求中包含 allow_always / reject_always 选项
flushOnTurnEndbooleantrue每个完成的 turn 后落盘会话
- id: acp-server
  config:
    agentName: my-dsh
    provider: liepin        # 钉死(或两者都不设,跟随实时默认)
    model: glm-5-3

行为遵循 harness 配置约定:插件加载时 schema 校验(类型错误或只设一半的 provider/model 会带确切键名大声失败),缺省键回退默认值(patch 层整体替换 config 值,schema 补齐其余),未设置的 provider/model 跟随 profile 的 agent-default-model——每次会话实时读取,GUI 里切模型对新 ACP 会话同样生效。

模型凭据来自 dsh 既有位置($DSH_HOME 设置 / 供应商 API key 环境变量),与 Web UI 共享——无需二次配置。

不装编辑器先试试

acp-chat 是仓库自带的零依赖交互式终端客户端(REPL:流式输出、工具展示、计划渲染、内联权限确认),支持两种传输:

node bin/acp-chat.mjs                                   # 启动 `dsh --profile acp`(stdio)
node bin/acp-chat.mjs --url http://127.0.0.1:7800 --token s3cret   # 远程 HTTP+SSE

当前可用的第三方 ACP 客户端:

客户端类型用法
Zed编辑器(参考客户端)上方 agent_servers 配置
acpxCLInpx acpx@latest --agent 'dsh --profile acp' "hello"
ghost.nvim / acpear.nvimNeovim插件配置 → 命令 dsh-acp-server
acp.elEmacs(setq acp-agent-command '("dsh-acp-server"))
obsidian-agent-clientObsidian插件设置
ACP-inspector一致性/调试校验线上流量

工作原理

传输在挂载时确定性选择:serve 子命令 → 独立 HTTP 服务;存在(或晚到)webServer 服务 → 路由注册到共享服务;否则 stdio。

ACP 客户端(Zed / curl / acp-chat)
   │  stdio NDJSON JSON-RPC          │  HTTP POST + SSE(serve / web 挂载)
   ▼                                 ▼
  dsh-acp-server 插件 ⇄ dsh 服务
      ├─ ctx.agents.create/dispose      (session/new、close)
      ├─ agent.followup/cancel/whenIdle (session/prompt、cancel)
      ├─ 'session/event'                (流式 session/update)
      ├─ 'approval/request'             (session/request_permission)
      └─ dsh-base:工具、沙箱、持久化、设置

源码结构:src/connection.ts(方法处理器)· translate.ts(纯线上映射,单测覆盖)· event-bridge.ts / perm-bridge.ts(dsh ⇄ ACP 桥接)· http-transport.ts(共享 HTTP 路由器)· serve-startup.tsserve 子命令)· config.ts(schema)· table.ts(会话表)。

每个映射背后的完整调研见 research/——ACP 协议DSH 架构同类实现设计蓝图

开发

pnpm install
pnpm run build     # tsc -> lib/
pnpm test          # 单元测试(纯翻译层 + 配置层)

# 端到端:在一次性 $DSH_HOME 里启动真实 dsh + 确定性 mock LLM,
# 断言完整线上行为:
pnpm run test:e2e  # stdio · serve(HTTP+SSE)· web 挂载 · 裸装宽限

e2e 套件是迭代协议行为最快的方式——每套都驱动一次完整会话(文本提问、工具调用生命周期、收尾)。设 DSH_ACP_PKG(默认仓库路径,可选 ./dsh-acp-server-*.tgz 或 npm 规格)指定安装来源。

贡献

欢迎 PR——见 CONTRIBUTING.md。里程碑计划在 research/acp-dsh-design.md

许可

MIT

REPOSITORY SIGNALS

安全与安装证据

该分数只基于公开仓库元数据与本站登记的安装证据,不等同于代码安全审计。

来源可追溯

来自公开插件目录,并链接到公开 GitHub 仓库。

许可证

仓库声明 MIT 许可证。

维护活跃度

最近 180 天内有代码更新。

安装证据

尚未登记可复验的精确安装元数据,请按仓库说明手动检查。

安装生命周期脚本

检测到 prepare,安装前请审阅脚本。

需要留意lifecycle-scripts