@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / 1b1e35aaf9
Fork 0

A high-throughput and memory-efficient inference and serving engine for LLMs

Mirrored from https://github.com/tduncan-lum/Nvidia-Optimization-Stack---VLLM.git

Synced Nov 12, 04:45 UTC

[BUGFIX] Fix regex pattern for Mistral Tool Call (#29918)

Signed-off-by: juliendenize <julien.denize@mistral.ai>

Julien Denize committed Dec 2, 2025 at 23:51 UTC 1b1e35aaf9d9561e1b5bf5b8e08b03565188e537
2 files changed +36 -1
tests/models/language/generation/test_mistral.py
+35
@@ -315,3 +315,38 @@ def test_mistral_function_call_nested_json():
315 assert json.loads(parsed.tool_calls[0].function.arguments) == args_dict
316 # No additional content outside the tool call should be returned.
317 assert parsed.content is None
318 +
319 + # multiple calls
320 + multiple_args_dict = [
321 + {
322 + "city": "Dallas",
323 + "state": "TX",
324 + "unit": "fahrenheit",
325 + "sub_dict": {"foo": "bar", "inner": {"x": 1, "y": 2}},
326 + },
327 + {},
328 + {"a": 0},
329 + {"a": 1, "b": "c"},
330 + ]
331 + names = ["get_current_weather", "get_current_weather_2", "random", "random_2"]
332 +
333 + model_output = "".join(
334 + [
335 + f"{parser.bot_token}{name}{json.dumps(args)}"
336 + for name, args in zip(names, multiple_args_dict)
337 + ]
338 + )
339 +
340 + parsed = parser.extract_tool_calls(model_output, None)
341 +
342 + # Assertions: the tool call is detected and the full nested JSON is parsed
343 + # without truncation.
344 + assert parsed.tools_called
345 + assert len(parsed.tool_calls) == len(multiple_args_dict)
346 +
347 + for i, tool_call in enumerate(parsed.tool_calls):
348 + assert MistralToolCall.is_valid_id(tool_call.id)
349 + assert tool_call.function.name == names[i]
350 + assert json.loads(tool_call.function.arguments) == multiple_args_dict[i]
351 + # No additional content outside the tool call should be returned.
352 + assert parsed.content is None
vllm/entrypoints/openai/tool_parsers/mistral_tool_parser.py
+1 -1
@@ -80,7 +80,7 @@ class MistralToolParser(ToolParser):
80 self.tool_call_regex = re.compile(r"\[{.*}\]", re.DOTALL)
81 if _is_fn_name_regex_support(self.model_tokenizer):
82 self.fn_name_regex = re.compile(
83 - r"([a-zA-Z0-9_-]+)(\{[\s\S]*?\})(?=\s*$|,|\s)?", re.DOTALL
83 + r"([a-zA-Z0-9_-]+)(\{[\s\S]*?\}+)", re.DOTALL
84 )
85 else:
86 self.fn_name_regex = None