Repository navigation
[BUG][Windows 0.2.1-rc.2] DeepSeek Messages 流式 tool 参数 JSON 损坏 → MALFORMED_RESPONSE 整轮中止且不重试 #10195
Replies: 2 comments
|
Thanks for the detailed report — the reproduction steps and the version numbers made this checkable in the source. Why nothing retriedThe failure is raised by the Messages adapter, not by the transport: // packages/llm/llm-deepseek/src/translate.ts
if (reason.kind !== 'max-tokens') {
for (const { content } of blocks.values()) {
if (content.type !== 'tool-call') continue
let parsed: unknown
try { parsed = JSON.parse(content.arguments) } catch (_invalidProviderToolJson) { return malformed('tool input is invalid JSON') }
object(parsed)
}
}and the provider retry policy only covers five codes: // packages/llm/llm/src/retry-policy.ts
const DEFAULT_RETRYABLE_CODES = Object.freeze([
EMPTY_RESPONSE_CODE, 'RATE_LIMIT', 'SERVER', 'TIMEOUT', 'TRANSPORT',
])
The one-line knob, and why it is awkward on your build
retryPolicy:
mode: normal
retryableCodes: ['EMPTY_RESPONSE', 'RATE_LIMIT', 'SERVER', 'TIMEOUT', 'TRANSPORT', 'MALFORMED_RESPONSE']works — but two things get in the way on a released desktop build. A profile's config entry replaces the provider config object as a whole rather than merging into it, so that block has to restate every field the deployment needs; and the desktop's own route configuration lives inside the packaged A plugin that does just thisSince the knob is hard to reach from where you are, I wrote the recovery as a plugin you can mount without touching the packaged config: https://github.com/argszero/dsh-malformed-tool-json-guard — - insert:
- id: malformed-tool-json-guard
name: '@argszero/dsh-malformed-tool-json-guard'
config:
mode: guard # or 'observe' to count without retryingIt listens to The package name is not yet on npm (the publish token is still pending), so Three causes it is notWhile reading the adapter I checked the explanations that seem most likely, so you do not have to:
That is also why the plugin retries rather than repairs: the harness cannot see where the corruption happened, and inventing a repair would be guessing. Being honest about what a retry buys
What I measuredI drove each of the 10 published lines this package claims — If you can run it with |
|
Thanks for the thorough reply — it was checkable end to end, and we followed it. Here is what we verified, what we found that differs from your build assumption, and what we already applied. 1. Your diagnosis checks out in the shipped 0.2.1-rc.2 app.asar
2. We audited the plugin tooFrom a checkout of Mutation arms: 21/21 caught, 0 survived — but we had to adapt the runner. 3. The one-line knob is reachable on this released desktop buildYour note assumes the desktop route config is only in - id: llm-deepseek-account
name: '@deepseek-ai/dsh-llm-deepseek-account'
config:
retryPolicy:
mode: normal
maxRetries: 2
retryableCodes:
- EMPTY_RESPONSE
- RATE_LIMIT
- SERVER
- TIMEOUT
- TRANSPORT
- MALFORMED_RESPONSE
4. On the observe-mode requestWe'll watch Two small doc nits: the README shows Thanks again — the asymmetry argument is what made the fix obvious, and the plugin is a clean fallback for profiles whose provider row does carry config. |
Uh oh!
There was an error while loading. Please reload this page.
环境
app.asar构建于 2026-10-17 17:20:50)@deepseek-ai/dsh-llm-deepseek0.2.1-rc.2、@deepseek-ai/dsh-llm0.2.1-rc.2、dsh-llm-retrydeepseek-flash,DeepSeek Messages(anthropic 兼容端点https://api.deepseek.com/anthropic)computer_*桌面操作 + CDP 浏览器脚本 + 长中文工具参数症状
会话多轮中出现整轮失败,界面报错:
代码定位(
app.asar,可直接检索)translate(),字节偏移 81261931:malformed()→ 固定错误码 MALFORMED_RESPONSE(偏移 81255782):→
EMPTY_RESPONSE(更坏的情况)会重试,MALFORMED_RESPONSE 不重试;而参数解析失败时工具从未执行,重试本身是安全的。可能根因(建议按顺序排查)
input_json_delta序列不完整/损坏(SSE 分帧、网关截断、网络抖动):adapter 校验正确,但错误被归为不可重试,且错误信息不含工具名/片段,无法定位。startBlock的native.input与后续 delta 的合并语义冲突:若提供方在content_block_start给了非空input、随后又发input_json_delta,当前实现会用block.json整体覆盖初始 input(丢前缀),拼出的 JSON 天然不完整 → 直接触发本错误。partial_json中混入替换字符,使 JSON 非法。建议修复
retryHints;理由:解析失败时工具未执行、无副作用。tool name、block index、arguments长度、首尾各 200 字符、provider request id。content_block_start.input非空时与 deltas 合并后再 parse,或对候选串分别尝试。复现建议
长会话 + 高频工具调用,且工具参数包含大段中文(40–60 汉字、含全角标点)与长 URL;预计 30–60 分钟内出现 1–3 次。开启 raw SSE 留痕后可直接区分:缺 delta(流中断)/ deltas 拼串非法(内容问题)/ start input 被覆盖(合并语义问题)。
All reactions