solved merge conficts with master

This commit is contained in:
Mishusha 2025-12-11 01:45:20 +00:00
parent c76f04cf04
commit 3a451fc845
3 changed files with 97 additions and 180 deletions

View File

@ -879,6 +879,32 @@ static void common_chat_parse_deepseek_v3_1(common_chat_msg_parser & builder) {
}
}
static void common_chat_parse_gigachat_v3(common_chat_msg_parser & builder) {
if (!builder.syntax().parse_tool_calls) {
builder.add_content(builder.consume_rest());
return;
}
// Regex to capture function name from JSON after "function call<|role_sep|\n"
static const common_regex function_regex(
R"(<\|message_sep\|>\n\nfunction call<\|role_sep\|>\n\s*\{\s*\"name\"\s*:\s*\"([^\"]+)\"\s*,\s*\"arguments\"\s*:)"
);
// Closing token of a tool call
static const common_regex close_regex(
R"(\}\s*)"
);
parse_json_tool_calls(
builder,
/* block_open = */ std::nullopt,
/* function_regex_start_only = */ std::nullopt,
/* function_regex = */ function_regex,
close_regex,
/* block_close = */ std::nullopt
);
}
static void common_chat_parse_minimax_m2(common_chat_msg_parser & builder) {
static const xml_tool_call_format form {
/* form.scope_start = */ "<minimax:tool_call>",
@ -1479,6 +1505,9 @@ static void common_chat_parse(common_chat_msg_parser & builder) {
case COMMON_CHAT_FORMAT_XIAOMI_MIMO:
common_chat_parse_xiaomi_mimo(builder);
break;
case COMMON_CHAT_FORMAT_GIGACHAT_V3:
common_chat_parse_gigachat_v3(builder);
break;
default:
throw std::runtime_error(std::string("Unsupported format: ") + common_chat_format_name(builder.syntax().format));
}

View File

@ -1677,115 +1677,6 @@ static common_chat_params common_chat_params_init_gigachat_v3(
return data;
}
static void common_chat_parse_gigachat_v3(common_chat_msg_parser & builder) {
if (!builder.syntax().parse_tool_calls) {
builder.add_content(builder.consume_rest());
return;
}
// Regex to capture function name from JSON after "function call<|role_sep|\n"
static const common_regex function_regex(
R"(<\|message_sep\|>\n\nfunction call<\|role_sep\|>\n\s*\{\s*\"name\"\s*:\s*\"([^\"]+)\"\s*,\s*\"arguments\"\s*:)"
);
// Closing token of a tool call
static const common_regex close_regex(
R"(\}\s*)"
);
parse_json_tool_calls(
builder,
/* block_open = */ std::nullopt,
/* function_regex_start_only = */ std::nullopt,
/* function_regex = */ function_regex,
close_regex,
/* block_close = */ std::nullopt
);
}
static void common_chat_parse_deepseek_r1(common_chat_msg_parser & builder) {
builder.try_parse_reasoning("<think>", "</think>");
if (!builder.syntax().parse_tool_calls) {
builder.add_content(builder.consume_rest());
return;
}
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>");
static const common_regex function_regex("(?:<tool▁call▁begin>)?function<toolsep>([^\n]+)\n```json\n");
static const common_regex close_regex("```[\\s\\r\\n]*<tool▁call▁end>");
parse_json_tool_calls(
builder,
/* block_open= */ tool_calls_begin,
/* function_regex_start_only= */ std::nullopt,
function_regex,
close_regex,
tool_calls_end);
}
static void common_chat_parse_deepseek_v3_1_content(common_chat_msg_parser & builder) {
static const common_regex function_regex("(?:<tool▁call▁begin>)?([^\\n<]+)(?:<toolsep>)");
static const common_regex close_regex("(?:[\\s]*)?<toolcallend>");
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>");
if (!builder.syntax().parse_tool_calls) {
LOG_DBG("%s: not parse_tool_calls\n", __func__);
builder.add_content(builder.consume_rest());
return;
}
LOG_DBG("%s: parse_tool_calls\n", __func__);
parse_json_tool_calls(
builder,
/* block_open= */ tool_calls_begin,
/* function_regex_start_only= */ std::nullopt,
function_regex,
close_regex,
tool_calls_end);
}
static void common_chat_parse_deepseek_v3_1(common_chat_msg_parser & builder) {
// DeepSeek V3.1 outputs reasoning content between "<think>" and "</think>" tags, followed by regular content
// First try to parse using the standard reasoning parsing method
LOG_DBG("%s: thinking_forced_open: %s\n", __func__, std::to_string(builder.syntax().thinking_forced_open).c_str());
auto start_pos = builder.pos();
auto found_end_think = builder.try_find_literal("</think>");
builder.move_to(start_pos);
if (builder.syntax().thinking_forced_open && !builder.is_partial() && !found_end_think) {
LOG_DBG("%s: no end_think, not partial, adding content\n", __func__);
common_chat_parse_deepseek_v3_1_content(builder);
} else if (builder.try_parse_reasoning("<think>", "</think>")) {
// If reasoning was parsed successfully, the remaining content is regular content
LOG_DBG("%s: parsed reasoning, adding content\n", __func__);
// </think><tool▁calls▁begin><tool▁call▁begin>function<tool▁sep>NAME\n```json\nJSON\n```<tool▁call▁end><tool▁calls▁end>
common_chat_parse_deepseek_v3_1_content(builder);
} else {
if (builder.syntax().reasoning_format == COMMON_REASONING_FORMAT_NONE) {
LOG_DBG("%s: reasoning_format none, adding content\n", __func__);
common_chat_parse_deepseek_v3_1_content(builder);
return;
}
// If no reasoning tags found, check if we should treat everything as reasoning
if (builder.syntax().thinking_forced_open) {
// If thinking is forced open but no tags found, treat everything as reasoning
LOG_DBG("%s: thinking_forced_open, adding reasoning content\n", __func__);
builder.add_reasoning_content(builder.consume_rest());
} else {
LOG_DBG("%s: no thinking_forced_open, adding content\n", __func__);
// <tool▁call▁begin>NAME<tool▁sep>JSON<tool▁call▁end>
common_chat_parse_deepseek_v3_1_content(builder);
}
}
}
static common_chat_params common_chat_params_init_minimax_m2(const common_chat_template & tmpl, const struct templates_params & params) {
common_chat_params data;
data.grammar_lazy = params.tools.is_array() && !params.tools.empty() && params.tool_choice != COMMON_CHAT_TOOL_CHOICE_REQUIRED;

View File

@ -3499,9 +3499,76 @@ Hey there!<|im_end|>
auto grammar = build_grammar(params.grammar);
GGML_ASSERT(grammar && "Failed to build Qwen3-Coder grammar with union types");
}
{
auto tmpls = read_templates("models/templates/GigaChat3-10B-A1.8B.jinja");
std::vector<std::string> end_tokens{ "</s>", "<|message_sep|>\n\n" };
assert_equals(COMMON_CHAT_FORMAT_GIGACHAT_V3, common_chat_templates_apply(tmpls.get(), inputs_no_tools).format);
assert_equals(COMMON_CHAT_FORMAT_GIGACHAT_V3, common_chat_templates_apply(tmpls.get(), inputs_tools).format);
// Test parsing regular content
assert_msg_equals(message_assist,
common_chat_parse(
"Hello, world!\nWhat's up?",
/* is_partial= */ false,
{COMMON_CHAT_FORMAT_GIGACHAT_V3}));
// Test parsing tool calls
assert_msg_equals(message_assist_call,
common_chat_parse(
"<|message_sep|>\n\nfunction call<|role_sep|>\n{\"name\": \"special_function\", \"arguments\": {\"arg1\": 1}}",
/* is_partial= */ false,
{COMMON_CHAT_FORMAT_GIGACHAT_V3}));
// Test tool calls with extra content
assert_msg_equals(message_assist_call_content,
common_chat_parse(
"Hello, world!\nWhat's up?<|message_sep|>\n\nfunction call<|role_sep|>\n{\"name\": \"special_function\", \"arguments\": {\"arg1\": 1}}",
/* is_partial= */ false,
{COMMON_CHAT_FORMAT_GIGACHAT_V3}
));
// Test streaming
test_parser_with_streaming(message_assist_call_withopt,
"<|message_sep|>\n\nfunction call<|role_sep|>\n{\"name\": \"special_function_with_opt\", \"arguments\": {\"arg1\": 1, \"arg2\": 2}}",
[&](const std::string &msg) { return common_chat_parse(msg, /* is_partial= */ true, {
/* .format = */ COMMON_CHAT_FORMAT_GIGACHAT_V3,
/* .reasoning_format = */ COMMON_REASONING_FORMAT_NONE
}); });
// Test template generation for regular content
test_templates(tmpls.get(), end_tokens, message_assist, tools,
"Hello, world!\nWhat's up?",
/* expect_grammar_triggered= */ false);
// Test template generation for tool calls
test_templates(tmpls.get(), end_tokens, message_assist_call, tools,
"<|message_sep|>\n\nfunction call<|role_sep|>\n{\"name\": \"special_function\", \"arguments\": {\"arg1\": 1}}",
/* expect_grammar_triggered= */ true,
/* test_grammar_if_triggered= */ true,
/* common_reasoning_format= */ COMMON_REASONING_FORMAT_NONE,
/* ignore_whitespace_differences= */ true
);
// Test template generation for tools with optional parameters
test_templates(tmpls.get(), end_tokens, message_assist_call_noopt, tools,
"<|message_sep|>\n\nfunction call<|role_sep|>\n{\"name\": \"special_function_with_opt\", \"arguments\": {\"arg1\": 1}}",
/* expect_grammar_triggered= */ true,
/* test_grammar_if_triggered= */ true,
/* common_reasoning_format= */ COMMON_REASONING_FORMAT_NONE,
/* ignore_whitespace_differences= */ true
);
test_templates(tmpls.get(), end_tokens, message_assist_call_withopt, tools,
"<|message_sep|>\n\nfunction call<|role_sep|>\n{\"name\": \"special_function_with_opt\", \"arguments\": {\"arg1\": 1, \"arg2\": 2}}",
/* expect_grammar_triggered= */ true,
/* test_grammar_if_triggered= */ true,
/* common_reasoning_format= */ COMMON_REASONING_FORMAT_NONE,
/* ignore_whitespace_differences= */ true
);
}
}
<<<<<<< HEAD
static void test_template_output_peg_parsers() {
printf("[%s]\n", __func__);
@ -3589,76 +3656,6 @@ static void test_template_output_peg_parsers() {
t.expect.content =R"({"amount": 123.45, "date": "2025-12-03"})";
});
}
=======
{
auto tmpls = read_templates("models/templates/GigaChat3-10B-A1.8B.jinja");
std::vector<std::string> end_tokens{ "</s>", "<|message_sep|>\n\n" };
assert_equals(COMMON_CHAT_FORMAT_GIGACHAT_V3, common_chat_templates_apply(tmpls.get(), inputs_no_tools).format);
assert_equals(COMMON_CHAT_FORMAT_GIGACHAT_V3, common_chat_templates_apply(tmpls.get(), inputs_tools).format);
// Test parsing regular content
assert_msg_equals(message_assist,
common_chat_parse(
"Hello, world!\nWhat's up?",
/* is_partial= */ false,
{COMMON_CHAT_FORMAT_GIGACHAT_V3}));
// Test parsing tool calls
assert_msg_equals(message_assist_call,
common_chat_parse(
"<|message_sep|>\n\nfunction call<|role_sep|>\n{\"name\": \"special_function\", \"arguments\": {\"arg1\": 1}}",
/* is_partial= */ false,
{COMMON_CHAT_FORMAT_GIGACHAT_V3}));
// Test tool calls with extra content
assert_msg_equals(message_assist_call_content,
common_chat_parse(
"Hello, world!\nWhat's up?<|message_sep|>\n\nfunction call<|role_sep|>\n{\"name\": \"special_function\", \"arguments\": {\"arg1\": 1}}",
/* is_partial= */ false,
{COMMON_CHAT_FORMAT_GIGACHAT_V3}
));
// Test streaming
test_parser_with_streaming(message_assist_call_withopt,
"<|message_sep|>\n\nfunction call<|role_sep|>\n{\"name\": \"special_function_with_opt\", \"arguments\": {\"arg1\": 1, \"arg2\": 2}}",
[&](const std::string &msg) { return common_chat_parse(msg, /* is_partial= */ true, {
/* .format = */ COMMON_CHAT_FORMAT_GIGACHAT_V3,
/* .reasoning_format = */ COMMON_REASONING_FORMAT_NONE
}); });
// Test template generation for regular content
test_templates(tmpls.get(), end_tokens, message_assist, tools,
"Hello, world!\nWhat's up?",
/* expect_grammar_triggered= */ false);
// Test template generation for tool calls
test_templates(tmpls.get(), end_tokens, message_assist_call, tools,
"<|message_sep|>\n\nfunction call<|role_sep|>\n{\"name\": \"special_function\", \"arguments\": {\"arg1\": 1}}",
/* expect_grammar_triggered= */ true,
/* test_grammar_if_triggered= */ true,
/* common_reasoning_format= */ COMMON_REASONING_FORMAT_NONE,
/* ignore_whitespace_differences= */ true
);
// Test template generation for tools with optional parameters
test_templates(tmpls.get(), end_tokens, message_assist_call_noopt, tools,
"<|message_sep|>\n\nfunction call<|role_sep|>\n{\"name\": \"special_function_with_opt\", \"arguments\": {\"arg1\": 1}}",
/* expect_grammar_triggered= */ true,
/* test_grammar_if_triggered= */ true,
/* common_reasoning_format= */ COMMON_REASONING_FORMAT_NONE,
/* ignore_whitespace_differences= */ true
);
test_templates(tmpls.get(), end_tokens, message_assist_call_withopt, tools,
"<|message_sep|>\n\nfunction call<|role_sep|>\n{\"name\": \"special_function_with_opt\", \"arguments\": {\"arg1\": 1, \"arg2\": 2}}",
/* expect_grammar_triggered= */ true,
/* test_grammar_if_triggered= */ true,
/* common_reasoning_format= */ COMMON_REASONING_FORMAT_NONE,
/* ignore_whitespace_differences= */ true
);
}
>>>>>>> 6f9ffbd9d (implement gigachat v3 toolcall parser)
}
static void test_msg_diffs_compute() {