← Back to home@Nagiko0739

dsh-turn-eraser

一款用于DeepSeek Harness的上下文管理插件,可删除单轮/多轮对话,可追溯,npm包同名

Stars
0
Language
JavaScript
Created
Oct 1, 2026
Updated
Oct 4, 2026

Introduction

dsh-turn-eraser

给 DeepSeek Harness(DSH)用的会话工具:删除某一轮对话,并在轮尾显示轮次编号(常驻)。

删除 = 把内容从模型可见的上下文里遮蔽掉。原始会话日志不变,随时可回溯。

使用删除后,模型在当轮会话中读取/占用的上下文是变小了的。

English summary ↓


为什么做这个

DSH 的会话记录是只追加的事件日志,本身不提供删除某一轮对话的入口。而实际使用中确实会遇到需要"擦掉"某段对话的场景:

  • 上下文被污染:某几轮让对话跑偏了,之后每轮都受影响,越聊越歪
  • 发错了话:提问打错、贴错文件
  • 整理会话:把试错的过程清理掉,留下干净的结论
  • 清理过长的上下文,防止模型上下文过重但是又暂时不想手动压缩。

本插件的特点是:每一轮都能删(包括"空回"轮次),并且删除可追溯。

功能

能力状态
删除某一轮(你的提问 + AI 的整轮输出)✅ 已实现
删除此处及以后✅ 已实现
每轮都有删除入口(含没有正式回答的"空回"轮次)✅ 已实现
删除后把该轮从界面上隐藏✅ 已实现
轮尾显示「第 N 轮」编号✅ 已实现
可追溯:读回被删除的原文✅ 已实现(见下)
删除整个会话❌ 未实现
彻底擦除(物理抹掉日志)❌ 未实现,也不建议(见「已知限制」)

安装

推荐:从 npm 安装(最省事)

在 DSH 的 设置 → 插件 → 添加插件 里,填入包名:

dsh-turn-eraser

或者用命令行:

dsh plugin --profile <你的配置档名> add dsh-turn-eraser

其他方式:同一个输入框也支持 GitHub 仓库地址或本地目录路径。 (本插件的仓库在 Nagiko0739/dsh-turn-eraser。)

使用

每一轮的尾部有一个小垃圾桶图标:

  1. 点它 → 浮出两个按钮:删除本轮 / 删除此处及以后
  2. 选中哪个,哪个就变成 再点一次确认
  3. 再点一次,才真正删除(4 秒不操作自动收起,防误触)

删除后:

  • 模型:从下一轮起再也看不到已删除的内容,只会看到一个占位符,例如 [已删除第 20~22 轮]
  • 界面:那一轮整体隐藏(含思考过程、工具调用的折叠块)
  • 磁盘上的日志:原文完整保留

工作原理:墓碑(tombstone)

DSH 的会话日志是"只追加"的,历史无法就地改写。所以本插件的删除是这样实现的:

往日志尾部追加一条墓碑事件,声明「把第 X 到第 Y 条事件从可见上下文里替换掉」。

原始事件仍然躺在日志里,只是不再进入模型可见的 surface。

墓碑里写什么是有讲究的:写的是轮次号(如 [已删除第 20~22 轮]),不是内容摘要。 因为模型只需要知道洞在哪,不需要知道洞里是什么——而被删的主题本身, 可能正是你想让它消失的东西。

一条墓碑长这样:

{
  "type": "user/message",
  "data": {
    "content": [{ "type": "text", "text": "[已删除第 20~22 轮]" }],
    "source": {
      "producer": "session-tools",
      "action": "delete",
      "removed": [1634, 1636, 1638],
      "turn": 20,
      "preview": "(被删内容的一小段预览)"
    }
  },
  "surfaceOp": { "op": "replace", "startSeq": 1634, "endSeq": 1654 },
  "sourceEventSeqs": [1634, 1636, 1638]
}

⚠️ 两个技术细节,踩过坑:

  1. 墓碑必须是 user/message,不能是 assistant/message(后者携带 sourceEventSeqs 会被 DSH 的写入校验拒绝)
  2. 墓碑内容不能为空(严格的第三方服务商会拒绝空 user 消息)

可追溯:把删除的内容读回来

这是本插件的一个设计:删除不等于销毁。

📌 这个小工具需要系统的 zstd 命令来解压会话日志。 macOS 默认没有,装一下:brew install zstd。 缺了它会直接告诉你缺什么,不会假装"这个会话没有删除记录"。

# 列出所有会话的删除记录
python3 tools/trace_deletions.py

# 筛选 + 展开被删原文
python3 tools/trace_deletions.py <关键词> --full

输出示例:

会话 session-xxxxxxxx
  共 1 条墓碑

  墓碑 seq=1891  动作=delete  遮蔽 8 个事件
  被删内容预览:'行,咱们试试新上手的 pypdf 工具…'
  ---- 以下为原始内容(模型已看不到,日志里仍在)----
    seq=1634 [user/message]      (你的原话,完整)
    seq=1636 [assistant/message] (AI 回复正文)
    seq=1638 [tool/result]       (工具执行结果)

能做与不能做,说清楚:

能不能
查出"删了什么、什么时候删的、属于哪一轮"❌ 查不出"谁删的"(日志里没有操作者身份)
读回被删的原文(含思考过程、工具结果)❌ 不能一键撤销删除

轮次编号

垃圾桶的右边常驻显示这一轮的编号,例如「第 38 轮」。

编号在人和 AI 眼里是同一个数字,所以可以直接说「咱们第 38 轮说过什么?」,双方指的一定是同一轮。配合本插件的可追溯设计,AI 还能据此把那一轮的原文从会话日志里捞回来,哪怕它早就被压缩出了上下文。

编号取的是官方写在界面上的 data-turn-tail 属性(不依赖插件插槽传参)。

已知限制

  1. 不能一键撤销。DSH 的 surface 只有 append 和 replace 两种操作,replace 一旦执行,被替换的节点就从可见列表里消失了,后续事件无法把它放回去。要恢复已删除的对话,可以用「可追溯:把删除的内容读回来」一节里的 tools/trace_deletions.py 把原文读出来,或者直接让 agent 找回第 X 轮。
  2. 可追溯不等于防篡改。日志是明文 JSON,谁能读就能改。如果需要防篡改,得引入哈希链或外部存证——本插件没有。
  3. 依赖 DSH 的界面结构。删除入口挂在官方插槽 conversation.chat.turnTail 上。这是官方支持的做法,但如果 DSH 大改界面结构,插件可能需要跟进。代码里做了"读 DOM 兜底"以防万一。
  4. 引用了一个官方组件库(@deepseek-ai/dsh-client-ui-primitives)。官方文档并不推荐插件引用它。代码里做了自绘兜底:拿不到这个库时按钮依然可用,只是外观退化。
  5. "删除整个会话"尚未实现,目前也没有实现这个功能的计划。
  6. 不做物理擦除。本插件不会去重写会话日志文件——那是高风险操作(日志有连续编号,重排出错会导致整个会话打不开)。
  7. 删除只作用于当前会话。已经在运行的子 Agent 持有自己的上下文快照,看不到你之后的删除操作。所以主会话里删掉的内容,正在跑的子代理可能仍然记得——没人会告诉它"这段已经被删了"。多 Agent 场景下请留意这一点。

开发与测试

零运行时依赖(安装插件不会带进任何第三方 npm 包)。

node --check index.js client.js
node tests/run-all.mjs        # 一键跑全部 9 个测试(等价于 npm test / pnpm test)

想单独跑某一个:

node tests/01-tombstone-shape.mjs      # 墓碑形状是否符合 DSH 的全部约束
node tests/02-tool-params.mjs          # 工具参数解析
node tests/03-tool-execute.mjs         # 工具执行路径(含防死锁)
node tests/04-http-entry.mjs           # 界面按钮走的 HTTP 入口
node tests/05-real-log-regression.mjs  # 真实日志回归(无日志时自动跳过)
node tests/06-client-load.mjs          # 客户端 bundle 加载
node tests/07-truncate-span.mjs        # 截断的区间计算
node tests/08-tombstone-text.mjs       # 墓碑文案(单轮 / 截断 / 跳号)
node tests/09-trace-tool.mjs           # trace_deletions.py 烟雾测试(需要 zstd + python3)

致谢

  • dsh-turn-delete(MIT,作者 hanshenmesen)—— 「整轮删除」的思路、以及"用 DOM 兄弟遍历隐藏整轮"的做法借鉴自它。
  • dsh-message-recall(MIT)—— 墓碑写入的方式(user/message + surfaceOp: replace)参考了它,包括"占位文本不能为空"这个踩坑经验。
  • 开发过程:本项目由 Nagiko0739(需求、产品决策、测试、验收)与 AI 助手协作完成。代码主要由 AI 编写,方向与判断由人把关。

    依照多数司法辖区的规则,AI 生成内容不享有著作权,因此版权行只署名人类作者;AI 的贡献记在这里。

License

MIT © 2026 Nagiko0739


English summary

dsh-turn-eraser — a plugin for DeepSeek Harness (DSH) that deletes a conversation turn and shows each turn's number.

Install from npm: dsh-turn-eraser (or add the GitHub repo / local path in the DSH Plugins page).

Deletion works by appending a tombstone event that hides the target range from the model-visible context. The underlying session log is never rewritten, so the original text can always be read back with tools/trace_deletions.py.

  • ✅ Delete one turn (your prompt + the whole assistant reply), including turns with no visible answer
  • ✅ Delete from this turn onward
  • ✅ Every turn has a delete entry point (official conversation.chat.turnTail slot)
  • ✅ Shows the turn number at each turn's footer (「第 N 轮」), so you and the AI can name the same turn
  • 🔎 The placeholder carries turn numbers (e.g. [已删除第 20~22 轮]), not a summary — the model learns where the gap is, never what was in it
  • ✅ Traceable by design — deleted content is hidden, not erased
  • ❌ No "undo"; to recover content, read it back from the log
  • ❌ Not tamper-proof (the log is plaintext)
  • ⚠️ Deletion applies to the current session only: a sub-agent that is already running keeps its own context snapshot and may still "remember" deleted content

Licensed under MIT. Built by Nagiko0739 in collaboration with an AI assistant.