mirror of
https://github.com/vllm-project/vllm.git
synced 2026-06-06 00:16:14 +00:00
f46e6be169
Signed-off-by: umut-polat <52835619+umut-polat@users.noreply.github.com>
184 lines
5.7 KiB
Python
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": ".*",
|
|
},
|
|
}
|
|
)
|