chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
# 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": ".*",
|
||||
},
|
||||
}
|
||||
)
|
||||
Reference in New Issue
Block a user