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(