From 1193f13181a21f69706c221a44200ed857cd6cf8 Mon Sep 17 00:00:00 2001 From: Xinyuan Tong <115166877+JustinTong0323@users.noreply.github.com> Date: Tue, 30 Sep 2025 17:44:44 -0700 Subject: [PATCH] fix: KimiK2Detector Improve tool call ID parsing with regex (#10972) --- .../srt/function_call/kimik2_detector.py | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/python/sglang/srt/function_call/kimik2_detector.py b/python/sglang/srt/function_call/kimik2_detector.py index 4f39433a6..ff29e7faa 100644 --- a/python/sglang/srt/function_call/kimik2_detector.py +++ b/python/sglang/srt/function_call/kimik2_detector.py @@ -50,6 +50,11 @@ class KimiK2Detector(BaseFormatDetector): self._last_arguments = "" + # Robust parser for ids like "functions.search:0" or fallback "search:0" + self.tool_call_id_regex = re.compile( + r"^(?:functions\.)?(?P[\w\.]+):(?P\d+)$" + ) + def has_tool_call(self, text: str) -> bool: """Check if the text contains a KimiK2 format tool call.""" return self.bot_token in text @@ -76,14 +81,18 @@ class KimiK2Detector(BaseFormatDetector): tool_calls = [] for match in function_call_tuples: function_id, function_args = match - function_name = function_id.split(".")[1].split(":")[0] - function_idx = int(function_id.split(".")[1].split(":")[1]) + m = self.tool_call_id_regex.match(function_id) + if not m: + logger.warning("Unexpected tool_call_id format: %s", function_id) + continue + function_name = m.group("name") + function_idx = int(m.group("index")) logger.info(f"function_name {function_name}") tool_calls.append( ToolCallItem( - tool_index=function_idx, # Use the call index in the response, not tool position + tool_index=function_idx, name=function_name, parameters=function_args, ) @@ -128,7 +137,11 @@ class KimiK2Detector(BaseFormatDetector): function_id = match.group("tool_call_id") function_args = match.group("function_arguments") - function_name = function_id.split(".")[1].split(":")[0] + m = self.tool_call_id_regex.match(function_id) + if not m: + logger.warning("Unexpected tool_call_id format: %s", function_id) + return StreamingParseResult(normal_text="", calls=calls) + function_name = m.group("name") # Initialize state if this is the first tool call if self.current_tool_id == -1: