把推理、工具调用与用量完整推送给 ACP 客户端
31.5/100
综合分
2
GitHub 星标
10
npm 周下载
—/5
用户评分
数据截至 2026/9/26 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/HarnessDesk/dsh-acp.git状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:待复验
装得上吗[实装验证]—
曾在 dsh 0.2.1-rc.2 下真实安装成功,但当前 dsh 已更新至 0.2.2-rc.1,本站尚未在新版下复验
L4 · 真实安装等级说明 →数据截至 2026/10/24·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 流式输出推理过程
- 推送工具调用
- 推送计划与用量
为 DeepSeek Harness 打造的完整 Agent Client Protocol 服务器,能流式输出推理、工具调用、计划和 token 用量,而 Harness 自带的自动化桥接却把这些都藏了起来。
README
由 DeepSeek 最新模型翻译生成dsh-acp — 一个完整的 DeepSeek Harness ACP 服务器
CI
license
从任意 Agent Client Protocol 客户端驱动 DeepSeek Harness——并且真正看到它做了什么。
为什么会有这个项目
DeepSeek Harness 自带一个 ACP 服务器,@deepseek-ai/dsh-acp。它的源码直白地说明了其范围:
只输出已提交的助手文本。原始分块、推理、工具、计划、标题和重试标记属于展示或追踪数据,不进入自动化通道。
对于它被构建出来所要完成的任务来说,这是正确的决定——它是一个自动化桥接层,其 README 也是这么说的。但对于一个正在观看对话的人来说,这是错误的决定。通过它驱动时,一次十五分钟的运行——加载了两个技能、写了一个 822 行的文件、构建了一个 virtualenv 并运行了一次浏览器测试——最终只呈现为两段散文。没有工具调用。没有推理。没有 token 计数,因此也没有上下文使用指示器。
这个适配器做出了相反的选择。同样的 harness,同样的会话,一切都在通道上。
自那段话写下以来,上游已经发生了变化。
展开完整文档(README 剩余 1 节)
dsh-acp — 一个完整的 DeepSeek Harness ACP 服务器
CI
license
从任意 Agent Client Protocol 客户端驱动 DeepSeek Harness——并且真正看到它做了什么。
为什么会有这个项目
DeepSeek Harness 自带一个 ACP 服务器,@deepseek-ai/dsh-acp。它的源码直白地说明了其范围:
只输出已提交的助手文本。原始分块、推理、工具、计划、标题和重试标记属于展示或追踪数据,不进入自动化通道。
对于它被构建出来所要完成的任务来说,这是正确的决定——它是一个自动化桥接层,其 README 也是这么说的。但对于一个正在观看对话的人来说,这是错误的决定。通过它驱动时,一次十五分钟的运行——加载了两个技能、写了一个 822 行的文件、构建了一个 virtualenv 并运行了一次浏览器测试——最终只呈现为两段散文。没有工具调用。没有推理。没有 token 计数,因此也没有上下文使用指示器。
这个适配器做出了相反的选择。同样的 harness,同样的会话,一切都在通道上。
自那段话写下以来,上游已经发生了变化。从 DeepSeek Harness 0.1.2-alpha.1(提交 511181684c,2026-08-22)起,它自己的服务器会流式传输推理、工具调用和 usage_update,并将模型和推理强度作为 configOptions 接收;其 README 仍然说它“为自动化而构建……而非 DSH 用户界面”,其 Known Limitations 仍然拒绝人们需要的那些动词。对照 v0.1.2-rc.1 测量:
| | @deepseek-ai/dsh-acp (rc.1) | 本项 |
| 助手文本 | ✅ 已提交消息 | ✅ 流式传输 |
| 推理 | ✅ agent_thought_chunk | ✅ agent_thought_chunk |
| 工具调用 | ✅ 通用生命周期 | ✅ tool_call / tool_call_update,带输出和每个 rc.1 工具一句话 |
| 计划(todo_write) | — | ✅ plan |
| Token 使用 | ✅ 仅 usage_update | ✅ usage_update + PromptResponse.usage(轮次总计、缓存读取和写入) |
| 上下文组成 | — | ✅ 系统 / 工具 / 消息,来自 harness 自己的计量器 |
| 模型 / 强度 | ✅ session/set_config_option | ✅ ACP configOptions |
| 沙箱模式 | — | ✅ ACP configOptions(mode) |
| session/new 上的 MCP 服务器 | ✅ stdio + HTTP | — 拒绝,并明确说明(见下文) |
| 图像提示 | ✅ 带附件存储 | — |
| 对话列表 | ✅ session/list(已存储、分页) | ✅ 实时和已存储,带 harness 自己的标题 |
| 重新打开对话 | ✅ session/resume | ✅ session/resume——在它当时所用的模型上 |
| ……并看到它说了什么 | — session/load 被拒绝 | ✅ session/load 重放整个日志 |
| 另一个 agent 写了什么 | — | ✅ send_message 转发和结算通知,带归属 |
| 权限提示 | ✅ 允许 / 拒绝 | ✅ 允许 / 拒绝 |
什么算作一次对话 harness 会在 agent 被组合的那一刻写入会话头和 sandbox/mode——在任何输入之前。因此,一个被打开又被放弃的会话仍然会持久化,并在 session/list 中作为一行无人发起的无标题记录出现,每次应用启动都会产生一条。
已存储的会话只有在其中存在人说话的内容时才会被列出:至少一条来源为 user 的 user/message。在 harness 的模型中,工具结果也是 user 角色的消息,因此决定因素是来源而非角色——若把它们计入,那么每个恰好运行过工具的废弃会话都会看起来像一段对话。
只有当某行的日志被读取并发现为空时,该行才会被隐藏。此 harness 拒绝解析的日志,或超出折叠预算的日志,都会被列出:没有任何东西检查过的行,也不是任何东西能评判的行,而隐藏一段真实对话远比显示一个废弃会话糟糕得多。
Node 24.0–24.11.1 与较旧的 harness
如果 harness 启动失败,且堆栈跟踪指向插件树而非你的组合,请先检查你的 Node 版本。
@deepseek-ai/cordis-plugin-loader 按主版本号对 Node 的内部 ESM loader 进行分类——>= 24 意味着“v2”——但 v2 直到 24.12.0 才落地。因此,24.0–24.11.1 中的每个 loader 都被错误标记,resolveSync 被以颠倒的参数调用,这会在本适配器的任何代码运行之前就破坏插件树。该问题已在 loader 1.0.3 中修复,它随 DeepSeek Harness 0.1.2-alpha.2 及更高版本一同发布。
本适配器无法绕过它——失败发生在 harness 组合自身的过程中。要么升级 harness,要么运行 Node 24.12+ 或 Node 22。当启动失败发生在该窗口内时,本适配器会打印一条指向此处的说明。
engines 有意仍然允许该范围:适配器本身在那里没问题,足够新、带有已修复 loader 的 harness 也没问题。直接排除它会拒绝那些可以正常工作的安装。
给从 0.4.0 或更早版本升级者的说明
在 0.4.1 之前记录的对话无法重新打开,这是本适配器的过错。harness 在回读日志时会验证每个消息事件——assertMessageEventShape 要求 id 为非空字符串——而本适配器生成用户消息时没有提供该字段。消息写入时没有任何报错;失败只在有东西尝试回读对话时出现,报告为 session event at seq N lacks an identified message。
原本用于借用 harness 自身消息工厂的动态 import() 也从未解析成功,因为 ESM import() 不会查询 NODE_PATH——而这正是像本插件这样的插件获得 harness 包的方式。所以那个回退从来不是回退;它是唯一的路径。已在 0.4.1 中修复,它生成与 harness 相同的 crypto.randomUUID() id,并且现在会在使用自己的工厂时明确说明。
重新打开对话
ACP 区分两个听起来相似的动词,而这一区别决定了某个客户端可以绘制任何内容:
- session/resume 将智能体重新置于已存储的会话上,并且明确不重放历史记录。
- session/load 会重放历史记录。
@deepseek-ai/dsh-acp 实现了 resume,并将 session/load 列在其拒绝的接口面中,这对于一个不保留对话记录的自动化桥接来说是自洽的。对于一个人正在查看的客户端而言,这意味着重新打开一段对话时,会在一个空窗格之上得到一个实时智能体。
本适配器同时实现了两者。重放是一次折叠,而不是第二个映射器:存储层保留与实时馈送所携带的相同的 SessionEvent 日志,因此这些事件会重新经过同一个投影,并作为客户端第一次本应收到的更新输出——包括用户轮次、推理、带有结果的工具调用、计划以及标题。
这两项能力都是根据实际挂载的内容来声明的。一个没有 @deepseek-ai/dsh-session-persistence 的组合会得到 loadSession: false 且没有 resume,并且只列出实际存在的内容——而不是本适配器无法兑现的承诺。
Token 用量遵循 ACP 的 Session Context Size and Cost RFD,包括其规则:缓存 token 仍然占用上下文窗口。
安装
npm install @harnessdesk/dsh-acp
你还需要在旁边安装一个 DeepSeek Harness——可以是全局的 @deepseek-ai/dsh,或者一个检出副本。适配器会按以下顺序查找它:从工作目录、从你指向的组合文件所在目录,或从它自己的包中。
使用
将插件挂载到 harness 组合中,与一个 agent spine 并列:
- id: spine
name: '@deepseek-ai/dsh-agent-spine-demo'
config:
provider: deepseek-official
model: deepseek-flash
- id: acp
name: '@harnessdesk/dsh-acp'
config:
provider: deepseek-official
model: deepseek-v4-pro
models: [deepseek-flash, deepseek-v4-pro]
新会话使用 DeepSeek 当前的 deepseek-flash 路由,显示为 DeepSeek V4.1 Flash,与 DeepSeek V4 Pro 并列。旧版 deepseek-v4-flash 标识符在历史会话日志中仍可读,但不再作为新会话选项对外公布。
官方 ACP 兼容性
DeepSeek 自己的 @deepseek-ai/dsh-acp 仍然是仅用于自动化的参考接口面;HarnessDesk 继续使用本适配器来处理面向渲染器的会话。这个可选启用的探针只检查官方桥接的 initialize 和 session/new 自动化边界,不会向模型发起提示,也不需要进行 API 调用。针对一个已初始化的官方 acp profile 运行它:
DSH_OFFICIAL_BIN=/path/to/deepseek-harness/apps/cli/lib/bin.js \
DSH_OFFICIAL_CWD=/path/to/deepseek-harness \
DSH_OFFICIAL_ARGS='["--profile","acp"]' \
npm run test:official
默认的 npm test 套件会跳过此探针,除非提供了 DSH_OFFICIAL_BIN,因此单元测试保持无需凭据且具有确定性。
然后让客户端指向该二进制文件:
harnessdesk-dsh-acp --config ./cordis.yml
标准输出只承载 JSON-RPC 帧,不承载其他任何内容,因此该组合绝不能挂载 stdout 日志记录器——测试框架自身的 ACP 组合出于同样的原因也省略了它。
在 Zed 中
{
"agent_servers": {
"DeepSeek Harness": {
"command": "harnessdesk-dsh-acp",
"args": ["--config", "/path/to/cordis.yml"]
}
}
}
在 HarnessDesk 中
向 ~/.harnessdesk/agents.json 添加一个条目:
{
"id": "dsh",
"name": "DeepSeek Harness",
"brand": "deepseek",
"command": "harnessdesk-dsh-acp",
"args": ["--config", "/path/to/cordis.yml"]
}
配置
| 键 | 含义 |
| provider | 所创建 agent 的 provider 路由,例如 deepseek-official |
| model | 所创建 agent 的模型,例如 deepseek-flash |
| models | 在选择器中提供的模型;少于两个则不提供任何模型 |
| efforts | 提供的推理级别;默认为 off, low, high, max |
设计
三条规则,每一条都源于一次具体的失败:
映射器是纯的。 SessionProjection 接收 harness 事件并返回 ACP 更新,没有 I/O,也没有 harness 导入,因此整个词汇表可以在毫秒级内针对从真实会话日志中记录的事件进行测试,而不是针对作者凭空编造的事件。
harness 是按结构进行类型化的,而不是被导入的。 它的各个包沿着独立的版本线演进——dsh-session 处于 0.0.1-rc.1,而 dsh-agent 处于 0.1.0-rc.6——因此一个将它们固定版本的适配器,只要其中任何一个发生变动,就需要发布一次新版本。我们实际依赖的是会话事件词汇表,而 harness 自身也将其视为兼容性表面。没有任何内容被 vendored:适配器只是位于你的 harness 旁边的几百行代码,而不是它的副本。
未知事件被忽略,绝不致命。 harness 的词汇表会不断增长。一个遇到新事件类型就抛异常的适配器,会在一次本可以安然度过的升级中崩溃。
Token 计量
两个容易搞错的细节,而且错得看似合理:
上下文填充量是最新一次请求,而不是每一步的总和。 harness 在每一步都会发送整个对话,因此对步骤求和会报告出一个远大于模型实际所见内容的会话规模。
ACP 的 inputTokens 是整个输入;harness 的则是未命中缓存的那部分。
将 harness 的数字原样传递,会让一个 12,574 token 的提示渲染为 157 token。适配器会进行转换,因此 cachedReadTokens 保持为 inputTokens 的一部分,而“% cached”在这里的含义与对所有其他 agent 而言相同。
上下文组成
一个挂载了 @deepseek-ai/dsh-token-meter 和 @deepseek-ai/dsh-session-projection 的组合,能获得两样事件流上任何东西都无法提供的东西。
在压缩后依然存续的占用率。 计量器的 contextPressure 投影报告的是下一次请求将耗费多少——一个以 provider 为锚点的样本,针对对话自那以来所增加或减少的一切重新定价。压缩不会报告任何用量,它自身如此,所以仅由 assistant/chunk 构建的指示器会一直保持陈旧,直到下一次请求恰好运行;而这一指示器会在对话被压缩的瞬间消失。适配器优先使用它,并在未挂载计量器时回退到按请求求和。
提示词由什么构成。 contextBreakdown 投影分别对系统提示词、工具模式和对话计价,适配器将这三者都携带在 usage_update._meta.harnessdesk.contextBreakdown 上,与它们所解释的占用情况并列:
{
"sessionUpdate": "usage_update",
"used": 43574, "size": 1000000,
"_meta": { "harnessdesk": { "contextBreakdown": {
"approximate": true,
"source": "DeepSeek Harness token meter",
"segments": [
{ "id": "system", "label": "System prompt", "tokens": 44 },
{ "id": "tools", "label": "Tool schemas", "tokens": 771, "count": 3 },
{ "id": "messages", "label": "Messages", "tokens": 325 }
]
} } }
}
approximate 不是装饰。这些分段来自计量器的固定密度估算,而 used 锚定于提供商实际计费的内容,因此两者处于不同的真实单位,分段之和不会等于 used。harness 自己也是这样说的,而此适配器会传递这一警告,而不是将其丢弃。不会发送总计,也不应通过相减来推断——请将这些渲染为构成的份额,而绝不是环的切片。
只有 count,即请求信封中工具模式的数量,是精确的;它从 request/header 读取,适配器在其他方面不碰它。在这里对该信封计价将意味着附带一个分词器并猜测 DeepSeek 的分词器,而 harness 已经用它给其他一切计价的估算器给它计价了。
本节中的所有内容都是可选的。ctx.inject(['sessionProjections'], …) 在没有注册表的情况下永远不会在组合中运行,而忽略 _meta 的客户端仍然会得到环。
状态
已针对真实 harness 端到端工作并测试——最近是 v0.1.2-rc.1,从源码构建并通过 stdio 驱动:流式传输、推理、带输出的工具调用、计划、用量、权限提示、三个会话控制、一个携带 harness 自身会话标题的对话列表、带重放的 session/load,以及用于模型、effort 和沙箱模式的 session/set_config_option。rc.1 的移除项——Session.events、SQLite 持久化后端、APIProxy——不触及此适配器注入的任何内容。
重新打开的对话会在其自身日志最后记录的路径上继续(request/header 的调用配置,或之后的 model/selection),而绝不会在部署的默认值上继续:存储的会话头不携带提供商或模型,因此日志是答案所在的唯一位置。选择器会显示该路径。
自 rc.1 起,子项通过 send_message 而不是单向的 report 工具回报,并且运行时会在子项落定。两者都以 user 角色消息的形式出现在父级日志中,其来源为 agent-message 或 subagent-settled;此适配器将它们作为 user_message_chunk 发送,并标记 _meta.harnessdesk.notice: true,附带一个 from 指明发送者,因此客户端会将它们绘制为该轮次上的通知,而非本人的话语——并且两者都不会在对话列表中计为本人发言。
列出的对话只有在组合生成名称时才有名称。标题服务及其提供者是独立的插件,挂载它们才能使一行从截断的首个提示词变为“Maximum landing score breakdown”:
- id: session-title
name: '@deepseek-ai/dsh-session-title'
config: { fallbackMaxWords: 5, fallbackMaxBytes: 40, maxTitleBytes: 80 }
- id: session-title-llm
name: '@deepseek-ai/dsh-session-title-first-prompt-llm'
config:
targetWords: 5
targetCjkCharacters: 10
maxInputBytes: 4096
maxOutputTokens: 64
timeoutMs: 60000
provider: deepseek-official
model: deepseek-flash
仅靠该服务会给出一个按词数回退的标题;而提供者则用一条廉价路由为对话命名。两者都没有时,session/list 仍会以 cwd 和预览作答,而 title 为 null。
尚未实现:
- MCP 服务器透传——明确拒绝,并大声说明。 该 harness 确实托管 MCP 服务器,通过 @deepseek-ai/dsh-mcp-client,但它在组合时连接它们:在 cordis.yml 中每个服务器一个插件实例。ACP 线路上没有任何东西能向一个已经组合好的 harness 添加服务器,而此适配器不会替他人编辑其组合。因此,session/new 上非空的 mcpServers 会被拒绝,并给出指明该参数的错误。
值得明确说明为什么这比另一种做法更好。
直到 0.3.0,此适配器接受该参数并忽略它,这让客户端相信其工具已到达模型。它们并没有,而唯一的症状是一个 agent 说它做不到某件它被告知可以做到的事。指明 mcpServers 的拒绝是客户端唯一能据以行动的答复:它会不带该服务器重试,并报告缺少哪些工具。
在 DeepSeek Harness 0.1.2-rc.1 上运行它
rc.1 移除了 packages/examples,随之移除了旧组合所挂载的 dsh-agent-spine-demo。现在的捷径是随附的 acp 配置文件加上一个覆盖层——profile/harnessdesk.patch.yml ——它会关闭 harness 自带的服务器,并将此服务器放到 stdio 上:
ln -s "$(pwd)" "$DSH_HOME/profiles/acp/node_modules/@harnessdesk/dsh-acp"
NODE_PATH="$DSH_HOME/profiles/node_modules" dsh --profile acp --patch profile/harnessdesk.patch.yml
NODE_PATH 很重要:适配器通过它访问 harness 自带的包以实现模型选择耦合,没有它,模型和推理选择器会被诚实地不予提供。基础 bundle 挂载了此适配器读取——持久化、标题、令牌计量、会话投影。
开发
npm install
npm run verify # typecheck, test, build
许可证
MIT。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
HarnessDesk/dsh-acp
把推理、工具调用与用量完整推送给 ACP 客户端
相关插件 · 模型接入
API 中继安全审计toby-bridges/api-relay-audit
面向 AI API 中转与 LLM 代理的本地安全审计。
★ 897已汉化DSH
69.4
免费搜索插件DDDMUC/dsh-free-search
DeepSeek Harness 免费搜索插件 —— 无需 API key,零成本,多引擎可切换。 一个给…
★ 938已汉化DSH
69
免费联网搜索liustack/modsearch
在官方 App 里模型能联网,切到 API 就不能了。ModSearch 把联网补回来:网页搜索、X…
★ 863已汉化DSH
68.5
WorkBuddy 账号池XDTrees/dsh-xdpool
把你能白嫖的模型额度接进 DSH 同一个池:WorkBuddy 多账号自动容错、十三家扫码登录、76…
★ 441已汉化DSH
67.9
OpenCode 免费模型FishBottle7/opencode2dsh
在 DSHDeepSeek Harness里原生使用 OpenCode Zen 的免费匿名模型。
★ 387已汉化DSH
67.8
AI 模型网关tingly-dev/tingly-box
Tingly Box Web UI 演示
★ 373已汉化DSH
67.4
这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。