From c28cd05d890919fbf355ce633017f4eed9011c82 Mon Sep 17 00:00:00 2001 From: Askhz <1361267452@qq.com> Date: Tue, 21 Apr 2026 15:48:22 +0800 Subject: [PATCH 1/2] fix: handle reasoning_content for thinking mode in OpenAI compatibility layer - Add reasoning_content field when thinking mode is enabled - Set reasoning_content to empty string when no thinking content available - Enable model auto-detection for kimi provider - Add thinking mode support to costrict provider --- .../src/shared/openaiConvertMessages.ts | 41 ++++++++++++------- src/costrict/provider/index.ts | 6 ++- src/services/api/openai/requestBody.ts | 4 +- 3 files changed, 34 insertions(+), 17 deletions(-) diff --git a/packages/@ant/model-provider/src/shared/openaiConvertMessages.ts b/packages/@ant/model-provider/src/shared/openaiConvertMessages.ts index 4d2553653..9535e3fa1 100644 --- a/packages/@ant/model-provider/src/shared/openaiConvertMessages.ts +++ b/packages/@ant/model-provider/src/shared/openaiConvertMessages.ts @@ -211,21 +211,29 @@ function convertInternalAssistantMessage( const content = msg.message.content if (typeof content === 'string') { - return [ - { - role: 'assistant', - content, - } satisfies ChatCompletionAssistantMessageParam, - ] + const result: ChatCompletionAssistantMessageParam & { reasoning_content?: string } = { + role: 'assistant', + content, + } + // 如果开启了thinking模式,必须提供reasoning_content字段 + if (preserveReasoning) { + // content是字符串,没有reasoning内容,设置为空字符串 + result.reasoning_content = ' ' + } + return [result] } if (!Array.isArray(content)) { - return [ - { - role: 'assistant', - content: '', - } satisfies ChatCompletionAssistantMessageParam, - ] + const result: ChatCompletionAssistantMessageParam & { reasoning_content?: string } = { + role: 'assistant', + content: '', + } + // 如果开启了thinking模式,必须提供reasoning_content字段 + if (preserveReasoning) { + // content不是数组,没有reasoning内容,设置为空字符串 + result.reasoning_content = ' ' + } + return [result] } const textParts: string[] = [] @@ -258,11 +266,16 @@ function convertInternalAssistantMessage( // Skip redacted_thinking, server_tool_use, etc. } - const result: ChatCompletionAssistantMessageParam = { + const result: ChatCompletionAssistantMessageParam & { reasoning_content?: string } = { role: 'assistant', content: textParts.length > 0 ? textParts.join('\n') : null, ...(toolCalls.length > 0 && { tool_calls: toolCalls }), - ...(reasoningParts.length > 0 && { reasoning_content: reasoningParts.join('\n') }), + } + + // 如果开启了thinking模式,必须提供reasoning_content字段 + if (preserveReasoning) { + // 如果有reasoning内容就用这些内容,没有才设置成空字符串 + result.reasoning_content = reasoningParts.length > 0 ? reasoningParts.join('\n') : ' ' } return [result] diff --git a/src/costrict/provider/index.ts b/src/costrict/provider/index.ts index fc2f916ee..1dcede320 100644 --- a/src/costrict/provider/index.ts +++ b/src/costrict/provider/index.ts @@ -31,6 +31,7 @@ import { createCoStrictFetch } from './fetch.js' import { resolveCoStrictModel } from './modelMapping.js' import { getCoStrictBaseURL } from './auth.js' import { loadCoStrictCredentials } from './credentials.js' +import { isOpenAIThinkingEnabled } from '../../services/api/openai/requestBody.js' /** * CoStrict 查询路径 @@ -80,9 +81,12 @@ export async function* queryModelCoStrict( ) // 5. 转换为 OpenAI 格式 + // 根据模型名称自动检测是否启用thinking模式 + const enableThinking = isOpenAIThinkingEnabled(costrictModel) const openaiMessages = anthropicMessagesToOpenAI( messagesForAPI, - systemPrompt + systemPrompt, + { enableThinking } ) const openaiTools = anthropicToolsToOpenAI(standardTools) const openaiToolChoice = anthropicToolChoiceToOpenAI(options.toolChoice) diff --git a/src/services/api/openai/requestBody.ts b/src/services/api/openai/requestBody.ts index e8f93ecfa..d49fdc1e1 100644 --- a/src/services/api/openai/requestBody.ts +++ b/src/services/api/openai/requestBody.ts @@ -25,9 +25,9 @@ export function isOpenAIThinkingEnabled(model: string): boolean { if (isEnvDefinedFalsy(process.env.OPENAI_ENABLE_THINKING)) return false // Explicit enable if (isEnvTruthy(process.env.OPENAI_ENABLE_THINKING)) return true - // Auto-detect from model name (deepseek-reasoner and DeepSeek-V3.2 support thinking mode) + // Auto-detect from model name (deepseek-reasoner, DeepSeek-V3.2, kimi support thinking mode) const modelLower = model.toLowerCase() - return modelLower.includes('deepseek-reasoner') || modelLower.includes('deepseek-v3.2') + return modelLower.includes('deepseek-reasoner') || modelLower.includes('deepseek-v3.2') || modelLower.includes('kimi') } /** From 32c6f687343571b88e557dccadab81a9f530aaaf Mon Sep 17 00:00:00 2001 From: Askhz <1361267452@qq.com> Date: Tue, 21 Apr 2026 19:28:08 +0800 Subject: [PATCH 2/2] test: fix empty thinking block test expectation The code sets reasoning_content to ' ' for empty thinking blocks when enableThinking is true, but the test expected undefined. Updated the test to match the actual behavior. Co-Authored-By: Claude Opus 4.6 --- .../src/shared/__tests__/openaiConvertMessages.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/@ant/model-provider/src/shared/__tests__/openaiConvertMessages.test.ts b/packages/@ant/model-provider/src/shared/__tests__/openaiConvertMessages.test.ts index 6de81d8a4..5ece2fd93 100644 --- a/packages/@ant/model-provider/src/shared/__tests__/openaiConvertMessages.test.ts +++ b/packages/@ant/model-provider/src/shared/__tests__/openaiConvertMessages.test.ts @@ -428,7 +428,7 @@ describe('DeepSeek thinking mode (enableThinking)', () => { { enableThinking: true }, ) const assistant = result.filter(m => m.role === 'assistant')[0] as any - expect(assistant.reasoning_content).toBeUndefined() + expect(assistant.reasoning_content).toBe(' ') }) // ── fix: reorder tool and user messages for OpenAI API compatibility (#168) ──