44from types import SimpleNamespace
55
66import pytest
7+ from vllm .parser .parser_manager import ParserManager
78from vllm .reasoning .minimax_m2_reasoning_parser import (
89 MiniMaxM2AppendThinkReasoningParser ,
910 MiniMaxM2ReasoningParser ,
1011)
1112
1213from vllm_ascend .patch .platform import (
13- patch_minimax_usage_accounting as minimax_usage_patch ,
14+ patch_chat_usage_accounting as usage_patch ,
1415)
16+ from vllm_ascend .patch .platform import patch_minimax_usage_accounting # noqa: F401
1517
1618
1719class FakeTokenizer :
1820 def get_vocab (self ):
1921 return {
2022 "<think>" : 1 ,
2123 "</think>" : 2 ,
24+ "<minimax:tool_call>" : 3 ,
25+ "</minimax:tool_call>" : 4 ,
2226 }
2327
2428
@@ -74,7 +78,7 @@ def test_count_reasoning_tokens(
7478
7579
7680def test_update_usage_tracking_state_tracks_prompt_and_completion_tokens ():
77- state = minimax_usage_patch ._create_usage_tracking_state (
81+ state = usage_patch ._create_usage_tracking_state (
7882 num_choices = 2 ,
7983 reasoning_parser = None ,
8084 )
@@ -89,7 +93,7 @@ def test_update_usage_tracking_state_tracks_prompt_and_completion_tokens():
8993 ],
9094 )
9195
92- minimax_usage_patch ._update_usage_tracking_state (state , res )
96+ usage_patch ._update_usage_tracking_state (state , res )
9397
9498 assert state .num_prompt_tokens == 3
9599 assert state .num_cached_tokens == 4
@@ -99,7 +103,7 @@ def test_update_usage_tracking_state_tracks_prompt_and_completion_tokens():
99103
100104def test_make_usage_info_injects_reasoning_token_details ():
101105 fake_serving = SimpleNamespace (enable_prompt_tokens_details = True )
102- usage = minimax_usage_patch ._make_usage_info (
106+ usage = usage_patch ._make_usage_info (
103107 fake_serving ,
104108 prompt_tokens = 3 ,
105109 completion_tokens = 4 ,
@@ -115,7 +119,7 @@ def test_make_usage_info_injects_reasoning_token_details():
115119
116120def test_make_usage_info_injects_zero_cached_tokens ():
117121 fake_serving = SimpleNamespace (enable_prompt_tokens_details = True )
118- usage = minimax_usage_patch ._make_usage_info (
122+ usage = usage_patch ._make_usage_info (
119123 fake_serving ,
120124 prompt_tokens = 3 ,
121125 completion_tokens = 4 ,
@@ -132,13 +136,13 @@ class FakeServing:
132136 enable_prompt_tokens_details = False
133137
134138 def _make_usage_info (self , ** kwargs ):
135- return minimax_usage_patch ._make_usage_info (self , ** kwargs )
139+ return usage_patch ._make_usage_info (self , ** kwargs )
136140
137141 class FakeReasoningParser :
138142 def count_reasoning_tokens (self , token_ids ):
139143 return 2 if 2 in token_ids else 0
140144
141- state = minimax_usage_patch ._create_usage_tracking_state (
145+ state = usage_patch ._create_usage_tracking_state (
142146 num_choices = 2 ,
143147 reasoning_parser = FakeReasoningParser (),
144148 )
@@ -148,7 +152,7 @@ def count_reasoning_tokens(self, token_ids):
148152 state .completion_tokens = [4 , 2 ]
149153 state .raw_output_token_ids = [[10 , 11 , 2 , 20 ], [30 , 31 ]]
150154
151- usage = minimax_usage_patch ._make_full_response_usage (FakeServing (), state )
155+ usage = usage_patch ._make_full_response_usage (FakeServing (), state )
152156
153157 assert usage .prompt_tokens == 3
154158 assert usage .completion_tokens == 6
@@ -157,12 +161,63 @@ def count_reasoning_tokens(self, token_ids):
157161 assert usage .prompt_tokens_details is None
158162
159163
164+ def test_make_full_response_usage_accepts_wrapped_reasoning_parser ():
165+ class FakeServing :
166+ enable_prompt_tokens_details = False
167+
168+ def _make_usage_info (self , ** kwargs ):
169+ return usage_patch ._make_usage_info (self , ** kwargs )
170+
171+ class FakeReasoningParser :
172+ def count_reasoning_tokens (self , token_ids ):
173+ return token_ids .index (2 ) if 2 in token_ids else len (token_ids )
174+
175+ state = usage_patch ._create_usage_tracking_state (
176+ num_choices = 1 ,
177+ reasoning_parser = SimpleNamespace (reasoning_parser = FakeReasoningParser ()),
178+ )
179+ state .num_prompt_tokens = 3
180+ state .final_res = SimpleNamespace (num_cached_tokens = None )
181+ state .completion_tokens = [4 ]
182+ state .raw_output_token_ids = [[10 , 11 , 2 , 20 ]]
183+
184+ usage = usage_patch ._make_full_response_usage (FakeServing (), state )
185+
186+ assert usage .completion_tokens_details .reasoning_tokens == 2
187+
188+
189+ def test_count_reasoning_tokens_accepts_minimax_unified_parser ():
190+ parser_cls = ParserManager .get_parser (
191+ tool_parser_name = "minimax_m2" ,
192+ reasoning_parser_name = "minimax_m2" ,
193+ enable_auto_tools = True ,
194+ model_name = "MiniMax-M2" ,
195+ )
196+ parser = parser_cls (FakeTokenizer (), tools = [])
197+
198+ assert not hasattr (parser , "count_reasoning_tokens" )
199+ assert usage_patch ._count_reasoning_tokens_for_usage ([10 , 11 , 2 , 20 ], parser ) == 2
200+
201+
202+ def test_count_reasoning_tokens_accepts_deepseek_parser_manager_wrapper ():
203+ parser_cls = ParserManager .get_parser (
204+ tool_parser_name = "deepseek_v4" ,
205+ reasoning_parser_name = "deepseek_v4" ,
206+ enable_auto_tools = True ,
207+ model_name = "DeepSeek-V4" ,
208+ )
209+ parser = parser_cls (FakeTokenizer (), tools = [])
210+
211+ assert not hasattr (parser , "count_reasoning_tokens" )
212+ assert usage_patch ._count_reasoning_tokens_for_usage ([10 , 11 ], parser ) == 0
213+
214+
160215def test_stream_usage_details_are_injected_without_replacing_source ():
161216 class FakeReasoningParser :
162217 def count_reasoning_tokens (self , token_ids ):
163218 return token_ids .index (2 ) if 2 in token_ids else len (token_ids )
164219
165- state = minimax_usage_patch ._create_usage_tracking_state (
220+ state = usage_patch ._create_usage_tracking_state (
166221 num_choices = 1 ,
167222 reasoning_parser = FakeReasoningParser (),
168223 enable_prompt_tokens_details = True ,
@@ -181,7 +236,7 @@ def count_reasoning_tokens(self, token_ids):
181236 },
182237 }
183238
184- data = minimax_usage_patch ._inject_stream_usage_details (
239+ data = usage_patch ._inject_stream_usage_details (
185240 f"data: { json .dumps (chunk )} \n \n " ,
186241 state ,
187242 )
@@ -193,12 +248,12 @@ def count_reasoning_tokens(self, token_ids):
193248 assert payload ["usage" ]["prompt_tokens_details" ] == {
194249 "cached_tokens" : 0 ,
195250 }
196- assert not hasattr (minimax_usage_patch , "_extract_class_method_source" )
197- assert not hasattr (minimax_usage_patch , "_patch_chat_completion_stream_generator" )
251+ assert not hasattr (usage_patch , "_extract_class_method_source" )
252+ assert not hasattr (usage_patch , "_patch_chat_completion_stream_generator" )
198253
199254
200255def test_stream_usage_details_inject_prompt_details_without_reasoning ():
201- state = minimax_usage_patch ._create_usage_tracking_state (
256+ state = usage_patch ._create_usage_tracking_state (
202257 num_choices = 1 ,
203258 reasoning_parser = None ,
204259 enable_prompt_tokens_details = True ,
@@ -216,7 +271,7 @@ def test_stream_usage_details_inject_prompt_details_without_reasoning():
216271 },
217272 }
218273
219- data = minimax_usage_patch ._inject_stream_usage_details (
274+ data = usage_patch ._inject_stream_usage_details (
220275 f"data: { json .dumps (chunk )} \n \n " ,
221276 state ,
222277 )
0 commit comments