dsh-compaction-zh
把 DeepSeek Harness 的压缩检查点(compaction checkpoint)变成中文,并且不修改 harness 任何一行源码。
插件走运行时注入:监听 llm/stream,只改压缩那一次辅助调用的尾部指令,其余请求分毫不动。
为什么需要它
dsh-compaction-basic 把压缩指令硬编码成英文常量(COMPACTION_INSTRUCTION),其中一条规则是 "Write concise English engineering prose"。压缩检查点会成为后续每个请求的持久前缀,所以这条规则直接决定了检查点的语言:哪怕你整场对话都用中文,摘要仍然是英文。
上游没有留指令注入口:
COMPACTION_INSTRUCTION 是模块私有常量,未从包入口导出;
summarizeWithLlm() 不接受指令参数;
BasicCompactionEngine.summarize() 虽然是官方覆写点,但覆写它要自己重做整段模型调用与目标解析。
所以在配置层与子类层都不好做。本插件改用 harness 公开的事件契约:llm/stream 是「每一次流式模型调用」的瀑布事件(官方文档明确写着可拦截),压缩辅助调用同样经过它。
它做了什么
- 以
{ global: true, prepend: true } 监听 llm/stream;
- 只处理
options.purpose === 'compaction' 的辅助调用(普通对话请求 purpose 未设置,完全不被触碰);
- 从末尾找到压缩指令消息(用上游指令的特征片段确认,避免误改别的插件用同一 purpose 发的指令),把它换成中文版本;
- 把同一个请求对象交给下游。
三条边界保证它不会帮倒忙:
- 前缀字节不变:system、tools、历史消息原样保留,只有最后一条指令变了,所以 provider 的前缀缓存(KV cache)复用不受影响;
- 不确定就放行:识别不到压缩指令、请求被深冻结(loop 构造的请求)、消息含图片块等情况都不改写,只按
debug 记一条日志;
- 异常不扩散:任何意外都只写 warn,然后把原请求继续交给下游 —— 宁可检查点是英文,也不能让压缩失败。
它不改变压缩的触发阈值、保留窗口、重试策略,也不改任何已有消息对象。
启用:热挂载,不重启(推荐)
patchReload: live 的 profile 会把用户补丁层里的新增条目当场重组进来:不装依赖、不改 bundles、不重启宿主。
# %USERPROFILE%\.dsh\profiles\web\cordis.patch.yml
- insert:
- id: llm-compaction-zh
name: file:///D:/Code/dsh-compaction-zh/lib/index.js
config:
enabled: true
mode: instruction
name 是相对 loader 的 baseUrl(= profile 目录)解析的;跨盘时相对写法走不通,所以一律写绝对 file:/// 最省心(POSIX 上写成 file:///home/you/dsh-compaction-zh/lib/index.js)。
改之前先备份该文件。补丁写坏会被 HMR 拒绝并保留上一个好状态,不会打断正在跑的会话;事后把 enabled: false 或删掉这段就是热卸载。
启用:登记成 bundle(要安装 + 重启)
只有希望插件随 profile 自动启动时才走这条路:
// %USERPROFILE%\.dsh\profiles\web\package.json
{
"dependencies": {
"dsh-compaction-zh": "link:D:/Code/dsh-compaction-zh"
},
"dsh": {
"profile": {
"bundles": [
// ……原有 bundles……
"dsh-compaction-zh"
]
}
}
}
然后在 profile 目录跑一次 pnpm install,重启宿主。包里的 cordis.patch.yml 会自动插入上面那一行(dsh.bundle.patch)。
配置
| 字段 | 默认 | 含义 |
|---|
enabled | true | 关掉即不安装监听器 |
mode | 'instruction' | instruction:整条替换为中文指令;rule:只替换上游那条英文语言规则,其余结构与措辞逐字保留 |
instruction | 内置中文模板 | instruction 模式下使用的完整指令文本 |
rule | 内置中文规则 | rule 模式下替换英文规则行的文本(不含前导 - ) |
debug | false | 打开后每次压缩写一条 localized / skipped: <原因> 日志 |
配置键拼错、类型不对会在启动时直接拒绝并写一条 warn,而不是静默忽略 —— 半生效的本地化比没有本地化更难排查。
内置中文模板与上游结构同构:同样八个小节(主要请求与意图、关键技术概念、文件与代码、错误与修复、待办任务、当前工作、下一步、关键上下文)、同样的 (none) 空节约定、同样要求逐字保留精确的文件路径、命令、错误原文、标识符、数值、函数签名与语法片段。rule 模式则保留上游的英文小节标题,只把语言要求换成中文。
生效范围与已知影响
- 只影响新产生的压缩:自动压力压缩、上下文溢出恢复、手动
/compact 都会走本地化后的指令;
- 旧检查点不变:已经落库的英文检查点是历史消息,本插件不改写历史。下一次压缩会把它并入被压缩区域,届时产出的是中文检查点;
- 检查点前导语仍是英文:
This is an automatically generated checkpoint condensing an earlier span… 由 harness 代码写入 user/message,不经过模型,插件无法替换。摘要内容与结构是中文;
- 语言权衡要知情:上游之所以规定英文,是因为检查点是持久前缀,跟随对话语言会让该语言在后续压缩周期里持续累积并影响推理文体(见 DSH 的
2026-07-31-english-compaction-checkpoints 决策记录)。本插件正是有意选择相反的方向,请确认这是你要的;
- 多插件叠加:本插件
prepend: true 最先执行;如果还有别的插件也改写同一条指令,最后写入者生效(debug 日志能看出本插件是否被覆盖)。
验证
npm run link-dsh -- ../deepseek-harness # 首次:把 DSH 检出链接进来(仅本地 node_modules)
npm test # 编译 + 22 个用例
测试分三层:
tests/localize.test.mjs —— 纯改写逻辑:识别、改写、放行、冻结、配置校验;
tests/e2e.test.mjs —— 用最小假 ctx 驱动真实 apply(),验证监听器注册与改写结果;
tests/integration.test.mjs —— 真实 Context + 真实 LlmRuntime + 记录型 adapter,断言适配器最终收到的请求最后一条消息已经是中文指令,并验证普通对话请求逐字不变、prepend 顺序正确。
运行中确认:宿主日志出现 compaction-zh: active, mode=instruction 即已装好;把 debug 打开,每次压缩会打印 compaction-zh: localized by instruction。
开发
npm run link-dsh -- <path-to-dsh-checkout> # 或设 DSH_CHECKOUT 环境变量
npm run build # tsc → lib/(产物已提交,clone 即可挂载)
npm run typecheck
npm test
源码是三模块:src/instruction.ts(中文指令模板)、src/localize.ts(配置解析 + 请求改写,纯函数、零 harness 依赖)、src/index.ts(插件入口,只做装配与日志)。运行时产物不 import 任何 @deepseek-ai/*(源码里全是 import type),因此不存在与 harness 版本耦合的运行时依赖。
许可证
MIT