@@ -580,10 +580,7 @@ static common_chat_msg parse_json_tool_calls(
580580    }
581581
582582    if  (!result.tool_calls .empty ()) {
583-         if  (!string_strip (result.content ).empty ()) {
584-             LOG_WRN (" Content found with tool calls: %s\n " content .c_str ());
585-         }
586-         result.content  = " " 
583+         result.content  = string_strip (result.content );
587584    }
588585    return  result;
589586}
@@ -1359,14 +1356,15 @@ static common_chat_params common_chat_params_init_phi_4(const common_chat_templa
13591356            std::string name = function.at (" name" 
13601357            auto  parameters = function.at (" parameters" 
13611358            builder.resolve_refs (parameters);
1362-             tool_rules. push_back ( builder.add_schema (name + " -call" 
1359+             auto  call_rule =  builder.add_schema (name + " -call" 
13631360                {" type" " object" 
13641361                {" properties" 
13651362                    {" name" " const" 
13661363                    {" arguments" 
13671364                }},
13681365                {" required" json::array ({" name" " arguments" 
1369-             }));
1366+             });
1367+             tool_rules.push_back (builder.add_rule (name + " -call" " \" <|tool_call|>\"  " "  \" <|/tool_call|>\" " 
13701368        });
13711369        auto  any_tool_call = builder.add_rule (" any_tool_call" " ( " string_join (tool_rules, "  | " "  ) space" 
13721370        std::vector<std::string> alt_tags {
@@ -1379,6 +1377,9 @@ static common_chat_params common_chat_params_init_phi_4(const common_chat_templa
13791377        data.preserved_tokens  = {
13801378            " <|tool_call|>" 
13811379            " </|tool_call|>" 
1380+             " <|tool_response|>" 
1381+             " <|tool|>" 
1382+             " </|tool|>" 
13821383        };
13831384    });
13841385
@@ -1437,89 +1438,9 @@ static common_chat_params common_chat_params_init_phi_4(const common_chat_templa
14371438}
14381439
14391440static  common_chat_msg common_chat_parse_phi_4 (const  std::string & input) {
1440-     common_chat_msg result;
1441-     result.role  = " assistant" 
1442-     
1443-     std::string final_content = " " 
1444-     
1445-     const  std::string opening_tag = " <|tool_call|>" 
1446-     const  std::string closing_tag = " </|tool_call|>" 
1447-     
1448-     size_t  start_pos = 0 ;
1449-     while  (true ) {
1450-         //  Find next tool call
1451-         size_t  tool_start = input.find (opening_tag, start_pos);
1452-         if  (tool_start == std::string::npos) {
1453-             //  No more tool calls.
1454- 
1455-             //  Is start_pos within string bounds?
1456-             if  (start_pos < input.length ()) {
1457-                 //  Add the rest of the string to final_content
1458-                 final_content += input.substr (start_pos);
1459-             }
1460-             break ;
1461-         }
1462-         
1463-         //  Add content before the tool call to final_content
1464-         final_content += input.substr (start_pos, tool_start - start_pos);
1465- 
1466-         //  Find closing tag
1467-         size_t  content_start = tool_start + opening_tag.length ();
1468-         size_t  tool_end = input.find (closing_tag, content_start);
1469-         
1470-         if  (tool_end == std::string::npos) {
1471-             //  No closing tag found, so just include the rest of the string as tool.
1472-             tool_end = input.length ();
1473-         }
1474-         
1475-         //  Extract tool call content
1476-         std::string tool_content = input.substr (
1477-             content_start,
1478-             tool_end - content_start
1479-         );
1480-         
1481-         //  Try to parse the tool call
1482-         try  {
1483-             auto  tool_call = json::parse (tool_content);
1484-             
1485-             //  Verify the required fields exist
1486-             if  (!tool_call.contains (" name" 
1487-                 throw  std::runtime_error (" Missing 'name' field in tool call" 
1488-             }
1489-             
1490-             if  (!tool_call.contains (" arguments" 
1491-                 throw  std::runtime_error (" Missing 'arguments' field in tool call" 
1492-             }
1493-             
1494-             std::string name = tool_call[" name" get <std::string>();
1495-             
1496-             std::string arguments;
1497-             try  {
1498-                 arguments = tool_call[" arguments" dump ();
1499-             } catch  (const  std::exception & e) {
1500-                 LOG_ERR (" Failed to serialize arguments: %s\n " what ());
1501-                 arguments = " {}" 
1502-             }
1503-             
1504-             result.tool_calls .push_back ({
1505-                 name,
1506-                 arguments,
1507-                 /*  id= */ " " 
1508-             });
1509-         } catch  (const  std::exception & e) {
1510-             //  If parsing fails, include the entire tool call in the content
1511-             final_content += input.substr (
1512-                 tool_start,
1513-                 tool_end + closing_tag.length () - tool_start
1514-             );
1515-         }
1516-         
1517-         //  Move past this tool call for next iteration
1518-         start_pos = tool_end + closing_tag.length ();
1519-     }
1520-     
1521-     result.content  = final_content;
1522-     return  result;
1441+     static  std::regex function_regex (" <\\ |tool_call\\ |>\\ s*\\ {\\ s*\" name\"\\ s*:\\ s*\" ([^\" ]+)\"\\ s*,\\ s*\" arguments\"\\ s*:" 
1442+     static  std::regex close_regex (R"( \}\s*(</\|tool_call\|>)?)" 
1443+     return  parse_json_tool_calls (input, std::nullopt , function_regex, close_regex);
15231444}
15241445
15251446
0 commit comments