DeepSeek Harness 插件

JohnXu22786/context-pruner

Star 数 ★ 0 分类 记忆 收录于 2026-08-16

面向 DeepSeek Harness 长会话的上下文分诊插件:通过官方 ctx.compaction 接缝,用确定性规则筛查并裁剪过期、重复、失败与超大的上下文内容。

安装

# GitHub 源码(首次需按提示配置 allowBuilds 构建授权后重试)

dsh plugin --profile web add github:JohnXu22786/context-pruner

装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络,工具审批管不到它。GitHub 来源的插件还会在安装时执行构建脚本。请只安装可信来源,并尽量锁定 commit(github:owner/repo#sha)。

README

English

dsh-context-triage

会话上下文分诊插件,为 DeepSeek Harness(dsh)自动管理长会话的上下文体积:识别并处理过期、重复、失败、超大与低价值的消息内容,节约 token 预算,缓解上下文膨胀。

特性

  • 确定性、零模型依赖:全部判定与改写由启发式规则完成,不调用 LLM、不需要额外服务,行为可预测、可离线测试。
  • 五种筛查器(Screeners),各自独立可开关:
    筛查器 判定规则 处理动作
    过期输出 staleOutput 距最近用户消息超过 N 轮、且结果仍完整的工具调用对 调用块改写为归档摘要,结果块移除
    重复调用 repeatedCall 同工具、同参数(JSON 键序无关)的调用对 仅保留最近一次,旧调用对被切除
    失败调用 failedCall 过期的错误结果(isError 输入参数替换为失败桩(防泄露/省体积),错误文本保留并裁剪
    超长块 oversizedBlock 工具结果文本超过字符上限 头尾裁剪,中间标注省略量
    过期思考 staleReasoning 超过保留轮次的 reasoning 块;保留的块超出长度上限 移除;或裁剪(保留区内只剪不删)
  • 保留区(reserve):最近 N 个用户轮次内的内容一概不动,避免破坏模型正在使用的上下文。
  • 豁免清单(exempt):工具名与文件路径 glob 双维度豁免(默认保护 task/skill/todowrite/todoread/write/edit/batch 等有状态工具)。
  • "值得"检查:任何归档/桩化动作都要求改写后严格小于原文,杜绝越改越贵;调用对级别的动作(归档 = 改写 + 切除)以原子组方式整体生效或整体放弃。
  • 审计报告:每次分诊输出结构化统计——按原因汇总的条数与节省量、逐条明细、建议压缩区间;通过工具、命令与 CLI 三处可见。
  • 原生接入 dsh 压缩接缝:实现 ctx.compactionCompactionEngine),自动压力、上下文溢出、手动与强制区间压缩四条路径全部走 harness 官方机制,替换型摘要消息使用 checkpoint 来源,任何后端无关的消费者都能识别。

安装与挂载

插件以 bundle 形态分发:package.jsondsh.bundle.patch 指向 cordis.patch.yml(补丁内容为插入插件行,配置项可整行覆盖)。

在 DSH 中安装

dsh plugin --profile demo add github:JohnXu22786/context-pruner

方式一(本地目录挂载,推荐):

dsh plugin --profile web add link:/绝对路径/context-pruner

方式二(手动补丁):把 cordis.patch.yml 中的条目合并进 profile 的 cordis.patch.yml,或直接作为 overlay 启动:

dsh web --patch ./cordis.patch.yml

方式三(git 源):

dsh plugin --profile web add "github:你的仓库/context-pruner#main"

挂载后可用 dsh --profile web --dump-config 检查插件行是否进入启动树。

注意:ctx.compaction 同一上下文只能有一个提供者。若你的 profile 已加载其他压缩实现(如自带的基础压缩后端),请通过补丁 disabled: true 关掉其一,二者不能共存。

接口

入口(manifest)

包名 dsh-context-triagepackage.jsondsh.bundle.patch 声明 bundle)
主入口 lib/index.jsmain/exports;另有 ./core./dsh 子路径供嵌入方使用)
插件名 context-triage
依赖注入 tools(必需);命令注册表通过 ctx.get('commands') 可选探测,无则静默跳过
配置 导出 Config(Schemastery Schema),默认值见下文配置表

插件形态为函数式插件:导出 name / inject / Config / apply(ctx, config),由 cordis 校验配置并填充默认值后调用。

提供的扩展点

扩展点 说明
服务 ctx.compaction TriageCompactionEngine extends CompactionEngine,实现 compactIfNeeded(自动压力 / 溢出)、compactNow(手动空闲压缩)、compactRegion(强制区间压缩)
工具 triage_history 模型可见;参数 dryRun?: boolean。执行一次分诊并把审计报告返回给模型;dryRun=false 且存在值得处理的区间时直接应用
命令 /triage 人类命令,不经过模型;输出审计报告并应用值得的处理

压缩事务如何落地

分诊结果以标准压缩事务写入会话日志(append-only,不改写历史):

  1. compaction/start(持锁,直到配对的 compaction/end
  2. compaction/summary(摘要内容、被遮蔽区间、遮蔽 seq 清单与启发式 token 代价;llmStreamCall 缺省 = 非模型摘要)
  3. user/message + surfaceOp: { op: 'replace', start, end } + sourceEventSeqs(替换型摘要消息,source 为 checkpoint 来源)
  4. compaction/end

模型可见历史由会话日志派生,替换发生后 deriveMessages() 自然产出 [摘要消息, ...保留内容]——无需任何对历史记录的原地修改。

配置

全部字段有默认值,仅需覆盖想调整的部分;非法值(负轮次、比率越界等)在加载期直接抛错。示例:

# cordis.patch.yml
- insert:
    id: context-triage
    name: dsh-context-triage
    config:
      budget:
        contextTokens: 200000   # 小上下文模型按需调低
        softRatio: 0.6
      screeners:
        staleOutput: { turns: 5 }
        staleReasoning: { enabled: false }
      exempt:
        tools: [task, skill, write, edit]
字段 默认值 说明
enabled true 总开关
reserve.turns 3 保留区:最近 N 个用户轮次内的内容不接受任何处理
budget.contextTokens 1000000 预估上下文窗口(token),决定压力比率
budget.softRatio 0.7 使用率超过该比例 → 自动压缩触发(pressure)
budget.hardRatio 0.9 使用率超过该比例 → 压力报告标记为强制(hard)等级
budget.minSavingsTokens 2000 预估节省低于该值不做任何动作
screeners.staleOutput.turns 8 距最近用户消息超过 N 轮的调用对归档
screeners.repeatedCall.enabled true 重复调用切除
screeners.failedCall.turns 4 失败调用处理阈值(轮)
screeners.failedCall.errorKeepChars 400 失败调用保留的错误文本上限(字符)
screeners.oversizedBlock.capChars 6000 工具结果文本上限(字符),超出则头尾裁剪
screeners.oversizedBlock.headChars / tailChars 800 / 400 裁剪保留的头部/尾部长度
screeners.staleReasoning.keepTurns 3 保留最近 N 轮用户消息内的思考块
screeners.staleReasoning.maxBlockChars 2000 保留思考块的长度上限,超出裁剪
exempt.tools [task, skill, todowrite, todoread, write, edit, batch] 豁免工具名
exempt.filePatterns [] 豁免路径 glob(匹配调用参数 filePath/path),如 ['**/*.lock']
summary.capChars 20000 压缩摘要字符上限
summary.headRatio 0.4 摘要裁剪时的头部保留比例

本地体验(无需 dsh)

src/core 是框架无关的引擎,附离线回放 CLI,可直接对一份 JSONL 会话文件运行:

npm install
npm run build
node lib/cli/replay.js examples/session.sample.jsonl --config examples/demo.config.json
node lib/cli/replay.js examples/session.sample.jsonl --config examples/demo.config.json --show-transcript

回放格式(每行一个 JSON 事件,seq 由行序决定):

{"type":"user/message","text":"项目构建失败了"}
{"type":"assistant/message","reasoning":"…","calls":[{"id":"c1","name":"bash","arguments":"{\"cmd\":\"npm run build\"}"}]}
{"type":"tool/result","callId":"c1","text":"…","isError":false}

示例输出见 examples/report.example.md;测试覆盖全部筛查器、合并优先级、原子组、审计一致性与端到端回放(npm test)。

设计取舍

  • token 估算是启发式:CJK 约 1 token/字、其余约 4 字符/token,仅用于压力判断与审计统计,不参与计费。窗口大小请按实际模型配置 budget.contextTokens
  • 改写必有净节省:归档摘要、失败桩、裁剪三者都在动作前比较改写前后规模,不划算的发现被自动放弃;调用对动作以原子组整体判定,不会出现"摘要留下、结果被拆"的半吊子状态。
  • 提示缓存:压缩会改变消息序列,使该点之后的提示缓存前缀失效。长会话中节省的 token 通常远大于缓存重算成本;对按请求计费的提供商(无缓存计费)则只有收益。
  • 不碰用户输入:超长块筛查只作用于工具结果;用户消息除非被整体保留区覆盖,否则永不被改写。

许可

本项目基于 MIT 许可开源。

内容来自项目 README(GitHub)↗

链接

同类插件

查看整个分类 →