[Tool Call] Stream DeepSeek-V3.2 function call parameters in JSON format. (#16091)
Co-authored-by: Huixxi <uestc.hugo@gmail.com>
This commit is contained in:
@@ -85,6 +85,7 @@ class DeepSeekV32Detector(BaseFormatDetector):
|
||||
r'<|DSML|invoke\s+name="([^"]+)"\s*>(.*?)(</|DSML|invoke>|$)'
|
||||
)
|
||||
self.prefix_parameter_end_call = ["</", "|DSML|", "parameter"]
|
||||
self.prefix_invoke_end_call = ["</", "|DSML|", "inv", "oke"]
|
||||
self.current_tool_id = -1
|
||||
|
||||
def has_tool_call(self, text: str) -> bool:
|
||||
@@ -93,9 +94,9 @@ class DeepSeekV32Detector(BaseFormatDetector):
|
||||
|
||||
def _parse_parameters_from_xml(
|
||||
self, invoke_content: str, allow_partial: bool = False
|
||||
) -> dict:
|
||||
) -> str:
|
||||
"""
|
||||
Parse parameters from either XML-like format or JSON format to dict.
|
||||
Parse parameters from either XML-like format or JSON format to str.
|
||||
|
||||
Supports two formats:
|
||||
1. XML parameter tags: <|DSML|parameter name="..." string="...">value</|DSML|parameter>
|
||||
@@ -103,17 +104,14 @@ class DeepSeekV32Detector(BaseFormatDetector):
|
||||
"""
|
||||
# First, try to parse as direct JSON (new format)
|
||||
invoke_content_stripped = invoke_content.strip()
|
||||
|
||||
if invoke_content_stripped.startswith("{") and invoke_content_stripped.endswith(
|
||||
"}"
|
||||
):
|
||||
try:
|
||||
parameters = json.loads(invoke_content_stripped)
|
||||
if isinstance(parameters, dict):
|
||||
return parameters
|
||||
except (json.JSONDecodeError, ValueError):
|
||||
# If JSON parsing fails, fall through to XML parsing
|
||||
pass
|
||||
if invoke_content_stripped.startswith("{"):
|
||||
if allow_partial:
|
||||
# Remove incomplete invoke end call prefix in case they are captured by param
|
||||
for token in reversed(self.prefix_invoke_end_call):
|
||||
invoke_content_stripped = invoke_content_stripped.rstrip(token)
|
||||
return invoke_content_stripped
|
||||
elif invoke_content_stripped.endswith("}"):
|
||||
return invoke_content_stripped
|
||||
|
||||
# Fall back to XML parameter tag parsing (original format)
|
||||
parameters = {}
|
||||
@@ -165,7 +163,7 @@ class DeepSeekV32Detector(BaseFormatDetector):
|
||||
except json.JSONDecodeError:
|
||||
parameters[param_name] = param_value.strip()
|
||||
|
||||
return parameters
|
||||
return json.dumps(parameters, ensure_ascii=False)
|
||||
|
||||
def detect_and_parse(self, text: str, tools: list[Tool]) -> StreamingParseResult:
|
||||
"""
|
||||
@@ -202,7 +200,7 @@ class DeepSeekV32Detector(BaseFormatDetector):
|
||||
# Parse parameters from XML format
|
||||
func_args = self._parse_parameters_from_xml(invoke_content)
|
||||
# construct match_result for parse_base_json
|
||||
match_result = {"name": func_name, "parameters": func_args}
|
||||
match_result = {"name": func_name, "parameters": json.loads(func_args)}
|
||||
calls.extend(self.parse_base_json(match_result, tools))
|
||||
|
||||
return StreamingParseResult(normal_text=normal_text, calls=calls)
|
||||
@@ -288,7 +286,6 @@ class DeepSeekV32Detector(BaseFormatDetector):
|
||||
current_params = self._parse_parameters_from_xml(
|
||||
invoke_content, allow_partial=not is_tool_end
|
||||
)
|
||||
current_args_json = json.dumps(current_params, ensure_ascii=False)
|
||||
|
||||
# 3. Calculate and send incremental arguments
|
||||
sent_len = len(self.streamed_args_for_tool[self.current_tool_id])
|
||||
@@ -300,12 +297,11 @@ class DeepSeekV32Detector(BaseFormatDetector):
|
||||
|
||||
if is_tool_end:
|
||||
# If complete, send everything remaining
|
||||
argument_diff = current_args_json[sent_len:]
|
||||
argument_diff = current_params[sent_len:]
|
||||
elif prev_params is not None:
|
||||
# If partial, send stable prefix diff
|
||||
prev_args_json = json.dumps(prev_params, ensure_ascii=False)
|
||||
if current_args_json != prev_args_json:
|
||||
prefix = _find_common_prefix(prev_args_json, current_args_json)
|
||||
if current_params != prev_params:
|
||||
prefix = _find_common_prefix(current_params, prev_params)
|
||||
if len(prefix) > sent_len:
|
||||
argument_diff = prefix[sent_len:]
|
||||
|
||||
@@ -353,5 +349,5 @@ class DeepSeekV32Detector(BaseFormatDetector):
|
||||
return lambda name: StructureInfo(
|
||||
begin=f'<|DSML|invoke name="{name}">',
|
||||
end="</|DSML|invoke>",
|
||||
trigger=f"<|DSML|invoke",
|
||||
trigger="<|DSML|invoke",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user