fix: Qwen tool_choice conflict with thinking/reasoning mode#564
fix: Qwen tool_choice conflict with thinking/reasoning mode#564nntrivi2001 wants to merge 1 commit intodecolua:masterfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes DashScope-backed Qwen request rejections (HTTP 400) caused by incompatible combinations of tool_choice (especially "required" / function-object) with thinking/reasoning mode.
Changes:
- Add a DashScope-provider guard in
translateRequest()to coercetool_choiceto"auto"when thinking mode is detected. - Add a Qwen-specific
transformRequest()safeguard to coerce problematictool_choicevalues to"auto"when thinking mode is active.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| open-sse/translator/index.js | Adds provider/thinking detection to force tool_choice to "auto" for DashScope-backed providers. |
| open-sse/executors/qwen.js | Adds Qwen executor-side coercion of tool_choice when thinking mode is enabled. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if ( | ||
| result.tool_choice && | ||
| result.tool_choice !== "auto" && | ||
| (provider === "qw" || provider === "alicode" || provider === "alicode-intl") | ||
| ) { | ||
| const hasThinkingMode = | ||
| !!result.reasoning_effort || | ||
| !!result.thinking?.budget_tokens || | ||
| !!result.thinking?.max_tokens || | ||
| result.thinking?.type === "enabled" || | ||
| (result.reasoning?.effort && result.reasoning.effort !== "none") || | ||
| !!result.enable_thinking; | ||
| if (hasThinkingMode) { | ||
| result.tool_choice = "auto"; | ||
| } | ||
| } |
There was a problem hiding this comment.
This forces tool_choice to "auto" for any non-"auto" value when thinking mode is detected. That also changes tool_choice: "none" semantics (disabling tools) into allowing tools, which is a behavior change beyond the stated conflict (“required”/object). Consider narrowing the override to only tool_choice === "required" or object values (and leave "none" untouched).
| // Qwen API does not support tool_choice "required" or object values when | ||
| // thinking/reasoning mode is active. This catches all code paths regardless | ||
| // of source format (Anthropic, OpenAI, Gemini, etc.). | ||
| // See: InternalError.Algo.InvalidParameter | ||
| const hasThinkingMode = !!result.reasoning_effort || result.thinking?.type === "enabled"; | ||
| if (hasThinkingMode && result.tool_choice) { | ||
| const tc = result.tool_choice; | ||
| if (tc === "required" || typeof tc === "object") { | ||
| result.tool_choice = "auto"; | ||
| } | ||
| } |
There was a problem hiding this comment.
The comment says this “catches all code paths”, but hasThinkingMode only checks reasoning_effort and thinking.type. Elsewhere (e.g. translateRequest) thinking can be represented via enable_thinking, thinking.budget_tokens/max_tokens, or reasoning.effort. If those fields reach this executor, tool_choice may still be left as required/object and trigger the same 400. Consider reusing a shared “has thinking enabled” predicate or expanding this check to match all supported thinking flags.
| if ( | ||
| result.tool_choice && | ||
| result.tool_choice !== "auto" && | ||
| (provider === "qw" || provider === "alicode" || provider === "alicode-intl") | ||
| ) { | ||
| const hasThinkingMode = | ||
| !!result.reasoning_effort || | ||
| !!result.thinking?.budget_tokens || | ||
| !!result.thinking?.max_tokens || | ||
| result.thinking?.type === "enabled" || | ||
| (result.reasoning?.effort && result.reasoning.effort !== "none") || | ||
| !!result.enable_thinking; | ||
| if (hasThinkingMode) { | ||
| result.tool_choice = "auto"; | ||
| } | ||
| } |
There was a problem hiding this comment.
There are existing Vitest unit tests for translateRequest normalization, but this new DashScope/Qwen-specific coercion isn’t covered. Adding a regression test for (a) thinking mode + tool_choice: "required" (or object) => coerced to "auto", and (b) thinking mode + tool_choice: "none" remains unchanged (if intended) would help prevent future regressions.
…Qwen Qwen API trả về 400 khi tool_choice != "auto" kết hợp với thinking/reasoning mode. Neutralize tool_choice về "auto" cho các provider dùng DashScope backend (qw, alicode, alicode-intl).
660d2c8 to
df34558
Compare
Qwen API đang bị reject với lỗi 400 khi client gửi
tool_choice: "required"(hoặc object) kèm theo thinking mode. Lỗi này xảy ra với các provider dùng DashScope backend (qw, alicode, alicode-intl).Fix này thêm một check nhỏ trong
translateRequest()để forcetool_choicevề"auto"khi phát hiện thinking mode trên các provider DashScope. Không ảnh hưởng đến các provider khác.