chat: add dedicated Cohere2MoE (North Code) parser (#24615)

* chat: add dedicated Cohere2MoE (North Code) parser

* Some renames to make @CISC happy :>
This commit is contained in:
Piotr Wilkin (ilintar)
2026-06-14 20:17:40 +02:00
committed by GitHub
parent 8edaca9034
commit aedb2a5e9c
3 changed files with 506 additions and 0 deletions

View File

@@ -2644,6 +2644,100 @@ static void test_template_output_peg_parsers(bool detailed_debug) {
.run();
}
{
// Cohere2 MoE (North Code) - dedicated parser.
// Marker-wrapped format: <|START_THINKING|>...<|END_THINKING|> then either
// <|START_TEXT|>...<|END_TEXT|> (content) or <|START_ACTION|>[json]<|END_ACTION|> (tools).
// The generation prompt forces a leading <|START_THINKING|>, so model output begins inside
// the thinking block: test inputs start with the reasoning body, not the <|START_THINKING|> tag.
auto tst = peg_tester("models/templates/Cohere2MoE.jinja", detailed_debug);
// Content with reasoning, extracted.
tst.test("I'm\nthinking<|END_THINKING|><|START_TEXT|>Hello, world!\nWhat's up?<|END_TEXT|>")
.reasoning_format(COMMON_REASONING_FORMAT_DEEPSEEK)
.expect(message_assist_thoughts)
.run();
// Content with reasoning, reasoning_format=NONE -> thinking kept inline in content (markers preserved).
tst.test("I'm\nthinking<|END_THINKING|><|START_TEXT|>Hello, world!\nWhat's up?<|END_TEXT|>")
.expect(message_assist_thoughts_unparsed_r7b)
.run();
// Content with empty thinking block.
tst.test("<|END_THINKING|><|START_TEXT|>Hello, world!\nWhat's up?<|END_TEXT|>")
.reasoning_format(COMMON_REASONING_FORMAT_DEEPSEEK)
.expect(message_assist)
.run();
// Single tool call with reasoning.
tst.test(
"I'm\nthinking<|END_THINKING|>"
"<|START_ACTION|>[\n"
" {\"tool_call_id\": \"0\", \"tool_name\": \"special_function\", \"parameters\": {\"arg1\": 1}}\n"
"]<|END_ACTION|>")
.reasoning_format(COMMON_REASONING_FORMAT_DEEPSEEK)
.tools({ special_function_tool })
.expect(message_assist_thoughts_call_idx)
.run();
// Single tool call, empty thinking block (no reasoning content).
tst.test(
"<|END_THINKING|>"
"<|START_ACTION|>[\n"
" {\"tool_call_id\": \"0\", \"tool_name\": \"special_function\", \"parameters\": {\"arg1\": 1}}\n"
"]<|END_ACTION|>")
.reasoning_format(COMMON_REASONING_FORMAT_DEEPSEEK)
.tools({ special_function_tool })
.expect(message_assist_call_idx)
.run();
// Tool call with an array argument (todo_list).
tst.test(
"<|END_THINKING|>"
"<|START_ACTION|>[\n"
" {\"tool_call_id\": \"0\", \"tool_name\": \"todo_list\", \"parameters\": {\"todos\": [\"buy milk\", \"walk dog\"]}}\n"
"]<|END_ACTION|>")
.reasoning_format(COMMON_REASONING_FORMAT_DEEPSEEK)
.tools({ todo_list })
.expect(simple_assist_msg("", "", "todo_list", "{\"todos\": [\"buy milk\", \"walk dog\"]}", "0"))
.run();
// Parallel tool calls with reasoning.
tst.test(
"I'm\nthinking<|END_THINKING|>"
"<|START_ACTION|>[\n"
" {\"tool_call_id\": \"0\", \"tool_name\": \"special_function\", \"parameters\": {\"arg1\": 1}},\n"
" {\"tool_call_id\": \"1\", \"tool_name\": \"python\", \"parameters\": {\"code\": \"print('hey')\"}}\n"
"]<|END_ACTION|>")
.reasoning_format(COMMON_REASONING_FORMAT_DEEPSEEK)
.parallel_tool_calls(true)
.tools({ special_function_tool, python_tool })
.expect_reasoning("I'm\nthinking")
.expect_tool_calls({
{ "special_function", R"({"arg1": 1})", "0" },
{ "python", "{\"code\": \"print('hey')\"}", "1" },
})
.run();
// Tools available but the model answers with content instead of calling a tool.
tst.test("I'm\nthinking<|END_THINKING|><|START_TEXT|>Hello, world!\nWhat's up?<|END_TEXT|>")
.reasoning_format(COMMON_REASONING_FORMAT_DEEPSEEK)
.tools({ special_function_tool })
.expect(message_assist_thoughts)
.run();
// Partial tool call (streaming): name/id resolved before arguments arrive.
tst.test(
"I'm\nthinking<|END_THINKING|>"
"<|START_ACTION|>[\n"
" {\"tool_call_id\": \"0\", \"tool_name\": \"special_function\", ")
.reasoning_format(COMMON_REASONING_FORMAT_DEEPSEEK)
.tools({ special_function_tool })
.is_partial(true)
.expect(message_assist_thoughts_partial_call)
.run();
}
{
// Google Gemma 2 2B - does not support tool calling
auto tst = peg_tester("models/templates/google-gemma-2-2b-it.jinja");