11import { describe , test , expect } from "vitest"
2- import { getModelMaxOutputTokens } from "../api"
2+ import { getModelMaxOutputTokens , shouldUseReasoningBudget , shouldUseReasoningEffort } from "../api"
33import type { ModelInfo , ProviderSettings } from "@roo-code/types"
4+ import { CLAUDE_CODE_DEFAULT_MAX_OUTPUT_TOKENS , ANTHROPIC_DEFAULT_MAX_TOKENS } from "@roo-code/types"
45
56describe ( "getModelMaxOutputTokens" , ( ) => {
67 const mockModel : ModelInfo = {
@@ -38,7 +39,7 @@ describe("getModelMaxOutputTokens", () => {
3839 expect ( result ) . toBe ( 8192 )
3940 } )
4041
41- test ( "should return default 8000 when claude-code provider has no custom max tokens" , ( ) => {
42+ test ( "should return default CLAUDE_CODE_DEFAULT_MAX_OUTPUT_TOKENS when claude-code provider has no custom max tokens" , ( ) => {
4243 const settings : ProviderSettings = {
4344 apiProvider : "claude-code" ,
4445 // No claudeCodeMaxOutputTokens set
@@ -50,7 +51,7 @@ describe("getModelMaxOutputTokens", () => {
5051 settings,
5152 } )
5253
53- expect ( result ) . toBe ( 8000 )
54+ expect ( result ) . toBe ( CLAUDE_CODE_DEFAULT_MAX_OUTPUT_TOKENS )
5455 } )
5556
5657 test ( "should handle reasoning budget models correctly" , ( ) => {
@@ -89,4 +90,202 @@ describe("getModelMaxOutputTokens", () => {
8990
9091 expect ( result ) . toBe ( 20000 ) // 20% of 100000
9192 } )
93+
94+ test ( "should return ANTHROPIC_DEFAULT_MAX_TOKENS for Anthropic models that support reasoning budget but aren't using it" , ( ) => {
95+ const anthropicModelId = "claude-sonnet-4-20250514"
96+ const model : ModelInfo = {
97+ contextWindow : 200_000 ,
98+ supportsPromptCache : true ,
99+ supportsReasoningBudget : true ,
100+ maxTokens : 64_000 , // This should be ignored
101+ }
102+
103+ const settings : ProviderSettings = {
104+ apiProvider : "anthropic" ,
105+ enableReasoningEffort : false , // Not using reasoning
106+ }
107+
108+ const result = getModelMaxOutputTokens ( { modelId : anthropicModelId , model, settings } )
109+ expect ( result ) . toBe ( ANTHROPIC_DEFAULT_MAX_TOKENS ) // Should be 8192, not 64_000
110+ } )
111+
112+ test ( "should return model.maxTokens for non-Anthropic models that support reasoning budget but aren't using it" , ( ) => {
113+ const geminiModelId = "gemini-2.5-flash-preview-04-17"
114+ const model : ModelInfo = {
115+ contextWindow : 1_048_576 ,
116+ supportsPromptCache : false ,
117+ supportsReasoningBudget : true ,
118+ maxTokens : 65_535 ,
119+ }
120+
121+ const settings : ProviderSettings = {
122+ apiProvider : "gemini" ,
123+ enableReasoningEffort : false , // Not using reasoning
124+ }
125+
126+ const result = getModelMaxOutputTokens ( { modelId : geminiModelId , model, settings } )
127+ expect ( result ) . toBe ( 65_535 ) // Should use model.maxTokens, not ANTHROPIC_DEFAULT_MAX_TOKENS
128+ } )
129+
130+ test ( "should return modelMaxTokens from settings when reasoning budget is required" , ( ) => {
131+ const model : ModelInfo = {
132+ contextWindow : 200_000 ,
133+ supportsPromptCache : true ,
134+ requiredReasoningBudget : true ,
135+ maxTokens : 8000 ,
136+ }
137+
138+ const settings : ProviderSettings = {
139+ modelMaxTokens : 4000 ,
140+ }
141+
142+ expect ( getModelMaxOutputTokens ( { modelId : "test" , model, settings } ) ) . toBe ( 4000 )
143+ } )
144+
145+ test ( "should return default 16_384 for reasoning budget models when modelMaxTokens not provided" , ( ) => {
146+ const model : ModelInfo = {
147+ contextWindow : 200_000 ,
148+ supportsPromptCache : true ,
149+ requiredReasoningBudget : true ,
150+ maxTokens : 8000 ,
151+ }
152+
153+ const settings = { }
154+
155+ expect ( getModelMaxOutputTokens ( { modelId : "test" , model, settings } ) ) . toBe ( 16_384 )
156+ } )
157+ } )
158+
159+ describe ( "shouldUseReasoningBudget" , ( ) => {
160+ test ( "should return true when model has requiredReasoningBudget" , ( ) => {
161+ const model : ModelInfo = {
162+ contextWindow : 200_000 ,
163+ supportsPromptCache : true ,
164+ requiredReasoningBudget : true ,
165+ }
166+
167+ // Should return true regardless of settings
168+ expect ( shouldUseReasoningBudget ( { model } ) ) . toBe ( true )
169+ expect ( shouldUseReasoningBudget ( { model, settings : { } } ) ) . toBe ( true )
170+ expect ( shouldUseReasoningBudget ( { model, settings : { enableReasoningEffort : false } } ) ) . toBe ( true )
171+ } )
172+
173+ test ( "should return true when model supports reasoning budget and settings enable reasoning effort" , ( ) => {
174+ const model : ModelInfo = {
175+ contextWindow : 200_000 ,
176+ supportsPromptCache : true ,
177+ supportsReasoningBudget : true ,
178+ }
179+
180+ const settings : ProviderSettings = {
181+ enableReasoningEffort : true ,
182+ }
183+
184+ expect ( shouldUseReasoningBudget ( { model, settings } ) ) . toBe ( true )
185+ } )
186+
187+ test ( "should return false when model supports reasoning budget but settings don't enable reasoning effort" , ( ) => {
188+ const model : ModelInfo = {
189+ contextWindow : 200_000 ,
190+ supportsPromptCache : true ,
191+ supportsReasoningBudget : true ,
192+ }
193+
194+ const settings : ProviderSettings = {
195+ enableReasoningEffort : false ,
196+ }
197+
198+ expect ( shouldUseReasoningBudget ( { model, settings } ) ) . toBe ( false )
199+ expect ( shouldUseReasoningBudget ( { model, settings : { } } ) ) . toBe ( false )
200+ expect ( shouldUseReasoningBudget ( { model } ) ) . toBe ( false )
201+ } )
202+
203+ test ( "should return false when model doesn't support reasoning budget" , ( ) => {
204+ const model : ModelInfo = {
205+ contextWindow : 200_000 ,
206+ supportsPromptCache : true ,
207+ }
208+
209+ const settings : ProviderSettings = {
210+ enableReasoningEffort : true ,
211+ }
212+
213+ expect ( shouldUseReasoningBudget ( { model, settings } ) ) . toBe ( false )
214+ expect ( shouldUseReasoningBudget ( { model } ) ) . toBe ( false )
215+ } )
216+ } )
217+
218+ describe ( "shouldUseReasoningEffort" , ( ) => {
219+ test ( "should return true when model has reasoningEffort property" , ( ) => {
220+ const model : ModelInfo = {
221+ contextWindow : 200_000 ,
222+ supportsPromptCache : true ,
223+ reasoningEffort : "medium" ,
224+ }
225+
226+ // Should return true regardless of settings
227+ expect ( shouldUseReasoningEffort ( { model } ) ) . toBe ( true )
228+ expect ( shouldUseReasoningEffort ( { model, settings : { } } ) ) . toBe ( true )
229+ expect ( shouldUseReasoningEffort ( { model, settings : { reasoningEffort : undefined } } ) ) . toBe ( true )
230+ } )
231+
232+ test ( "should return true when model supports reasoning effort and settings provide reasoning effort" , ( ) => {
233+ const model : ModelInfo = {
234+ contextWindow : 200_000 ,
235+ supportsPromptCache : true ,
236+ supportsReasoningEffort : true ,
237+ }
238+
239+ const settings : ProviderSettings = {
240+ reasoningEffort : "high" ,
241+ }
242+
243+ expect ( shouldUseReasoningEffort ( { model, settings } ) ) . toBe ( true )
244+ } )
245+
246+ test ( "should return false when model supports reasoning effort but settings don't provide reasoning effort" , ( ) => {
247+ const model : ModelInfo = {
248+ contextWindow : 200_000 ,
249+ supportsPromptCache : true ,
250+ supportsReasoningEffort : true ,
251+ }
252+
253+ const settings : ProviderSettings = {
254+ reasoningEffort : undefined ,
255+ }
256+
257+ expect ( shouldUseReasoningEffort ( { model, settings } ) ) . toBe ( false )
258+ expect ( shouldUseReasoningEffort ( { model, settings : { } } ) ) . toBe ( false )
259+ expect ( shouldUseReasoningEffort ( { model } ) ) . toBe ( false )
260+ } )
261+
262+ test ( "should return false when model doesn't support reasoning effort" , ( ) => {
263+ const model : ModelInfo = {
264+ contextWindow : 200_000 ,
265+ supportsPromptCache : true ,
266+ }
267+
268+ const settings : ProviderSettings = {
269+ reasoningEffort : "high" ,
270+ }
271+
272+ expect ( shouldUseReasoningEffort ( { model, settings } ) ) . toBe ( false )
273+ expect ( shouldUseReasoningEffort ( { model } ) ) . toBe ( false )
274+ } )
275+
276+ test ( "should handle different reasoning effort values" , ( ) => {
277+ const model : ModelInfo = {
278+ contextWindow : 200_000 ,
279+ supportsPromptCache : true ,
280+ supportsReasoningEffort : true ,
281+ }
282+
283+ const settingsLow : ProviderSettings = { reasoningEffort : "low" }
284+ const settingsMedium : ProviderSettings = { reasoningEffort : "medium" }
285+ const settingsHigh : ProviderSettings = { reasoningEffort : "high" }
286+
287+ expect ( shouldUseReasoningEffort ( { model, settings : settingsLow } ) ) . toBe ( true )
288+ expect ( shouldUseReasoningEffort ( { model, settings : settingsMedium } ) ) . toBe ( true )
289+ expect ( shouldUseReasoningEffort ( { model, settings : settingsHigh } ) ) . toBe ( true )
290+ } )
92291} )
0 commit comments