Skip to content

fix(deepseek): support reasoning_content in tools and streaming#288

Open
Damonsoul wants to merge 4 commits intoposit-dev:mainfrom
Damonsoul:fix-deepseek-reasoning-and-tools
Open

fix(deepseek): support reasoning_content in tools and streaming#288
Damonsoul wants to merge 4 commits intoposit-dev:mainfrom
Damonsoul:fix-deepseek-reasoning-and-tools

Conversation

@Damonsoul
Copy link
Copy Markdown

Description

DeepSeek's thinking models (like deepseek-v4-flash) require reasoning_content to be passed back in subsequent messages during tool calls, otherwise it returns a 400 error.

This PR:

  1. Updates _turns_as_inputs to preserve and send reasoning_content.
  2. Updates _response_as_turn and stream_content to correctly capture reasoning from DeepSeek's API response.

Tested with deepseek-v4-flash and tool calls - the 400 error is resolved and thinking process is visible.

@Damonsoul Damonsoul force-pushed the fix-deepseek-reasoning-and-tools branch from 9f2feef to 9fb4304 Compare April 30, 2026 03:28
@cpsievert
Copy link
Copy Markdown
Collaborator

Thanks @Damonsoul. I'd love to get this fixed, but this also feels like possibly more code than we really need to support this. Did you by chance consider the angle of adding support inside of OpenAICompletionsProvider? That way we might be able to get away with less duplication of logic?

@Damonsoul Damonsoul force-pushed the fix-deepseek-reasoning-and-tools branch 2 times, most recently from c0f19de to e6b6d3a Compare May 5, 2026 04:23
@Damonsoul
Copy link
Copy Markdown
Author

@cpsievert That is a fantastic point, and you're absolutely right! Moving the logic to the base class is a much cleaner architecture.

I have force-pushed a single, clean commit to this PR that does exactly what you suggested: All extraction, streaming, and serialization of reasoning_content (as ContentThinking) now lives entirely inside OpenAICompletionsProvider. This keeps DeepSeekProvider untouched while future-proofing other OpenAI-compatible providers that might adopt reasoning_content.

Comment on lines -64 to -73
"""
Chat with an OpenAI-compatible model (via the Completions API).

This function exists mainly for historical reasons; new code should
prefer `ChatOpenAI()`, which uses the newer Responses API.

This function may also be useful for using an "OpenAI-compatible model"
hosted by another provider (e.g., vLLM, Ollama, etc.) that supports the
OpenAI Completions API.
"""
Copy link
Copy Markdown
Collaborator

@cpsievert cpsievert May 5, 2026

Choose a reason for hiding this comment

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

There are a number of unnecessary deletions here, notably this docstring and numerous other comments. Please try to keep the changes minimal and focused on the bug fix.

Comment on lines +378 to +387
reasoning_content = getattr(message, "reasoning_content", None)
if (
reasoning_content is None
and hasattr(message, "model_extra")
and message.model_extra
):
reasoning_content = message.model_extra.get("reasoning_content")

if reasoning_content:
contents.append(ContentThinking(thinking=reasoning_content))
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

It'd be great to have a test covering this logic.

@Damonsoul Damonsoul force-pushed the fix-deepseek-reasoning-and-tools branch from e6b6d3a to ed88e6a Compare May 5, 2026 14:08
@Damonsoul Damonsoul force-pushed the fix-deepseek-reasoning-and-tools branch from ed88e6a to 8c527ac Compare May 5, 2026 14:50
@Damonsoul
Copy link
Copy Markdown
Author

I completely understand! I've updated the PR to strictly minimize the diff footprint. I kept all of your original comments, docstrings, and structure untouched.

@cpsievert
Copy link
Copy Markdown
Collaborator

cpsievert commented May 7, 2026

Thanks again for this contribution @Damonsoul. It helped me realize that we need more general controls over preserving thinking content or not. See #295 for more on that, which renders most of this PR irrelevant.

Although, as you'll see in the PR description for #295, the one thing here that that other PR did not address is this:

reordering tool result messages to precede user content in _turns_as_inputs

If you're willing to, I'd really appreciate it if you would look deeper into this topic. A reproducible example using DeepSeek would be welcome in a new issue. If you want to go above and beyond a more general investigation into whether other providers also want this format, that'd be awesome.

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