From df25b28af87da6589c878638b020b155e832769e Mon Sep 17 00:00:00 2001 From: t Date: Fri, 14 Aug 2026 12:23:43 +0800 Subject: [PATCH] docs: decide what to take from DeepSeek Harness, and what not to Cloned deepseek-ai/deepseek-harness@47f9438 and read its source tree and docs rather than release notes. It is the closest thing DeepCode has to a direct comparison: another DeepSeek-powered coding agent facing the same constraints. The research doc grades every claim A/B/C the way the Floatboat report did, and records where dsh is ahead (context economy, execution shape, frontend extensibility) alongside where DeepCode already is (file contract, change ledger, sandbox network allowlist, cache-hit pricing). Two real DeepCode defects fell out of the comparison, both verified against our own source: WebFetch returns the whole response body to the model with no text cap, and Bash discards everything past 30 KB with no way to get it back. One capability fixes both. The adoption plan argues each candidate as proponent/opponent/verdict so the implementation PRs execute a decision instead of relitigating one. The largest verdict is a rejection: dsh spends 219 packages expressing what DeepCode expresses in 4, and that ratio buys a third-party plugin ecosystem we do not ship. Take the discipline, not the framework. Co-Authored-By: Claude Opus 5 --- docs/DSH_ADOPTION_PLAN.md | 317 ++++++++++++++++++++++++++++++ docs/research/deepseek-harness.md | 193 ++++++++++++++++++ 2 files changed, 510 insertions(+) create mode 100644 docs/DSH_ADOPTION_PLAN.md create mode 100644 docs/research/deepseek-harness.md diff --git a/docs/DSH_ADOPTION_PLAN.md b/docs/DSH_ADOPTION_PLAN.md new file mode 100644 index 0000000..95b6eea --- /dev/null +++ b/docs/DSH_ADOPTION_PLAN.md @@ -0,0 +1,317 @@ +# DeepSeek Harness 采纳方案与决策记录 + +> 基线:DeepCode `main@4d56f44`(0.3.0)· 调研对象 `dsh@47f94385`(0.1.0-rc.5, MIT) +> 前置阅读:[调研报告](research/deepseek-harness.md) +> 体例沿用 [`FLOATBOAT_ADOPTION_PLAN.md`](FLOATBOAT_ADOPTION_PLAN.md):每个候选项走**正方 / 反方 / 裁决**, +> 裁决写进文档,实现 PR 只负责执行,不重开辩论。 + +--- + +## 0. 结论先行 + +本轮采纳的主题是**上下文经济学**:_agent 的注意力预算花在哪、超支时怎么办_。 + +dsh 在这一层领先 DeepCode 一代。它的答案不是"把上下文做大",而是三件具体的事: +**超限输出落盘可取回**(spill)、**无效重复被打断**(护栏)、**历史可检索而非只可回放**(session query)。 + +对照之下查实了 DeepCode 的两处真实缺陷 —— `WebFetch` 无模型可见上限、`Bash` 截断即永久丢失 +(证据见[调研 §2.1](research/deepseek-harness.md))。它们由同一个能力修复,这构成本轮的第一优先级。 + +**同时明确拒绝 Cordis 化重写**(§2.1)。dsh 用 219 个包表达 DeepCode 用 4 个包表达的东西, +这个倍率来自它需要对外分发插件生态的产品前提 —— DeepCode 没有这个前提,抄成本不抄收益。 + +| 裁决 | 项目 | +| -------- | -------------------------------------------------------------------------------------------- | +| **采纳** | spill · 重复调用护栏 · 逐工具超时 · 持久 shell 会话 · session 检索 · 工具渲染意图 · 结果剪枝 | +| **推迟** | 作业注册表统一 · goal 域 · Ralph 循环 · UI 包拆分 | +| **拒绝** | Cordis 化重写 · workflow 引擎 · seam 三包拆分体例 | + +--- + +## 1. 采纳项 + +### 1.1 工具输出溢出(spill)—— P0 + +**做什么**:任何工具的输出超过阈值时,全文写入 session 作用域的文件,模型收到的是 +`预览(头 + 尾)+ 字节数 + 取回路径`。取回沿用现成的 `Read`(带 offset/limit),不新增工具。 + + + + +
+ +**正方** + + + +**反方** + +
+ +- 修复的是已查实的 bug,不是锦上添花:`WebFetch` 现在能把 5 MiB 正文灌进上下文(约 150 万 token), + 一次调用即毁掉整个 session。 +- `Bash` 30 KB 截断后尾部**无处可寻** —— 而失败测试的关键信息通常正在尾部。 +- 成本极低:DeepCode 已有 `sessionDir` 与 `PostToolUse` 后置点,落点现成。 +- 与 DeepCode 已有的 snapshot / ledger 同构 —— 都是"把易失的东西钉在 session 目录里"。 + + + +- 又多一类要清理的 session 产物;`~/.deepcode/sessions` 已经有 snapshots 了。 +- 模型未必会去 `Read` 那个文件,可能拿着预览就瞎猜 —— 那还不如直接截断来得诚实。 +- 阈值定错会有反效果:定低了,本该直接进上下文的中等输出被推到盘上,多花一轮 `Read`。 + +
+ +**裁决:采纳。** 反方第 2、3 点是**设计约束而非否决理由**,按它们收紧设计: + +- 预览必须**同时保留头和尾**(dsh 只要求 bounded preview;这里加严)。测试失败、堆栈、报错 + 几乎总在尾部,只留头是最糟的截断方式 —— 也正是 DeepCode 今天在做的。 +- 取回提示写进结果文本本身("完整输出见 X,用 Read 的 offset/limit 取"),不靠模型自己想到。 +- 阈值可配置,默认取 Bash 现有的 30 KB —— 这样对既有行为**不新增**推到盘上的情况,只是把 + 原本丢掉的部分变成可取回。 +- 反方第 1 点接受为已知代价:spill 文件与 snapshots 同在 session 目录下,共享未来的保留期清理。 + +### 1.2 重复调用护栏 —— P0 + +**做什么**:连续以**完全相同的参数**调用同一工具达到阈值(3/5/8)时,向下一轮注入升级式提醒: +先短提示,再详细提示(点名工具、连续次数、参数摘要)。不拦截、不改写、不进工具列表。 + + + + +
+ +**正方** + + + +**反方** + +
+ +- 卡死循环是 agent 最贵的失败模式:不报错、不停止,安静地烧完预算。 +- DeepCode 已有 `reminders/` 子系统(纯函数 builder + `` 包装),这是**零架构成本**的落点。 +- 纯建议、不否决 —— 合法的重复调用一点不受影响,误判代价是几十 token。 +- 与 DeepCode 的 `/cost` 计价意识天然互补:省下的是真金白银。 + + + +- 启发式,必然误伤:轮询一个文件等它变化,就是合法的同参重复。 +- 状态放内存,session 恢复后清零 —— 恢复到一半的循环要重新数。 +- 阈值是又一个要调的旋钮。 + +
+ +**裁决:采纳。** 反方三点全部接受为**已知且可容忍的代价**,理由是本机制的否决权为零: +误判的唯一后果是模型多读一句提醒。dsh 的取舍相同(其 README 明说 in-memory only、 +"later reminders are the accepted cost"),这里沿用。 + +一处**加严**:dsh 默认排除 `todo_write`,理由是记账工具不该洗白循环。DeepCode 对应的 +`TodoWrite` 同样排除,并追加排除 `AskUserQuestion`(等用户回答期间的重复是正常的)。 + +### 1.3 逐工具超时策略 —— P1 + +**做什么**:在中央调度点为每次工具调用武装一个 deadline,超时则以错误结果收尾并解释原因。 +默认值按工具族给(网络类宽、本地类紧),可配置。 + +**正方**:今天只有 `Bash` 自带 timeout;一个 `Grep` 打到网络挂载盘、一个 `WebFetch` 卡在慢 +TLS 握手,都能让整个 turn 无限期挂起,而**用户在 REPL 里看到的只是光标在闪**。 +**反方**:多数工具本就有自己的超时(fetch 有、ripgrep 会退出),加一层可能与内层超时打架, +出现"两个超时谁先响"的模糊语义;且强行中止的工具可能留下半截副作用。 + +**裁决:采纳,但明确分层。** 外层 deadline 定位为**兜底**,默认值显著大于各工具内层超时, +使内层先响、错误信息更具体;外层只负责"内层根本没响"这一种情况。对有副作用的工具 +(`Edit`/`Write`/`Bash`),超时后的结果文本必须**明说副作用状态未知** —— 不假装什么都没发生。 + +### 1.4 持久 shell 会话 —— P1 + +**做什么**:一组工具开启/发送/读取/关闭长生命周期 shell,跨调用保留 `cwd`、环境变量、 +shell 函数与后台进程。 + + + + +
+ +**正方** + + + +**反方** + +
+ +- 今天每次 `Bash` 都是全新进程:`cd` 白做、`export` 白做、`source venv/bin/activate` 白做。 + 模型的应对是把整串前缀重复拼进每条命令 —— 又长又易错。 +- 起了 dev server 之后想看增量日志,现在只能 `Read` 那个日志文件轮询,而**轮询正是 §1.2 会触发的模式**。 +- 这是 DeepCode 与 dsh 之间**执行形态**上最实的一条差距。 + + + +- 长生命周期进程 = 泄漏源:session 崩了、进程没收,机器上留一堆孤儿 shell。 +- 与沙箱语义纠缠:DeepCode 的沙箱是**每次 spawn 时**包 argv 的,一个持久 shell 在开启时确定 + 沙箱策略,之后策略变了它也不会重新武装。 +- `node-pty` 是原生依赖,要给 Tauri 打包的每个平台各编一份 —— 对一个 Mac 优先的产品是实打实的发布风险。 + +
+ +**裁决:采纳,但不用 PTY。** 反方第 3 点是决定性的:为交互式 TUI(vim、top)付出原生依赖 + +多平台编译的代价,而真实收益 90% 在"保留 cwd/env + 读增量输出"上 —— 这部分**不需要 PTY**。 + +改为 **marker 协议**:持有一个长期 `bash` 进程,命令后追加哨兵 echo,读到哨兵即认为该命令结束 +并取回退出码。纯 Node 管道,零原生依赖,跨平台。代价是不支持全屏 TUI 程序 —— 明确写进工具描述, +让模型知道该退回一次性 `Bash`。 + +反方第 1、2 点转为硬性设计要求: + +- 会话与 session 同生命周期,agent 退出时**全部收割**;再加空闲超时。 +- 沙箱策略在**开启时**固化并记录在案;策略变更不影响已开会话,工具描述明说这一点。 + +### 1.5 session 检索 —— P1 + +**做什么**:让 agent 检索**自己过去的 session**:按文本搜、按 session 取回片段。 + +**正方**:DeepCode 已经把每个 session 以 JSONL 写在 `~/.deepcode/sessions` —— 数据在那儿, +只是没有出口。"上次我们怎么解决这个 CI 报错的" 现在无法回答,而这正是本地 agent 相对云端 +agent 的天然优势(数据全在本机)。 +**反方**:跨 session 检索是**隐私与安全的新面**:A 项目的 session 可能被 B 项目的 agent 搜到, +把凭证片段、别的客户的代码带进当前上下文。dsh 用 SQLite FTS,等于再引一个原生依赖 + +一份要维护的索引与 schema 版本。 + +**裁决:采纳,但按反方收窄两处。** + +- **默认按 workspace 限定**:只搜 `cwd` 相同(或其子目录)的 session。跨 workspace 检索需显式开启。 + dsh 的工具名即 "workspace-authorized session queries",方向一致,这里作为默认而非选项。 +- **不引 SQLite**:流式扫 JSONL + 正则。个人本地 agent 的 session 量级(数百到数千个文件)下, + 一次扫描是几十毫秒量级,不值得为它背一个索引的一致性问题。真到量级不够时再加索引, + 接口不变。 + +### 1.6 工具渲染意图 + 桌面端渲染 —— P1(UI) + +**做什么**:`ToolDefinition` 增加一个**渲染意图**声明(`generic` / `terminal` / `diff` / `locations`), +桌面端 `ToolCard` 按意图选择呈现:`Edit`/`Write` 出真 diff,`Bash` 出终端样式, +`Read`/`Grep`/`Glob` 出可点击的文件位置列表。 + +**正方**:[`THREE_WAY_REVIEW.md`](THREE_WAY_REVIEW.md) 判定"**下一阶段 ROI 几乎全在 UI 出口**", +而这是 UI 出口里最集中的一处:用户 90% 时间盯着工具卡片,今天它们**全长一个样**。 +dsh 把渲染意图定为工具设计的一部分("decided up front",且呈现函数必须是 args 的纯函数), +这条纪律恰好能让 CLI 与桌面端**共用同一份判断**。 +**反方**:把呈现关注点塞进 `ToolDefinition` 会污染内核 —— `packages/core` 一直标榜"无 UI 依赖"。 +而且现有 `ToolCard` 已经有 `diff` 布尔参数,不做这层抽象也能给 Edit 出 diff。 + +**裁决:采纳,按反方保持内核纯净。** 渲染意图是**枚举字符串 + 纯数据**,不含任何 React/DOM 类型, +不引入 UI 依赖 —— 这与 `packages/shared-ui` 只放跨端类型的既有做法一致。反方的替代方案 +(在桌面端硬编码 `name === 'Edit'`)会把同一份知识在 CLI、桌面端、VS Code **各抄一遍**, +下一个新工具就得改三处。声明在工具自己身上,三端各自读。 + +### 1.7 模型无关的结果剪枝 —— P2 + +**做什么**:compaction 触发前,先跑一遍**不花模型调用**的剪枝:丢弃早期已被同路径新结果覆盖的 +文件读取、已失效的目录列表等。 + +**正方**:今天 compaction 一律走 LLM 摘要,**要钱要时间**;而历史里最大的一块往往是同一个文件 +被读了五遍,其中四遍已经过时 —— 这部分丢弃是无损的,不需要模型判断。 +**反方**:判断"已被覆盖"要有语义,判错就是删掉模型还需要的东西,而且**静默** —— 比 LLM 摘要 +更难发现出了问题。 + +**裁决:采纳,但只做能证明无损的一类。** 首版仅剪枝"**同一 `file_path` 的更早 `Read` 结果, +且其后存在同路径的成功 `Read`/`Edit`/`Write`**" —— 这一类可以从工具调用记录本身证明后者取代前者。 +被剪枝的位置留一行占位说明("此处有一次已被后续读取取代的 Read"),使其可见而非静默。 +其余类型不做。 + +--- + +## 2. 拒绝项 + +### 2.1 Cordis 化重写 —— 拒绝 + +即"一切皆插件",把 agent loop、工具注册表、session 日志都变成可从配置替换的插件行。 + + + + +
+ +**正方** + + + +**反方** + +
+ +- 这是 dsh 最核心的主张,也确实解释了它为什么能长出 52 个工具而不失控。 +- 可逆 effect(注册即返回 disposer)是真优雅,能一举解决 DeepCode 现在插件卸载残留的问题。 +- 用户明确授权了"可以整体重构"。 + + + +- **219 包 vs 4 包**。这个倍率的来源是 dsh 要**对外分发插件生态**(`dsh-plugin` topic、 + 第三方 bundle、profile 模板)。DeepCode 没有这个产品前提 —— 抄的是成本,抄不来收益。 +- dsh 自称 developer preview 且**首屏明示会破坏兼容**。DeepCode 已发 0.3.0,有 npm 包、VSIX、 + DMG、update feed 这些下游。拿一个自称会破坏兼容的框架重写已发布产品的地基,风险收益完全不对称。 +- Cordis 是 **vendored** 进 dsh 的 —— 连它自己都不敢直接依赖。DeepCode 采纳意味着要么也 vendor + 一份(多一个上游要跟),要么依赖一个 0.x 外部框架。 +- 机会成本:这次重写会吃掉本轮全部预算,而 §1 的七项**没有一项需要它**。 + +
+ +**裁决:拒绝。** 用户授权了"可以整体重构",但授权是**许可不是要求** —— 判断哪里值得重构正是 +这份方案该给的答案。这里的答案是:**取它的纪律,不取它的框架**。 + +具体地,`ctx.spillStore` 式的三角色 seam 在**真有第二个 provider 时**才建(例如 spill 的 +"本地文件 vs 未来的远程存储"),且在 DeepCode 里表现为**一个模块里的接口 + 实现**, +不拆成三个包。dsh 的三包拆分在 219 包的规模下自洽,在 4 包的仓库里只是目录噪声。 + +### 2.2 workflow 引擎 —— 拒绝(本轮) + +模型编写编排脚本、worker thread 执行。 + +**正方**:表达力远超固定的 sub-agent 派发,能跑出真正的 fan-out/verify 结构。 +**反方**:引入"**模型写代码然后我们直接执行**"这一整个新攻击面 —— 而 worker thread +(dsh 自己也承认)**不是安全边界**。DeepCode 的 `Task` + `TaskCreate` 已覆盖多数编排场景。 + +**裁决:拒绝本轮。** 收益是"更强的编排",而 DeepCode 尚无被现有 sub-agent 卡住的实际用例。 +在没有用例的情况下引入一个明知不是安全边界的代码执行路径,顺序错了。 + +### 2.3 goal 域与 Ralph 循环 —— 推迟 + +**推迟理由**:这两项改变的是"**agent 什么时候停**" —— 是产品取舍,不是能力补齐。 +一个持久目标 + 自动续跑会显著改变 DeepCode 的交互性格(从"回合制"变成"自主推进"), +这该由用户拍板,不该由实现方在一轮技术采纳里顺手决定。列入 backlog。 + +### 2.4 作业注册表统一 —— 推迟 + +DeepCode 今天有两套后台机制:sub-agent 走 `TaskManager`,后台 Bash 走日志文件。dsh 用一个 +`ctx.jobs` 统一。**推迟理由**:这是纯重构(用户可见行为不变),价值在于未来少写一套; +而 §1.4 的持久 shell 会**改变**后台执行的形态。先落 §1.4,等形态稳定后再统一, +否则会统一到一个即将过时的模型上。 + +--- + +## 3. PR 拆分 + +每个 PR 独立可回退,按依赖顺序: + +| # | 内容 | 依赖 | 类型 | +| --- | --------------------------------------- | ---- | ------- | +| 1 | 本文档 + 调研报告 | — | docs | +| 2 | spill:存储 + 策略 + 接入 Bash/WebFetch | — | feature | +| 3 | 重复调用护栏 | — | feature | +| 4 | 逐工具超时兜底 | — | feature | +| 5 | 持久 shell 会话(marker 协议) | — | feature | +| 6 | session 检索(workspace 限定) | — | feature | +| 7 | 工具渲染意图 + 桌面端 diff/终端渲染 | — | feature | +| 8 | 模型无关的结果剪枝 | — | feature | + +PR 2 与 PR 7 各自触及 `ToolResult` / `ToolDefinition`,若并行会在 `types.ts` 冲突 —— +按上表顺序合并,或后者 rebase。 + +## 4. 验证要求 + +每个实现 PR 必须满足: + +- 新增纯函数逻辑有单元测试(阈值边界、预览首尾保留、workspace 过滤等) +- `pnpm typecheck && pnpm lint && pnpm format:check && pnpm test` 全绿 +- 触及桌面端的 PR 需在预览 harness 中实际渲染并截图自验(沿用 `preview-app.html` 的既有做法) +- 不引入原生依赖(§1.4 与 §1.5 的裁决即由此约束推出) diff --git a/docs/research/deepseek-harness.md b/docs/research/deepseek-harness.md new file mode 100644 index 0000000..14370a8 --- /dev/null +++ b/docs/research/deepseek-harness.md @@ -0,0 +1,193 @@ +# DeepSeek Harness (`dsh`) 调研报告 + +> 调研对象:[`deepseek-ai/deepseek-harness`](https://github.com/deepseek-ai/deepseek-harness) +> 基线:`47f94385`(2026-08-13)· 版本 `0.1.0-rc.5` · MIT +> 方式:**一手克隆通读**源码树与 `docs/`,不采信第三方转述 +> 对照基线:DeepCode `main@4d56f44`(0.3.0) +> 配套文档:[采纳方案与辩论](../DSH_ADOPTION_PLAN.md) + +--- + +## 0. 证据分级 + +沿用 [Floatboat 调研](floatboat.md)确立的分级,**只有 A/B 级可作为设计依据**: + +| 级别 | 含义 | +| ---- | ---------------------------------------------------- | +| A | 亲自读过该仓库的源码或规范文本,可指出文件路径 | +| B | 该仓库自己的文档明确声明,但未跑通验证 | +| C | 第三方转述、发布稿、社区讨论 —— **不得作为设计依据** | + +本报告未运行 `dsh`(需要 `DEEPSEEK_API_KEY` 与完整 `pnpm build`),因此**所有关于运行时行为的 +结论均为 B 级**;关于代码组织、接口形状、包边界的结论为 A 级。凡 B 级结论,本文在采纳时 +一律要求 DeepCode 侧**自己重新设计并测试**,而不是照抄实现。 + +--- + +## 1. 它是什么 + +DeepSeek 官方的开源 agent harness,与 DeepCode 属于**同一生态位的直接对照物**:都是驱动 +DeepSeek 模型的 coding agent 运行时。这使它比 Claude Code / Codex 更值得逐项比对 —— 后两者的 +一半功能(云端任务、团队、MDM)在 DeepCode 的定位下没有价值,而 dsh 的取舍面对的是同一组约束。 + +规模(A 级): + +| 维度 | 数字 | +| ------------ | -------------------------------------------- | +| workspace 包 | **219** 个(`packages/<组>/<包>/`) | +| 模型可见工具 | **52** 个(`docs/tool-catalog.md` 逐个列出) | +| 前端 UI 包 | 40 个(`packages/client/ui-*`) | +| 应用 | `apps/cli`、`apps/web` | +| 状态 | developer preview,**明示会破坏兼容** | + +### 1.1 架构:一切皆插件 + +核心主张是 **everything is a plugin**(A 级,`docs/architecture.md`):模型适配器、工具注册表、 +session 日志、**乃至 agent loop 本身**都是插件,全部可从配置替换。没有"特权内核"可打补丁 —— +扩展方式是在插件树旁边挂一个新插件。 + +底座是 [Cordis](https://github.com/cordiverse/cordis)(vendored 进仓库):插件向共享 context +贡献 service、类型化事件与**可逆 effect**;`register()` 返回 disposer,插件卸载时注册自动回滚。 + +组合方式是三层: + +- **profile** —— 一个命名组合(`web` / `headless`),列出它叠的 bundle +- **bundle** —— Cordis 配置行的分发格式 +- **patch** —— 按 id 覆盖某一行的整份 config + +`dsh --profile web --dump-config` 打印实际启动的树,任何一行都能被自己的 patch 换掉。 + +### 1.2 capability seam(能力缝) + +贯穿全仓的组织纪律(A 级,`docs/capability-seams.md`):一条 seam 由**三个角色**构成 —— + +| 角色 | 职责 | 例 | +| ------------------ | ------------------ | ----------------------------------- | +| Service Definition | 声明接口 | `dsh-spill` 定义 `ctx.spillStore` | +| Service Provider | 实现它 | `dsh-spill-local` 存本地文件 | +| Consumer | 使用它(常为工具) | `dsh-spill-policy` 在后置钩子上应用 | + +规则是"**一条 seam 是完整的三者,绝不是其中之一**"。收益不是抽象洁癖:文件系统与子进程 +provider 共享同一个执行世界,于是**把它们指向远程沙箱,Bash / PTY / LSP 会一起搬过去**, +不需要给每个工具各写一份远程分支。这是本次调研里最值得学的一条纪律。 + +### 1.3 turn 流水线 + +```text +turn/start + claim 输入 → 装配 prompt sections + tool schemas + → agent/pre-step (waterfall: 可改写或拒绝这一步要送给模型的消息) + step/start + agent/request → llm/stream → assistant/chunk* → assistant/message + tool/call* → tools/pre-execute → tools/execute → tools/post-execute → tool/result* + step/end + → agent/turn-stopping +turn/end +``` + +**model-visible ⟺ logged**(A 级):任何进入模型请求的东西都必须能从 session 日志重建,且有 +runtime invariant 断言这一点。这条不变量比它听起来重要 —— 它把"注入上下文"从一个随手能加的 +后门,变成一个必须先扩展事件表的动作。 + +--- + +## 2. 能力差异矩阵 + +图例:`✅` 有 · `🟡` 有但形态不同/受限 · `❌` 无 + +| 能力 | dsh | DeepCode 0.3.0 | 差距判定 | +| ------------------------- | ----------------------------------------------------- | ----------------------------------------------------------------- | -------------------- | +| **工具输出溢出(spill)** | ✅ 超限输出落盘,模型拿到预览 + 定位符 | ❌ Bash 30 KB 硬截断,尾部**永久丢失** | **真差距 · 高价值** | +| **重复调用护栏** | ✅ 连续同参调用达阈值注入升级式提醒 | ❌ 无 | **真差距 · 低成本** | +| **逐工具超时** | ✅ 部署策略层统一武装 deadline | 🟡 仅 Bash 自带 timeout | **真差距 · 低成本** | +| **持久 shell / PTY** | ✅ `terminal_open/send/read/signal/close/list` | ❌ 仅一次性 Bash;后台命令写日志文件 | **真差距 · 中成本** | +| **session 检索** | ✅ `session_search` / `session_trace` + SQLite FTS | ❌ JSONL 在盘上,无检索 | **真差距 · 中成本** | +| **后台作业注册表** | ✅ 统一 `ctx.jobs`:list/output/kill + 完成通知 | 🟡 sub-agent 有 TaskManager;后台 Bash 走日志文件(**两套机制**) | 中差距 | +| **持久目标(goal)** | ✅ 事件溯源的 goal + 续跑驱动 | 🟡 TodoWrite(每 session 文件,无续跑) | 中差距 · 需产品取舍 | +| **Ralph 循环** | ✅ 一个不可变目标喂给一串全新子 agent | ❌ 无 | 中差距 · 需产品取舍 | +| **模型无关的结果剪枝** | ✅ compaction-tool-result-pruner | 🟡 只有 LLM 摘要式 compaction | 中差距 · 低成本 | +| **workflow 引擎** | ✅ 模型编写脚本,worker thread 执行 | 🟡 Task/sub-agent 覆盖多数场景 | 弱差距 | +| **工具渲染意图** | ✅ 每个工具声明 `generic`/`terminal`/`diff`+locations | ❌ ToolCard 一律通用卡片 | **真差距 · UI 杠杆** | +| **UI 可扩展性** | ✅ 40 个 `ui-*` 包 + Chat 节点注册表 | 🟡 Repl.tsx 单体 | 中差距 | +| **ACP(编辑器协议)** | ✅ 自动化用 ACP server | 🟡 自有 app-server 协议 + LSP + VS Code | 弱差距 | +| 沙箱 | ✅ landlock(Linux) / seatbelt | ✅ + 选择性网络白名单 | **DeepCode 更强** | +| 文件契约 / 变更账本 | ❌ | ✅ File Contract + Change Ledger + rollback | **DeepCode 更强** | +| 计价意识 | ❌(未见 cache-hit 计价) | ✅ cache-hit 分档 + `/cost` 命中率 | **DeepCode 更强** | +| cron / 定时 | ✅ `schedule_*` | ✅ cron + 日历/文件触发 | 持平 | +| hooks | ✅ 桥接 Claude Code / Codex 钩子协议 | ✅ 原生 hooks | 持平 | +| skills / plugins / MCP | ✅ | ✅ | 持平 | + +### 2.1 顺带查实的两处 DeepCode 缺陷 + +调研过程中对照代码查实(A 级,指向本仓库源码): + +1. **`WebFetch` 把整个响应体灌进模型上下文** + [`web-fetch.ts:149`](../../packages/core/src/tools/web-fetch.ts) 直接 `content: body`, + 上游只有 5 MiB 的**字节**上限(`DEFAULT_MAX_BYTES`),**没有模型可见文本上限**。 + 一个 5 MiB 的 HTML 页面约合 150 万 token —— 远超任何上下文窗口,等于一次调用即毁掉整个 session。 + 这不是"可优化",是 bug。 + +2. **`Bash` 截断即丢失** + [`bash.ts:43-52`](../../packages/core/src/tools/bash.ts) 在 30 KB 处 `slice` 并追加 + `... [stdout truncated]`。被切掉的部分**不写任何地方**,模型没有任何手段取回 —— 一次 + `npm test` 的完整失败输出就这样消失了。 + +两者都由同一个能力修复:spill。 + +--- + +## 3. 值得抄与不值得抄 + +### 3.1 值得抄的:纪律与具体能力 + +- **capability seam 的三角色纪律** —— 但只在真有第二个 provider 的地方用(见方案文档的辩论) +- **spill** —— 直接修复上面两个缺陷 +- **重复调用护栏** —— DeepCode 已有 `reminders/` 子系统,这是现成的落点 +- **逐工具超时策略** +- **持久 shell 会话** +- **session 检索** +- **工具渲染意图** —— 前端最大的单点杠杆 + +### 3.2 不值得抄的:Cordis 化重写 + +**这是本次调研最重要的否定结论。** 详细辩论见[方案文档 §2.1](../DSH_ADOPTION_PLAN.md),此处只记事实: + +- dsh 用 **219 个包**表达 DeepCode 用 **4 个包**表达的东西。这个倍率不是浪费,是它的产品前提 + (对外分发插件生态、`dsh-plugin` topic、第三方 bundle)造成的必要成本。**DeepCode 没有这个 + 产品前提**,抄成本不抄收益。 +- dsh 自己标注 developer preview 且**明示会破坏兼容**;DeepCode 已发 0.3.0 且有下游(npm、VSIX、 + DMG、update feed)。拿一个自称会破坏兼容的框架去重写一个已发布产品的地基,风险与收益完全不对称。 +- Cordis 是 vendored 进 dsh 的;采纳它意味着 DeepCode 要么也 vendor 一份(多一个需要跟进的上游), + 要么依赖一个 0.x 的外部框架。 + +### 3.3 不确定、留待观察 + +- **workflow 引擎**(模型编写编排脚本,worker thread 执行)—— 概念上强,但 DeepCode 的 + Task/sub-agent 已覆盖多数场景,且它引入"模型写代码然后我们执行"的新攻击面。**暂不采纳**, + 等有真实用例再说。 +- **goal + Ralph** —— 是产品取舍而非补齐差距:它们改变的是"agent 什么时候停",属于需要用户 + 拍板的方向,不宜由实现方单方面决定。**列入 backlog,不进本轮。** + +--- + +## 4. 对方的不利事实 + +按调研纪律,同时记录不支持采纳的证据: + +- 版本 `0.1.0-rc.5`,README 首屏即为 **"THERE WILL BE COMPATIBILITY-BREAKING CHANGES"**(A 级)。 +- 219 个包中大量是三角色拆分的产物(如 spill 拆 3 包、goal 拆 4 包、terminal 拆 3 包)。这套 + 纪律在 219 包的规模下自洽,**在 4 包的仓库里照搬会变成纯粹的目录噪声**。 +- 文档密度极高(`docs/config-catalog.md` 3151 行、`tool-catalog.md` 1873 行)且大量为生成物 —— + 说明其可配置面已经大到必须靠生成器维护。这是能力的证据,也是复杂度的证据。 +- 未能验证运行时行为(无 key、未 build),所有行为结论均为 B 级。 + +--- + +## 5. 结论 + +dsh 与 DeepCode 在**内核能力上互有胜负**:DeepCode 在治理(文件契约、变更账本、沙箱网络白名单) +与计价意识上更强;dsh 在**上下文经济学**(spill、剪枝、检索)与**执行形态**(持久终端、作业注册表) +上更强,并且在**前端可扩展性**上领先一代。 + +采纳应当是**能力级的,不是架构级的**:取它的 spill、护栏、持久 shell、session 检索、渲染意图, +拒绝它的 Cordis 化重写。逐项辩论与 PR 拆分见[采纳方案](../DSH_ADOPTION_PLAN.md)。