fix: strip reasoning parts from messages when switching to non-thinking models (#11571)

When switching from a model with extended thinking (e.g., Claude Opus) to a model without thinking support (e.g., GPT 5.2, Claude Sonnet without thinking) mid-session, reasoning parts from previous messages were still being sent to the API, causing validation errors.

This fix ensures that reasoning parts are only included in providerOptions when the target model supports interleaved reasoning (capabilities.interleaved is an object with a field). For models that don't support interleaved reasoning, the reasoning parts are filtered out from the content array but not added to providerOptions, preventing the API error.

Changes:
- Modified normalizeMessages() in transform.ts to check if model supports interleaved reasoning before including reasoning in providerOptions
- Reasoning parts are now correctly filtered for both thinking and non-thinking models
This commit is contained in:
01luyicheng
2026-02-01 17:15:53 +08:00
parent f15214f59a
commit cd2e0352e7

View File

@@ -129,40 +129,39 @@ export namespace ProviderTransform {
return result
}
if (typeof model.capabilities.interleaved === "object" && model.capabilities.interleaved.field) {
const field = model.capabilities.interleaved.field
return msgs.map((msg) => {
if (msg.role === "assistant" && Array.isArray(msg.content)) {
const reasoningParts = msg.content.filter((part: any) => part.type === "reasoning")
const reasoningText = reasoningParts.map((part: any) => part.text).join("")
const supportsInterleaved = typeof model.capabilities.interleaved === "object" && model.capabilities.interleaved.field
const field = supportsInterleaved ? model.capabilities.interleaved.field : undefined
// Filter out reasoning parts from content
const filteredContent = msg.content.filter((part: any) => part.type !== "reasoning")
// Include reasoning_content | reasoning_details directly on the message for all assistant messages
if (reasoningText) {
return {
...msg,
content: filteredContent,
providerOptions: {
...msg.providerOptions,
openaiCompatible: {
...(msg.providerOptions as any)?.openaiCompatible,
[field]: reasoningText,
},
},
}
}
return msgs.map((msg) => {
if (msg.role === "assistant" && Array.isArray(msg.content)) {
const reasoningParts = msg.content.filter((part: any) => part.type === "reasoning")
const reasoningText = reasoningParts.map((part: any) => part.text).join("")
// Filter out reasoning parts from content
const filteredContent = msg.content.filter((part: any) => part.type !== "reasoning")
// Include reasoning_content | reasoning_details directly on message for models that support interleaved reasoning
if (reasoningText && supportsInterleaved && field) {
return {
...msg,
content: filteredContent,
providerOptions: {
...msg.providerOptions,
openaiCompatible: {
...(msg.providerOptions as any)?.openaiCompatible,
[field]: reasoningText,
},
},
}
}
return msg
})
}
return {
...msg,
content: filteredContent,
}
}
return msg
})
return msgs
}