Skip to content

fix: Qwen tool_choice conflict with thinking/reasoning mode#564

Closed
nntrivi2001 wants to merge 1 commit intodecolua:masterfrom
nntrivi2001:fix/qwen-thinking-tool-choice-conflict
Closed

fix: Qwen tool_choice conflict with thinking/reasoning mode#564
nntrivi2001 wants to merge 1 commit intodecolua:masterfrom
nntrivi2001:fix/qwen-thinking-tool-choice-conflict

Conversation

@nntrivi2001
Copy link
Copy Markdown

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() để force tool_choice về "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.

Copilot AI review requested due to automatic review settings April 11, 2026 19:38
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

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 coerce tool_choice to "auto" when thinking mode is detected.
  • Add a Qwen-specific transformRequest() safeguard to coerce problematic tool_choice values 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.

Comment thread open-sse/translator/index.js
Comment on lines +145 to +160
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";
}
}
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

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

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

Copilot uses AI. Check for mistakes.
Comment thread open-sse/executors/qwen.js Outdated
Comment on lines +79 to +89
// 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";
}
}
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
Comment on lines +145 to +160
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";
}
}
Copy link

Copilot AI Apr 11, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
…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).
@nntrivi2001 nntrivi2001 force-pushed the fix/qwen-thinking-tool-choice-conflict branch from 660d2c8 to df34558 Compare April 11, 2026 19:46
@nntrivi2001 nntrivi2001 deleted the fix/qwen-thinking-tool-choice-conflict branch April 12, 2026 07:58
@nntrivi2001 nntrivi2001 restored the fix/qwen-thinking-tool-choice-conflict branch April 12, 2026 10:46
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