Skip to content

fix: include reasoning_content field for DeepSeek Reasoner models#11290

Merged
RomneyDa merged 2 commits into
continuedev:mainfrom
mvanhorn:fix/deepseek-reasoning-content
Mar 21, 2026
Merged

fix: include reasoning_content field for DeepSeek Reasoner models#11290
RomneyDa merged 2 commits into
continuedev:mainfrom
mvanhorn:fix/deepseek-reasoning-content

Conversation

@mvanhorn

@mvanhorn mvanhorn commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

Summary

  • DeepSeek Reasoner API requires reasoning_content on every assistant message, but appendReasoningFieldsIfSupported returned early when no thinking message preceded the assistant message (e.g. in resumed sessions)
  • Now reasoning_content defaults to an empty string when includeReasoningContentField is true but no thinking content is available, preventing 400 "Missing reasoning_content field" errors

How it works

  • Moved the includeReasoningContent check before the early return guard so it always runs for providers that need it
  • When a thinking message precedes the assistant message, the actual reasoning content is used
  • When no thinking message is present, an empty string is used as the default
  • Other reasoning fields (reasoning, reasoning_details) still require a preceding thinking message

Test plan

  • Verify DeepSeek Reasoner no longer returns 400 errors in resumed sessions
  • Verify DeepSeek Reasoner still includes actual reasoning_content when thinking messages are present
  • Verify Claude and other providers are unaffected (they use reasoning_details, not reasoning_content)

Fixes #11285

🤖 Generated with Claude Code


Summary by cubic

Always include reasoning_content for DeepSeek Reasoner models, defaulting to an empty string when no prior thinking message exists. Prevents 400 errors in resumed sessions and safely handles mixed message content.

  • Bug Fixes
    • Run includeReasoningContentField before the early return and set msg.reasoning_content to the previous thinking content or "" if missing.
    • Use stripImages to populate reasoning_content and reasoning, handling string or MessagePart[] content; keep reasoning_details unchanged and only set when a thinking message is present.

Written for commit 8cd24cb. Summary will update on new commits.

DeepSeek Reasoner API requires the reasoning_content field on every
assistant message, even when no thinking message precedes it (e.g. in
resumed sessions). Previously, appendReasoningFieldsIfSupported returned
early when prevMessage was missing or not a thinking role, causing 400
"Missing reasoning_content field" errors. Now reasoning_content defaults
to an empty string when no thinking content is available.

Fixes continuedev#11285

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@mvanhorn
mvanhorn requested a review from a team as a code owner March 11, 2026 06:18
@mvanhorn
mvanhorn requested review from RomneyDa and removed request for a team March 11, 2026 06:18
@mvanhorn

Copy link
Copy Markdown
Contributor Author

I have read the CLA Document and I hereby sign the CLA

@dosubot dosubot Bot added the size:S This PR changes 10-29 lines, ignoring generated files. label Mar 11, 2026

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 1 file

Comment thread core/llm/openaiTypeConverters.ts Outdated
// Default to empty string to avoid 400 "Missing reasoning_content field".
if (includeReasoningContent) {
msg.reasoning_content = hasThinkingContent
? (prevMessage.content as string)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mvanhorn is it possible to remove this typecast? I think MessageContent can be an array of text content for example. There are some utilities in the codebase to render any message content to string. Or did I miss reason for type cast?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced both as string casts with stripImages() from core/util/messageContent in 8cd24cb. That handles the MessagePart[] case properly.

Replace `as string` typecasts with stripImages() which safely handles
both string and MessagePart[] content types.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

@RomneyDa RomneyDa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Appreciate the fix!

@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Mar 21, 2026
@RomneyDa
RomneyDa merged commit 4b6a09c into continuedev:main Mar 21, 2026
50 of 65 checks passed
@github-actions github-actions Bot locked and limited conversation to collaborators Mar 21, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

lgtm This PR has been approved by a maintainer size:S This PR changes 10-29 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error: DeepSeek Reasoner - 400

2 participants