Files
vllm/tests/tool_use/test_chat_completion_request_validations.py

184 lines
5.7 KiB
Python

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
import pytest
from vllm.entrypoints.openai.chat_completion.protocol import ChatCompletionRequest
def test_chat_completion_request_with_no_tools():
# tools key is not present
request = ChatCompletionRequest.model_validate(
{
"messages": [{"role": "user", "content": "Hello"}],
"model": "facebook/opt-125m",
}
)
assert request.tool_choice == "none"
# tools key is None
request = ChatCompletionRequest.model_validate(
{
"messages": [{"role": "user", "content": "Hello"}],
"model": "facebook/opt-125m",
"tools": None,
}
)
assert request.tool_choice == "none"
# tools key present but empty -- should be rejected
with pytest.raises(ValueError, match="must not be an empty array"):
ChatCompletionRequest.model_validate(
{
"messages": [{"role": "user", "content": "Hello"}],
"model": "facebook/opt-125m",
"tools": [],
}
)
@pytest.mark.parametrize("tool_choice", ["auto", "required"])
def test_chat_completion_request_with_tool_choice_but_no_tools(tool_choice):
with pytest.raises(
ValueError, match="When using `tool_choice`, `tools` must be set."
):
ChatCompletionRequest.model_validate(
{
"messages": [{"role": "user", "content": "Hello"}],
"model": "facebook/opt-125m",
"tool_choice": tool_choice,
}
)
with pytest.raises(
ValueError, match="When using `tool_choice`, `tools` must be set."
):
ChatCompletionRequest.model_validate(
{
"messages": [{"role": "user", "content": "Hello"}],
"model": "facebook/opt-125m",
"tool_choice": tool_choice,
"tools": None,
}
)
def test_reasoning_content_normalized_to_reasoning():
request = ChatCompletionRequest.model_validate(
{
"messages": [
{"role": "user", "content": "What is 2+2?"},
{
"role": "assistant",
"content": "4",
"reasoning_content": "2+2 equals 4",
},
{"role": "user", "content": "Are you sure?"},
],
"model": "facebook/opt-125m",
}
)
assistant_msg = request.messages[1]
assert assistant_msg.get("reasoning") == "2+2 equals 4"
assert "reasoning_content" not in assistant_msg
def test_reasoning_takes_precedence_over_reasoning_content():
request = ChatCompletionRequest.model_validate(
{
"messages": [
{"role": "user", "content": "What is 2+2?"},
{
"role": "assistant",
"content": "4",
"reasoning": "from reasoning field",
"reasoning_content": "from reasoning_content field",
},
],
"model": "facebook/opt-125m",
}
)
assistant_msg = request.messages[1]
assert assistant_msg.get("reasoning") == "from reasoning field"
assert "reasoning_content" not in assistant_msg
def test_no_reasoning_fields_unchanged():
request = ChatCompletionRequest.model_validate(
{
"messages": [
{"role": "user", "content": "Hello"},
{"role": "assistant", "content": "Hi"},
],
"model": "facebook/opt-125m",
}
)
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": ".*",
},
}
)