跳到主要内容

dsh-tool-result-guard

已验证

dsh-tool-result-guard · v0.1.0 · MIT

Zero-loss tool-result pruning for the DeepSeek Harness (DSH): oversized tool results are spilled to a file first, then pruned with exact elided-span offsets and a recovery locator. A dsh-plugin.

安装

dsh plugin add dsh-tool-result-guard

dsh --profile default --dump-config 确认 layer 已生效 —— 参见安装指南

源码

发布到 npm 但没有公开仓库。安装前请检查包内容。

标签

作者

说明文档

dsh-tool-result-guard

English | 中文

DeepSeek Harness (DSH) 的零丢失工具结果剪枝插件。 一个 dsh-plugin

超大的纯文本工具结果会先完整落盘(spill),然后才被替换为有界的首尾预览;位于第 0 位的标记携带精确的被省略区间与 spill 文件定位符。模型永远可以找回中间部分;任何文本都不会在没有持久副本的情况下被丢弃。

[pruned: kept chars [0, 4096) + [28976, 30000) of 30000; the elided middle
[4096, 28976) is NOT lost — full output saved at: /tmp/dsh-spill/.../bash.txt.
Recover any elided span with the read tool (offset/limit), grep, or sed on that file.]

<head:前 4096 字符>

[... middle elided ...]

<tail:最后 1024 字符>

为什么

DSH 内置两套机制:

机制 触发时机 行为
dsh-spill-policy 结果 > maxInlineBytes(默认 50000 字节),post-execute 时 全文写入 ctx.spillStore,返回有界预览 + 定位符 —— 零丢失
dsh-compaction-tool-result-pruner 文本 > 8192 字符,且仅在 compaction 压力满足时 保留头 4096 + [... tool result middle pruned ...] + 尾 1024。原始事件虽留在 append-only 会话日志里供 replay,但模型没有定位符、没有偏移、也没有读日志的工具 —— 中间部分对模型不可恢复

缺口:约 8K 字符到 50K 字节之间、存活到 compaction 的结果会被无恢复路径地剪掉。本插件把剪枝提前到 tools/post-execute,先 spill 全文,再在标记里写入精确的省略区间 [head, total-tail) 和定位符。

安装后,内置 pruner 在 surface 上找不到超过 8K 字符的结果,自然空转;其行可留可删,spill-policy 同理(上限永远不会触达)。两者保留无害。

安装

一条命令:

dsh plugin --profile web add dsh-tool-result-guard

重启 DSH 即生效 —— 对该 profile 下的所有预设生效。卸载:dsh plugin --profile web remove dsh-tool-result-guard

调预算:在 profile 自己的 ~/.dsh/profiles/web/cordis.patch.yml 里按 id 覆盖:

- id: tool-result-guard
  config:
    thresholdChars: 16384
备选:免 pnpm 的单 preset 安装(只对某一个 agent preset 生效)
npx dsh-tool-result-guard install --preset my-preset --from standard

会把 shipped standard preset 复制到 ~/.dsh/.agent-presets/my-preset/,把 dsh-tool-result-guard.js 放到它的 agent.cordis.yml 旁边并追加插件行;用 my-preset会话即可。已有 user preset 用 --preset <id>(不带 --from)原地打补丁,remove --preset <id> 卸载,--print 只打印片段。等价手动安装 —— 把 index.js 复制到 preset 的 agent.cordis.yml 旁边并追加:

- id: tool-result-guard
  name: './dsh-tool-result-guard.js'

配置

未知键在加载时报错。所有预算以 Unicode code point 计(不会拆散代理对)。

默认 含义
thresholdChars 8192 扁平化后的纯文本结果超过该 code point 数时剪枝。
headChars 4096 内联保留的头部 code point 数。
tailChars 1024 内联保留的尾部 code point 数。
excludeTools ["read"] 结果永远放行的工具。默认排除 read 以防止 读 spill 文件 → 再被剪 → 再读 循环。可改为如 ["read", "subagent", "memory_search"]
spillDir (不设) 覆盖本地兜底 spill 目录(默认:OS 临时目录下的私有目录)。

headChars + tailChars 必须小于 thresholdChars,保证标记永远放得下。

行为准则

  • 失败放行(fail-open)。 没有会话属主、spill 后端不可用、写盘失败、或替换结果不满足更小/在预算内 —— 一律保留原始内联结果。剪枝绝不隐藏输出,绝不把成功调用变成错误。
  • 先 spill 后剪枝。 中间内容离开模型视野之前,全文已经持久化(优先走部署的 ctx.spillStore,否则写入进程私有的本地目录)。
  • 放行规则。 非 accept 决策、value 替换、嵌套复合子调用、被排除工具、含非文本块的结果(图片永不被修改)、以及阈值内的结果,原样返回。
  • 可组合。 以 prepend 方式注册 tools/post-execute waterfall 监听器并通过 next() 委托,工具自身的投影和其他 hook 先执行;被剪的是它们替换后的内容。additionalContexts 原样保留。
  • 幂等。 替换结果永远在 thresholdChars 以内,第二次经过不会再次剪枝。

模型如何找回中间部分

标记给出 spill 文件路径和精确的字符区间。模型用 read(offset/limit)、grep -nsed -n 'X,Yp' 读取该文件即可 —— read 的默认排除保证恢复性读取自身不会被剪。

开发

npm test          # node:test,零依赖

许可证

MIT