main
py 184 lines 5.81 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 import pytest
5
6 from vllm.entrypoints.openai.chat_completion.protocol import ChatCompletionRequest
7 from vllm.exceptions import VLLMValidationError
8
9
10 def test_chat_completion_request_with_no_tools():
11 # tools key is not present
12 request = ChatCompletionRequest.model_validate(
13 {
14 "messages": [{"role": "user", "content": "Hello"}],
15 "model": "facebook/opt-125m",
16 }
17 )
18 assert request.tool_choice == "none"
19
20 # tools key is None
21 request = ChatCompletionRequest.model_validate(
22 {
23 "messages": [{"role": "user", "content": "Hello"}],
24 "model": "facebook/opt-125m",
25 "tools": None,
26 }
27 )
28 assert request.tool_choice == "none"
29
30 # tools key present but empty -- should be rejected
31 with pytest.raises(VLLMValidationError, match="must not be an empty array"):
32 ChatCompletionRequest.model_validate(
33 {
34 "messages": [{"role": "user", "content": "Hello"}],
35 "model": "facebook/opt-125m",
36 "tools": [],
37 }
38 )
39
40
41 @pytest.mark.parametrize("tool_choice", ["auto", "required"])
42 def test_chat_completion_request_with_tool_choice_but_no_tools(tool_choice):
43 with pytest.raises(
44 VLLMValidationError, match="When using `tool_choice`, `tools` must be set."
45 ):
46 ChatCompletionRequest.model_validate(
47 {
48 "messages": [{"role": "user", "content": "Hello"}],
49 "model": "facebook/opt-125m",
50 "tool_choice": tool_choice,
51 }
52 )
53
54 with pytest.raises(
55 VLLMValidationError, match="When using `tool_choice`, `tools` must be set."
56 ):
57 ChatCompletionRequest.model_validate(
58 {
59 "messages": [{"role": "user", "content": "Hello"}],
60 "model": "facebook/opt-125m",
61 "tool_choice": tool_choice,
62 "tools": None,
63 }
64 )
65
66
67 def test_reasoning_content_normalized_to_reasoning():
68 request = ChatCompletionRequest.model_validate(
69 {
70 "messages": [
71 {"role": "user", "content": "What is 2+2?"},
72 {
73 "role": "assistant",
74 "content": "4",
75 "reasoning_content": "2+2 equals 4",
76 },
77 {"role": "user", "content": "Are you sure?"},
78 ],
79 "model": "facebook/opt-125m",
80 }
81 )
82 assistant_msg = request.messages[1]
83 assert assistant_msg.get("reasoning") == "2+2 equals 4"
84 assert "reasoning_content" not in assistant_msg
85
86
87 def test_reasoning_takes_precedence_over_reasoning_content():
88 request = ChatCompletionRequest.model_validate(
89 {
90 "messages": [
91 {"role": "user", "content": "What is 2+2?"},
92 {
93 "role": "assistant",
94 "content": "4",
95 "reasoning": "from reasoning field",
96 "reasoning_content": "from reasoning_content field",
97 },
98 ],
99 "model": "facebook/opt-125m",
100 }
101 )
102 assistant_msg = request.messages[1]
103 assert assistant_msg.get("reasoning") == "from reasoning field"
104 assert "reasoning_content" not in assistant_msg
105
106
107 def test_no_reasoning_fields_unchanged():
108 request = ChatCompletionRequest.model_validate(
109 {
110 "messages": [
111 {"role": "user", "content": "Hello"},
112 {"role": "assistant", "content": "Hi"},
113 ],
114 "model": "facebook/opt-125m",
115 }
116 )
117 assistant_msg = request.messages[1]
118 assert assistant_msg.get("reasoning") is None
119 assert "reasoning_content" not in assistant_msg
120
121
122 SAMPLE_TOOL = {
123 "type": "function",
124 "function": {
125 "name": "get_weather",
126 "description": "Get the weather",
127 "parameters": {
128 "type": "object",
129 "properties": {"location": {"type": "string"}},
130 },
131 },
132 }
133
134
135 def test_structured_outputs_with_named_tool_choice_rejected():
136 """structured_outputs cannot be combined with a named tool_choice."""
137 with pytest.raises(
138 VLLMValidationError,
139 match="structured outputs or tools, not both",
140 ):
141 ChatCompletionRequest.model_validate(
142 {
143 "messages": [{"role": "user", "content": "Hello"}],
144 "model": "facebook/opt-125m",
145 "tools": [SAMPLE_TOOL],
146 "tool_choice": {
147 "type": "function",
148 "function": {"name": "get_weather"},
149 },
150 "structured_outputs": {"json": {"type": "object"}},
151 }
152 )
153
154
155 def test_structured_outputs_with_auto_tool_choice_allowed():
156 """structured_outputs with tool_choice 'auto' should be allowed."""
157 request = ChatCompletionRequest.model_validate(
158 {
159 "messages": [{"role": "user", "content": "Hello"}],
160 "model": "facebook/opt-125m",
161 "tools": [SAMPLE_TOOL],
162 "tool_choice": "auto",
163 "structured_outputs": {"json": {"type": "object"}},
164 }
165 )
166 assert request.tool_choice == "auto"
167
168
169 def test_multiple_structured_outputs_rejected():
170 """Only one kind of structured output constraint is allowed."""
171 with pytest.raises(
172 VLLMValidationError,
173 match="You can only use one kind of constraints",
174 ):
175 ChatCompletionRequest.model_validate(
176 {
177 "messages": [{"role": "user", "content": "Hello"}],
178 "model": "facebook/opt-125m",
179 "structured_outputs": {
180 "json": {"type": "object"},
181 "regex": ".*",
182 },
183 }
184 )