Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 96 additions & 0 deletions common/chat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -649,6 +649,7 @@ const char * common_chat_format_name(common_chat_format format) {
case COMMON_CHAT_FORMAT_QWEN3_CODER_XML: return "Qwen3 Coder";
case COMMON_CHAT_FORMAT_APRIEL_1_5: return "Apriel 1.5";
case COMMON_CHAT_FORMAT_XIAOMI_MIMO: return "Xiaomi MiMo";
case COMMON_CHAT_FORMAT_GIGACHAT_V3: return "GigaChat V3";
default:
throw std::runtime_error("Unknown chat format");
}
Expand Down Expand Up @@ -1732,6 +1733,93 @@ static common_chat_params common_chat_params_init_deepseek_v3_1(const common_cha
return data;
}

static common_chat_params common_chat_params_init_gigachat_v3(
const common_chat_template & tmpl,
const struct templates_params & inputs) {

common_chat_params data;

auto prompt = apply(tmpl, inputs);
data.prompt = prompt;
data.format = COMMON_CHAT_FORMAT_GIGACHAT_V3;

data.preserved_tokens = {
"<|message_sep|>\n\n",
"<|role_sep|>\n",
};

if (inputs.tools.is_array() && !inputs.tools.empty()) {
data.grammar_lazy = inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_REQUIRED && inputs.json_schema.is_null();

data.grammar = build_grammar([&](const common_grammar_builder & builder) {
std::vector<std::string> rules;


foreach_function(inputs.tools, [&](const json & tool) {
const auto & function = tool.at("function");
std::string name = function.at("name");
auto parameters = function.at("parameters");
builder.resolve_refs(parameters);

// JSON schema for this tool
json schema = {
{"type", "object"},
{"properties", {
{"name", {{"type", "string"}, {"const", name}}},
{"arguments", parameters}
}},
{"required", json::array({"name", "arguments"})}
};

// Add a rule for this tool
rules.push_back(
R"("<|message_sep|>\n\nfunction call<|role_sep|>\n")" +
builder.add_schema(name + "-call", schema)
);
});

builder.add_rule("root",
"(" + string_join(rules, " | ") + ")" +
(inputs.parallel_tool_calls ? "*" : "")
);

data.grammar_triggers.push_back({
COMMON_GRAMMAR_TRIGGER_TYPE_WORD,
"<|message_sep|>\n\nfunction call<|role_sep|>\n"
});
});
}

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) {
Expand Down Expand Up @@ -3308,6 +3396,11 @@ static common_chat_params common_chat_templates_apply_jinja(
return common_chat_params_init_apriel_1_5(tmpl, params);
}

// GigaChatV3 format detection
if (src.find("<|role_sep|>") != std::string::npos && src.find("<|message_sep|>") != std::string::npos) {
return common_chat_params_init_gigachat_v3(tmpl, params);
}

// Use generic handler when mixing tools + JSON schema.
// TODO: support that mix in handlers below.
if ((params.tools.is_array() && params.json_schema.is_object())) {
Expand Down Expand Up @@ -3513,6 +3606,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));
}
Expand Down
1 change: 1 addition & 0 deletions common/chat.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ enum common_chat_format {
COMMON_CHAT_FORMAT_QWEN3_CODER_XML,
COMMON_CHAT_FORMAT_APRIEL_1_5,
COMMON_CHAT_FORMAT_XIAOMI_MIMO,
COMMON_CHAT_FORMAT_GIGACHAT_V3,

COMMON_CHAT_FORMAT_COUNT, // Not a format, just the # formats
};
Expand Down
Loading