Skip to content

fix(deepseek): align V4 thinking behavior with the official API - #1962

Open
junliu-mde wants to merge 6 commits into
smg-project:mainfrom
junliu-mde:fix/deepseek-v4-official-compat
Open

fix(deepseek): align V4 thinking behavior with the official API#1962
junliu-mde wants to merge 6 commits into
smg-project:mainfrom
junliu-mde:fix/deepseek-v4-official-compat

Conversation

@junliu-mde

@junliu-mde junliu-mde commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Description

Problem

The gateway's DeepSeek V4 handling diverges from DeepSeek's official API in three ways:

  1. Thinking defaults off; the official default is on. The official docs state "The thinking toggle defaults to enabled", and the V4 encoder's thinking_mode is a required argument with the default supplied at the API layer. We reused the V3.2 DefaultOff contract, so every request without an explicit toggle got a chat-mode prompt (…<|Assistant|></think>) — the served model silently behaves unlike api.deepseek.com for identical requests.
  2. No thinking request field. The official switch is thinking: {"type": "enabled" | "disabled"} (Create Chat Completion). Clients migrating from the official API had it swallowed into the other flatten and ignored — a request explicitly disabling thinking still paid for reasoning tokens.
  3. reasoning_effort mapping was incomplete. Official semantics: real levels are high and max; low/medium map to high, xhigh maps to max. We only recognized max and high, so xhigh (sent by e.g. Claude Code) silently lost the max-effort prompt preamble.

Solution

  • ChatThinkingConfig on ChatCompletionRequest: the official {"type": "enabled" | "disabled"} schema, strict (deny_unknown_fields) so malformed variants fail loudly instead of being ignored.
  • ThinkingToggle::DefaultOn for the V4 renderer (V3.2 keeps DefaultOff); derive_thinking_mode takes the renderer's official default as its fallback.
  • One precedence everywhere, matching the Jinja path: explicit chat_template_kwargs toggle > thinking field > reasoning_effort compatibility mapping > renderer default. Both the prompt-building path (process_chat_messages_with_placeholders) and the reasoning-parser arming path (resolve_user_thinking, now taking the request) resolve identically, so the parser state always agrees with what the prefill actually contains.
  • reasoning_effort normalization in the V4 shim: xhigh → Max, low|medium|high → High, verbatim per the official mapping.
  • deepseek_v4 reasoning parser registration + deepseek-v4 model-name pattern, so CLI/parser selection matches the served model instead of falling through.

Behavior notes

  • Default flip: V4 requests without any thinking signal now produce reasoning content. This is the point of the fix — the old default was the incompatibility — but deployments relying on it will see higher output-token usage; worth a release-note line.
  • The strict thinking schema rejects shapes the official API also rejects (booleans, Anthropic-style budget_tokens) that were previously silently ignored — now a 400.
  • The Anthropic messages endpoint keeps its own ThinkingConfig; an omitted config on a V4 model now inherits the model's official default-on rather than Anthropic's default-off.
  • Messages responses now separate reasoning whenever thinking is effectively on — including template-default-on with an omitted thinking config. This covers DeepSeek V4 and also fixes the same <think>-tag leak for other default-on templates (Qwen3, GLM) on the Messages endpoint, matching the chat endpoint's long-standing arming semantics. An explicit Disabled config still opts out.
  • Not implemented: the official server-side auto-raise to max effort for agent traffic (Claude Code, OpenCode) — that's origin-side heuristics, out of scope for a passthrough gateway.

Changes

  • crates/protocols/chat.rs: ChatThinkingConfig, thinking field, thinking_preference() accessor.
  • crates/tokenizer/huggingface.rs: per-renderer thinking default (V4 → DefaultOn), xhigh/low/medium effort normalization; encoders/deepseek_v4.rs source comment now points at the DeepSeek-V4-Pro upstream.
  • crates/reasoning_parser/factory.rs: deepseek_v4 parser + pattern (shared helper with deepseek_v31).
  • model_gateway grpc: resolve_user_thinking(&request, tokenizer) signature; chat prompt building uses thinking_preference().

Test Plan

  • New tests: strict thinking deserialization round-trip + rejection cases, thinking-vs-reasoning_effort precedence, V4 factory/parser arming, per-renderer toggle defaults, effort normalization (incl. xhigh → "Absolute maximum" preamble), end-to-end prompt assertions through process_chat_messages with a real V4-detected tokenizer dir.
  • cargo test -p openai-protocol (83+126), -p reasoning-parser (75), -p llm-tokenizer (146 lib + integration incl. deepseek_renderer_detection), -p smg --lib routers::grpc::utils (34): all green.

Summary by CodeRabbit

  • New Features

    • Added DeepSeek chat “thinking mode” controls to support {type: enabled|disabled} with clear precedence over reasoning-effort inputs.
    • Enabled DeepSeek V4 default-on thinking and added xhigh handling (“absolute maximum” marker).
  • Bug Fixes

    • Improved consistency of how “reasoning started” is determined across streaming and non-streaming flows.
    • Corrected DeepSeek thinking prompt formatting and normalized reasoning-effort markers.
  • Tests

    • Expanded coverage for DeepSeek V3.2 vs V4 defaults, precedence, prompt rendering, and /v1/chat/completions HTTP compatibility behavior.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@github-actions github-actions Bot added tokenizer Tokenizer related changes grpc gRPC client and router changes tests Test changes reasoning-parser Reasoning parser changes protocols Protocols crate changes model-gateway Model gateway crate changes labels Jul 23, 2026
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds typed DeepSeek thinking configuration, DeepSeek V4 parser and tokenizer defaults, reasoning-effort normalization, HTTP control translation, and request-based gateway precedence handling. Tests cover validation, parser selection, prompt rendering, routing translation, and reasoning-state resolution.

Changes

DeepSeek thinking flow

Layer / File(s) Summary
Protocol thinking contract
crates/protocols/src/chat.rs
Adds typed enabled/disabled thinking configuration, request-level storage, preference resolution, and precedence tests.
DeepSeek parser and renderer behavior
crates/reasoning_parser/src/factory.rs, crates/tokenizer/src/encoders/deepseek_v4.rs, crates/tokenizer/src/huggingface.rs, crates/tokenizer/tests/deepseek_renderer_detection.rs
Registers DeepSeek V4 parsing, separates V3.2 and V4 defaults, normalizes reasoning efforts, and updates rendering tests.
Gateway preference propagation
model_gateway/src/routers/grpc/utils/..., model_gateway/src/routers/grpc/regular/..., bindings/golang/src/utils.rs
Resolves thinking from complete requests and applies precedence across rendering, streaming, response processing, and Go bindings.
DeepSeek V4 HTTP compatibility
model_gateway/src/routers/http/...
Translates DeepSeek V4 thinking and reasoning-effort controls into worker-compatible template arguments before request dispatch and retry metadata injection.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Router
  participant ChatGateway
  participant HuggingFaceTokenizer
  participant ReasoningParser
  Client->>Router: submit DeepSeek V4 thinking controls
  Router->>ChatGateway: forward translated request
  ChatGateway->>HuggingFaceTokenizer: render thinking-aware prompt
  ChatGateway->>ReasoningParser: select and start reasoning parsing
  ReasoningParser-->>Client: return separated reasoning and response
Loading

Possibly related PRs

Suggested reviewers: slin1237

Poem

I’m a rabbit with thoughts in a DeepSeek stream,
<think> opens each bright little dream.
V3 stays quiet, V4 hops on,
Preferences travel from dusk to dawn.
Tests nibble bugs till they’re gone—
Hop hop! Thinking mode is born.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: aligning DeepSeek V4 thinking behavior with the official API.
Docstring Coverage ✅ Passed Docstring coverage is 95.12% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mergify

mergify Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Hi @junliu-mde, the DCO sign-off check has failed. All commits must include a Signed-off-by line.

To fix existing commits:

# Sign off the last N commits (replace N with the number of unsigned commits)
git rebase HEAD~N --signoff
git push --force-with-lease

To sign off future commits automatically:

  • Use git commit -s every time, or
  • VSCode: enable Git: Always Sign Off in Settings
  • PyCharm: enable Sign-off commit in the Commit tool window

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@model_gateway/src/routers/grpc/utils/parsers.rs`:
- Around line 50-74: Update resolve_user_thinking to reuse
ChatCompletionRequest::thinking_preference() for the protocol and
reasoning_effort fallback instead of passing request.thinking and
request.reasoning_effort through resolve_thinking_pref; preserve
template_thinking as the highest-priority value. Adjust
resolve_thinking_pref_explicit_kwarg_wins to exercise the simplified
resolve_user_thinking with an appropriate request fixture, or remove it in favor
of coverage through resolve_user_thinking.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3b22415c-ced2-41e5-beff-96187f88f248

📥 Commits

Reviewing files that changed from the base of the PR and between fec23aa and 0441fa6.

📒 Files selected for processing (10)
  • crates/protocols/src/chat.rs
  • crates/reasoning_parser/src/factory.rs
  • crates/tokenizer/src/encoders/deepseek_v4.rs
  • crates/tokenizer/src/huggingface.rs
  • crates/tokenizer/tests/deepseek_renderer_detection.rs
  • model_gateway/src/routers/grpc/regular/processor.rs
  • model_gateway/src/routers/grpc/regular/stages/chat/request_building.rs
  • model_gateway/src/routers/grpc/regular/streaming.rs
  • model_gateway/src/routers/grpc/utils/chat_utils.rs
  • model_gateway/src/routers/grpc/utils/parsers.rs

Comment thread model_gateway/src/routers/grpc/utils/parsers.rs Outdated
@junliu-mde
junliu-mde force-pushed the fix/deepseek-v4-official-compat branch from 0441fa6 to 586a5ba Compare July 23, 2026 20:51

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 586a5ba918

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

let owned = inject_tools_into_messages(messages, params.tools);
let msgs: &[serde_json::Value] = owned.as_deref().unwrap_or(messages);
let thinking_mode = derive_thinking_mode(params);
let thinking_mode = derive_thinking_mode(params, true);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Separate V4 default reasoning in Messages responses

When this default makes DeepSeek V4 prompts enter thinking mode for Anthropic Messages requests with no thinking config, the response paths still only enable separate_reasoning for explicit Enabled/Adaptive configs (process_non_streaming_messages_response and the Messages streaming setup). In that omitted-config case the registered V4 parser is never run, so output like reasoning</think>answer is emitted as a text block/SSE text instead of a thinking block plus answer, leaking/corrupting reasoning content for the Messages API.

Useful? React with 👍 / 👎.

@junliu-mde junliu-mde Jul 24, 2026

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.

fixed in 486a618.

Both Messages response paths (non-streaming process_non_streaming_messages_response and the streaming setup) now compute separate_reasoning as: explicit Enabled/Adaptive OR should_mark_reasoning_started(user_thinking, tokenizer), so a V4 request with an omitted thinking config (template default on) runs the reasoning parser and emits a proper thinking block instead of leaking reasoning</think> into text content. Explicit Disabled still opts out.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/tokenizer/src/huggingface.rs`:
- Around line 581-589: Update the changelog or release notes to explicitly
document that DeepSeek V4 now defaults thinking mode to on when neither thinking
nor reasoning_effort is specified, causing responses to include
<think>...</think> reasoning content. Reference the DeepSeek V4 default behavior
introduced by thinking_toggle and the related request mapping changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ad216246-e226-4e9c-a0de-bd49e2ae0264

📥 Commits

Reviewing files that changed from the base of the PR and between 0441fa6 and 586a5ba.

📒 Files selected for processing (10)
  • crates/protocols/src/chat.rs
  • crates/reasoning_parser/src/factory.rs
  • crates/tokenizer/src/encoders/deepseek_v4.rs
  • crates/tokenizer/src/huggingface.rs
  • crates/tokenizer/tests/deepseek_renderer_detection.rs
  • model_gateway/src/routers/grpc/regular/processor.rs
  • model_gateway/src/routers/grpc/regular/stages/chat/request_building.rs
  • model_gateway/src/routers/grpc/regular/streaming.rs
  • model_gateway/src/routers/grpc/utils/chat_utils.rs
  • model_gateway/src/routers/grpc/utils/parsers.rs

Comment thread crates/tokenizer/src/huggingface.rs
@junliu-mde
junliu-mde force-pushed the fix/deepseek-v4-official-compat branch from 586a5ba to afc6e8a Compare July 23, 2026 21:29

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: afc6e8a26b

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

registry.register_pattern("deepseek-r1", "deepseek_r1");
registry.register_pattern("deepseek-v3.1", "deepseek_v31");
registry.register_pattern("deepseek-v3-1", "deepseek_v31");
registry.register_pattern("deepseek-v4", "deepseek_v4");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Arm the V4 parser for aliased model ids

When a DeepSeek V4 tokenizer is registered under an alias such as a label/namespace model id that does not contain deepseek-v4, the native renderer still selects V4 from config.json::architectures and now opens <think> by default, but response processing asks check_reasoning_parser_availability(..., &chat_request.model) and this registration only matches names containing deepseek-v4. In that alias case separate_reasoning has no parser and the model's reasoning is returned as normal content; tie parser selection to the V4 renderer or register/use the parser for the effective tokenizer instead of only this name pattern.

Useful? React with 👍 / 👎.

@slin1237

Copy link
Copy Markdown
Member

@key4ng please also take a look, thanks

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@model_gateway/src/routers/http/pd_router.rs`:
- Around line 219-280: Gate the entire thinking-translation logic in
apply_deepseek_v4_http_compat on is_deepseek_v4, returning before inspecting or
writing chat_template_kwargs.thinking for other models. Preserve the existing
DeepSeek V4 reasoning_effort remapping and translation behavior, and add a
regression test proving non-DeepSeek-V4 requests with reasoning_effort "none" or
explicit thinking remain unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 0c1b5bb2-1952-49eb-be8b-1b1ea611231d

📥 Commits

Reviewing files that changed from the base of the PR and between 586a5ba and 50345f1.

📒 Files selected for processing (12)
  • bindings/golang/src/utils.rs
  • crates/protocols/src/chat.rs
  • crates/reasoning_parser/src/factory.rs
  • crates/tokenizer/src/encoders/deepseek_v4.rs
  • crates/tokenizer/src/huggingface.rs
  • crates/tokenizer/tests/deepseek_renderer_detection.rs
  • model_gateway/src/routers/grpc/regular/processor.rs
  • model_gateway/src/routers/grpc/regular/stages/chat/request_building.rs
  • model_gateway/src/routers/grpc/regular/streaming.rs
  • model_gateway/src/routers/grpc/utils/chat_utils.rs
  • model_gateway/src/routers/grpc/utils/parsers.rs
  • model_gateway/src/routers/http/pd_router.rs

Comment thread model_gateway/src/routers/http/pd_router.rs Outdated
@junliu-mde

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 486a61845f

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread model_gateway/src/routers/http/pd_router.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@model_gateway/src/routers/http/deepseek_compat.rs`:
- Around line 102-115: Extend
deepseek_v4_http_compat_preserves_internal_override_and_maps_effort to assert
all documented V4 reasoning_effort normalizations: low, medium, and high must
each become high, while preserving the existing xhigh-to-max and non-V4
assertions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5c0f2b38-35f6-4835-9eed-2fca1edfb024

📥 Commits

Reviewing files that changed from the base of the PR and between 486a618 and 9d386b6.

📒 Files selected for processing (4)
  • model_gateway/src/routers/http/deepseek_compat.rs
  • model_gateway/src/routers/http/mod.rs
  • model_gateway/src/routers/http/pd_router.rs
  • model_gateway/src/routers/http/router.rs

Comment thread model_gateway/src/routers/http/deepseek_compat.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9d386b6df0

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread model_gateway/src/routers/http/deepseek_compat.rs
@github-actions github-actions Bot added the documentation Improvements or additions to documentation label Jul 24, 2026
@junliu-mde
junliu-mde force-pushed the fix/deepseek-v4-official-compat branch from df090a8 to ff4df69 Compare July 24, 2026 09:35
@github-actions github-actions Bot removed the documentation Improvements or additions to documentation label Jul 24, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ff4df69543

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +65 to +66
let explicit_thinking = request
.get("thinking")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Drop the public thinking field before forwarding

For DeepSeek V4 HTTP requests that use the new official thinking object, this shim reads it and adds chat_template_kwargs.thinking, but the original top-level thinking field is still forwarded to the SGLang HTTP worker. The file-level contract says this translates public controls into SGLang worker controls before forwarding, and the code already consumes unsupported off-signal reasoning_effort values for the same reason; leaving thinking in the payload can make otherwise valid DeepSeek requests fail or be misinterpreted by workers that only understand the translated kwarg. Remove it after reading it, including before the chat_template_kwargs.thinking override return path.

Useful? React with 👍 / 👎.

Comment thread model_gateway/src/routers/http/deepseek_compat.rs
@mergify

mergify Bot commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Hi @junliu-mde, this PR has merge conflicts that must be resolved before it can be merged. Please rebase your branch:

git fetch origin main
git rebase origin/main
# resolve any conflicts, then:
git push --force-with-lease

@mergify mergify Bot added the needs-rebase PR has merge conflicts that need to be resolved label Jul 26, 2026
Signed-off-by: Jun Liu <jun.c.liu@rakuten.com>
Signed-off-by: Jun Liu <jun.c.liu@rakuten.com>
…soning in messages

- Gate all of apply_deepseek_v4_http_compat on the model check so other
  models' requests never receive a DeepSeek-only chat_template_kwargs
  thinking key or a remapped reasoning_effort.
- Messages responses (non-streaming and streaming) now also separate
  reasoning when the template default turns thinking on (DeepSeek V4)
  with no explicit thinking config, instead of emitting the reasoning
  as text content.

Signed-off-by: Jun Liu <jun.c.liu@rakuten.com>
Move the V4 translation out of PDRouter into a shared
http/deepseek_compat module and call it from the regular Router's
send_typed_request for /v1/chat/completions, so non-PD HTTP workers
also receive the thinking kwarg projection and effort remap.

Signed-off-by: Jun Liu <jun.c.liu@rakuten.com>
…HTTP workers

none/minimal are the gateway's thinking-off signal, not official V4
levels; the worker only understands absent/high/max, so remove the
field from the forwarded JSON once consumed.

Signed-off-by: Jun Liu <jun.c.liu@rakuten.com>
… HTTP workers

The shim translates it into chat_template_kwargs.thinking; leaving the
original in the payload lets a worker that natively understands the
official field contradict the translation (e.g. an explicit kwarg
override). Remove it on every path, matching the off-signal
reasoning_effort handling.

Signed-off-by: Jun Liu <jun.c.liu@rakuten.com>
@junliu-mde
junliu-mde force-pushed the fix/deepseek-v4-official-compat branch from 7d6e757 to 7df8476 Compare July 26, 2026 01:11
@mergify mergify Bot removed the needs-rebase PR has merge conflicts that need to be resolved label Jul 26, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7df84764a9

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

thinking: openai_protocol::chat::thinking_from_reasoning_effort(
request.reasoning_effort.as_deref(),
),
thinking: request.thinking_preference(),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Scope DeepSeek thinking controls to V4 in gRPC

When a gRPC chat request targets another toggle-capable model such as Qwen or GLM and includes the new DeepSeek-specific thinking object, this unconditional preference is projected by ChatTemplateState::apply onto that model's own enable_thinking key, unexpectedly enabling or disabling its reasoning and changing a field that was previously ignored. The HTTP compatibility path explicitly no-ops for non-V4 models, so gate this protocol field by the effective DeepSeek V4 renderer/model while retaining the generic reasoning_effort mapping.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

grpc gRPC client and router changes model-gateway Model gateway crate changes protocols Protocols crate changes reasoning-parser Reasoning parser changes tests Test changes tokenizer Tokenizer related changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants