diff --git a/packages/core/src/core/openaiContentGenerator/provider/deepseek.test.ts b/packages/core/src/core/openaiContentGenerator/provider/deepseek.test.ts index cff092bdc..a38ffb52b 100644 --- a/packages/core/src/core/openaiContentGenerator/provider/deepseek.test.ts +++ b/packages/core/src/core/openaiContentGenerator/provider/deepseek.test.ts @@ -180,9 +180,9 @@ describe('DeepSeekOpenAICompatibleProvider', () => { }); // https://github.com/QwenLM/qwen-code/issues/3695 — DeepSeek's thinking - // mode rejects subsequent requests when a prior tool-calling assistant - // turn omits reasoning_content, even if the model itself returned no - // reasoning text. The provider must always send the field. + // mode rejects subsequent requests when any prior assistant turn omits + // reasoning_content, even if the model itself returned no reasoning text. + // The provider must always send the field. it('injects empty reasoning_content on tool-calling assistant turns missing it', () => { const originalRequest: OpenAI.Chat.ChatCompletionCreateParams = { model: 'deepseek-v4-flash', @@ -245,7 +245,7 @@ describe('DeepSeekOpenAICompatibleProvider', () => { expect(assistant.reasoning_content).toBe('Let me glob first.'); }); - it('does not add reasoning_content to assistant turns without tool_calls', () => { + it('injects empty reasoning_content on assistant turns without tool_calls', () => { const originalRequest: OpenAI.Chat.ChatCompletionCreateParams = { model: 'deepseek-v4-flash', messages: [ @@ -259,7 +259,7 @@ describe('DeepSeekOpenAICompatibleProvider', () => { const assistant = result.messages?.[1] as { reasoning_content?: string; }; - expect(assistant.reasoning_content).toBeUndefined(); + expect(assistant.reasoning_content).toBe(''); }); }); diff --git a/packages/core/src/core/openaiContentGenerator/provider/deepseek.ts b/packages/core/src/core/openaiContentGenerator/provider/deepseek.ts index 235c5cf00..0500cc939 100644 --- a/packages/core/src/core/openaiContentGenerator/provider/deepseek.ts +++ b/packages/core/src/core/openaiContentGenerator/provider/deepseek.ts @@ -108,19 +108,16 @@ function flattenContentParts( } // DeepSeek's thinking mode requires reasoning_content to be replayed on every -// prior assistant turn that carried tool_calls. The model may legitimately -// return a tool round without reasoning text, so the field can be missing -// when we rebuild the request. Send an empty string in that case so the API -// contract is satisfied. https://github.com/QwenLM/qwen-code/issues/3695 +// prior assistant turn, including ones without tool_calls. The model may +// legitimately return a turn without reasoning text, so the field can be +// missing when we rebuild the request. Send an empty string in that case so +// the API contract is satisfied. https://github.com/QwenLM/qwen-code/issues/3695 function ensureReasoningContentOnToolCalls( message: OpenAI.Chat.ChatCompletionMessageParam, ): OpenAI.Chat.ChatCompletionMessageParam { if (message.role !== 'assistant') { return message; } - if (!Array.isArray(message.tool_calls) || message.tool_calls.length === 0) { - return message; - } const extended = message as ExtendedChatCompletionAssistantMessageParam; if ( typeof extended.reasoning_content === 'string' &&