@@ -580,10 +580,7 @@ static common_chat_msg parse_json_tool_calls(
580
580
}
581
581
582
582
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 );
587
584
}
588
585
return result;
589
586
}
@@ -1359,14 +1356,15 @@ static common_chat_params common_chat_params_init_phi_4(const common_chat_templa
1359
1356
std::string name = function.at (" name" );
1360
1357
auto parameters = function.at (" parameters" );
1361
1358
builder.resolve_refs (parameters);
1362
- tool_rules. push_back ( builder.add_schema (name + " -call" , {
1359
+ auto call_rule = builder.add_schema (name + " -call" , {
1363
1360
{" type" , " object" },
1364
1361
{" properties" , {
1365
1362
{" name" , {{" const" , name}}},
1366
1363
{" arguments" , parameters},
1367
1364
}},
1368
1365
{" required" , json::array ({" name" , " arguments" })},
1369
- }));
1366
+ });
1367
+ tool_rules.push_back (builder.add_rule (name + " -call" , " \" <|tool_call|>\" " + call_rule + " \" <|/tool_call|>\" " ));
1370
1368
});
1371
1369
auto any_tool_call = builder.add_rule (" any_tool_call" , " ( " + string_join (tool_rules, " | " ) + " ) space" );
1372
1370
std::vector<std::string> alt_tags {
@@ -1379,6 +1377,9 @@ static common_chat_params common_chat_params_init_phi_4(const common_chat_templa
1379
1377
data.preserved_tokens = {
1380
1378
" <|tool_call|>" ,
1381
1379
" </|tool_call|>" ,
1380
+ " <|tool_response|>" ,
1381
+ " <|tool|>" ,
1382
+ " </|tool|>" ,
1382
1383
};
1383
1384
});
1384
1385
@@ -1437,89 +1438,9 @@ static common_chat_params common_chat_params_init_phi_4(const common_chat_templa
1437
1438
}
1438
1439
1439
1440
static 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);
1523
1444
}
1524
1445
1525
1446
0 commit comments