main
py 62 lines 1.84 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3 """Named tool choice for Kimi K3: allowed when the XTML structural tag is
4 attached (strict tool calling), rejected otherwise."""
5
6 import pytest
7
8 from vllm.entrypoints.openai.chat_completion.protocol import (
9 ChatCompletionRequest,
10 )
11 from vllm.exceptions import VLLMValidationError
12 from vllm.sampling_params import StructuredOutputsParams
13
14
15 class _DummyTokenizer:
16 def get_vocab(self):
17 return {}
18
19 def encode(self, text, add_special_tokens=False):
20 return [ord(c) for c in text]
21
22
23 def _request(with_tag: bool) -> ChatCompletionRequest:
24 req = ChatCompletionRequest(
25 model="k3",
26 messages=[{"role": "user", "content": "hi"}],
27 tools=[
28 {
29 "type": "function",
30 "function": {
31 "name": "get_weather",
32 "parameters": {
33 "type": "object",
34 "properties": {"city": {"type": "string"}},
35 "required": ["city"],
36 },
37 },
38 }
39 ],
40 tool_choice={"type": "function", "function": {"name": "get_weather"}},
41 )
42 if with_tag:
43 req.structured_outputs = StructuredOutputsParams(
44 structural_tag='{"type": "structural_tag", "format": {}}'
45 )
46 return req
47
48
49 def _parser():
50 from vllm.tool_parsers.kimi_k3_tool_parser import KimiK3ToolParser
51
52 return KimiK3ToolParser(_DummyTokenizer())
53
54
55 def test_named_choice_allowed_with_structural_tag():
56 req = _parser().adjust_request(_request(with_tag=True))
57 assert req.skip_special_tokens is False
58
59
60 def test_named_choice_rejected_without_structural_tag():
61 with pytest.raises(VLLMValidationError):
62 _parser().adjust_request(_request(with_tag=False))