[Frontend] Migrate Responses harmony input validation to VLLMValidationError (#55701)
Signed-off-by: shaolila <shaolila@buaa.edu.cn> Co-authored-by: shaolila <shaolila@buaa.edu.cn>
Adababy committed
Sep 7, 2026 at 21:30 UTC
167858ea174efd0655ae821d3f3a50b51d721525
3 files changed
+36
-7
tests/entrypoints/openai/responses/test_harmony_utils.py
+11
@@ -16,6 +16,7 @@ from vllm.entrypoints.openai.responses.harmony import (
16
harmony_to_response_output,
17
response_previous_input_to_harmony,
18
)
19
+from vllm.exceptions import VLLMValidationError
20
21
22
class TestResponsePreviousInputToHarmony:
@@ -92,6 +93,16 @@ class TestResponsePreviousInputToHarmony:
93
assert messages[0].author.name == "functions.empty_tool"
94
assert messages[0].content[0].text == ""
95
96
+ def test_chat_message_without_role_raises_validation_error(self):
97
+ """A chat-format message missing the 'role' key is invalid input."""
98
+ chat_msg = {"content": "hello, no role here"}
99
+
100
+ with pytest.raises(
101
+ VLLMValidationError, match="Message has no 'role' key"
102
+ ) as exc_info:
103
+ response_previous_input_to_harmony(chat_msg)
104
+ assert exc_info.value.parameter == "input"
105
+
106
107
class TestHarmonyToResponseOutput:
108
"""Tests for harmony_to_response_output function."""
tests/entrypoints/openai/responses/test_response_input_to_harmony.py
+12
-4
@@ -15,6 +15,7 @@ from openai.types.responses.response_reasoning_item import (
15
from openai_harmony import DeveloperContent, Role
16
17
from vllm.entrypoints.openai.responses.harmony import response_input_to_harmony
18
+from vllm.exceptions import VLLMValidationError
19
20
# ---------------------------------------------------------------------------
21
# Shared fixtures
@@ -252,7 +253,9 @@ class TestResponseInputToHarmonyMessage:
253
assert msg.author.name == "functions.get_weather"
254
255
def test_function_call_output_raises_if_no_matching_call(self):
255
- with pytest.raises(ValueError, match="No call message found for"):
256
+ with pytest.raises(
257
+ VLLMValidationError, match="No call message found for"
258
+ ) as exc_info:
259
response_input_to_harmony(
260
{
261
"type": "function_call_output",
@@ -261,21 +264,26 @@ class TestResponseInputToHarmonyMessage:
264
},
265
prev_responses=[_PREV_CALL],
266
)
267
+ assert exc_info.value.parameter == "input"
268
269
def test_function_call_output_raises_on_empty_prev_responses(self):
266
- with pytest.raises(ValueError, match="No call message found for"):
270
+ with pytest.raises(
271
+ VLLMValidationError, match="No call message found for"
272
+ ) as exc_info:
273
response_input_to_harmony(
274
{"type": "function_call_output", "call_id": "call_test", "output": "x"},
275
prev_responses=[],
276
)
277
+ assert exc_info.value.parameter == "input"
278
279
# -----------------------------------------------------------------------
280
# Error cases
281
# -----------------------------------------------------------------------
282
276
- def test_unknown_type_raises_value_error(self):
277
- with pytest.raises(ValueError, match="Unknown input type"):
283
+ def test_unknown_type_raises_validation_error(self):
284
+ with pytest.raises(VLLMValidationError, match="Unknown input type") as exc_info:
285
response_input_to_harmony(
286
{"type": "image_url", "url": "https://example.com/img.png"},
287
prev_responses=[],
288
)
289
+ assert exc_info.value.parameter == "input"
vllm/entrypoints/openai/responses/harmony.py
+13
-3
@@ -40,6 +40,7 @@ from vllm.entrypoints.openai.responses.protocol import (
40
ResponseInputOutputItem,
41
ResponsesRequest,
42
)
43
+from vllm.exceptions import VLLMValidationError
44
from vllm.logger import init_logger
45
from vllm.utils import random_uuid
46
@@ -88,7 +89,10 @@ def _parse_chat_format_message(chat_msg: dict) -> list[Message]:
89
"""Parse an OpenAI chat-format dict into Harmony messages."""
90
role = chat_msg.get("role")
91
if role is None:
91
- raise ValueError(f"Message has no 'role' key: {chat_msg}")
92
+ raise VLLMValidationError(
93
+ f"Message has no 'role' key: {chat_msg}",
94
+ parameter="input",
95
+ )
96
97
# Assistant message with tool calls
98
tool_calls = chat_msg.get("tool_calls")
@@ -184,7 +188,10 @@ def response_input_to_harmony(
188
call_response = prev_response
189
break
190
if call_response is None:
187
- raise ValueError(f"No call message found for {call_id}")
191
+ raise VLLMValidationError(
192
+ f"No call message found for {call_id}",
193
+ parameter="input",
194
+ )
195
msg = Message.from_author_and_content(
196
Author.new(Role.TOOL, f"functions.{call_response.name}"),
197
response_msg["output"],
@@ -205,7 +212,10 @@ def response_input_to_harmony(
212
msg = msg.with_recipient(f"functions.{response_msg['name']}")
213
msg = msg.with_content_type("json")
214
else:
208
- raise ValueError(f"Unknown input type: {response_msg['type']}")
215
+ raise VLLMValidationError(
216
+ f"Unknown input type: {response_msg['type']}",
217
+ parameter="input",
218
+ )
219
return msg
220
221