diff --git a/tests/tool_parsers/test_glm47_moe_tool_parser.py b/tests/tool_parsers/test_glm47_moe_tool_parser.py index 5e5501e4abff..51696c954788 100644 --- a/tests/tool_parsers/test_glm47_moe_tool_parser.py +++ b/tests/tool_parsers/test_glm47_moe_tool_parser.py @@ -91,6 +91,12 @@ def test_args_with_newlines(self, glm47_tool_parser, mock_request): assert r.tools_called assert json.loads(r.tool_calls[0].function.arguments) == {"city": "Beijing"} + def test_whitespace_preserved_in_arg_values(self, glm47_tool_parser, mock_request): + out = "get_weathercity Beijing " + r = glm47_tool_parser.extract_tool_calls(out, request=mock_request) + assert r.tools_called + assert json.loads(r.tool_calls[0].function.arguments) == {"city": " Beijing "} + def test_content_before(self, glm47_tool_parser, mock_request): out = "Checking.get_current_date" r = glm47_tool_parser.extract_tool_calls(out, request=mock_request) diff --git a/tests/tool_parsers/test_glm4_moe_tool_parser.py b/tests/tool_parsers/test_glm4_moe_tool_parser.py index 9f430b7814fc..c706d0a4c257 100644 --- a/tests/tool_parsers/test_glm4_moe_tool_parser.py +++ b/tests/tool_parsers/test_glm4_moe_tool_parser.py @@ -801,6 +801,36 @@ def test_extract_tool_calls_numeric_deserialization(glm4_moe_tool_parser, mock_r assert isinstance(args["enabled"], bool) +def test_whitespace_preserved_in_arg_values(glm4_moe_tokenizer): + """Test that string arguments preserve leading and trailing whitespace.""" + tools = [ + ChatCompletionToolsParam( + function=FunctionDefinition( + name="apply_diff", + parameters={ + "type": "object", + "properties": { + "s": {"type": "string"}, + }, + "required": ["s"], + }, + ), + ), + ] + parser = Glm4MoeModelToolParser(glm4_moe_tokenizer, tools=tools) + request = ChatCompletionRequest(model=MODEL, messages=[], tools=tools) + + model_output = """apply_diff +s + indented code +""" + + extracted_tool_calls = parser.extract_tool_calls(model_output, request=request) + args = json.loads(extracted_tool_calls.tool_calls[0].function.arguments) + + assert args["s"] == " indented code " + + def test_zero_argument_tool_call(glm4_moe_tool_parser, mock_request): """Regression: zero-argument tool call crash (PR #32321).""" model_output = """get_time diff --git a/vllm/tool_parsers/glm4_moe_tool_parser.py b/vllm/tool_parsers/glm4_moe_tool_parser.py index ac266ede3f48..64c4beb14357 100644 --- a/vllm/tool_parsers/glm4_moe_tool_parser.py +++ b/vllm/tool_parsers/glm4_moe_tool_parser.py @@ -210,9 +210,10 @@ def extract_tool_calls( arg_dct: dict[str, Any] = {} for key, value in pairs: arg_key = key.strip() - arg_val = value.strip() - if not self._is_string_type(tc_name, arg_key, self.tools): - arg_val = self._deserialize(arg_val) + if self._is_string_type(tc_name, arg_key, self.tools): + arg_val = value + else: + arg_val = self._deserialize(value.strip()) logger.debug("arg_key = %s, arg_val = %s", arg_key, arg_val) arg_dct[arg_key] = arg_val tool_calls.append(