main
py 109 lines 4.27 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 from unittest.mock import MagicMock
5
6 import pytest
7
8 from tests.tool_parsers.common_tests import (
9 ToolParserTestConfig,
10 ToolParserTests,
11 )
12 from vllm.tokenizers import TokenizerLike
13
14
15 class TestPhi4MiniToolParser(ToolParserTests):
16 @pytest.fixture
17 def tokenizer(self, default_tokenizer: TokenizerLike) -> TokenizerLike:
18 """Add some phi4mini specific tokens to the default vocab."""
19 tokenizer = default_tokenizer
20 tokenizer_vocab = tokenizer.get_vocab()
21 tokenizer.get_vocab = MagicMock()
22 tokenizer_vocab.update(
23 {
24 "functools": 32000,
25 }
26 )
27 tokenizer.get_vocab.return_value = tokenizer_vocab
28 return tokenizer
29
30 @pytest.fixture
31 def test_config(self) -> ToolParserTestConfig:
32 return ToolParserTestConfig(
33 parser_name="phi4_mini_json",
34 # Test data
35 no_tool_calls_output="This is a regular response without any tool calls.",
36 single_tool_call_output=(
37 'functools[{"name": "get_weather", "arguments": {"city": "Tokyo"}}]'
38 ),
39 parallel_tool_calls_output="""functools[
40 {"name": "get_weather", "arguments": {"city": "Tokyo"}},
41 {"name": "get_time", "arguments": {"timezone": "Asia/Tokyo"}}
42 ]""",
43 various_data_types_output="""functools[{
44 "name": "test_function",
45 "arguments": {
46 "string_field": "hello",
47 "int_field": 42,
48 "float_field": 3.14,
49 "bool_field": true,
50 "null_field": null,
51 "array_field": ["a", "b", "c"],
52 "object_field": {"nested": "value"},
53 "empty_array": [],
54 "empty_object": {}
55 }
56 }]""",
57 empty_arguments_output='functools[{"name": "refresh", "arguments": {}}]',
58 surrounding_text_output="""Let me check the weather for you.
59 functools[{"name": "get_weather", "arguments": {"city": "Tokyo"}}]
60 Would you like to know more?""",
61 escaped_strings_output="""functools[{
62 "name": "test_function",
63 "arguments": {
64 "quoted": "He said \\"hello\\"",
65 "path": "C:\\\\Users\\\\file.txt",
66 "newline": "line1\\nline2",
67 "unicode": "emoji: 🎉"
68 }
69 }]""",
70 malformed_input_outputs=[
71 'functools[{"name": "func", "arguments": {',
72 'functools[{"name": "func", "arguments": "not a dict"}]',
73 'functools{"name": "func"}', # Missing brackets
74 'functools[{"name": "func"}]', # Missing arguments/parameters
75 "functools[] This is just text", # Empty functools
76 "functools[ This is just text ]", # functools with invalid JSON
77 ],
78 # Expected results
79 single_tool_call_expected_name="get_weather",
80 single_tool_call_expected_args={"city": "Tokyo"},
81 # Phi-4 Mini strips content when tool calls present
82 single_tool_call_expected_content=None,
83 parallel_tool_calls_count=2,
84 parallel_tool_calls_names=["get_weather", "get_time"],
85 parallel_tool_calls_expected_content=None,
86 # xfail markers
87 xfail_streaming={
88 "test_no_tool_calls": "Phi4 Mini streaming not implemented",
89 "test_single_tool_call_simple_args": (
90 "Phi4 Mini streaming not implemented"
91 ),
92 "test_parallel_tool_calls": "Phi4 Mini streaming not implemented",
93 "test_various_data_types": "Phi4 Mini streaming not implemented",
94 "test_empty_arguments": "Phi4 Mini streaming not implemented",
95 "test_surrounding_text": "Phi4 Mini streaming not implemented",
96 "test_escaped_strings": "Phi4 Mini streaming not implemented",
97 "test_streaming_reconstruction": "Phi4 Mini streaming not implemented",
98 },
99 xfail_nonstreaming={
100 "test_various_data_types": (
101 "Phi4MiniJsonToolParser regex has nesting limitations "
102 "with nested objects"
103 ),
104 "test_malformed_input": (
105 "Phi4MiniJsonToolParser incorrectly sets "
106 "tools_called=True on empty array"
107 ),
108 },
109 )