按含义裁剪智能体的大型工具输出,而不是按被截断的位置。
34.1/100
综合分
11
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/9/19 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
自动兼容检查有告警:未发布到 npm registry,仅可从源码安装。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add unclecode/toolshrink该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:仅索引
是什么
dsh 原生插件 · chat
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
更新放缓:最近一次提交在 76 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查⚠ 装前注意未发布到 npm registry,仅可从源码安装
展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✗npm 包toolshrink(未发布到 npm,仅可源码安装)
✓Node 引擎未声明 engines.node
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/25 17:10:47
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读写/删除本地文件
查看扫描证据(共 8 处,展示前 8 条)
- 写入本地文件adapters/harness/toolshrink.mjs:35
if (config.log) appendFileSync(config.log, text + '\n') - 读取本地文件dist/pipeline.js:102
for (const entry of readdirSync(dir).sort()) { - 写入本地文件dist/spill.js:21
mkdirSync(this.dir, { recursive: true }); - 写入本地文件dist/spill.js:28
writeFileSync(join(this.dir, `${tool}-${hash}.txt`), text); - 读取本地文件dist/spill.js:36
return readFileSync(join(this.dir, `${name}.txt`), 'utf8'); - 读取本地文件dist/spill.js:46
entries = readdirSync(this.dir); - 读取本地文件dist/spill.js:56
if (statSync(path).mtimeMs < cutoff) - 删除本地文件dist/spill.js:57
unlinkSync(path);
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
功能亮点
- 按语义压缩工具输出
- 内容感知精简器
按语义而非截断位置压缩智能体工具输出,含 13 个内容感知精简器和 DeepSeek Harness 插件。
README
由 DeepSeek 最新模型翻译生成toolshrink
按含义裁剪智能体的大型工具输出,而不是按被截断的位置。
我每天都在用 Claude Code,一直想插手它管理上下文的方式。早期还能直接改会话 JSONL,后来这扇门关上了。
DeepSeek 开源 Harness 之后,我翻了进去——那里一切都是插件。工具输出按大小裁剪:留头、留尾、丢掉中间。我又读了 Codex 和 pi,做法一样。没有谁去看文本里到底装了什么。
这种做法的失败方式完全可以预料。你的测试套件打印 5,000 行通过,中间夹着 3 个失败。按大小裁剪会留下通过的行,扔掉失败的行。模型读完,信了这次运行,答错了。
于是我做了这个裁剪器,就是我一直希望 Claude Code 有的那个。
展开完整文档(README 剩余 1 节)
toolshrink
按含义裁剪智能体的大型工具输出,而不是按被截断的位置。
我每天都在用 Claude Code,一直想插手它管理上下文的方式。早期还能直接改会话 JSONL,后来这扇门关上了。
DeepSeek 开源 Harness 之后,我翻了进去——那里一切都是插件。工具输出按大小裁剪:留头、留尾、丢掉中间。我又读了 Codex 和 pi,做法一样。没有谁去看文本里到底装了什么。
这种做法的失败方式完全可以预料。你的测试套件打印 5,000 行通过,中间夹着 3 个失败。按大小裁剪会留下通过的行,扔掉失败的行。模型读完,信了这次运行,答错了。
于是我做了这个裁剪器,就是我一直希望 Claude Code 有的那个。它先读输出,认出它的形状,然后留下真正承载信息的那部分:
input: a vitest run, 31,958 chars, 805 lines, budget 2,000 chars
head+tail cut: 1,904 chars the model learns: the summary
toolshrink: 255 chars the model learns: which test failed,
why, at which line, and the summary
删掉的内容全部计入一个模型能读到的标记,完整原文连同定位信息一起存到磁盘。没有任何东西被悄悄丢掉。
裁剪器
每个裁剪器认一种文本形状。第一个认出输入的裁剪器负责执行。一个都没认出时,走按大小的兜底逻辑,所以结果总能塞进预算。
| 裁剪器 | 识别 | 保留 | 丢弃 |
| diff | git diff、补丁 | 变更行、文件和 hunk 头、每侧 1 行上下文 | 未变更的上下文 |
| json | 单个 JSON 值 | 结构、长数组每 3 个采样、宽对象每 5 个键、计数 | 重复记录 |
| tests | vitest、jest、pytest、cargo test、go test | 失败用例及其说明、摘要 | 通过的测试 |
| build | tsc、cargo、gcc、webpack、esbuild | 错误和警告及其代码框、摘要 | 构建进度 |
| stacktrace | node、Python、Java、Ruby 堆栈 | 消息和你代码里的栈帧 | 依赖栈帧,已计数 |
| log | 带时间戳的日志 | 错误和警告及其前面的行、结尾 | 常规行 |
| tree | find、ls -R、文件列表 | 结构、每个目录 8 个条目、计数 | 过于拥挤的目录 |
| repeat | 重试风暴、进度刷屏 | 每轮 2 个采样,外加「2,998 similar lines omitted」 | 连续近似相同的行 |
| lint | eslint、ruff、clippy | 每条规则及其计数和示例位置、问题最多的文件 | 同一规则的重复出现 |
| install | npm、pip、pnpm、cargo | 摘要、版本、弃用提示、漏洞、错误 | 拉取和下载进度 |
| csv | CSV、TSV、管道表格 | 表头、开头 5 行、结尾 2 行、行列计数 | 中间的行 |
| gitlog | git log,两种格式都支持 | 最新的 15 条提交、总数、作者及各自数量 | 更早的提交 |
| size | 全部内容(兜底) | bash:末尾 · grep/read:开头 · 未知:两端 | 其余部分,只计数 |
今天随包发布的有十三种裁剪。每一种都是一个普通文件,共用同一套接口,所以你想加自己的裁剪,只需写一个文件,不必 fork。
每种裁剪都遵守四条规则,取自我看过的那三个智能体:
- 绝不返回半行(来自 pi)
- 绝不拆开 UTF-16 代理对(来自 DeepSeek Harness)
- 明确说清删掉了多少:... 15,903 characters, 401 lines omitted ...(来自 Codex)
- 再跑一遍不会有任何变化
配合 DeepSeek Harness 使用
一条命令:
dsh plugin --profile web add github:unclecode/toolshrink
安装就这一步。包里带了 dsh.bundle 清单,所以下次启动时插件就会挂载,默认预算 50,000 字符。想改预算,在你自己的层里改,~/.dsh/cordis.patch.yml:
- id: toolshrink
config:
maxChars: 20000
log: /tmp/toolshrink.log
想直接改代码?克隆下来,npm install && npm run build,然后用 insert 行按路径挂载适配器文件(见下面的适配器配置)。
适配器配置
- insert:
- id: toolshrink
name: /path/to/toolshrink/adapters/harness/toolshrink.mjs
config:
maxChars: 50000 # cut above this many characters (default 50000)
maxLines: 2000 # or above this many lines (default 2000)
maxLineChars: 0 # cap single long lines, 0 = off (default 0)
disable: [json] # skip named cuts (default none)
spillDir: ~/.dsh-toolshrink # where full originals go
log: /tmp/toolshrink.log # one line per cut, omit for silence
日志行格式:bash 64151 -> 2942 via tree+size。
当库来用
import { shrink, FileSpillStore } from 'toolshrink'
const out = shrink(bigText, { tool: 'bash', command: 'npm test' }, {
budget: { maxChars: 20_000 },
spill: new FileSpillStore({ dir: '/tmp/spills' }), // optional
})
out.content // the text to give the model
out.reduced // false when the input already fit
out.strategy // "tests", "diff+size", "size:tail", "none", ...
out.note // one human-readable line about what happened
out.stats // inputChars, outputChars, keptLines, droppedLines, ...
hint(第二个参数)可选,能让路由更准:tool 决定裁剪方向,command 帮助识别测试运行和 diff,path 帮助识别 JSON 和日志。
写你自己的裁剪
一种裁剪就是一个文件,默认导出三个成员。文件名就是裁剪名。
// mycut.mjs
export default {
name: 'mycut',
// Cheap and certain. When unsure, return false: a wrong match is worse
// than the size fallback.
detect(text, hint) {
return hint.command?.startsWith('kubectl') ?? false
},
// Return null to decline after a closer look; the next cut then tries.
reduce(text, hint, budget) {
const content = text.slice(0, budget.maxChars) // your real logic here
return {
content,
reduced: true,
strategy: 'mycut',
note: 'kept the part I know matters',
stats: {
inputChars: text.length, inputLines: 0,
outputChars: content.length, outputLines: 0,
},
}
},
}
用法:
import { shrink, loadReducers } from 'toolshrink'
const mine = await loadReducers('/path/to/my-cuts') // reads the directory
shrink(text, hint, { extra: mine }) // tried BEFORE built-ins
也可以控制内置规则:{ only: ['tests', 'diff'] } 限定并排序,{ disable: ['json'] } 跳过。
Spill:什么都不丢
有了 spill 存储,任何裁剪之前都会先保存完整原文,裁剪后的文本末尾会带上:
[full output saved as spill:bash-d63d2aebb643: directories sampled to 8 entries each]
store.load('spill:bash-d63d2aebb643') 返回原文,逐字节一致。文件 24 小时后清理。存储是一个接口;默认实现写文件,宿主也可以接入自己的存储。
实际使用中我看到的情况
预算 3,000 字符时,智能体拿到一个 60,000 字符的 find 结果,被裁到只剩开头。它的回复开头是:「输出被截断了。让我按目录统计一下数量」——它看到了省略标记,改用聚合重新查询,最后用总共 4,000 字符就答对了,而不是 60,000。
这就是设计生效的样子:一个诚实的标记,把裁剪从静默的数据丢失变成模型会据此行动的信号。这是我一直想要的干预手段,现在它只是一行 YAML。
TODO:接下来想做的裁剪
每一个都是一份文件,接口相同。挑一个,发个 pull request。
| 裁剪 | 识别 | 会保留 |
| semantic | 任何内容,只要给出智能体当前目标 | 与目标最相关的片段。分两阶段:先做词法打分(BM25,不需要模型),再可选做嵌入打分,捕捉字面之外的语义 |
| sql | 查询结果、EXPLAIN 计划 | 计划里开销大的节点,抽样结果行 |
| docker | 构建与 compose 输出 | 失败的层、最终镜像,丢掉构建过程中的杂音 |
semantic 是最有意思的一个:上面每个裁剪都按形状判断,这个要按相关性判断。它需要多一个输入——一个描述智能体当前在做什么的查询,宿主适配器可以通过 hint 传进来。
其他智能体的适配器
这个库对任何智能体一无所知。Harness 适配器只有 70 行:捕获结果事件,调用 shrink,返回替换内容。
- pi(earendil-works/pi)有扩展 API,可以访问工具结果。
- Codex(openai/codex)在 codex-rs/core-plugins 里有插件系统。
两个适配器都还没人做。如果你写了一个,欢迎发 pull request。
许可证
MIT。随便用,随便改,不用问。
作者 @unclecode,也是 Crawl4AI 。
在 X 上关注我,看我接下来做什么:x.com/unclecode。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
unclecode/toolshrink
按含义裁剪智能体的大型工具输出,而不是按被截断的位置。
相关插件 · 对话 / 记忆
上下文中枢oceanbase/powercontext
上下文跟着工作走 —— 跨会话、跨智能体、跨人。
★ 1,489已汉化DSH
73.1
智能体记忆库plastic-labs/honcho
Honcho 是记忆基础设施,用来构建有状态的智能体。这些智能体能理解不断变化的人、智能体、群组、项目和想法。
★ 7,918已汉化DSH
71.7
长程智能体控制面loopx-project/loopx
给 Agent 一个目标,让工作持续向前。
★ 6,358已汉化DSH
71.3
智能体上下文数据库volcengine/OpenViking
给 AI 智能体用的上下文数据库
★ 41,453已汉化DSH
71.3
长效机器人团队Fei2411/DS-Bot
Download DS Bot for Windows 10/11 64-bit / 下载 Windows…
★ 5,293已汉化DSH
71.2
可携带记忆层EverMind-AI/EverOS
为什么选择 EverOS
★ 13,797已汉化DSH
71.1
这是你的仓库?认领条目