@@ -1337,13 +1337,15 @@ static common_chat_params common_chat_params_init_glm_4_5(const common_chat_temp
13371337}
13381338
13391339static  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