@@ -1586,8 +1586,9 @@ static common_chat_params common_chat_params_init_hermes_2_pro(const common_chat
15861586 }
15871587
15881588 if (!inputs.tools .is_null ()) {
1589+ auto supports_thinking = tmpl.source ().find (" <think>" ) != std::string::npos && data.thinking_forced_open == false ;
15891590 // (content)?(<tool_call>{"name": "foo", "arguments": {"a": 1}}</tool_call>)*
1590- data.grammar_lazy = inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_REQUIRED;
1591+ data.grammar_lazy = inputs.tool_choice != COMMON_CHAT_TOOL_CHOICE_REQUIRED || supports_thinking ;
15911592 data.grammar = build_grammar ([&](const common_grammar_builder & builder) {
15921593 std::vector<std::string> tool_rules;
15931594 std::vector<std::string> tool_call_alts;
@@ -1639,9 +1640,19 @@ static common_chat_params common_chat_params_init_hermes_2_pro(const common_chat
16391640 tool_call_alts.push_back (
16401641 " ( \" ```\\ n\" | \" ```json\\ n\" | \" ```xml\\ n\" ) space " + wrappable_tool_call + " space \" ```\" space " );
16411642 auto tool_call = builder.add_rule (" tool_call" , string_join (tool_call_alts, " | " ));
1642- builder.add_rule (" root" ,
1643+ if (supports_thinking)
1644+ {
1645+ builder.add_rule (" thinking" , " \" <think>\" [^\\ x00]* \" </think>\" space" );
1646+ builder.add_rule (" root" ,
1647+ " (thinking)? space " +
1648+ (inputs.parallel_tool_calls ? " (" + tool_call + " )+" : tool_call));
1649+ }
1650+ else
1651+ {
1652+ builder.add_rule (" root" ,
16431653 std::string (data.thinking_forced_open ? " ( \" </think>\" space )? " : " " ) +
16441654 (inputs.parallel_tool_calls ? " (" + tool_call + " )+" : tool_call));
1655+ }
16451656 // Trigger on some common known "good bad" outputs (only from the start and with a json that's about a specific argument name to avoid false positives)
16461657 data.grammar_triggers .push_back ({
16471658 COMMON_GRAMMAR_TRIGGER_TYPE_PATTERN_FULL,
0 commit comments