diff --git a/common/chat.cpp b/common/chat.cpp index f79fe703db..03cd9e25f4 100644 --- a/common/chat.cpp +++ b/common/chat.cpp @@ -1083,7 +1083,9 @@ static common_chat_params common_chat_params_init_gemma4(const common_chat_templ data.prompt = common_chat_template_direct_apply_impl(tmpl, inputs); data.format = COMMON_CHAT_FORMAT_PEG_GEMMA4; - data.supports_thinking = true; + data.supports_thinking = true; + data.thinking_start_tag = "<|channel>thought"; + data.thinking_end_tag = ""; data.preserved_tokens = { "<|channel>", @@ -1102,9 +1104,9 @@ static common_chat_params common_chat_params_init_gemma4(const common_chat_templ auto start = p.rule("start", p.prefix(inputs.generation_prompt, "<|channel>")); if (extract_reasoning) { - p.rule("thought", p.literal("<|channel>thought\n") + p.reasoning(p.until("")) + p.literal("")); + p.rule("thought", p.literal("<|channel>thought") + p.space() + p.reasoning(p.until("")) + p.literal("")); } else { - p.rule("thought", p.content(p.literal("<|channel>thought\n") + p.until("") + p.literal(""))); + p.rule("thought", p.content(p.literal("<|channel>thought") + p.space() + p.until("") + p.literal(""))); } auto thought = (p.peek(p.literal("<|channel>")) + p.ref("thought")) | p.negate(p.literal("<|channel>")); diff --git a/tests/test-chat.cpp b/tests/test-chat.cpp index f8b2b584e2..1d3a77bc05 100644 --- a/tests/test-chat.cpp +++ b/tests/test-chat.cpp @@ -1988,6 +1988,13 @@ static void test_template_output_peg_parsers(bool detailed_debug) { .expect(message_assist_thoughts) .run(); + // Empty reasoning (budget=0: sampler forces end tag before newline) + tst.test( + "<|channel>thoughtHello, world!\nWhat's up?") + .reasoning_format(COMMON_REASONING_FORMAT_AUTO) + .expect(simple_assist_msg("Hello, world!\nWhat's up?", "")) + .run(); + // Reasoning and content with reasoning_format = none tst.test( "<|channel>thought\nI'm\nthinkingHello, world!\nWhat's up?")