[Bugfix] Fix parallel_tool_calls=null crash in Responses API from_request() (#48098)

Signed-off-by: mahadrehmann <mahadrehman04@gmail.com> Signed-off-by: Mahad Rehman <114791389+mahadrehmann@users.noreply.github.com> Co-authored-by: muhammadfawaz1 <135441198+professorsab@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Chauncey <chaunceyjiang@gmail.com>

Mahad Rehman committed Jul 15, 2026 at 15:01 UTC c0302d949740321c145b6b19852706b6f1b43854
2 files changed +46 -2
tests/tool_use/test_responses_request_validations.py
+43 -1
@@ -4,7 +4,10 @@
4 import pytest
5 from pydantic import ValidationError
6
7 -from vllm.entrypoints.openai.responses.protocol import ResponsesRequest
7 +from vllm.entrypoints.openai.responses.protocol import (
8 + ResponsesRequest,
9 + ResponsesResponse,
10 +)
11
12 SAMPLE_TOOL = {
13 "type": "function",
@@ -182,3 +185,42 @@ def test_responses_request_empty_tools_named_tool_choice():
185 "tool_choice": NAMED_TOOL_CHOICE,
186 }
187 )
188 +
189 +
190 +# Regression tests for parallel_tool_calls=null crash in Responses API
191 +# (from_request() passed None to ResponsesResponse.parallel_tool_calls,
192 +# a non-optional bool field, causing a Pydantic ValidationError during
193 +# response construction)
194 +@pytest.mark.parametrize(
195 + "value,expected",
196 + [
197 + (True, True),
198 + (False, False),
199 + (None, True), # null must resolve to the documented default (true)
200 + ],
201 +)
202 +def test_responses_response_parallel_tool_calls_null_resolves_to_default(
203 + value, expected
204 +):
205 + request = ResponsesRequest.model_validate(
206 + {"input": "Hello", "model": "test-model", "parallel_tool_calls": value}
207 + )
208 + sampling_params = request.to_sampling_params(default_max_tokens=16)
209 + r = ResponsesResponse.from_request(
210 + request=request,
211 + sampling_params=sampling_params,
212 + model_name="test-model",
213 + created_time=0,
214 + output=[],
215 + status="completed",
216 + usage=None,
217 + )
218 + assert r.parallel_tool_calls == expected
219 +
220 +
221 +def test_responses_request_parallel_tool_calls_null_accepted():
222 + """Client sending null must be accepted at request validation time."""
223 + req = ResponsesRequest.model_validate(
224 + {"input": "Hello", "model": "test-model", "parallel_tool_calls": None}
225 + )
226 + assert req.parallel_tool_calls is None
vllm/entrypoints/openai/responses/protocol.py
+3 -1
@@ -749,7 +749,9 @@ class ResponsesResponse(OpenAIBaseModel):
749 output=output,
750 input_messages=input_messages,
751 output_messages=output_messages,
752 - parallel_tool_calls=request.parallel_tool_calls,
752 + parallel_tool_calls=request.parallel_tool_calls
753 + if request.parallel_tool_calls is not None
754 + else ResponsesRequest.model_fields["parallel_tool_calls"].default,
755 temperature=sampling_params.temperature,
756 tool_choice=request.tool_choice,
757 tools=request.tools,