chat : scope qwen3-coder workarounds (#27679)

This commit is contained in:
Aldehir Rojas
2026-08-25 09:33:00 -05:00
committed by GitHub
parent 790b5713ca
commit 0cc5b14959
+17 -10
View File
@@ -1177,6 +1177,8 @@ static common_chat_params common_chat_params_init_qwen3_coder(const common_chat_
"</tool_call>",
};
auto is_qwen3_coder = !supports_reasoning;
if (supports_reasoning) {
data.thinking_start_tag = "<think>";
// Support both </think> and <tool_call> as reasoning end sequences.
@@ -1217,13 +1219,15 @@ static common_chat_params common_chat_params_init_qwen3_coder(const common_chat_
std::vector<std::string> tool_call_starts = { "<tool_call>" };
// Match complete <function=name> opener for Qwen3-Coder models that occasionally omit the
// starting <tool_call>. The model may hallucinate a tool name, but it is preferable over
// constraining on <function which may occur in valid content generation, e.g. #include <functional>
foreach_function(inputs.tools, [&](const json & tool) {
const std::string name = tool.at("function").at("name");
tool_call_starts.push_back("<function=" + name + ">");
});
if (is_qwen3_coder) {
// Match complete <function=name> opener for Qwen3-Coder models that occasionally omit the
// starting <tool_call>. The model may hallucinate a tool name, but it is preferable over
// constraining on <function which may occur in valid content generation, e.g. #include <functional>
foreach_function(inputs.tools, [&](const json & tool) {
const std::string name = tool.at("function").at("name");
tool_call_starts.push_back("<function=" + name + ">");
});
}
auto parser = build_chat_peg_parser([&](common_chat_peg_builder & p) {
auto generation_prompt = p.literal(GEN_PREFIX);
@@ -1288,10 +1292,13 @@ static common_chat_params common_chat_params_init_qwen3_coder(const common_chat_
auto min_calls = inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED ? 1 : 0;
auto tool_call_body = tool_choice + "</tool_call>" + p.space();
auto tool_call = p.rule("tool-call", "<tool_call>\n" + tool_call_body);
// Qwen3-Coder models may occasionally omit the <tool_call> token.
auto tool_call_body = tool_choice + "</tool_call>" + p.space();
auto tool_call_first = p.rule("tool-call-first", p.optional(p.literal("<tool_call>\n")) + tool_call_body);
auto tool_call = p.rule("tool-call", "<tool_call>\n" + tool_call_body);
auto tool_call_first = is_qwen3_coder ?
p.rule("tool-call-first", p.optional(p.literal("<tool_call>\n")) + tool_call_body) :
tool_call;
auto calls = inputs.parallel_tool_calls ? tool_call_first + p.zero_or_more(tool_call) : tool_call_first;
auto tool_calls = p.trigger_rule("tool-call-root", p.repeat(calls, min_calls, 1));