chat : strip the think block in the qwen3-coder with reasoning_format none (#31380)
* chat : accept the think block in the qwen3-coder response format with reasoning_format none Assisted-by: Claude Opus 5.5 * chat : define both qwen3-coder think block variants up front
This commit is contained in:
1 parent
8956c769e8
commit
1052f7e1d6
2 files changed
+37
-4
No files matched your search
@@ -74,16 +74,24 @@ common_chat_params common_chat_params_init_qwen3_coder(const common_chat_templat
|
||||
data.parser = build_chat_peg_parser([&](common_chat_peg_builder & p) {
|
||||
auto generation_prompt = p.literal(GEN_PREFIX);
|
||||
|
||||
// The template strips the newline before </think>, so leave it out of the reasoning
|
||||
auto think_body = p.until_one_of({ "\n</think>", "</think>", "<tool_call>" });
|
||||
auto think_close = p.literal("\n</think>") | p.literal("</think>") | p.peek(p.literal("<tool_call>"));
|
||||
|
||||
auto reasoning_extracted = p.optional("<think>" + p.space() + p.reasoning(think_body) + think_close);
|
||||
auto reasoning_skipped = p.optional("<think>" + p.space() + think_body + think_close);
|
||||
|
||||
auto reasoning = p.eps();
|
||||
if (supports_reasoning && extract_reasoning) {
|
||||
// The template strips the newline before </think>, so leave it out of the reasoning
|
||||
reasoning = p.optional("<think>" + p.space() +
|
||||
p.reasoning(p.until_one_of({ "\n</think>", "</think>", "<tool_call>" })) +
|
||||
(p.literal("\n</think>") | p.literal("</think>") | p.peek(p.literal("<tool_call>"))));
|
||||
reasoning = reasoning_extracted;
|
||||
}
|
||||
|
||||
// Response format parser
|
||||
if (has_response_format) {
|
||||
// The answer must be bare JSON, so the think block is consumed even when it is not extracted
|
||||
if (supports_reasoning && !extract_reasoning) {
|
||||
reasoning = reasoning_skipped;
|
||||
}
|
||||
return generation_prompt + (reasoning << p.content(p.schema(p.json(), "response-format", inputs.json_schema)));
|
||||
}
|
||||
|
||||
|
||||
@@ -5629,6 +5629,31 @@ static void test_template_output_peg_parsers(bool detailed_debug) {
|
||||
.expect(message_assist_call_thoughts)
|
||||
.run();
|
||||
|
||||
const std::string answer_schema = R"({"type":"object","properties":{"answer":{"type":"integer"}},"required":["answer"]})";
|
||||
|
||||
tst.test("I'm\nthinking</think>{\"answer\":42}")
|
||||
.enable_thinking(true)
|
||||
.reasoning_format(COMMON_REASONING_FORMAT_AUTO)
|
||||
.json_schema(answer_schema)
|
||||
.expect_reasoning("I'm\nthinking")
|
||||
.expect_content(R"({"answer":42})")
|
||||
.run();
|
||||
|
||||
// the reasoning block of the generation prompt must still be accepted when it is not extracted
|
||||
tst.test("{\"answer\":42}")
|
||||
.enable_thinking(false)
|
||||
.reasoning_format(COMMON_REASONING_FORMAT_NONE)
|
||||
.json_schema(answer_schema)
|
||||
.expect_content(R"({"answer":42})")
|
||||
.run();
|
||||
|
||||
tst.test("I'm\nthinking</think>{\"answer\":42}")
|
||||
.enable_thinking(true)
|
||||
.reasoning_format(COMMON_REASONING_FORMAT_NONE)
|
||||
.json_schema(answer_schema)
|
||||
.expect_content(R"({"answer":42})")
|
||||
.run();
|
||||
|
||||
// a deferred tool is left out of <tools>, a tool_reference renders it, and its schema types the call
|
||||
const auto deferred_tools = common_chat_tools_parse_oaicompat(json::parse(R"([
|
||||
{"type": "function", "function": {"name": "tool_search", "description": "Search for tools",
|
||||
|
||||
Reference in new issue
Block a user