Skip to content

fix(deepseek): add native thinking/reasoning_effort support#22218

Closed
asdlem wants to merge 2 commits into
NousResearch:mainfrom
asdlem:fix/deepseek-reasoning-effort
Closed

fix(deepseek): add native thinking/reasoning_effort support#22218
asdlem wants to merge 2 commits into
NousResearch:mainfrom
asdlem:fix/deepseek-reasoning-effort

Conversation

@asdlem

@asdlem asdlem commented May 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Enable DeepSeek V4+ native thinking mode via extra_body.thinking + top-level reasoning_effort
  • Previously the generic code path never sent these parameters for the deepseek provider so /reasoning had zero effect

Motivation

DeepSeek uses its own protocol for reasoning (extra_body.thinking={"type":"enabled"} + reasoning_effort="high"/"max"), NOT OpenRouter-style extra_body.reasoning. The codebase only emitted the OpenRouter protocol. This meant /reasoning low/medium/high/xhigh were all no-ops for the deepseek provider.

Closes #15700, #21577

Changes

  • Introduce DeepSeekProfile (subclass of ProviderProfile) in plugins/model-providers/deepseek/__init__.py
  • Add build_api_kwargs_extras() that emits the correct parameter shape per effort level:
    Hermes /reasoning extra_body.thinking reasoning_effort
    default / unset {type: enabled} high
    none (disabled) {type: disabled} (omitted)
    low, medium, high {type: enabled} high
    xhigh {type: enabled} max
  • Follows the same pattern as the existing Kimi provider

Test Plan

  • Unit-level: Python snippet directly testing build_api_kwargs_extras() for all effort levels confirmed correct parameter shape
  • End-to-end: /reasoning xhigh in Feishu with deepseek-v4-pro confirmed thinking mode active (response detail length increased from ~30 to ~185 chars)
  • /reasoning high and /reasoning max both confirmed through Feishu handler
  • No regressions: default behavior (no reasoning config) adds thinking+effort=high, matching DeepSeek defaults

Notes for Reviewers

DeepSeek V4+ uses extra_body.thinking + top-level reasoning_effort
(native protocol, same as Kimi/Z.AI), not OpenRouter-style
extra_body.reasoning. Previously the generic code path never sent
these parameters for the deepseek provider, so /reasoning commands
had zero effect.

Changes:
- Introduce DeepSeekProfile (subclass of ProviderProfile) with
  build_api_kwargs_extras() that emits the correct parameter shape
- Map Hermes effort levels: low/medium/high → reasoning_effort=high,
  xhigh → reasoning_effort=max
- Default (no reasoning config) enables thinking with effort=high
- disabled reasoning sends thinking.type=disabled (no effort param)

This follows the same pattern as the existing Kimi provider.

Fixes: the deepseek provider previously had no reasoning support at
all — /reasoning low/medium/high/xhigh were all no-ops.
@tuobi2

tuobi2 commented May 13, 2026

Copy link
Copy Markdown

@asdlem — closed my #25000 as duplicate, per @alt-glitch's consolidation guidance. Two pieces from our diff that might be worth adding here:

1. Transport-layer is_deepseek fallback

When get_provider_profile() fails or the profile isn't loaded, the Kimi path has a transport-level is_kimi safety net (chat_completions.py L341-349). DeepSeek should too:

  • run_agent.py: _is_deepseek detection + param forwarding (2 lines)
  • chat_completions.py: mirror the is_kimi block for is_deepseek (11 lines)

This ensures thinking works even if the profile subsystem has an issue.

2. Transport parity tests

tests/providers/test_transport_parity.py::TestDeepSeekParity — verifies ChatCompletionsTransport correctly integrates DeepSeekProfile (same pattern as existing TestKimiParity).

Both diffs are visible at https://github.com/NousResearch/hermes-agent/pull/25000/files — feel free to cherry-pick or ignore. Happy to help if you want a separate PR against your branch with just these two additions.

- run_agent.py: detect api.deepseek.com and forward is_deepseek param
  (mirrors existing is_kimi pattern)
- chat_completions.py: handle is_deepseek in extra_body.thinking
  (same protocol as Kimi — fallback when profile subsystem fails)
- tests: TestDeepSeekParity (transport) + TestDeepSeekProfile (profile)
  (5 tests, all passing)

Refs: NousResearch#22218, closes NousResearch#25000
@teknium1

Copy link
Copy Markdown
Contributor

Automated hermes-sweeper review: this DeepSeek reasoning support is already implemented on current main.

Evidence:

  • plugins/model-providers/deepseek/__init__.py:47 defines DeepSeekProfile.build_api_kwargs_extras(), emitting DeepSeek's native extra_body.thinking plus top-level reasoning_effort for DeepSeek V4+/reasoner models.
  • agent/transports/chat_completions.py:526 wires provider-profile extras into the actual chat-completions request kwargs, so the DeepSeek profile path is active in transport.
  • tests/plugins/model_providers/test_deepseek_profile.py:39 covers the requested wire shape: default thinking enabled, disabled thinking marker, low/medium/high passthrough, and xhigh/max -> max; tests/plugins/model_providers/test_deepseek_profile.py:155 verifies full transport kwargs for deepseek-v4-pro.
  • Implementing commit: cd9470f41638bd515db096cd934c463205790110 (fix(deepseek): wire thinking-mode via DeepSeekProfile, not legacy fallback), shipped in v2026.5.16.

I also checked the discussion about adding an is_deepseek transport fallback. Main implemented this through the active ProviderProfile path instead; the fixing commit notes the legacy fallback route was not the path DeepSeek uses.

@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/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have provider/deepseek DeepSeek API sweeper:implemented-on-main Sweeper: behavior already present on current main type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DeepSeek API: Missing 'thinking: disabled' parameter causes 400 error

4 participants