S
dsh-session-repair-ui
semidia/dsh-session-repair-ui
Session repair button in the conversation header: detects & fixes session-log corruption — tool-call id swaps, empty call ids (`message must have tool source`), unknown event types from disabled plugins (marks `ignorable`), torn zstd tails, missing final-frame newlines; ghost-style UI, auto-backup before writes.
安装
dsh plugin --profile web add github:semidia/dsh-session-repair-uiREADME
dsh-session-repair-ui
在 DeepSeek Harness 的会话头部(「导出会话」按钮旁)增加一个「修复会话」按钮,用于检测并修复会导致会话「加载失败 / 发不了新消息」的日志损坏:
- 助手消息声明了某个工具调用 id(
tool_calls),但落盘的工具结果却记成了另一个 id —— 接口在续写历史时报An assistant message with 'tool_calls' must be followed by tool messages responding to each 'tool_call_id'。- 模型输出了 id 为空的工具调用(
tool-call id=""、tool/call callId=""、tool/result source.callId="")—— 会话加载时报session event at seq N message must have tool source,整个历史被拒载。- 停用/移除插件留下的未知事件类型(如
polyglot/served)——加载时报SessionFormatUnsupportedError: … unknown to this harness and not marked ignorable。- 崩溃写入留下的 zstd 尾部残缺帧(torn tail)。
功能(v2)
- 点按钮弹出面板,自动只检测当前会话(只读,不改任何东西)。
- 诊断分类显示:
无损坏 / 发现 N 处空工具调用 id / N 处调用-结果串号 / N 个未知事件类型(可安全修复)/ N 处需手动处理(seq 缺口 / 版本不匹配)。 - 可安全修复项(自动):
- 调用-结果 id 串号 → 重映射(同 turn 内数量相等时);
- 空工具调用 id → 补确定性合成 id(
repaired-call-<seq>-<i>,message / tool/call / tool/result 三处一致); - 未知事件类型 → 事件信封标记
ignorable: true(官方信封契约的"可安全跳过"机制); - zstd 尾部残缺 → 截断到最后一个完整帧(与 DSH 自身 crash-repair 行为一致)。
- 只报告不自动修:seq 缺口/重复、header 版本不匹配(日志由更新版本 harness 写入)、torn 之外的不平衡。
- 修复前自动备份(
.bak-repair),绝不删已提交事件、绝不改 seq,其余字节原样保留。 - 修复成功后面板提示「已修复 N 处,请刷新页面重新打开本会话」。
- 样式遵循全局规则:幽灵式(透明底 + 细边框 + 主题文字色,激活态表面色填充),按钮与弹窗内部全部使用
--dsw-alias-*主题变量,浅色/深色/任意强调色主题下都清晰,与 DSH 官方按钮一致。
原理
修复逻辑在包内自带的 tools/repair-toolcalls.cjs(zstd 帧级读写,v2)里:
- 加载门分析(
analyzeLog):模拟 DSH 加载校验——header 版本、事件类型白名单(内置KNOWN_EVENT_TYPES镜像 + chunk 存储行标签)、chunk 行展开后 seq 连续性、JSONL 可解析性、zstd 帧完整性。 - 工具调用配对:按 turn 折叠「声明/发起的工具调用 id」与「结果 id」;
dangling(有调用没结果)与orphan(有结果但 id 对不上)数量相等时重映射;empty三队列(空 block/toolcall/result id)平衡时补合成 id;不平衡只报告、不猜。 - 未知事件 → ignorable:白名单外且非 chunk 存储行、未标
ignorable的事件,标记ignorable: true(纯诊断/插件事件可安全跳过,不参与 surface 折叠)。 - torn 尾截断:
scanZstdFrames找到最后一个完整帧之后的残缺字节,截断(备份后),与 DSHdsh-session-persistence-jsonl的 crash-repair 语义一致。 - 修复后自验:重跑加载门 + 配对分析,无残留才报告成功。
安装
- 把本目录放到 web profile 的
node_modules/dsh-session-repair-ui(或建 junction)。 - 在 profile 的
cordis.patch.yml里加一行:
- insert:
- id: dsh-session-repair-ui
name: 'dsh-session-repair-ui'
- 重启
dsh web。
架构
- Host(
lib/index.js):通过ctx.connection.rpc.handle('/dsh-session-repair-ui', …)暴露repair/scan(dry-run)与repair/apply,内部用node:child_process.execFile调用包内修复工具;摘要解析会区分「空 id 修复数」与「串号重映射数」返回给前端。 - Client(
lib/client.js):window.__ModuleLoader__.load客户端,注册到conversation.session.header.utilities,通过rpc.call调 Host;按钮与弹窗均使用幽灵式样式(--dsw-alias-*主题变量:透明底、细边框、主题文字色,hover/激活态用--dsw-alias-interactive-bg-hover/active表面色填充)。
独立 CLI
修复工具也可脱离 UI 单独用:
node tools/repair-toolcalls.cjs --root <sessions目录> --dry-run
node tools/repair-toolcalls.cjs --root <sessions目录> <session-id>
License
MIT