main
py 106 lines 3.08 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 import json
5
6 import pytest
7
8 from tests.parser.engine.replay_harness import MockTokenizer, _test_request
9 from vllm.reasoning import ReasoningParserManager
10 from vllm.tool_parsers import ToolParserManager
11
12
13 def _tokenizer() -> MockTokenizer:
14 vocab = {
15 "<think>": 1,
16 "</think>": 2,
17 "<tool_call>": 3,
18 "</tool_call>": 4,
19 "<arg_key>": 5,
20 "</arg_key>": 6,
21 "<arg_value>": 7,
22 "</arg_value>": 8,
23 }
24 return MockTokenizer(vocab=vocab, tokens=[])
25
26
27 def test_ling3_registered():
28 assert ReasoningParserManager.get_reasoning_parser("ling3") is not None
29 assert ToolParserManager.get_tool_parser("ling3") is not None
30
31
32 def test_ling3_defaults_thinking_on():
33 parser_cls = ReasoningParserManager.get_reasoning_parser("ling3")
34 parser = parser_cls(_tokenizer())
35
36 assert parser.reasoning_start_str == "<think>"
37 assert parser.reasoning_end_str == "</think>"
38
39 reasoning, content = parser.extract_reasoning(
40 "<think>reason</think>answer", _test_request()
41 )
42
43 assert reasoning == "reason"
44 assert content == "answer"
45
46
47 def test_ling3_disable_thinking_keeps_reasoning_as_content():
48 parser_cls = ReasoningParserManager.get_reasoning_parser("ling3")
49 parser = parser_cls(
50 _tokenizer(),
51 chat_template_kwargs={"enable_thinking": False},
52 )
53
54 reasoning, content = parser.extract_reasoning(
55 "<think>reason</think>answer", _test_request()
56 )
57
58 assert reasoning is None
59 assert content == "<think>reason</think>answer"
60
61
62 @pytest.mark.parametrize("model_output", ["only reasoning", "<think>only reasoning"])
63 def test_ling3_truncated_reasoning_stays_reasoning(model_output):
64 parser_cls = ReasoningParserManager.get_reasoning_parser("ling3")
65 parser = parser_cls(
66 _tokenizer(),
67 chat_template_kwargs={"enable_thinking": True},
68 )
69
70 reasoning, content = parser.extract_reasoning(model_output, _test_request())
71
72 assert reasoning == "only reasoning"
73 assert content is None
74
75
76 def test_ling3_tool_call_without_newline():
77 parser_cls = ToolParserManager.get_tool_parser("ling3")
78 parser = parser_cls(_tokenizer())
79
80 result = parser.extract_tool_calls(
81 "<tool_call>get_weather<arg_key>city</arg_key>"
82 "<arg_value>Beijing</arg_value></tool_call>",
83 request=_test_request(),
84 )
85
86 assert result.tools_called
87 assert result.content is None
88 assert result.tool_calls[0].function.name == "get_weather"
89 assert json.loads(result.tool_calls[0].function.arguments) == {
90 "city": "Beijing",
91 }
92
93
94 def test_ling3_tool_call_without_args():
95 parser_cls = ToolParserManager.get_tool_parser("ling3")
96 parser = parser_cls(_tokenizer())
97
98 result = parser.extract_tool_calls(
99 "<tool_call>ping</tool_call>",
100 request=_test_request(),
101 )
102
103 assert result.tools_called
104 assert result.content is None
105 assert result.tool_calls[0].function.name == "ping"
106 assert json.loads(result.tool_calls[0].function.arguments) == {}