What happened?
问题描述
症状:长会话(对话轮次较多、上下文较长)时,调用启用了 thinking 模式的模型(如 DeepSeek-V4-Pro)会报错:
[API Error: 400 The reasoning_content in the thinking mode must be passed back to the API.]
根因:packages/core/src/core/openaiContentGenerator/converter.ts 中存在两处导致 reasoning_content 丢失的缺陷:
1. mergeConsecutiveAssistantMessages 丢弃 reasoning_content
// converter.ts 原 line ~1395
// Combine tool calls
const combinedToolCalls = [...lastToolCalls, ...currentToolCalls];
// Update the last message with combined data
// ❌ 只合并了 content 和 tool_calls,
// message 上的 reasoning_content 被悄悄丢弃
触发条件:cleanOrphanedToolCalls 删除位于两个 assistant 消息之间的孤立 tool message 后,两个 assistant 消息变为相邻。mergeConsecutiveAssistantMessages 将它们合并,第二条消息的 reasoning_content 被丢弃。会话越长、工具调用越多,出现孤立 tool call 的概率越大,越容易触发。
2. cleanOrphanedToolCalls 丢弃仅含 reasoning_content 的消息
第一轮和第二轮清理中,当 assistant 消息的 tool_calls 没有对应响应且 content 为空时,整条消息被移除——即使它含有 reasoning_content。条件仅检查了 message.content 是字符串,没有检查 reasoning_content。
What did you expect to happen?
修改方案
(我已经使用qwen code在本地完成了修改,可以运行,问题解决了,但不知道为什么界面的语言变成了英文且无法切换,)
文件:packages/core/src/core/openaiContentGenerator/converter.ts
修改 1:mergeConsecutiveAssistantMessages — 合并时保留 reasoning_content
在合并 content 和 tool_calls 之后,增加 reasoning_content 的拼接:
// Combine reasoning_content (新增)
const lastReasoning =
'reasoning_content' in lastMessage
? ((lastMessage as ExtendedChatCompletionAssistantMessageParam)
.reasoning_content ?? '')
: '';
const currentReasoning =
'reasoning_content' in message
? ((message as ExtendedChatCompletionAssistantMessageParam)
.reasoning_content ?? '')
: '';
const combinedReasoning = [lastReasoning, currentReasoning]
.filter(Boolean)
.join('');
// ...更新 content 和 tool_calls 后...
if (combinedReasoning) {
(lastMessage as ExtendedChatCompletionAssistantMessageParam)
.reasoning_content = combinedReasoning;
}
修改 2:cleanOrphanedToolCalls — 两轮清理均检查 reasoning_content
将保留条件从"有文本内容"扩展为"有文本内容或有 reasoning_content":
// 旧:
} else if (
typeof message.content === 'string' &&
message.content.trim()
) {
// 新:
} else if (
(typeof message.content === 'string' && message.content.trim()) ||
('reasoning_content' in message &&
typeof (message as ExtendedChatCompletionAssistantMessageParam)
.reasoning_content === 'string' &&
(message as ExtendedChatCompletionAssistantMessageParam)
.reasoning_content!.trim())
) {
第一轮和最终验证轮均做相同修改。
Client information
Qwen Code: 0.15.4 (b0ed821)
运行环境: Node.js v24.14.0 / npm 11.9.0
操作系统: linux arm64 (6.17.0-PRoot-Distro)
认证: API Key - openai
基础 URL: https://api.deepseek.com
模型: deepseek-v4-pro
快速模型: deepseek-v4-pro
会话 ID: 9271c74a-3ddc-4b8a-9505-a66c7331dabc
沙箱: no sandbox
代理: no proxy
内存使用: 658.8 MB
Login information
API https://api.deepseek.com
Anything else we need to know?
No response
What happened?
问题描述
症状:长会话(对话轮次较多、上下文较长)时,调用启用了 thinking 模式的模型(如 DeepSeek-V4-Pro)会报错:
根因:
packages/core/src/core/openaiContentGenerator/converter.ts中存在两处导致reasoning_content丢失的缺陷:1.
mergeConsecutiveAssistantMessages丢弃 reasoning_content触发条件:
cleanOrphanedToolCalls删除位于两个 assistant 消息之间的孤立 tool message 后,两个 assistant 消息变为相邻。mergeConsecutiveAssistantMessages将它们合并,第二条消息的reasoning_content被丢弃。会话越长、工具调用越多,出现孤立 tool call 的概率越大,越容易触发。2.
cleanOrphanedToolCalls丢弃仅含 reasoning_content 的消息第一轮和第二轮清理中,当 assistant 消息的 tool_calls 没有对应响应且 content 为空时,整条消息被移除——即使它含有
reasoning_content。条件仅检查了message.content是字符串,没有检查reasoning_content。What did you expect to happen?
修改方案
(我已经使用qwen code在本地完成了修改,可以运行,问题解决了,但不知道为什么界面的语言变成了英文且无法切换,)
文件:
packages/core/src/core/openaiContentGenerator/converter.ts修改 1:
mergeConsecutiveAssistantMessages— 合并时保留 reasoning_content在合并 content 和 tool_calls 之后,增加 reasoning_content 的拼接:
修改 2:
cleanOrphanedToolCalls— 两轮清理均检查 reasoning_content将保留条件从"有文本内容"扩展为"有文本内容或有 reasoning_content":
第一轮和最终验证轮均做相同修改。
Client information
Qwen Code: 0.15.4 (b0ed821)
运行环境: Node.js v24.14.0 / npm 11.9.0
操作系统: linux arm64 (6.17.0-PRoot-Distro)
认证: API Key - openai
基础 URL: https://api.deepseek.com
模型: deepseek-v4-pro
快速模型: deepseek-v4-pro
会话 ID: 9271c74a-3ddc-4b8a-9505-a66c7331dabc
沙箱: no sandbox
代理: no proxy
内存使用: 658.8 MB
Login information
API https://api.deepseek.com
Anything else we need to know?
No response