Skip to content

Commit 3600a31

Browse files
added json parsing support
added fall back json parsing support, not stable yet, testing complex scenarios.
1 parent 45fac2a commit 3600a31

File tree

1 file changed

+71
-0
lines changed

1 file changed

+71
-0
lines changed

common/chat.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1337,13 +1337,15 @@ static common_chat_params common_chat_params_init_glm_4_5(const common_chat_temp
13371337
}
13381338

13391339
static void common_chat_parse_glm_4_5(common_chat_msg_parser & builder) {
1340+
// consume initial spaces
13401341
builder.consume_spaces();
13411342
builder.try_parse_reasoning("<think>", "</think>");
13421343
if (!builder.syntax().parse_tool_calls) {
13431344
builder.add_content(builder.consume_rest());
13441345
return;
13451346
}
13461347

1348+
// GLM's XML tool calling, we also need fall back json parsing
13471349
// GLM 4.5 uses format: <tool_call>function_name\n<arg_key>key</arg_key>\n<arg_value>value</arg_value>\n</tool_call>
13481350
static const common_regex tool_call_start("<tool_call>([^\n<]+)");
13491351
static const common_regex arg_key_regex("<arg_key>([^<]+)</arg_key>");
@@ -1384,6 +1386,75 @@ static void common_chat_parse_glm_4_5(common_chat_msg_parser & builder) {
13841386
}
13851387
}
13861388

1389+
// If XML fails, fall back to JSON parsing.
1390+
static const common_regex json_tool_calls_start("\\{[^}]*\"tool_calls\"\\s*:\\s*\\[");
1391+
1392+
if (auto res = builder.try_find_regex(json_tool_calls_start)) {
1393+
// Move to start of JSON and consume it
1394+
builder.move_to(res->groups[0].begin);
1395+
1396+
// Define paths for extracting tool call data
1397+
static const std::vector<std::vector<std::string>> args_paths = {{"tool_calls", "arguments"}};
1398+
static const std::vector<std::vector<std::string>> content_paths = {{"content"}};
1399+
1400+
auto json_result = builder.try_consume_json_with_dumped_args(args_paths, content_paths);
1401+
1402+
if (json_result) {
1403+
// if partial skip
1404+
if (json_result->is_partial) {
1405+
throw common_chat_msg_partial_exception("incomplete tool call");
1406+
}
1407+
1408+
// Handle content field if present
1409+
if (json_result->value.contains("content") && json_result->value.at("content").is_string()) {
1410+
std::string content = json_result->value.at("content");
1411+
builder.add_content(content);
1412+
}
1413+
1414+
// Handle tool_calls array if present
1415+
if (json_result->value.contains("tool_calls") && json_result->value.at("tool_calls").is_array()) {
1416+
const auto& tool_calls_array = json_result->value.at("tool_calls");
1417+
1418+
for (size_t i = 0; i < tool_calls_array.size(); i++) {
1419+
const auto& tool_call = tool_calls_array[i];
1420+
1421+
if (!tool_call.is_object()) {
1422+
continue;
1423+
}
1424+
1425+
// Extract tool call fields
1426+
std::string name = tool_call.contains("name") && tool_call.at("name").is_string()
1427+
? tool_call.at("name").get<std::string>()
1428+
: "";
1429+
std::string id = tool_call.contains("id") && tool_call.at("id").is_string()
1430+
? tool_call.at("id").get<std::string>()
1431+
: "";
1432+
std::string arguments = tool_call.contains("arguments")
1433+
? tool_call.at("arguments").dump()
1434+
: "{}";
1435+
1436+
if (name.empty()) {
1437+
continue;
1438+
}
1439+
1440+
// Add the tool call
1441+
if (!builder.add_tool_call(name, id, arguments)) {
1442+
if (json_result->is_partial) {
1443+
throw common_chat_msg_partial_exception("incomplete JSON tool call");
1444+
}
1445+
}
1446+
}
1447+
1448+
return; // Exit function after successful JSON parsing
1449+
}
1450+
1451+
// If partial JSON without complete structure, throw exception
1452+
if (json_result->is_partial) {
1453+
throw common_chat_msg_partial_exception("incomplete JSON response");
1454+
}
1455+
}
1456+
}
1457+
13871458
builder.add_content(builder.consume_rest());
13881459
}
13891460

0 commit comments

Comments
 (0)