@@ -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 " , result.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" , name}}},
13661363 {" arguments" , parameters},
13671364 }},
13681365 {" required" , json::array ({" name" , " arguments" })},
1369- }));
1366+ });
1367+ tool_rules.push_back (builder.add_rule (name + " -call" , " \" <|tool_call|>\" " + call_rule + " \" <|/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 " , e.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