Skip to content

fix(deepseek): send explicit thinking:disabled when reasoning is off#21668

Closed
wjameswen888 wants to merge 1 commit into
NousResearch:mainfrom
wjameswen888:fix/deepseek-thinking-disabled
Closed

fix(deepseek): send explicit thinking:disabled when reasoning is off#21668
wjameswen888 wants to merge 1 commit into
NousResearch:mainfrom
wjameswen888:fix/deepseek-thinking-disabled

Conversation

@wjameswen888

Copy link
Copy Markdown

Problem

When using DeepSeek direct API (api.deepseek.com) with reasoning_effort: none, Hermes fails with HTTP 400:

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

Root cause: The DeepSeek API requires an explicit thinking: {"type": "disabled"} parameter when thinking is off. Without it, the API defaults to thinking=enabled — generating reasoning_content that gets stripped by the compression pipeline, then rejected on the next turn.

This is the same pattern already handled for Kimi, but missing for DeepSeek.

Fix

Mirrors the existing Kimi extra_body.thinking block:

  1. run_agent.py: Detect DeepSeek provider/model/base_url (_is_deepseek), pass to transport
  2. agent/transports/chat_completions.py: Send {"thinking": {"type": "disabled"}} to DeepSeek API when reasoning_config.enabled=false or effort=none

Verification

  • Tested on production install (DeepSeek v4-pro direct API, reasoning_effort: none)
  • Multi-turn conversations with tool calls that previously hit HTTP 400 now complete successfully
  • No impact on thinking=enabled path

Related Issues

Fixes #15700 — "DeepSeek API: Missing thinking:disabled parameter causes 400"
Fixes #17212 — "DeepSeek direct API 400 reasoning_content must be passed back"
Related #15213 — "HTTP 400 reasoning_content in cron/auxiliary path"

DeepSeek direct API requires an explicit thinking.type parameter.
When thinking is disabled (reasoning_effort=none or enabled=false),
the API defaults to thinking=enabled — generating reasoning_content
that gets stripped/not passed back, causing HTTP 400 on subsequent
turns.

This mirrors the existing Kimi extra_body.thinking pattern:
- Detect DeepSeek provider/model/base_url in run_agent.py
- Send {"thinking": {"type": "disabled"}} when appropriate
- Respect reasoning_config.effort=none as disabled

Fixes: NousResearch#15700, NousResearch#17212
Related: NousResearch#15213
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent loop, run_agent.py, prompt builder provider/deepseek DeepSeek API labels May 8, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Duplicate of #17225 — same fix (send explicit thinking: {type: disabled} to DeepSeek direct API when reasoning is off). Both fix #17212 and #15700.

@teknium1

Copy link
Copy Markdown
Contributor

This looks implemented on current main, so this duplicate PR can be closed by the automated hermes-sweeper review.

Evidence:

  • plugins/model-providers/deepseek/__init__.py:67 now emits extra_body["thinking"] = {"type": "enabled" if enabled else "disabled"} for DeepSeek thinking-capable models, and returns the disabled marker without reasoning_effort when reasoning_config.enabled is false.
  • agent/transports/chat_completions.py:528 wires provider-profile extras into the chat-completions request kwargs, so the DeepSeek profile's thinking payload reaches the outgoing API call.
  • tests/plugins/model_providers/test_deepseek_profile.py:71 covers the specific disabled case: reasoning_config={"enabled": False} produces {"thinking": {"type": "disabled"}}.
  • The implementation landed in cd9470f41638bd515db096cd934c463205790110 (fix(deepseek): wire thinking-mode via DeepSeekProfile, not legacy fallback), with the earlier mapping introduced by 068c24f8a4203e86de32b0d84ccaf047e8cd6ef7.
  • @alt-glitch already noted in the PR discussion that this was a duplicate of fix(agent): send thinking control to DeepSeek direct API to prevent 400 on tool-call replay #17225 covering the same DeepSeek direct API thinking: {type: disabled} fix.

Thanks for the report and patch — the fix is now present on main in the provider-profile implementation.

@teknium1 teknium1 closed this Jun 11, 2026
@teknium1 teknium1 added the sweeper:implemented-on-main Sweeper: behavior already present on current main label Jun 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent loop, run_agent.py, prompt builder P2 Medium — degraded but workaround exists provider/deepseek DeepSeek API sweeper:implemented-on-main Sweeper: behavior already present on current main type/bug Something isn't working

Projects

None yet

3 participants