Leeminjing/dsh-messages-sanitizer ↗★ 0
dsh-messages-sanitizer
DeepSeek Harness plugin: auto-repairs an invalid messages array (orphaned tool_calls / tool messages) to stop 400 INVALID_REQUEST session lock-ups.
安装
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:Leeminjing/dsh-messages-sanitizer说明文档
阅读完整 README ↗dsh-messages-sanitizer
🔧 你在 DeepSeek Harness 里创建 / 加载插件,对话崩了吗?本插件专治这个。
开发或加载本地插件时,一次工具调度崩溃(
Cannot read properties of undefined (reading 'prepare'))就会在会话里留下孤儿tool_calls,之后每一轮都被400 INVALID_REQUEST拒绝、重试无效、会话卡死。本插件自动把 messages 数组修回 合法,让对话继续,不再卡死。
💥 Before ✅ After (安装本插件后)
插件崩溃 插件崩溃
↓ ↓
留下孤儿 tool_calls messages 自动修复
↓ ↓
400 INVALID_REQUEST 死循环 对话继续
↓
对话卡死
DeepSeek Harness 消息数组自动矫正插件:防止一切因 messages 数组不合法导致的聊天崩溃。
背景:你遇到的那个崩溃
OpenAI 兼容协议要求工具调用成对出现,且 tool 消息必须紧邻其 assistant tool_calls 消息(中间不能插入任何 user / assistant 消息):
assistant { content: ..., tool_calls: [{ id: "call_A", ... }] }
tool { tool_call_id: "call_A", ... } ← 必须紧跟覆盖每个 id
当一次工具调度在「记录 assistant tool_calls / tool/call 之后、产出 tool 结果之前」
崩溃时(例如 ctx.tools[symbol].prepare 抛 Cannot read properties of undefined),
会话日志会留下一个没有 tool 消息响应的孤儿 tool_calls。下一轮请求把历史拼成:
[..., assistant{tool_calls:[write]}, user{...}] ← 非法
API 直接返回 400 INVALID_REQUEST,且重试时历史原封不动,反复被拒,会话卡死。
如果崩溃后还有多次失败重试,日志里还会留下多条重复的 user 消息横在孤儿
assistant 与注入点之间,让"补插 tool 消息"也无法满足紧邻约束。
插件如何修复(三层防御)
-
预防(agent/pre-step,主路径):追踪每个会话中「已声明但从未被 tool/result 响应」的调用;仅当其声明所在的 assistant 消息就是 surface 的最后一个节点时 (新崩溃的典型形态),在模型请求构建前把合成 error tool-result 消息插到该步消息 最前面。合成消息随 decision.messages 以
user/message事件落盘,deriveMessages()从根上恢复合法——循环构建的请求(deep-frozen、不可改写) 自然就合法了,从源头杜绝 400。 -
治愈(agent/request-error):若 API 仍因 tool_calls 配对/紧邻违规返回 400 (例如旧版本已污染的会话、或孤儿 assistant 后面已横着过期消息),用 surface 替换完成修复,然后强制重试一次(重试基于修复后的日志重建请求,一次成功):
- 把悬空 assistant 消息改写成 的版本(剥离无响应的调用);