[fix] Handle escaped characters in GLM tool call parser to prevent double serialization (#12456)

This commit is contained in:
soaringk
2025-11-05 08:48:14 +08:00
committed by GitHub
parent fb9582c4e1
commit 44da737770
2 changed files with 127 additions and 13 deletions

View File

@@ -24,13 +24,23 @@ def get_argument_type(func_name: str, arg_key: str, defined_tools: list):
def parse_arguments(json_value):
try:
try:
parsed_value = json.loads(json_value)
except:
parsed_value = ast.literal_eval(json_value)
parsed_value = json.loads(json_value)
return parsed_value, True
except:
return json_value, False
# If that fails, try wrapping it to unescape JSON characters
try:
# Wrap the value as a JSON string field
wrapped = json.loads('{"tmp": "' + json_value + '"}')
# parse the unescaped value
parsed_value = json.loads(wrapped["tmp"])
return parsed_value, True
except:
# Final fallback to ast.literal_eval
try:
parsed_value = ast.literal_eval(json_value)
return parsed_value, True
except:
return json_value, False
class Glm4MoeDetector(BaseFormatDetector):
@@ -45,8 +55,13 @@ class Glm4MoeDetector(BaseFormatDetector):
self.bot_token = "<tool_call>"
self.eot_token = "</tool_call>"
self.func_call_regex = r"<tool_call>.*?</tool_call>"
self.func_detail_regex = r"<tool_call>([^\n]*)\n(.*)</tool_call>"
self.func_arg_regex = r"<arg_key>(.*?)</arg_key>\s*<arg_value>(.*?)</arg_value>"
self.func_detail_regex = re.compile(
r"<tool_call>(.*?)(?:\\n|\n)(.*)</tool_call>", re.DOTALL
)
self.func_arg_regex = re.compile(
r"<arg_key>(.*?)</arg_key>(?:\\n|\s)*<arg_value>(.*?)</arg_value>",
re.DOTALL,
)
def has_tool_call(self, text: str) -> bool:
"""Check if the text contains a glm-4.5 / glm-4.6 format tool call."""
@@ -69,14 +84,10 @@ class Glm4MoeDetector(BaseFormatDetector):
try:
for match_result in match_result_list:
# Get function name
func_detail = re.search(self.func_detail_regex, match_result, re.DOTALL)
func_detail = self.func_detail_regex.search(match_result)
func_name = func_detail.group(1)
func_args = func_detail.group(2)
pairs = re.findall(
r"<arg_key>(.*?)</arg_key>\s*<arg_value>(.*?)</arg_value>",
func_args,
re.DOTALL,
)
pairs = self.func_arg_regex.findall(func_args)
arguments = {}
for arg_key, arg_value in pairs:
arg_key = arg_key.strip()