@tduncan / Nvidia-Optimization-Stack-VLLM Mirror · read-only / commits / c6bb5b5603
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 10, 06:30 UTC

[BugFix] Fix engine crash caused by chat tools + response_format (#32127)

Signed-off-by: Nick Hill <nickhill123@gmail.com>

Nick Hill committed Jan 12, 2026 at 18:33 UTC c6bb5b56030df628697bcccad551276f81d2019e
3 files changed +47
tests/tool_use/test_chat_completions.py
+42
@@ -151,3 +151,45 @@ async def test_chat_completion_with_tools(
151 assert chunk.choices[0].finish_reason != "tool_calls"
152 assert len(chunks)
153 assert "".join(chunks) == output_text
154 +
155 +
156 +# Regression test for https://github.com/vllm-project/vllm/issues/32006
157 +# Engine crash when combining response_format: json_object with
158 +# tool_choice: required
159 +@pytest.mark.asyncio
160 +@pytest.mark.timeout(120)
161 +async def test_response_format_with_tool_choice_required(
162 + client: openai.AsyncOpenAI, server_config: ServerConfig
163 +):
164 + """
165 + Test that combining response_format: json_object with tool_choice: required
166 + doesn't crash the engine.
167 +
168 + Before the fix, this would cause a validation error:
169 + "You can only use one kind of structured outputs constraint but multiple
170 + are specified" because both json_object and json (from tool schema) would
171 + be set in StructuredOutputsParams.
172 + """
173 + models = await client.models.list()
174 + model_name: str = models.data[0].id
175 +
176 + # This combination previously crashed the engine
177 + chat_completion = await client.chat.completions.create(
178 + messages=ensure_system_prompt(
179 + [{"role": "user", "content": "What is the weather in Dallas, Texas?"}],
180 + server_config,
181 + ),
182 + temperature=0,
183 + max_completion_tokens=150,
184 + model=model_name,
185 + tools=[WEATHER_TOOL],
186 + tool_choice="required",
187 + response_format={"type": "json_object"},
188 + )
189 +
190 + # The fix clears response_format when tool_choice forces tool calling,
191 + # so the request should complete successfully with tool calls
192 + choice = chat_completion.choices[0]
193 + assert choice.finish_reason == "tool_calls"
194 + assert choice.message.tool_calls is not None
195 + assert len(choice.message.tool_calls) > 0
vllm/tool_parsers/abstract_tool_parser.py
+1
@@ -67,6 +67,7 @@ class ToolParser:
67 # tool_choice: "Forced Function" or "required" will override
68 # structured output json settings to make tool calling work correctly
69 request.structured_outputs.json = json_schema_from_tool
70 + request.response_format = None
71 if isinstance(request, ResponsesRequest):
72 request.text = ResponseTextConfig()
73 request.text.format = ResponseFormatTextJSONSchemaConfig(
vllm/v1/engine/input_processor.py
+4
@@ -370,6 +370,10 @@ class InputProcessor:
370 # Remember that this backend was set automatically
371 params.structured_outputs._backend_was_auto = True
372
373 + # Run post-init validation. This is also important to ensure subsequent
374 + # roundtrip serialization/deserialization won't fail.
375 + params.structured_outputs.__post_init__()
376 +
377 def _maybe_build_mm_uuids(
378 self,
379 request_id: str,