Replies: 1 comment
|
对着 master(47f943859b)把五条主张逐一核实——全部成立,而且这条是序列化中毒家族的第四条路径、也是 #1337 的镜像。逐条确认 + 一个你还没点到的更广缺口 + 修复排序: 源码确认(5 条全中)
你没点到的更广缺口:surface fold 本身也不做配对校验
家族定位:第四条路径 + 首个文件系统层机制
修复排序(在你的 5 条之上补一层)
|
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
[BUG] 会话日志中一条 tool/result 引用了不存在的 call id,导致该会话所有后续请求被供应商以 400 拒绝,永久不可用、无自愈路径
English Summary (TL;DR)
A single corrupted
tool/resultevent in a session log cites a call id that never existed in any assistant message. From then on, every LLM request in that session is rejected by the provider with400 INVALID_REQUEST— "An assistant message with 'tool_calls' must be followed by tool messages responding to each 'tool_call_id', The following tool_call_ids did not have response messages: …" — and the session is permanently deadlocked. The harness has no validation of tool-call ↔ tool-result pairing when deriving/serializing the transcript, and the crash-repair path (interruptedTurnClosers) only covers open tail turns at load, so a mismatched call id inside a closed turn is never detected or repaired. Surface replacement fortool/resultis additionally restricted to changing onlycontent(assertToolResultRewrite: "may change only content"), so even manual recovery through supported APIs is impossible; we had to patch the JSONL file directly.Environment:
@deepseek-ai/dsh0.1.0-rc.6, web profile, Windows, JSONL+zstd session persistence.1. 现象
本轮运行失败+An assistant message with 'tool_calls' must be followed by tool messages responding to each 'tool_call_id', The following tool_call_ids did not have response messages: call_efaab339117449e8b1e79c44(HTTP 400, INVALID_REQUEST)。2. 根因(有完整证据链)
会话
session-28edf83f-…,第 7 轮 step 1:assistant/messagetodo_write(call_f8b23eafdd7a4237b572fcec)+pwsh(call_97d60fa2b6314cd383925ab6)(流式 chunk 10293–10435 中的 id 与此一致)tool/call/tool/resultf8b23eaf…✓tool/call97d60fa2…✓tool/resultcall_efaab339117449e8b1e79c44—— 该 id 在整份日志中从未出现在任何 assistant 消息或 tool/call 里;且 step=2(调用在 step 1)、无sourceEventSeqs、isError=false用与
dsh-llm-deepseek完全相同的 wire 序列化逻辑复现,发给供应商的历史为:该坏事件不符合 Harness 任何正常写入路径的特征:
appendToolResult(dsh-agent-loop)总是带sourceEventSeqs且使用 assistant block 的 id;interruptedTurnClosers合成的结果总是isError=true且带 error code;surfaceOp: replace且保留 callId。→ 结论:该事件来自写入竞争(torn/interleaved write),而非正常逻辑。
3. 触发场景(重要)
第 7 轮代理执行的 pwsh 命令本身在重命名 sessions 目录:
即:Harness 正在向会话日志追加写入时,其持久化目录被改名 + 换成 junction(Windows 下 O_APPEND 句柄与目录 rename/junction 并发)。同一会话更早还有另一处损坏(seq 488
agent/inbox/spliced的removedCount异常,只能手工修补),进一步佐证写入流被破坏。4. Harness 缺口(希望修复的点)
Session.deriveMessages()/ 各 adapter 的 wire 序列化不做 "assistant tool-call ↔ tool 消息" 配对校验。日志一旦出现错配记录,wire 历史必然非法,供应商 400,Harness 无检测、无恢复。interruptedTurnClosers只处理加载时「尾轮未闭合」的情况;「已闭合轮次内的错配 call id」完全覆盖不到(本例轮次已正常闭合,只是轮内结果引用错误)。tool/result的 surface replacement 被assertToolResultRewrite限制为只能改content(message.source.callId在比对范围内),因此即使想通过受支持的 API 修正 call id 也不被允许,只能手工改文件。5. 建议修复方向
session/corruption事件并在 UI 提示。interruptedTurnClosers(或新增 transcript-repair pass)覆盖已闭合轮次:扫描全日志,修正/清除引用了未知 call id 的tool/result。6. 证据材料(可按需提供)
C:\Users\Administrator\.dsh\sessions\…\session-28edf83f-….jsonl.zstd(修复前备份在D:\ds harness默认工作区\session-28edf83f.jsonl.zstd.bak)D:\ds harness默认工作区\repair-broken-session.mjs(逐帧重编码,仅改 seq 10443 的 callId + step)D:\ds harness默认工作区\wire-repro.mjsD:\ds harness默认工作区\scan-all-sessions.mjs(可复现"全日志仅此一处错配")修复方式说明:由于 surface replacement 不允许改 callId,只能直接重写 zstd-jsonl 中 seq 10443 这一条记录(
callId/toolCallId改为call_97d60fa2…,step 2→1),其余 1693 个 zstd 帧字节原样保留;修复后全日志 0 悬挂调用、0 孤儿结果,wire 校验通过。All reactions