@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / f6490a2841
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 4, 01:15 UTC

[Bugfix] Preserve leading/trailing whitespace in GLM non-streaming tool parser (#42026)

Signed-off-by: Rishapveer Singh <singhrishapveer@gmail.com>

Rishapveer Singh committed May 9, 2026 at 06:49 UTC f6490a28413526adefae8dd7af32906d060e0436
3 files changed +40 -3
tests/tool_parsers/test_glm47_moe_tool_parser.py
+6
@@ -91,6 +91,12 @@ class TestGlm47ExtractToolCalls:
91 assert r.tools_called
92 assert json.loads(r.tool_calls[0].function.arguments) == {"city": "Beijing"}
93
94 + def test_whitespace_preserved_in_arg_values(self, glm47_tool_parser, mock_request):
95 + out = "<tool_call>get_weather<arg_key>city</arg_key><arg_value> Beijing </arg_value></tool_call>"
96 + r = glm47_tool_parser.extract_tool_calls(out, request=mock_request)
97 + assert r.tools_called
98 + assert json.loads(r.tool_calls[0].function.arguments) == {"city": " Beijing "}
99 +
100 def test_content_before(self, glm47_tool_parser, mock_request):
101 out = "Checking.<tool_call>get_current_date</tool_call>"
102 r = glm47_tool_parser.extract_tool_calls(out, request=mock_request)
tests/tool_parsers/test_glm4_moe_tool_parser.py
+30
@@ -801,6 +801,36 @@ def test_extract_tool_calls_numeric_deserialization(glm4_moe_tool_parser, mock_r
801 assert isinstance(args["enabled"], bool)
802
803
804 +def test_whitespace_preserved_in_arg_values(glm4_moe_tokenizer):
805 + """Test that string arguments preserve leading and trailing whitespace."""
806 + tools = [
807 + ChatCompletionToolsParam(
808 + function=FunctionDefinition(
809 + name="apply_diff",
810 + parameters={
811 + "type": "object",
812 + "properties": {
813 + "s": {"type": "string"},
814 + },
815 + "required": ["s"],
816 + },
817 + ),
818 + ),
819 + ]
820 + parser = Glm4MoeModelToolParser(glm4_moe_tokenizer, tools=tools)
821 + request = ChatCompletionRequest(model=MODEL, messages=[], tools=tools)
822 +
823 + model_output = """<tool_call>apply_diff
824 +<arg_key>s</arg_key>
825 +<arg_value> indented code </arg_value>
826 +</tool_call>"""
827 +
828 + extracted_tool_calls = parser.extract_tool_calls(model_output, request=request)
829 + args = json.loads(extracted_tool_calls.tool_calls[0].function.arguments)
830 +
831 + assert args["s"] == " indented code "
832 +
833 +
834 def test_zero_argument_tool_call(glm4_moe_tool_parser, mock_request):
835 """Regression: zero-argument tool call crash (PR #32321)."""
836 model_output = """<tool_call>get_time
vllm/tool_parsers/glm4_moe_tool_parser.py
+4 -3
@@ -210,9 +210,10 @@ class Glm4MoeModelToolParser(ToolParser):
210 arg_dct: dict[str, Any] = {}
211 for key, value in pairs:
212 arg_key = key.strip()
213 - arg_val = value.strip()
214 - if not self._is_string_type(tc_name, arg_key, self.tools):
215 - arg_val = self._deserialize(arg_val)
213 + if self._is_string_type(tc_name, arg_key, self.tools):
214 + arg_val = value
215 + else:
216 + arg_val = self._deserialize(value.strip())
217 logger.debug("arg_key = %s, arg_val = %s", arg_key, arg_val)
218 arg_dct[arg_key] = arg_val
219 tool_calls.append(