Repository navigation
Replies: 8 comments
|
Thanks for the precise report — the whole chain is traceable in the tree, and your four suggestions turn out to have three different owners. Two of them are already reachable today without a code change. Where it is thrown, exactly
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)
}
}
One detail worth keeping: the block itself has already been delivered. The tool call's Why nothing retries (and why suggestion ③ needs no code)The throw happens inside the adapter's own stream iteration, so } else if (!policy.retryableCodes.includes(failure.code)) {
return next()
}
- name: '@deepseek-ai/dsh-llm-deepseek-api-key' # the route instance serving the failing calls
config:
retryPolicy:
mode: normal
maxRetries: 5
retryableCodes: [EMPTY_RESPONSE, RATE_LIMIT, SERVER, TIMEOUT, TRANSPORT, MALFORMED_RESPONSE]Each retry is another billed provider request; the configuration shape is documented in Suggestion ② is half satisfied already, and ④ already holdsThe raw arguments are durable today, in the session log. The attempt's chunks are compacted per delta run by And ④ holds by construction: a failed attempt is never committed as an The other two belong to the adapter
Two notes for whoever picks this up
|
|
感谢定位,逐条对齐(这条只谈
(另有一支工具调用标记漏进正文的问题,与这条是两个出口,我另起一条评论分开记,避免混线。) |
|
完整现场:工具调用标记漏进正文(DSML)——与上面那支 形态: 这段标记落在正文、不是结构化 tool_call ⇒ 该轮没有可用的工具参数、也没有正常工具结果。 与模型侧已知报告的异同(供判断):
(我们本机在自己的文本清洗层做了兜底,但那只管上屏与后续文本流,改不了已经写进历史记录的部分。) |
|
Following up this report with an implementation, released today.
For the shape you described: the Tool call's arguments never became JSON, so It is deliberately narrower than listing On your other ask: the raw arguments are not lost. The attempt is recorded before the failure, so the corrupt Install and mount: npm install @argszero/cordis-plugin-empty-response-retry# in a profile
- insert:
- id: empty-response-retry
name: '@argszero/cordis-plugin-empty-response-retry'Start with |
|
0.5.0 is on npm — Mount and go — add to your profile: - insert:
- id: empty-response-retry
name: '@argszero/cordis-plugin-empty-response-retry'Nothing about the #9402 rewrite changed in this release. What changed is what the package can prove about it. The three supported lines do not run the same A third arm failed for an unrelated reason worth recording, because it is the kind of failure that hides rather than announces itself: the fixture that wires the installed adapter named the credential hook
The one place the rewrite is wider than the installed table, stated plainly: on a |
|
Thanks — 0.5.0 noted. We are on the 0.1.7-rc.2 line, and our side already handles this shape through a wholesale Once we mount it I can post what |
|
补一台机器的独立复现,并建议把 ①(适配器内容错解析)作为正解——理由在最后。 三件可以补的事实1. 量化:低频,但跨会话复现,且默认表确实从未覆盖它。 2. 长度不是阈值,但长参数是放大器。 3. 一处我先说错、核实后更正的观察:失败"看得见",但没有一句能读的话。 为什么建议走 ①,而不是"把码加进默认重试表"配置层(
① 的形状(提出来讨论,不当下结论):
另外无论 ① 怎么裁,第 3 点那条建议都值得单独做:把失败原因与下一步("回一句继续即可")放进会话正文, |
|
Correction to the read above, on our side: we do not run a fix here, only the config-table route, and it is not in effect at this moment — the profile carries the wholesale The argument that stands is yours: a whole-step retry discards the readable calls in the same step. That is also why the config table is only a stopgap — it removes the dead turn without touching the cause, since the block is written badly and the model never hears about it. So we back ①: keep the block, hand it back as a tool failure with its own non-fatal code, and fall back to a step retry only when nothing readable remains — plus the separate change of putting the failure reason and the next step into the conversation body. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
DSH issue · 工具参数 JSON 损坏(tool input is invalid JSON)
现象
模型返回的工具调用,其参数偶尔不是合法 JSON,宿主直接抛硬错:
该轮就此终止,没有重试,报错也不带原始参数原文。
复现(普通消息即可,无需任何打断)
网页端(provider=deepseek-account,model=deepseek-flash)同样中;
真 TTY 探针(stdout 留控制台、stderr 落文件)也能稳定复现 ⇒ 与 TUI 渲染无关,是适配器层。
定位
app.asar 内的 DeepSeek Messages 适配器:对每个 tool-call 块执行 JSON.parse(content.arguments),
失败即抛 MALFORMED_RESPONSE:
实测(2026-10-11,本机会话件可查)
用例说明(防误读)
上面那条消息本身毫无异常:纯中文、一条指令、无插话、无特殊字符、约 25 字。
不是必现(偶发);当天本机已复现 ≥4 次。换任何要求工具调用的普通消息都可能中 ⇒
该句只作现场定格,不是触发条件。
建议(代价从低到高)
llm/stream外层包不住(解析跑在适配器内部块状态上)2. 报错带原文—— 已澄清:原文本就落在会话记录的assistant/attempt.stream(tool-call-chunks),缺的只是错误信息不回显3. 并入可重试类—— 已澄清:retryPolicy.retryableCodes是 provider route 的受支持字段,配置即可、不用改码(整表替换)4. 不入档—— 已澄清:失败的 attempt 从不提交成assistant/message,本就成立环境
实际跑该 TUI 的 CLI:@deepseek-ai/dsh 0.1.7-rc.2(node 22.23.2;该版本的重试策略源码在
dsh-llm/lib/types/retry-policy.js——默认可重试码正是 EMPTY_RESPONSE/RATE_LIMIT/SERVER/TIMEOUT/TRANSPORT 五个,retryableCodes是整表替换);桌面壳另为 0.2.0-rc.2(自带内嵌 runtime);app.asar 115.7 MB(app.asar.unpacked 只有 node_modules,外部改不了)
相关上游(提之前先看,避免重复)
All reactions