Skip to content

Commit 7db87d5

Browse files
author
firecoperana
committed
Add support for MiroThinker with new jinja template
1 parent a8320d2 commit 7db87d5

File tree

3 files changed

+120
-1
lines changed

3 files changed

+120
-1
lines changed

common/chat.cpp

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,6 +1287,116 @@ static common_chat_params common_chat_params_init_kimi_k2(const common_chat_temp
12871287
return data;
12881288
}
12891289

1290+
// MiroThinker - uses MCP style toolcalling
1291+
static common_chat_params common_chat_params_init_mirothinker(const common_chat_template & tmpl,
1292+
const autoparser::templates_params & inputs) {
1293+
common_chat_params data;
1294+
1295+
data.prompt = common_chat_template_direct_apply(tmpl, inputs);
1296+
data.format = COMMON_CHAT_FORMAT_PEG_NATIVE;
1297+
data.supports_thinking = true;
1298+
data.thinking_start_tag = "<think>";
1299+
data.thinking_end_tag = "</think>";
1300+
data.preserved_tokens = {
1301+
"<think>",
1302+
"</think>",
1303+
};
1304+
1305+
auto has_tools = inputs.tools.is_array() && !inputs.tools.empty();
1306+
auto extract_reasoning = inputs.reasoning_format != COMMON_REASONING_FORMAT_NONE;
1307+
auto include_grammar = has_tools && inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_NONE;
1308+
1309+
auto parser = build_chat_peg_parser([&](common_chat_peg_builder & p) {
1310+
// MiroThinker Thinking format:
1311+
// - Reasoning: <think>{reasoning}</think>
1312+
// - Content: text after reasoning
1313+
// - Tool calls section:
1314+
// <use_mcp_tool>
1315+
// <server_name>{server_name}</server_name>
1316+
// <tool_name>{tool_name}</tool_name>
1317+
// <arguments>
1318+
// {json_args}
1319+
// </arguments>
1320+
// ...
1321+
// </use_mcp_tool>
1322+
1323+
auto reasoning = extract_reasoning ? p.optional("<think>" + p.reasoning(p.until("</think>")) + "</think>") : p.eps();
1324+
1325+
// Tool call markers
1326+
const std::string SECTION_BEGIN = "<use_mcp_tool>";
1327+
const std::string SECTION_END = "</use_mcp_tool>";
1328+
const std::string CALL_BEGIN = "<server_name>";
1329+
const std::string ARGS_BEGIN = "<arguments>";
1330+
const std::string CALL_END = "</arguments>";
1331+
1332+
auto end = p.end();
1333+
1334+
// Content only parser (no tools)
1335+
if (!has_tools || inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_NONE) {
1336+
return reasoning + p.content(p.rest()) + end;
1337+
}
1338+
1339+
// Build tool call parsers for each available function
1340+
// Function name format is: <tool_name>{tool_name}</tool_name>
1341+
// We need to match: {what_ever}</server_name>{spaces}<tool_name>{tool_name}</tool_name>
1342+
auto tool_choice = p.choice();
1343+
foreach_function(inputs.tools, [&](const json & tool) {
1344+
const auto & function = tool.at("function");
1345+
std::string name = function.at("name");
1346+
const auto & schema = function.at("parameters");
1347+
1348+
// Match: {what_ever}</server_name>{spaces}<tool_name>{tool_name}</tool_name>
1349+
auto tool_parser = p.tool(
1350+
p.tool_open(
1351+
p.until("</server_name>") +
1352+
p.literal("</server_name>") +
1353+
p.space() +
1354+
p.literal("<tool_name>") +
1355+
p.tool_name(p.literal(name)) +
1356+
p.literal(ARGS_BEGIN)
1357+
) + p.space() +
1358+
p.tool_args(p.schema(p.json(), "tool-" + name + "-schema", schema)) +
1359+
p.space() + p.tool_close(p.literal(CALL_END))
1360+
);
1361+
1362+
tool_choice |= p.rule("tool-" + name, tool_parser);
1363+
});
1364+
1365+
// Tool calls section: <use_mcp_tool> tool_calls </use_mcp_tool>
1366+
auto min_calls = inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_REQUIRED ? 1 : 0;
1367+
auto max_calls = inputs.parallel_tool_calls ? -1 : 1;
1368+
auto tool_calls = p.trigger_rule("tool-calls",
1369+
p.literal(SECTION_BEGIN) + p.space() +
1370+
p.rule("tool-call", p.repeat(CALL_BEGIN + tool_choice, min_calls, max_calls) +
1371+
p.space() + p.literal(SECTION_END))
1372+
);
1373+
1374+
auto content_before_tools = p.content(p.until(SECTION_BEGIN));
1375+
1376+
return reasoning + content_before_tools + tool_calls + end;
1377+
});
1378+
1379+
data.parser = parser.save();
1380+
1381+
if (include_grammar) {
1382+
data.grammar_lazy = inputs.tool_choice == COMMON_CHAT_TOOL_CHOICE_AUTO;
1383+
data.grammar = build_grammar([&](const common_grammar_builder & builder) {
1384+
foreach_function(inputs.tools, [&](const json & tool) {
1385+
const auto & function = tool.at("function");
1386+
auto schema = function.at("parameters");
1387+
builder.resolve_refs(schema);
1388+
});
1389+
parser.build_grammar(builder, data.grammar_lazy);
1390+
});
1391+
1392+
data.grammar_triggers = {
1393+
{ COMMON_GRAMMAR_TRIGGER_TYPE_WORD, "<use_mcp_tool>" }
1394+
};
1395+
}
1396+
1397+
return data;
1398+
}
1399+
12901400
// LFM2 format:
12911401
// - Reasoning: <think>{reasoning}</think> (optional, only if enable_thinking is true)
12921402
// - Content: text after reasoning (optional)
@@ -1526,6 +1636,14 @@ static common_chat_params common_chat_templates_apply_jinja(const struct common_
15261636
return common_chat_params_init_kimi_k2(tmpl, params);
15271637
}
15281638

1639+
// MiroThinker - uses MCP style toolcalling <use_mcp_tool> ... </use_mcp_tool>
1640+
// Detection: template has "</use_mcp_tool>" and "</server_name>"
1641+
if (src.find("</use_mcp_tool>") != std::string::npos &&
1642+
src.find("</server_name>") != std::string::npos) {
1643+
LOG_DBG("Using specialized template: MiroThinker\n");
1644+
return common_chat_params_init_mirothinker(tmpl, params);
1645+
}
1646+
15291647
// LFM2 - uses <|tool_list_start|>/<|tool_list_end|> markers and <|tool_call_start|>[name(args)]<|tool_call_end|> format
15301648
// Detection: template has "<|tool_list_start|>" and "<|tool_list_end|>" markers
15311649
if (src.find("<|tool_list_start|>") != std::string::npos &&

common/chat.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ struct common_chat_params {
218218
std::vector<std::string> preserved_tokens;
219219
std::vector<std::string> additional_stops;
220220
std::string parser;
221+
std::string thinking_start_tag;
222+
std::string thinking_end_tag;
221223
};
222224

223225
struct common_chat_parser_params {

common/common.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,6 @@ struct gpt_params {
392392

393393
std::string hostname = "127.0.0.1";
394394
std::string public_path = "";
395-
std::string system_prompt = "";
396395

397396
// tool call and template
398397
std::string chat_template = "";

0 commit comments

Comments
 (0)