diff --git a/common/chat.cpp b/common/chat.cpp index 1236e766921d2..1fc43c42a873c 100644 --- a/common/chat.cpp +++ b/common/chat.cpp @@ -1366,9 +1366,9 @@ static common_chat_params common_chat_params_init_deepseek_v3_1(const common_cha auto parameters = function.at("parameters"); builder.resolve_refs(parameters); tool_rules.push_back(builder.add_rule(name + "-call", - "( \"<|tool▁call▁begin|>\" )? \"function<|tool▁sep|>" + name + "\\n" - "```json\\n\" " + builder.add_schema(name + "-args", parameters) + " " - "\"```<|tool▁call▁end|>\"")); + "( \"<|tool▁call▁begin|>\" )? \"" + name + "<|tool▁sep|>" + "\" " + builder.add_schema(name + "-args", parameters) + " " + "\"<|tool▁call▁end|>\"")); }); // Distill Qwen 7B & 32B models seem confused re/ syntax of their tool call opening tag, // so we accept common variants (then it's all constrained) @@ -1421,9 +1421,9 @@ static void common_chat_parse_deepseek_r1(common_chat_msg_parser & builder) { } static void common_chat_parse_deepseek_v3_1_content(common_chat_msg_parser & builder) { - static const common_regex function_regex("(?:<|tool▁call▁begin|>)?(?:function<|tool▁sep|>)?([^\\n<]+)(?:\\n```json\\n|<|tool▁sep|>)"); + static const common_regex function_regex("(?:<|tool▁call▁begin|>)?([^\\n<]+)(?:<|tool▁sep|>)"); - static const common_regex close_regex("(?:[\\n]*```[\\s\\r\\n]*)?<|tool▁call▁end|>"); + static const common_regex close_regex("(?:[\\s]*)?<|tool▁call▁end|>"); static const common_regex tool_calls_begin("(?:<|tool▁calls▁begin|>|<|tool_calls_begin|>|<|tool calls begin|>|<|tool\\\\_calls\\\\_begin|>|<|tool▁calls|>)"); static const common_regex tool_calls_end("<|tool▁calls▁end|>"); diff --git a/tests/test-chat-parser.cpp b/tests/test-chat-parser.cpp index 7ddd5babc706f..caa9be8ec1f9c 100644 --- a/tests/test-chat-parser.cpp +++ b/tests/test-chat-parser.cpp @@ -243,19 +243,7 @@ static void test_deepseek_v3_1_tool_calls() { assert_equals(variant, std::string(""), msg.content); assert_equals(variant, std::string(""), msg.reasoning_content); - // variant: function + fenced JSON - { - const std::string variant("fenced"); - const std::string in = "<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_time\n```json\n{\"city\": \"Tokyo\"}\n```<|tool▁call▁end|><|tool▁calls▁end|>"; - auto m = common_chat_parse(in, false, syntax); - assert_equals(variant, 1, m.tool_calls.size()); - assert_equals(variant, std::string("get_time"), m.tool_calls[0].name); - assert_equals(variant, std::string("{\"city\":\"Tokyo\"}"), m.tool_calls[0].arguments); - assert_equals(variant, std::string(""), m.content); - assert_equals(variant, std::string(""), m.reasoning_content); - } - - // variant: function + fenced JSON + thinking open + // variant: simple + thinking open { common_chat_syntax syntax = { /* .format = */ COMMON_CHAT_FORMAT_DEEPSEEK_V3_1, @@ -264,8 +252,8 @@ static void test_deepseek_v3_1_tool_calls() { /* .thinking_forced_open = */ true, /* .parse_tool_calls = */ true, }; - const std::string variant("fenced_thinking"); - const std::string in = "REASONING<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_time\n```json\n{\"city\": \"Tokyo\"}\n```<|tool▁call▁end|><|tool▁calls▁end|>"; + const std::string variant("simple_thinking"); + const std::string in = "REASONING<|tool▁calls▁begin|><|tool▁call▁begin|>get_time<|tool▁sep|>{\"city\": \"Tokyo\"}<|tool▁call▁end|><|tool▁calls▁end|>"; auto m = common_chat_parse(in, false, syntax); assert_equals(variant, 1, m.tool_calls.size()); assert_equals(variant, std::string("get_time"), m.tool_calls[0].name); @@ -295,7 +283,7 @@ static void test_deepseek_v3_1_tool_calls() { } - // variant: thinking forced open + tool call in reasoning content + function + fenced JSON + // variant: thinking forced open + tool call in reasoning content { common_chat_syntax syntax = { /* .format = */ COMMON_CHAT_FORMAT_DEEPSEEK_V3_1, @@ -304,8 +292,8 @@ static void test_deepseek_v3_1_tool_calls() { /* .thinking_forced_open = */ true, /* .parse_tool_calls = */ true, }; - const std::string variant("thinking_forced_open_tool_call_in_reasoning_fenced_thinking"); - const std::string in = "REASONING<|tool▁calls▁begin|><|tool▁call▁begin|>get_time2<|tool▁sep|>{\"city\": \"Tokyo2\"}<|tool▁call▁end|><|tool▁calls▁end|>REASONING<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_time\n```json\n{\"city\": \"Tokyo\"}\n```<|tool▁call▁end|><|tool▁calls▁end|>"; + const std::string variant("thinking_forced_open_tool_call_in_reasoning"); + const std::string in = "REASONING<|tool▁calls▁begin|><|tool▁call▁begin|>get_time2<|tool▁sep|>{\"city\": \"Tokyo2\"}<|tool▁call▁end|><|tool▁calls▁end|>REASONING<|tool▁calls▁begin|><|tool▁call▁begin|>get_time<|tool▁sep|>{\"city\": \"Tokyo\"}<|tool▁call▁end|><|tool▁calls▁end|>"; auto m = common_chat_parse(in, false, syntax); assert_equals(variant, 1, m.tool_calls.size()); assert_equals(variant, std::string("get_time"), m.tool_calls[0].name); diff --git a/tests/test-chat.cpp b/tests/test-chat.cpp index 4bcbf97a0e212..d6a3383dda7b7 100644 --- a/tests/test-chat.cpp +++ b/tests/test-chat.cpp @@ -1804,24 +1804,11 @@ static void test_template_output_parsers() { /* .thinking_forced_open = */ false, /* .parse_tool_calls = */ true, })); - // variant: function + fenced JSON - assert_msg_equals( - simple_assist_msg("", "", "get_time", "{\"city\":\"Tokyo\"}"), - common_chat_parse( - "<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_time\n```json\n{\"city\": \"Tokyo\"}\n```<|tool▁call▁end|><|tool▁calls▁end|>", - /* is_partial= */ false, - { - COMMON_CHAT_FORMAT_DEEPSEEK_V3_1, - /* .reasoning_format = */ COMMON_REASONING_FORMAT_DEEPSEEK, - /* .reasoning_in_content = */ false, - /* .thinking_forced_open = */ false, - /* .parse_tool_calls = */ true, - })); - // variant: function + fenced JSON + thinking open + // variant: simple + thinking open assert_msg_equals( simple_assist_msg("", "REASONING", "get_time", "{\"city\":\"Tokyo\"}"), common_chat_parse( - "REASONING<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_time\n```json\n{\"city\": \"Tokyo\"}\n```<|tool▁call▁end|><|tool▁calls▁end|>", + "REASONING<|tool▁calls▁begin|><|tool▁call▁begin|>get_time<|tool▁sep|>{\"city\": \"Tokyo\"}<|tool▁call▁end|><|tool▁calls▁end|>", /* is_partial= */ false, { COMMON_CHAT_FORMAT_DEEPSEEK_V3_1, @@ -1848,11 +1835,11 @@ static void test_template_output_parsers() { /* .thinking_forced_open = */ false, /* .parse_tool_calls = */ true, })); - // variant: thinking forced open + tool call in reasoning content + function + fenced JSON + // variant: thinking forced open + tool call in reasoning content assert_msg_equals( simple_assist_msg("", "REASONING<|tool▁calls▁begin|><|tool▁call▁begin|>get_time2<|tool▁sep|>{\"city\": \"Tokyo2\"}<|tool▁call▁end|><|tool▁calls▁end|>REASONING", "get_time", "{\"city\":\"Tokyo\"}"), common_chat_parse( - "REASONING<|tool▁calls▁begin|><|tool▁call▁begin|>get_time2<|tool▁sep|>{\"city\": \"Tokyo2\"}<|tool▁call▁end|><|tool▁calls▁end|>REASONING<|tool▁calls▁begin|><|tool▁call▁begin|>function<|tool▁sep|>get_time\n```json\n{\"city\": \"Tokyo\"}\n```<|tool▁call▁end|><|tool▁calls▁end|>", + "REASONING<|tool▁calls▁begin|><|tool▁call▁begin|>get_time2<|tool▁sep|>{\"city\": \"Tokyo2\"}<|tool▁call▁end|><|tool▁calls▁end|>REASONING<|tool▁calls▁begin|><|tool▁call▁begin|>get_time<|tool▁sep|>{\"city\": \"Tokyo\"}<|tool▁call▁end|><|tool▁calls▁end|>", /* is_partial= */ false, { COMMON_CHAT_FORMAT_DEEPSEEK_V3_1,