@@ -1449,6 +1449,7 @@ static common_chat_params common_chat_params_init_hermes_2_pro(const common_chat
14491449 data.grammar = build_grammar ([&](const common_grammar_builder & builder) {
14501450 std::vector<std::string> tool_rules;
14511451 std::vector<std::string> tool_call_alts;
1452+ std::vector<std::string> escaped_names;
14521453 foreach_function (inputs.tools , [&](const json & tool) {
14531454 const auto & function = tool.at (" function" );
14541455 std::string name = function.at (" name" );
@@ -1477,6 +1478,7 @@ static common_chat_params common_chat_params_init_hermes_2_pro(const common_chat
14771478 COMMON_GRAMMAR_TRIGGER_TYPE_PATTERN,
14781479 " <function\\ s+name\\ s*=\\ s*\" " + escaped_name + " \" " ,
14791480 });
1481+ escaped_names.push_back (escaped_name);
14801482 });
14811483 auto any_tool_call = builder.add_rule (" any_tool_call" , " ( " + string_join (tool_rules, " | " ) + " ) space" );
14821484 std::vector<std::string> alt_tags {
@@ -1504,9 +1506,12 @@ static common_chat_params common_chat_params_init_hermes_2_pro(const common_chat
15041506 // If thinking_forced_open, then we capture the </think> tag in the grammar,
15051507 // (important for required tool choice) and in the trigger's first capture (decides what is sent to the grammar)
15061508 std::string (data.thinking_forced_open ? " [\\ s\\ S]*?(</think>\\ s*)" : " (?:<think>[\\ s\\ S]*?</think>\\ s*)?" ) + (
1507- " (<tool_call>"
1509+ " (\\ s*"
1510+ " (?:<tool_call>"
15081511 " |<function"
1509- " |(?:```(?:json|xml)?\n\\ s*)?(?:<function_call>|<tools>|<xml><json>|<response>)?\\ s*\\ {\\ s*\" "
1512+ " |(?:```(?:json|xml)?\n\\ s*)?(?:<function_call>|<tools>|<xml><json>|<response>)?"
1513+ " \\ s*\\ {\\ s*\" name\"\\ s*:\\ s*\" (?:" + string_join (escaped_names, " |" ) + " )\" "
1514+ " )"
15101515 " )[\\ s\\ S]*"
15111516 ),
15121517 });
@@ -1550,20 +1555,13 @@ static void common_chat_parse_hermes_2_pro(common_chat_msg_parser & builder) {
15501555 " |<xml>"
15511556 " |<JSON>"
15521557 " )?"
1553- " (\\ s*\\ {\\ s*\" name\"\\ s*: )" // match 3 (named tool call)
1558+ " (\\ s*\\ {\\ s*\" name\" )" // match 3 (named tool call)
15541559 " )"
15551560 " |<function=([^>]+)>" // match 4 (function name)
15561561 " |<function name=\" ([^\" ]+)\" >" // match 5 (function name again)
15571562 );
15581563
1559- auto start = builder.pos ();
15601564 if (auto res = builder.try_find_regex (open_regex)) {
1561- if (res->groups [0 ].begin != start && builder.str (res->groups [2 ]) != " <tool_call>" && res->groups [4 ].empty () && res->groups [5 ].empty ()) {
1562- // The only syntaxes we allow after the very start are <tool_call>, <function=...> or <function name=...>
1563- builder.move_to (start);
1564- builder.add_content (builder.consume_rest ());
1565- return ;
1566- }
15671565 builder.add_content (res->prelude );
15681566
15691567 const auto & block_start = res->groups [1 ];
0 commit comments