DeepSeek Harness 能力接缝图:四个包名在 packages 下找不到
先说这篇要解决的具体处境。
你在读 DeepSeek Harness 的 docs/capability-seams.md,看到 ctx.lsp 那一行的 Implementations 列写着 lsp-local。你想去看这个 provider 是怎么实现的,于是去 packages/lsp/lsp-local 找源码——没有这个目录。你以为是自己路径拼错了,全树 grep 一遍包名,也没有任何一个包叫 @deepseek-ai/dsh-lsp-local。
这不是个例。截至 2026-08-16、对应快照 47f9438,我们把 packages/*/* 下 219 个真实包的 name 去掉 @deepseek-ai/dsh- 前缀,与 capability-seams.md mermaid 里的 130 个 pkg_* 节点标签逐个比对,扣掉「用短名指代 host-* / client-* 包」这类前缀差异之后,剩下四个名字在整个 packages/ 树下既没有同名目录、也没有同名包。
这篇讲的就是这四个名字,以及一条可以自己走一遍的定位路径。
四个名字,各自在哪一行
| 图里的名字 | 出现位置 | packages/ 下的实况 |
|---|---|---|
host-runtime | :13(mermaid 节点)、:414(ctx.attachments 的 Direct consumers) | packages/host/ 的 8 个子包是 apiproxy、directory-picker、directory-picker-auto、directory-picker-browse、directory-picker-native、frontend-static、plugin-inventory、webserver,没有 runtime |
subagent-inprocess | :31(节点)、:418(ctx.sessions)、:442(ctx.agents) | 没有 packages/subagent/subagent-inprocess;相近的真实目录是 subagent-in-process-driver,另有 subagent-fork-in-process、subagent-spawn-in-process |
code-runtime-worker | :146(节点)、:455(ctx.codeRuntime 的 Implementations) | 没有 packages/code-runtime/code-runtime-worker;真实目录是 code-runtime-worker-thread |
lsp-local | :190(节点)、:466(ctx.lsp 的 Implementations) | 没有 packages/lsp/lsp-local;真实目录是 lsp-stdio |
行号都是 docs/capability-seams.md 里的,这份文件我们实读为 471 行。它 :414 到 :469 是一张 56 行的表,每行一个 ctx key;按 Role 列统计是 core 29 行、seam 26 行、bundle 1 行(ctx.agentLoop,在 :443)。
先搞清这张图是怎么来的
docs/graph-atlas.md 是这个仓库的文档图索引,24 行,表头「Graph | Mode」。capability-seams.md 在那张表里的 Mode 标的是 hybrid generated——不是纯手写,也不是纯生成。
它自己在末行把 hybrid 的含义写清楚了:服务是从 Cordis 的声明里发现的,而 interface / implementation / consumer 三个角色的归类是在 scripts/gen-doc-graphs.ts 里做的,带一个 completeness guard。
「角色在脚本里分类」这句话是整条线索的关键。回 scripts/gen-doc-graphs.ts 看,这四个名字确实都以字面量的形式写在脚本里:
host-runtime在:105,形如consumers: ['host-runtime', 'llm-pi-ai']subagent-inprocess在:138与:331code-runtime-worker在:440lsp-local在:538
也就是说,这四个字符串不来自扫描 packages/ 得到的包清单,而是脚本里手写的分类输入。至于生成/校验这两条命令的原文,docs/graph-atlas.md 末行给的是 pnpm run gen-doc-graphs 和 pnpm run verify-doc-graphs——这两条我们一条都没执行过,所以这篇不能替你判断校验闸会不会对这四个名字报错,上面全部是文本比对的结果。
顺带给个对照。同一份 docs/graph-atlas.md 的索引表里,module-graph.md 那行的 Mode 标的是 generated,与 capability-seams.md 的 hybrid generated 不是同一档。module-graph.md 我们实读为 1638 行,把它 mermaid 里的 219 个 pkg_* 节点标签去掉 @deepseek-ai/dsh- 前缀后与 219 个真实包名逐一比对,不匹配数是 0。两张图在索引表里的 Mode 标注不同、名字命中情况也不同,这两件事我们只并列记在这里,不推断其中一件导致了另一件。
改名台账在 .agents/notes/ 里
这个仓库的 .agents/notes/implemented 下有 507 份 .md(同样是 2026-08-16 的计数,不含 .zh.md 中译本)。其中一份是命名契约与改名台账:.agents/notes/implemented/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md。四个名字里有三个能在这份台账里查到对应条目:
:118登记@deepseek-ai/dsh-lsp-local→@deepseek-ai/dsh-lsp-stdio,理由原文写的是「The provider speaks LSP over stdio through replaceable filesystem and subprocess services. It is not necessarily local.」:227登记@deepseek-ai/dsh-code-runtime-worker、类名WorkerCodeRuntime→@deepseek-ai/dsh-code-runtime-worker-thread、WorkerThreadCodeRuntime:245登记@deepseek-ai/dsh-subagent-inprocess、目录subagent-inprocess/→@deepseek-ai/dsh-subagent-in-process-driver、目录subagent-in-process-driver/
所以从读者角度,定位路径是这样一条:图里的名字 → gen-doc-graphs.ts 里的字面量 → 台账里的旧名条目 → 台账给出的新包名 → packages/<组>/<新目录>。这条路对上面三个名字都走得通。
第四个 host-runtime,我们没有在这份台账里查到对应的改名条目。能查到的另一处记录在 .agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.md:66,那里把 dsh-host-runtime 描述为「装配层」。这一条我们只能记到这里:台账里没有它的改名条目,packages/host/ 下也没有对应目录,两处并存,我们不推断哪一处是当前状态。
顺带一条同类现象:packages/subagent/README.md:10 的表格里,链接文字写的是 subagent-inprocess/,而同一处链接的目标写的是 subagent-in-process-driver/README.md。文字与目标不一致,两处位置都在这一行上,可以自己打开核对。
什么情况说明不是这个原因
比对包名时最容易误判的,是把「组前缀差异」当成失效名。packages/host/* 与 packages/client/* 这两组有一条专门的命名规则,写在 .agents/notes/implemented/architecture/2026-07-19-gui-layering-and-rpc-protocol.md:74:这两组下的包必须在包名里带上目录组前缀,因此包名尾段 ≠ 目录名。落到实处就是 host/apiproxy 的包名是 @deepseek-ai/dsh-host-apiproxy,client/runtime 的包名是 @deepseek-ai/dsh-client-runtime。
于是 capability-seams.md 表里那些写成 apiproxy、webserver、directory-picker*、connection、modules、hmr 的短名,在 packages/ 下是找得到对应包的,只是你要自己补上 host- 或 client- 前缀再找。这类不算本篇说的四个名字。
跨组不同名的例子也不止这两组:test-support/client-runtime 的包名是 @deepseek-ai/dsh-client-test-runtime(不是 dsh-test-support-client-runtime),interaction/commands 的包名是 @deepseek-ai/dsh-commands(不带 interaction- 前缀)。:453 那行的 approval 也是一例,真实目录是 interaction/user-approval、包名 @deepseek-ai/dsh-user-approval。所以「按名字直接拼路径找不到」这件事本身,绝大多数时候只是命名规则问题,不是名字失效。
还有一条容易被当成判据、但其实靠不住的信号:在 :414-469 那张表里,这四个名字都是不带链接的裸 code span,而多数其它包名写成 [`x`](../packages/组/包) 形式的链接。裸 code span 看着像是一个提示,但刚才列的 approval、apiproxy、webserver、connection、modules、hmr 同样是裸 code span,它们都能找到对应包。所以裸 code span 不等于失效名,别拿它当判据。
真正能拍板的动作只有一个:把 219 个包的 name 去掉 @deepseek-ai/dsh- 前缀,做成一个集合,再拿图里的名字去命中;命不中的,补 host- / client- 前缀再试一次;还是命不中,才去 gen-doc-graphs.ts 和改名台账里查。这个顺序反过来走,很容易在前缀问题上白折腾半天。
补一句关于集合怎么建:包名的权威来源是 packages/*/*/package.json 的 name 字段,不是目录名。这两者在多数组里确实一致,但上面已经列了好几组不一致的例子,拿目录名当包名建集合,等于把前缀差异重新塞回结果里。另外注意 packages/ 下那 49 个目录是组目录,它们自己没有 package.json,真正的包在第二层——工作区 glob 在 pnpm-workspace.yaml 里写的就是 packages/*/*,两层。用一层 glob 去扫,一个包也扫不到。
读这张图时顺带记住的几件事
一是 seam 这个词在这个仓库里有严格定义。docs/architecture.md:100 写的是:一个 seam 是可替换的能力,由 Service Definition(声明接口)、Service Provider(实现它)、Consumer(使用它,常见是一个模型可见的工具)三个角色构成;一个包可以兼任多个角色,但单独一个角色不构成 seam。根 AGENTS.md:109 把同一条写成硬约定。所以你在表里看到的 Implementations 列、Direct consumers 列,对应的正是这套三角色划分。
二是这张表的覆盖面有边界。capability-seams.md 的 56 个 ctx key,我们没有回 packages/*/*/src 去逐一确认这 56 个服务是否都已实现,也没有去确认还有没有未被这张表收录的 ctx 服务。这篇只核了「被引用的包名是否存在」这一层。
三是这些结论的保质期。这个仓库建立于 2026-08-13,我们采集时是 2026-08-16,前后只差三天;根 package.json 版本是 0.1.0-rc.5,219 个包的 version 也全是这个值,GitHub 上没有任何 Release。README 自述处于开发者预览阶段,并明写未来会出现破坏兼容性的变更。文档图本身是脚本生成的,改名台账还在往里加条目——今天这四个名字,明天可能是三个或者六个,本文给的是定位方法,不是一份可以照抄的清单。
延伸阅读
- 从头读起:DeepSeek Harness 是什么:建仓三天、13 万 star 的 Agent 框架
- 本专题共 45 篇,完整分组目录见专题页
- DeepSeek Harness 的 AGENTS.md 分组清单:两个目录不存在、漏 17 个
- DeepSeek Harness 的 core 有几个子包:三份文档分别说 6、7、8
本文依据 DeepSeek Harness 官方仓库(github.com/deepseek-ai/deepseek-harness)的 README、docs/ 下的
架构与子系统文档、以及 packages/ 下的源码整理,核对日 2026-08-16,对应仓库快照 47f9438(版本 0.1.0-rc.5)。
本文内容为仓库源码与文档口径,我们没有安装、也没有运行过这个项目,
因此不涉及界面外观、操作手感与运行速度的任何描述。
该仓库建立于 2026-08-13,README 自述处于开发者预览阶段并明确说明未来会有破坏兼容性的变更,
文中出现的命令、配置与默认值随时可能变动,请以仓库最新内容为准。