Skip to content

fix: preserve Qwen thinking_budget passthrough - #5836

Merged
Calcium-Ion merged 8 commits into
QuantumNous:mainfrom
wxwwt:codex/fix-qwen-thinking-budget
Jul 29, 2026
Merged

fix: preserve Qwen thinking_budget passthrough#5836
Calcium-Ion merged 8 commits into
QuantumNous:mainfrom
wxwwt:codex/fix-qwen-thinking-budget

Conversation

@wxwwt

@wxwwt wxwwt commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

背景

  • 阿里 DashScope compatible-mode 支持在 OpenAI-compatible 请求中传 enable_thinkingthinking_budget
  • 目前 NewAPI 在非 pass-through 路径会先把请求反序列化为 GeneralOpenAIRequest,再重新序列化后转发。
  • GeneralOpenAIRequest 之前没有 thinking_budget 字段,导致 Qwen 请求中的该参数在转发前被丢弃。

修复内容

  • 为 OpenAI Chat/Responses 请求 DTO 增加 thinking_budget 字段,类型使用 json.RawMessage,保留显式 0 等值。
  • 仅在 Qwen/QwQ 模型名下输出 thinking_budget,避免影响其它不支持该参数的模型。
  • 阿里 adaptor 使用映射后的 upstream model name 再做一次过滤,确保只对真正发往 Qwen/QwQ 的请求透传。
  • 补齐 Chat Completions 与 Responses 兼容转换路径中的 thinking_budget 保留。

测试

  • go test ./dto ./relay/channel/ali ./service/relayconvert
  • go test ./...:根包 setup 因缺少 web/classic/dist 嵌入目录失败;其余可运行 Go 包通过。

Summary by CodeRabbit

  • New Features

    • Added support for Qwen thinking controls (enable_thinking, thinking_budget) and preserved them across compatible OpenAI/Responses, Chat Completions, and ALI conversions.
  • Bug Fixes

    • thinking_budget is now omitted for non-Qwen thinking-budget models to avoid sending incompatible payload fields.
    • Improved streaming handling for Dify requests.
    • Unimplemented Claude conversions now fail fast instead of silently returning empty results.
  • Tests

    • Added unit tests covering Qwen vs non-Qwen thinking_budget behavior across conversions.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

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

Changes

Qwen thinking budget handling

Layer / File(s) Summary
Thinking budget fields and serialization
relaykit/dto/openai_request.go, relaykit/dto/openai_request_zero_value_test.go
Adds Qwen model detection and conditionally serializes thinking_budget for both OpenAI request DTOs.
Thinking settings through request conversions
relaykit/relayconvert/internal/oai_chat/..., relaykit/relayconvert/internal/oai_responses/...
Propagates EnableThinking and ThinkingBudget between chat-completion and responses requests, with preservation tests.
Ali conversion uses the upstream model
relay/channel/ali/adaptor.go, relay/channel/ali/text.go, relay/channel/ali/adaptor_test.go
Passes the upstream model into Ali conversion and removes thinking_budget for non-Qwen models.

Adaptor unsupported-path behavior

Layer / File(s) Summary
Explicit failures for unsupported conversions
relay/channel/{baidu,cloudflare,cohere,jina,mistral,mokaai,palm,tencent,xunfei,zhipu}/adaptor.go
Unsupported Claude conversions now panic, and Cloudflare Gemini conversion returns a not-implemented error.
Dify response handler routing
relay/channel/dify/adaptor.go
Selects the streaming or non-streaming Dify response handler according to info.IsStream.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant OpenAIRequest
  participant RequestConversion
  participant ConvertOpenAIRequest
  participant requestOpenAI2Ali
  OpenAIRequest->>RequestConversion: preserve EnableThinking and ThinkingBudget
  RequestConversion-->>ConvertOpenAIRequest: converted request
  ConvertOpenAIRequest->>requestOpenAI2Ali: pass UpstreamModelName
  requestOpenAI2Ali-->>OpenAIRequest: serialize model-specific thinking fields
Loading

Poem

A rabbit hops through fields so bright,
Qwen keeps its budget just right.
Other models let it go,
Conversions carry thoughts in tow.
Stubs now thump instead of hide!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: preserving Qwen thinking_budget passthrough across request conversions.
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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@dto/openai_request_zero_value_test.go`:
- Around line 54-102: The tests in
GeneralOpenAIRequestPreserveQwenThinkingBudget,
GeneralOpenAIRequestDropsThinkingBudgetForNonQwenModel, and
TestIsQwenThinkingBudgetModel are using require for non-fatal value assertions;
switch those checks to assert while keeping require only for setup/fatal steps
like common.Unmarshal and common.Marshal. Update the value comparisons in this
file to follow the same assert/require split used by the sibling relayconvert
tests, and keep the helper IsQwenThinkingBudgetModel coverage unchanged aside
from the assertion style.

In `@relay/channel/ali/adaptor_test.go`:
- Around line 14-55: The test assertions on the marshaled request output are
using require where they should be non-fatal assert checks; update
TestConvertOpenAIRequestPreservesThinkingBudgetForQwen and
TestConvertOpenAIRequestDropsThinkingBudgetForNonQwen to keep require.NoError
for setup/fatal failures, but switch the value checks on gjson.GetBytes(...) to
assert-based assertions so the test reports all mismatches without stopping
early.
🪄 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: CHILL

Plan: Pro

Run ID: ac7ef7a5-39ae-42b6-90ff-3c1681a38b29

📥 Commits

Reviewing files that changed from the base of the PR and between 5bf3468 and 94c8836.

📒 Files selected for processing (9)
  • dto/openai_request.go
  • dto/openai_request_zero_value_test.go
  • relay/channel/ali/adaptor.go
  • relay/channel/ali/adaptor_test.go
  • relay/channel/ali/text.go
  • service/relayconvert/chat_responses_compat_test.go
  • service/relayconvert/chat_to_responses.go
  • service/relayconvert/responses_request_to_chat.go
  • service/relayconvert/responses_request_to_chat_test.go

Comment thread relaykit/dto/openai_request_zero_value_test.go
Comment thread relay/channel/ali/adaptor_test.go Outdated
wxwwt added 2 commits July 1, 2026 15:04
…ng-budget

# Conflicts:
#	service/relayconvert/internal/oai_responses/to_oai_chat_resp_test.go
@wxwwt

wxwwt commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

@Calcium-Ion 你好,麻烦有空帮忙 review 一下这个 PR~

Calcium-Ion and others added 3 commits July 29, 2026 14:01
…thinking-budget

# Conflicts:
#	relaykit/dto/openai_request_zero_value_test.go
#	relaykit/relayconvert/internal/oai_chat/to_oai_responses_req_test.go
…ng-budget

# Conflicts:
#	relaykit/dto/openai_request_zero_value_test.go
#	relaykit/relayconvert/internal/oai_chat/to_oai_responses_req_test.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
relaykit/dto/openai_request.go (1)

9-10: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Use common/json.go wrappers for relaykit JSON operations.

relaykit/relayconvert/kitutil/json.go is a local relaykit wrapper, so importing it here violates the required business-code contract to use common/json.go for JSON marshaling/unmarshaling. Update relaykit/dto/openai_request.go, relaykit/relayconvert/internal/oai_chat/to_oai_responses_req.go, and relaykit/relayconvert/internal/oai_responses/to_oai_chat_req.go to use common.Marshal/Unmarshal/helpers instead of kitutil.

🤖 Prompt for 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.

In `@relaykit/dto/openai_request.go` around lines 9 - 10, Replace
relaykit/relayconvert/kitutil JSON usage with the common/json.go wrappers in
relaykit/dto/openai_request.go,
relaykit/relayconvert/internal/oai_chat/to_oai_responses_req.go, and
relaykit/relayconvert/internal/oai_responses/to_oai_chat_req.go. Update the
affected imports and calls to use common.Marshal, common.Unmarshal, or the
corresponding common helpers while preserving existing request-conversion
behavior.

Sources: Coding guidelines, Learnings

🧹 Nitpick comments (2)
relaykit/relayconvert/internal/oai_chat/to_oai_responses_req_test.go (1)

42-59: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cover explicit zero in both conversion paths.

Both tests verify only thinking_budget: 128; add explicit 0 cases so zero-value passthrough remains protected end to end.

  • relaykit/relayconvert/internal/oai_chat/to_oai_responses_req_test.go#L42-L59: add a Qwen request with ThinkingBudget: json.RawMessage(\0`)`.
  • relaykit/relayconvert/internal/oai_responses/to_oai_chat_req_test.go#L59-L72: add the corresponding Responses-to-Chat zero-value case.
🤖 Prompt for 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.

In `@relaykit/relayconvert/internal/oai_chat/to_oai_responses_req_test.go` around
lines 42 - 59, Add explicit zero-budget test coverage in both conversion paths:
extend TestChatCompletionsRequestToResponsesRequestPreservesQwenThinkingBudget
in relaykit/relayconvert/internal/oai_chat/to_oai_responses_req_test.go (lines
42-59) with a Qwen request using ThinkingBudget set to JSON 0 and assert the
converted value remains 0; add the corresponding Responses-to-Chat zero-value
case in relaykit/relayconvert/internal/oai_responses/to_oai_chat_req_test.go
(lines 59-72), preserving the existing 128 cases.

Source: Coding guidelines

relaykit/dto/openai_request_zero_value_test.go (1)

85-101: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cover provider-prefixed Qwen model names directly.

Qwen/Qwen3-... matches the HasPrefix("qwen") branch, so the /qwen and /qwq matching paths are not actually tested. Add cases such as provider/qwen-plus and provider/qwq-32b to protect the model-aware serialization contract.

🤖 Prompt for 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.

In `@relaykit/dto/openai_request_zero_value_test.go` around lines 85 - 101, Extend
TestIsQwenThinkingBudgetModel with provider-prefixed positive cases such as
provider/qwen-plus and provider/qwq-32b, ensuring the slash-based matching paths
are exercised while preserving the existing expectations.

Source: Coding guidelines

🤖 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.

Outside diff comments:
In `@relaykit/dto/openai_request.go`:
- Around line 9-10: Replace relaykit/relayconvert/kitutil JSON usage with the
common/json.go wrappers in relaykit/dto/openai_request.go,
relaykit/relayconvert/internal/oai_chat/to_oai_responses_req.go, and
relaykit/relayconvert/internal/oai_responses/to_oai_chat_req.go. Update the
affected imports and calls to use common.Marshal, common.Unmarshal, or the
corresponding common helpers while preserving existing request-conversion
behavior.

---

Nitpick comments:
In `@relaykit/dto/openai_request_zero_value_test.go`:
- Around line 85-101: Extend TestIsQwenThinkingBudgetModel with
provider-prefixed positive cases such as provider/qwen-plus and
provider/qwq-32b, ensuring the slash-based matching paths are exercised while
preserving the existing expectations.

In `@relaykit/relayconvert/internal/oai_chat/to_oai_responses_req_test.go`:
- Around line 42-59: Add explicit zero-budget test coverage in both conversion
paths: extend
TestChatCompletionsRequestToResponsesRequestPreservesQwenThinkingBudget in
relaykit/relayconvert/internal/oai_chat/to_oai_responses_req_test.go (lines
42-59) with a Qwen request using ThinkingBudget set to JSON 0 and assert the
converted value remains 0; add the corresponding Responses-to-Chat zero-value
case in relaykit/relayconvert/internal/oai_responses/to_oai_chat_req_test.go
(lines 59-72), preserving the existing 128 cases.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c3fb14c5-388b-4ff6-acff-836682ebc43e

📥 Commits

Reviewing files that changed from the base of the PR and between 0150c42 and 1a85781.

📒 Files selected for processing (9)
  • relay/channel/ali/adaptor.go
  • relay/channel/ali/adaptor_test.go
  • relay/channel/ali/text.go
  • relaykit/dto/openai_request.go
  • relaykit/dto/openai_request_zero_value_test.go
  • relaykit/relayconvert/internal/oai_chat/to_oai_responses_req.go
  • relaykit/relayconvert/internal/oai_chat/to_oai_responses_req_test.go
  • relaykit/relayconvert/internal/oai_responses/to_oai_chat_req.go
  • relaykit/relayconvert/internal/oai_responses/to_oai_chat_req_test.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • relay/channel/ali/adaptor_test.go
  • relay/channel/ali/text.go
  • relay/channel/ali/adaptor.go

@Calcium-Ion
Calcium-Ion merged commit 66ee6b8 into QuantumNous:main Jul 29, 2026
3 checks passed
kimberxu pushed a commit to kimberxu/new-api that referenced this pull request Jul 30, 2026
* fix: preserve qwen thinking budget

* test: address qwen thinking budget review comments

* chore: remove unreachable adaptor code

* test: cover zero Qwen thinking budgets
bilicapr pushed a commit to bilicapr/new-api that referenced this pull request Jul 30, 2026
* fix: preserve qwen thinking budget

* test: address qwen thinking budget review comments

* chore: remove unreachable adaptor code

* test: cover zero Qwen thinking budgets
IQZZ020501 pushed a commit to IQZZ020501/new-api that referenced this pull request Jul 30, 2026
* fix: preserve qwen thinking budget

* test: address qwen thinking budget review comments

* chore: remove unreachable adaptor code

* test: cover zero Qwen thinking budgets
@coderabbitai coderabbitai Bot mentioned this pull request Jul 31, 2026
11 tasks
0401lucky pushed a commit to 0401lucky/new-api that referenced this pull request Aug 2, 2026
* fix: preserve qwen thinking budget

* test: address qwen thinking budget review comments

* chore: remove unreachable adaptor code

* test: cover zero Qwen thinking budgets
yuqiyi pushed a commit to yuqiyi/new-api that referenced this pull request Aug 16, 2026
* v1.0.0-rc.24: (117 commits)
  CI: enhance release synchronization workflow with optional file syncing
  fix: 修复兑换码额度精度损失 (QuantumNous#6685)
  feat(rate-limit): add user critical rate limit middleware for access token and aff transfer routes
  fix: test Claude/Gemini endpoints with native request format (QuantumNous#6698)
  feat(channels): refine fetched model categorization (QuantumNous#6632)
  Merge commit from fork
  refactor(relay): move replay metadata onto request bodies
  fix(relay): set Request.GetBody so the HTTP/2 transport can transparently retry after an upstream stream reset (QuantumNous#6249)
  Feat/auto group (QuantumNous#6590)
  fix(aws): cancel Bedrock requests on client disconnect (QuantumNous#6589)
  fix(billing): harden tiered retry group-switch billing (QuantumNous#6570)
  fix(billing): settle tiered retries with final group (QuantumNous#6518)
  feat: deepseek responses api (QuantumNous#6562)
  style: use text-sm for public header nav links to match other nav components (QuantumNous#6557)
  fix(oauth): stop treating a foreign window.opener as a bind flow (QuantumNous#6425)
  fix(relay): preserve multipart image edits for New API channels (QuantumNous#6559)
  feat(logs): expose stream status to log owners (QuantumNous#6558)
  feat: support zstd request decompression (QuantumNous#6545)
  fix: preserve Qwen thinking_budget passthrough (QuantumNous#5836)
  feat(oidc): 支持自定义 OIDC 登录显示名称 (QuantumNous#6012)
  ...

# Conflicts:
#	service/text_quota.go
#	web/src/features/models/components/drawers/model-mutate-drawer.tsx
#	web/src/features/pricing/components/model-details.tsx
#	web/src/features/pricing/lib/price.ts
refeiner pushed a commit to wuqiang44444444/new-api that referenced this pull request Aug 17, 2026
* fix: preserve qwen thinking budget

* test: address qwen thinking budget review comments

* chore: remove unreachable adaptor code

* test: cover zero Qwen thinking budgets
330079598 pushed a commit to 330079598/new-api that referenced this pull request Aug 19, 2026
* fix: preserve qwen thinking budget

* test: address qwen thinking budget review comments

* chore: remove unreachable adaptor code

* test: cover zero Qwen thinking budgets
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.

2 participants