[Misc] Use VLLMValidationError consistently in chat completion and completion protocol validators (#36254)

Signed-off-by: umut-polat <52835619+umut-polat@users.noreply.github.com>
This commit is contained in:
Umut Polat
2026-06-01 04:04:11 +00:00
committed by GitHub
parent 8b8546da1c
commit f46e6be169
3 changed files with 100 additions and 24 deletions
@@ -116,3 +116,68 @@ def test_no_reasoning_fields_unchanged():
assistant_msg = request.messages[1]
assert assistant_msg.get("reasoning") is None
assert "reasoning_content" not in assistant_msg
SAMPLE_TOOL = {
"type": "function",
"function": {
"name": "get_weather",
"description": "Get the weather",
"parameters": {
"type": "object",
"properties": {"location": {"type": "string"}},
},
},
}
def test_structured_outputs_with_named_tool_choice_rejected():
"""structured_outputs cannot be combined with a named tool_choice."""
with pytest.raises(
ValueError,
match="structured outputs or tools, not both",
):
ChatCompletionRequest.model_validate(
{
"messages": [{"role": "user", "content": "Hello"}],
"model": "facebook/opt-125m",
"tools": [SAMPLE_TOOL],
"tool_choice": {
"type": "function",
"function": {"name": "get_weather"},
},
"structured_outputs": {"json": {"type": "object"}},
}
)
def test_structured_outputs_with_auto_tool_choice_allowed():
"""structured_outputs with tool_choice 'auto' should be allowed."""
request = ChatCompletionRequest.model_validate(
{
"messages": [{"role": "user", "content": "Hello"}],
"model": "facebook/opt-125m",
"tools": [SAMPLE_TOOL],
"tool_choice": "auto",
"structured_outputs": {"json": {"type": "object"}},
}
)
assert request.tool_choice == "auto"
def test_multiple_structured_outputs_rejected():
"""Only one kind of structured output constraint is allowed."""
with pytest.raises(
ValueError,
match="You can only use one kind of constraints",
):
ChatCompletionRequest.model_validate(
{
"messages": [{"role": "user", "content": "Hello"}],
"model": "facebook/opt-125m",
"structured_outputs": {
"json": {"type": "object"},
"regex": ".*",
},
}
)
@@ -740,19 +740,19 @@ class ChatCompletionRequest(OpenAIBaseModel):
)
# you can only use one kind of constraints for structured outputs
if count > 1:
raise ValueError(
raise VLLMValidationError(
"You can only use one kind of constraints for structured "
"outputs ('json', 'regex' or 'choice')."
"outputs ('json', 'regex' or 'choice').",
)
# you can only either use structured outputs or tools, not both
if count > 1 and data.get("tool_choice", "none") not in (
if count > 0 and data.get("tool_choice", "none") not in (
"none",
"auto",
"required",
):
raise ValueError(
raise VLLMValidationError(
"You can only either use constraints for structured outputs "
"or tools, not both."
"or tools, not both.",
)
return data
@@ -784,17 +784,21 @@ class ChatCompletionRequest(OpenAIBaseModel):
if "tool_choice" in data and data["tool_choice"] is not None:
# ensure that if "tool choice" is specified, tools are present
if "tools" not in data or data["tools"] is None:
raise ValueError("When using `tool_choice`, `tools` must be set.")
raise VLLMValidationError(
"When using `tool_choice`, `tools` must be set.",
parameter="tool_choice",
)
# make sure that tool choice is either a named tool
# OR that it's set to "auto" or "required"
if data["tool_choice"] not in ["auto", "required"] and not isinstance(
data["tool_choice"], dict
):
raise ValueError(
raise VLLMValidationError(
f"Invalid value for `tool_choice`: {data['tool_choice']}! "
'Only named tools, "none", "auto" or "required" '
"are supported."
"are supported.",
parameter="tool_choice",
)
# ensure that if "tool_choice" is specified as an object,
@@ -807,29 +811,33 @@ class ChatCompletionRequest(OpenAIBaseModel):
valid_tool = False
function = data["tool_choice"].get("function")
if not isinstance(function, dict):
raise ValueError(
raise VLLMValidationError(
f"Invalid value for `function`: `{function}` in "
f"`tool_choice`! {correct_usage_message}"
f"`tool_choice`! {correct_usage_message}",
parameter="tool_choice.function",
)
if "name" not in function:
raise ValueError(
raise VLLMValidationError(
f"Expected field `name` in `function` in "
f"`tool_choice`! {correct_usage_message}"
f"`tool_choice`! {correct_usage_message}",
parameter="tool_choice.function.name",
)
function_name = function["name"]
if not isinstance(function_name, str) or len(function_name) == 0:
raise ValueError(
raise VLLMValidationError(
f"Invalid `name` in `function`: `{function_name}`"
f" in `tool_choice`! {correct_usage_message}"
f" in `tool_choice`! {correct_usage_message}",
parameter="tool_choice.function.name",
)
for tool in data["tools"]:
if tool["function"]["name"] == function_name:
valid_tool = True
break
if not valid_tool:
raise ValueError(
raise VLLMValidationError(
"The tool specified in `tool_choice` does not match any"
" of the specified `tools`"
" of the specified `tools`",
parameter="tool_choice",
)
return data
@@ -837,9 +845,9 @@ class ChatCompletionRequest(OpenAIBaseModel):
@classmethod
def check_generation_prompt(cls, data):
if data.get("continue_final_message") and data.get("add_generation_prompt"):
raise ValueError(
raise VLLMValidationError(
"Cannot set both `continue_final_message` and "
"`add_generation_prompt` to True."
"`add_generation_prompt` to True.",
)
return data
@@ -849,8 +857,9 @@ class ChatCompletionRequest(OpenAIBaseModel):
if data.get("cache_salt") is not None and (
not isinstance(data["cache_salt"], str) or not data["cache_salt"]
):
raise ValueError(
"Parameter 'cache_salt' must be a non-empty string if provided."
raise VLLMValidationError(
"Parameter 'cache_salt' must be a non-empty string if provided.",
parameter="cache_salt",
)
return data
@@ -447,8 +447,9 @@ class CompletionRequest(OpenAIBaseModel):
)
if prompt_is_empty and embeds_is_empty:
raise ValueError(
"Either prompt or prompt_embeds must be provided and non-empty."
raise VLLMValidationError(
"Either prompt or prompt_embeds must be provided and non-empty.",
parameter="prompt",
)
return data
@@ -459,8 +460,9 @@ class CompletionRequest(OpenAIBaseModel):
if data.get("cache_salt") is not None and (
not isinstance(data["cache_salt"], str) or not data["cache_salt"]
):
raise ValueError(
"Parameter 'cache_salt' must be a non-empty string if provided."
raise VLLMValidationError(
"Parameter 'cache_salt' must be a non-empty string if provided.",
parameter="cache_salt",
)
return data