Skip to content

Fix deepseek-reasoner multi-turn requests missing reasoning_content#749

Merged
crmne merged 5 commits into
crmne:mainfrom
iuhoay:fix/deepseek-reasoning-content
Jun 23, 2026
Merged

Fix deepseek-reasoner multi-turn requests missing reasoning_content#749
crmne merged 5 commits into
crmne:mainfrom
iuhoay:fix/deepseek-reasoning-content

Conversation

@iuhoay

@iuhoay iuhoay commented Apr 25, 2026

Copy link
Copy Markdown
Contributor

Summary

DeepSeek's thinking-capable models (deepseek-reasoner, the newer deepseek-v4-flash / deepseek-v4-pro, and presumably anything else DeepSeek ships with thinking mode) reject multi-turn requests when any prior assistant message is missing a reasoning_content key:

The reasoning_content in the thinking mode must be passed back to the API.

The inherited OpenAI format_thinking (lib/ruby_llm/providers/openai/chat.rb:111-124) returns {} when msg.thinking is nil and omits both reasoning / reasoning_content when thinking.text is empty. Any assistant turn that emitted only tool calls — or that simply didn't capture thinking text — therefore breaks the next request.

This PR overrides format_thinking on RubyLLM::Providers::DeepSeek::Chat to always emit reasoning_content on assistant messages (empty string when no thinking text was captured), preserving the existing reasoning / reasoning_signature semantics for everything else.

The override is provider-level (not gated on model id), so it applies to every DeepSeek model. For non-thinking models like deepseek-chat the API ignores the empty key.

Test plan

  • New spec at spec/ruby_llm/providers/deep_seek/chat_spec.rb covers: thinking text + signature present, no thinking captured (the regression case), and non-assistant messages
  • bundle exec rspec spec/ruby_llm/providers/deep_seek/chat_spec.rb — 3 examples, 0 failures
  • bundle exec rubocop lib/ruby_llm/providers/deepseek/chat.rb spec/ruby_llm/providers/deep_seek/chat_spec.rb — no offenses
  • Reviewer to confirm the existing deepseek-chat VCR-backed flows still pass (cassettes were recorded before this change; the empty reasoning_content should be ignored, but worth a re-record if the live API tightens validation)

🤖 Generated with Claude Code

DeepSeek's thinking-mode models reject multi-turn requests when any
prior assistant message is missing a reasoning_content key:

  "The `reasoning_content` in the thinking mode must be passed back
   to the API."

The inherited OpenAI format_thinking returns {} when msg.thinking is
nil and omits both keys when thinking.text is empty, which breaks the
next request after any assistant turn that emitted only tool calls.

Override format_thinking on the DeepSeek Chat module to always emit
reasoning_content (empty string when no thinking text was captured),
preserving the existing reasoning / reasoning_signature semantics.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ashishbista

Copy link
Copy Markdown

+1

@codecov

codecov Bot commented May 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 81.76%. Comparing base (a5f3dbd) to head (c09cfc4).
⚠️ Report is 3 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #749      +/-   ##
==========================================
+ Coverage   81.67%   81.76%   +0.08%     
==========================================
  Files         169      169              
  Lines        7641     7684      +43     
  Branches     1269     1281      +12     
==========================================
+ Hits         6241     6283      +42     
+ Misses        891      889       -2     
- Partials      509      512       +3     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@crmne crmne merged commit 29ba557 into crmne:main Jun 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants