Repository navigation
会话中途注册的 MCP 工具会让该会话此后每一轮 400:tool_addition blocks can only be in system messages
#10547
Replies: 1 comment
Update: instrumented the client, the blocks are in a
|
Uh oh!
There was an error while loading. Please reload this page.
Summary
会话进行到中途时,一个 MCP server 连上并把工具补进注册表,DSH 会在该轮写出一条
developer/message(source.kind = "tool-registry",内容是若干tool-addition块)。此后每一轮都要重放这条消息,而 Messages 端点返回 400:结果是该会话永久不可用:用户消息正常入库、助手一轮都不回,UI 侧没有任何错误提示,用户只能丢弃会话重新开始。
English: after an MCP server registers tools mid-session, the session is poisoned by the recorded tool-addition message; every later turn is rejected with
messages.N: tool_addition blocks can only be in system messages(400, INVALID_REQUEST).Reproduction
developer/message,source.kind = "tool-registry",content 为若干{"type":"tool-addition","toolName":"…"};messages.N: tool_addition blocks can only be in system messages,表现为"发消息没有回复"。复现性:我本地两次踩到(一次是 29 个工具的中继首次连上,一次是重启后补连),无例外。
Current behavior
同一会话连续三轮
step 1直接失败,assistant/attempt的错误逐字如下(code: INVALID_REQUEST,status: 400):会话记录(第 12 轮)里唯一新增的记录是工具注册:
第 13、14 轮只多了一条
user/message,没有新的developer/message,错误依旧且下标相同(messages.112)——说明失败请求被当作历史的一部分反复重放,会话自身无法恢复。注意该下标是 0 基:线上被拒的是第 113 条消息,其角色不是
system。Expected behavior
tool_addition只出现在system消息里)。Environment
@deepseek-ai/dsh0.2.1-rc.2(npm 全局安装,launchd 常驻dsh --profile web)deepseek-account/deepseek-flash(systemPromptUpdate: "in-history")klox(streamable-http 本地中继,29 个工具,会话进行中才连上)Additional analysis
按 0.2.1-rc.2 的
@deepseek-ai/dsh-llm-deepseek(lib/index.js)阅读,这条developer消息只可能落到末尾的 system 消息里:lib/index.js:1625flushSystemUpdates:仅在messages.at(-1)?.role === "user"时追加累积的 system 更新;lib/index.js:1638/:1645:tool-addition/tool-removal被翻成{type:"tool_addition", tool:{type:"tool_reference", name}}并包进{role:"system", content:[…]};lib/index.js:1685:只在进入 assistant 消息前以及循环结束时 flush;lib/index.js:2216:仅当body.messages含有tool_addition/tool_removal时才加anthropic-beta: mid-conversation-tool-changes-2026-07-01(常量在:560)。但我用同一把 key 直连
https://api.deepseek.com/anthropic/v1/messages(model: deepseek-flash)做对照,凡是"末尾 system 消息 + 若干 tool_addition 块"的形状全部 200,包括:system参数,以及[user, system(text), system(tool_addition)]相邻;[user, system(tool_addition)];[user, system(tool_addition), user]、[user, assistant, system, user]。唯一能复现逐字相同错误的形状,是把块放进非
system消息:(我已逐一排除
prepareRequestExtensions、dsh-deepseek-llm-api-extensions(只加顶层字段)与prepareImages(只替换图片引用)会改动messages。)因此想请你们确认:除了
serialize(),还有哪条路径会把历史重新投影成messages,从而可能把 tool-change 块放在非system消息里? 可疑方向:compaction / 标题等旁路请求、dsh-api-session-controller的重放路径,或端点对"末尾 system 更新"在某些条件下做的内部合并。Workaround
在
serialize()之后、prepareRequestExtensions之前加一层归一化:把任意消息里的tool_addition/tool_removal块改写成等价文本(Tool now available: <name>/Tool no longer available: <name>,任何位置都合法),并把改写前的消息角色与块结构写进日志。上述 29 块形状改写后实测 200,会话立即恢复。建议官方在请求出口做同类防御,或保证重放时丢弃失效的工具变更。
本报告由本人 DSH 会话中的 Agent 整理;日志、请求下标(0 基)与上述直连对照均在本机复现。
All reactions