跳到正文
dsh-market 浏览插件 GitHub EN

zzdhsxk/dsh-session-migration-repair

修复无法被当前 DSH 版本迁移的旧版会话日志:从日志自身恢复缺失的工具调用 id/name,写盘前先用真实 v0→v3 迁移链验证,修复前自动备份。

Star 数 ★ 1 分类 会话与消息 收录于 2026-09-13

安装

在 DeepSeek Harness 里通过 dsh-market 安装

dsh plugin --profile web add dshmarket

或使用命令行

dsh plugin --profile web add github:zzdhsxk/dsh-session-migration-repair

装任何插件都等于在你的机器上跑第三方代码,权限和你本人一样大——能读你的文件、用你的凭据、访问网络。请先审阅源码,并尽量锁定 commit(github:owner/repo#sha)。

README

修复无法被当前 DSH 版本迁移的旧版(format v0)会话日志:诊断 → 备份 → 修复 → 用宿主自带的迁移链离线验证 → 落盘。

English | 中文

它解决什么问题

DSH 0.1.5 起,会话存储格式升级到 v3;打开老会话时 DSH 会走 v0 → v1 → v2 → v3 的迁移链,并对每一步做严格校验。旧版本写入时留下的空字段,当时的版本并不在意,但在迁移链上会直接拒绝,表现为「历史加载失败 / history unavailable」。本工具处理的就是这类日志。

它修的四类确定性缺陷(全部可自动修复):

报错 真因 修法
released tool-call-chunks row N id and optional name must be strings 流式工具调用的分片行 id 为空(旧版只在首行写 id) 从同 turn|step|index 的 assistant/chunk tool-call-delta 取回真实 id/name
assistant/message N message content[k] name must be a non-empty string 工具调用块的 name 为空(常见于更早的修复工具改写之后) 从同 step 的 delta 取回工具名
format v2 assistant/message ... invalid message content kind "tool-call": user/message 0 content[0] id must be a non-empty string assistant/chunk 的 block-end 里 tool-call 块的 id 为空(外层报错是误导,内层才是真因) 同样用 delta 的 id 补齐
tool/call ... does not match one advertised tool call tool/call.arguments 与消息里对外声明的 arguments 不一致 以未含替换字符(U+FFFD)的一侧为准,两侧写回同一份

安装

作为 DSH 插件(宿主侧注册一个模型可调用的工具 + 一个技能):

dsh plugin --profile web add dsh-session-migration-repair        # 从 npm
dsh plugin --profile web add github:<owner>/dsh-session-migration-repair   # 从 GitHub
# 之后重启 dsh web 并刷新页面

也可以完全脱离 DSH 单独用命令行(零依赖,需要 Node ≥ 22.15 —— Node 20 的 node:zlib 还没有 zstd API):

node bin/cli.mjs --help

命令行

dsh-session-migration-repair list                      # 列出所有会话(含代际与隔离文件)
dsh-session-migration-repair scan   <会话ID|路径>      # 只读诊断,不改任何文件
dsh-session-migration-repair validate <会话ID|路径>    # 跑完整迁移链(等价于"打开会话",但不影响服务)
dsh-session-migration-repair fix    <会话ID|路径> --yes # 备份 → 修复 → 校验 → 落盘

常用选项:--dry-run(只报告将改哪些行)、--no-fix-arguments(不动 arguments)、--dsh-home <dir>、--dsh-root <dir>(指定 DSH 安装位置用于离线校验)、--json。

示例输出:

$ dsh-session-migration-repair scan session-61c010f4-...
行数               : 59289
阻塞迁移的缺陷     : 160
  - packedChunkMissingId        : 112
  - messageToolCallMissingName  : 12
  - blockEndMissingId           : 12
  - blockEndMissingName         : 12
  - toolCallMissingName         : 12
工具链             : advertised=607 calls=607 results=607

$ dsh-session-migration-repair fix session-61c010f4-... --yes
已修复 session-61c010f4-...
  备份      : ~/.dsh/session-migration-repair/backups/<时间戳>/....pre-repair.jsonl.zstd
  改动行数  : 148
  体积      : 12280330 → 3851062 字节
  迁移链    : 通过 ✅ (3530 个 v3 事件)

安全设计

  • 先备份后改写:原件复制到 $DSH_HOME/session-migration-repair/backups/<时间戳>/,并追加一条审计记录到 audit/repair-log.jsonl。
  • 最小差异:只重新序列化真正变化的行(实测 59,289 行的会话只改 148 行),其余行原样保留。
  • 写前验证:修复结果先在本地跑完整 v0→v1→v2→v3 迁移链,通过才落盘;写文件用「临时文件 + rename」保证原子性。
  • 零依赖:不引入任何 npm 依赖,自带多帧 zstd 读写(DSH 的日志是多帧的,且首帧必须只含 header 一行;Node 自带的 zstd 只能解首帧)。

原理

  1. 多帧 zstd:lib/core/zstd.mjs 自己按帧边界拆分(只解析帧头与块头,不重实现压缩),逐帧解压后一次性 UTF-8 解码 —— 直接逐块拼接字符串会在块边界切断多字节字符,凭空制造 U+FFFD。
  2. 缺陷索引:每一次流式工具调用都由 assistant/chunk 的 tool-call-delta 宣告(含真实 id 与工具名),因此所有空字段都能从这张索引里补回。
  3. 离线验证:DSH 的 sessionFormatCatalog.createRestore() 就是它自己的装载路径,本工具直接驱动它 —— 校验结果与真实打开会话完全一致,不需要反复重启服务试错。

局限

  • 只能修文件仍在的日志(哪怕只剩 .corrupt-* 隔离备份)。整个会话目录被 rm -rf 的情况,本工具无能为力。
  • 只处理上述四类确定性缺陷;迁移链报出其它错误时会拒绝写入并原样保留文件。
  • 若日志里的文本本身已被写坏(含 U+FFFD),本工具只能保证「不再新增」破坏,无法凭空还原丢失的字符。

开发

node --test test/*.test.mjs                 # 单元测试
DSH_REAL_V0_LOG=/path/to/defective.jsonl.zstd node --test test/*.test.mjs   # 真实日志回归

许可

MIT

内容来自项目 README(GitHub)↗

评论

评论存放在 GitHub Discussions。用 GitHub 账号登录后可发表评论或点表情。