[Tool Call][DSV32] Streamline function call parameters (#14750)
Signed-off-by: Muqi Li <muqi1029@gmail.com>
This commit is contained in:
@@ -2,6 +2,8 @@ import json
|
||||
import logging
|
||||
import re
|
||||
|
||||
from partial_json_parser.core.options import Allow
|
||||
|
||||
from sglang.srt.entrypoints.openai.protocol import Tool
|
||||
from sglang.srt.function_call.base_format_detector import BaseFormatDetector
|
||||
from sglang.srt.function_call.core_types import (
|
||||
@@ -10,7 +12,7 @@ from sglang.srt.function_call.core_types import (
|
||||
ToolCallItem,
|
||||
_GetInfoFunc,
|
||||
)
|
||||
from sglang.srt.function_call.utils import _find_common_prefix
|
||||
from sglang.srt.function_call.utils import _find_common_prefix, _partial_json_loads
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -82,11 +84,12 @@ class DeepSeekV32Detector(BaseFormatDetector):
|
||||
self.invoke_regex = (
|
||||
r'<|DSML|invoke\s+name="([^"]+)"\s*>(.*?)(</|DSML|invoke>|$)'
|
||||
)
|
||||
self.prefix_parameter_end_call = ["</", "|DSML|", "parameter"]
|
||||
self.current_tool_id = -1
|
||||
|
||||
def has_tool_call(self, text: str) -> bool:
|
||||
"""Check if the text contains a deepseek v32 format tool call."""
|
||||
return self.bot_token in text
|
||||
return self.bot_token in text or "<|DSML|invoke" in text
|
||||
|
||||
def _parse_parameters_from_xml(
|
||||
self, invoke_content: str, allow_partial: bool = False
|
||||
@@ -139,16 +142,25 @@ class DeepSeekV32Detector(BaseFormatDetector):
|
||||
# If allowed, try to parse a partial parameter at the end
|
||||
if allow_partial:
|
||||
remaining_content = invoke_content[last_match_end:]
|
||||
|
||||
# Remove incomplete parameter_end_call prefix in case they are captured by param
|
||||
for token in reversed(self.prefix_parameter_end_call):
|
||||
remaining_content = remaining_content.rstrip(token)
|
||||
|
||||
# Match start of a parameter tag + value (potentially incomplete)
|
||||
# Regex: <tag name="..." string="...">VALUE... (no end tag)
|
||||
partial_match = re.search(
|
||||
self.partial_parameter_regex, remaining_content, re.DOTALL
|
||||
)
|
||||
|
||||
if partial_match:
|
||||
if partial_match and (param_value := partial_match.group(3)):
|
||||
param_name = partial_match.group(1)
|
||||
param_value = partial_match.group(3)
|
||||
parameters[param_name] = param_value
|
||||
if partial_match.group(2) == "true":
|
||||
parameters[param_name] = param_value.strip()
|
||||
else:
|
||||
parameters[param_name] = _partial_json_loads(
|
||||
param_value, Allow.ALL
|
||||
)[0]
|
||||
|
||||
return parameters
|
||||
|
||||
@@ -206,13 +218,6 @@ class DeepSeekV32Detector(BaseFormatDetector):
|
||||
self._buffer += new_text
|
||||
current_text = self._buffer
|
||||
|
||||
# Check if we have a tool call or any DSML-related content
|
||||
# Key insight: DSML tags contain distinctive markers like "|DSML|"
|
||||
# If we see these markers anywhere, we should keep buffering
|
||||
has_tool_call = (
|
||||
self.bot_token in current_text or "<|DSML|invoke" in current_text
|
||||
)
|
||||
|
||||
# Check if buffer contains any DSML markers or ends with potential tag prefix
|
||||
# This handles partial/streaming DSML content
|
||||
dsml_markers = ["|DSML|", "<|", "</|"]
|
||||
@@ -224,7 +229,11 @@ class DeepSeekV32Detector(BaseFormatDetector):
|
||||
current_text.rstrip().endswith(prefix) for prefix in dsml_prefixes
|
||||
)
|
||||
|
||||
if not has_tool_call and not potentially_dsml and not ends_with_prefix:
|
||||
if (
|
||||
not self.has_tool_call(current_text)
|
||||
and not potentially_dsml
|
||||
and not ends_with_prefix
|
||||
):
|
||||
self._buffer = ""
|
||||
for e_token in [self.eot_token, self.invoke_end_token]:
|
||||
if e_token in current_text:
|
||||
@@ -241,7 +250,6 @@ class DeepSeekV32Detector(BaseFormatDetector):
|
||||
string=current_text,
|
||||
flags=re.DOTALL,
|
||||
)
|
||||
|
||||
if not invoke_match:
|
||||
break
|
||||
|
||||
@@ -342,5 +350,5 @@ class DeepSeekV32Detector(BaseFormatDetector):
|
||||
return lambda name: StructureInfo(
|
||||
begin=f'<|DSML|invoke name="{name}">',
|
||||
end="</|DSML|invoke>",
|
||||
trigger=f'<|DSML|invoke name="{name}">',
|
||||
trigger=f"<|DSML|invoke",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user