@@ -352,8 +352,9 @@ func StripThinkingConfigIfUnsupported(model string, body []byte) []byte {
352352
353353// NormalizeGeminiThinkingBudget normalizes the thinkingBudget value in a standard Gemini
354354// request body (generationConfig.thinkingConfig.thinkingBudget path).
355- // For Gemini 3 models, converts thinkingBudget to thinkingLevel per Google's documentation.
356- func NormalizeGeminiThinkingBudget (model string , body []byte ) []byte {
355+ // For Gemini 3 models, converts thinkingBudget to thinkingLevel per Google's documentation,
356+ // unless skipGemini3Check is provided and true.
357+ func NormalizeGeminiThinkingBudget (model string , body []byte , skipGemini3Check ... bool ) []byte {
357358 const budgetPath = "generationConfig.thinkingConfig.thinkingBudget"
358359 const levelPath = "generationConfig.thinkingConfig.thinkingLevel"
359360
@@ -363,7 +364,8 @@ func NormalizeGeminiThinkingBudget(model string, body []byte) []byte {
363364 }
364365
365366 // For Gemini 3 models, convert thinkingBudget to thinkingLevel
366- if IsGemini3Model (model ) {
367+ skipGemini3 := len (skipGemini3Check ) > 0 && skipGemini3Check [0 ]
368+ if IsGemini3Model (model ) && ! skipGemini3 {
367369 if level , ok := ThinkingBudgetToGemini3Level (model , int (budget .Int ())); ok {
368370 updated , _ := sjson .SetBytes (body , levelPath , level )
369371 updated , _ = sjson .DeleteBytes (updated , budgetPath )
@@ -382,8 +384,9 @@ func NormalizeGeminiThinkingBudget(model string, body []byte) []byte {
382384
383385// NormalizeGeminiCLIThinkingBudget normalizes the thinkingBudget value in a Gemini CLI
384386// request body (request.generationConfig.thinkingConfig.thinkingBudget path).
385- // For Gemini 3 models, converts thinkingBudget to thinkingLevel per Google's documentation.
386- func NormalizeGeminiCLIThinkingBudget (model string , body []byte ) []byte {
387+ // For Gemini 3 models, converts thinkingBudget to thinkingLevel per Google's documentation,
388+ // unless skipGemini3Check is provided and true.
389+ func NormalizeGeminiCLIThinkingBudget (model string , body []byte , skipGemini3Check ... bool ) []byte {
387390 const budgetPath = "request.generationConfig.thinkingConfig.thinkingBudget"
388391 const levelPath = "request.generationConfig.thinkingConfig.thinkingLevel"
389392
@@ -393,7 +396,8 @@ func NormalizeGeminiCLIThinkingBudget(model string, body []byte) []byte {
393396 }
394397
395398 // For Gemini 3 models, convert thinkingBudget to thinkingLevel
396- if IsGemini3Model (model ) {
399+ skipGemini3 := len (skipGemini3Check ) > 0 && skipGemini3Check [0 ]
400+ if IsGemini3Model (model ) && ! skipGemini3 {
397401 if level , ok := ThinkingBudgetToGemini3Level (model , int (budget .Int ())); ok {
398402 updated , _ := sjson .SetBytes (body , levelPath , level )
399403 updated , _ = sjson .DeleteBytes (updated , budgetPath )
@@ -477,51 +481,39 @@ func ApplyReasoningEffortToGeminiCLI(body []byte, effort string) []byte {
477481
478482// ConvertThinkingLevelToBudget checks for "generationConfig.thinkingConfig.thinkingLevel"
479483// and converts it to "thinkingBudget" for Gemini 2.5 models.
480- // For Gemini 3 models, preserves thinkingLevel as- is (does not convert) .
484+ // For Gemini 3 models, preserves thinkingLevel unless skipGemini3Check is provided and true .
481485// Mappings for Gemini 2.5:
482486// - "high" -> 32768
483487// - "medium" -> 8192
484488// - "low" -> 1024
485489// - "minimal" -> 512
486490//
487491// It removes "thinkingLevel" after conversion (for Gemini 2.5 only).
488- func ConvertThinkingLevelToBudget (body []byte , model string ) []byte {
492+ func ConvertThinkingLevelToBudget (body []byte , model string , skipGemini3Check ... bool ) []byte {
489493 levelPath := "generationConfig.thinkingConfig.thinkingLevel"
490494 res := gjson .GetBytes (body , levelPath )
491495 if ! res .Exists () {
492496 return body
493497 }
494498
495- // For Gemini 3 models, preserve thinkingLevel - don't convert to budget
496- if IsGemini3Model (model ) {
499+ // For Gemini 3 models, preserve thinkingLevel unless explicitly skipped
500+ skipGemini3 := len (skipGemini3Check ) > 0 && skipGemini3Check [0 ]
501+ if IsGemini3Model (model ) && ! skipGemini3 {
497502 return body
498503 }
499504
500- level := strings .ToLower (res .String ())
501- var budget int
502- switch level {
503- case "high" :
504- budget = 32768
505- case "medium" :
506- budget = 8192
507- case "low" :
508- budget = 1024
509- case "minimal" :
510- budget = 512
511- default :
512- // Unknown level - remove it and let the API use defaults
505+ budget , ok := ThinkingLevelToBudget (res .String ())
506+ if ! ok {
513507 updated , _ := sjson .DeleteBytes (body , levelPath )
514508 return updated
515509 }
516510
517- // Set budget
518511 budgetPath := "generationConfig.thinkingConfig.thinkingBudget"
519512 updated , err := sjson .SetBytes (body , budgetPath , budget )
520513 if err != nil {
521514 return body
522515 }
523516
524- // Remove level
525517 updated , err = sjson .DeleteBytes (updated , levelPath )
526518 if err != nil {
527519 return body
@@ -544,31 +536,18 @@ func ConvertThinkingLevelToBudgetCLI(body []byte, model string) []byte {
544536 return body
545537 }
546538
547- level := strings .ToLower (res .String ())
548- var budget int
549- switch level {
550- case "high" :
551- budget = 32768
552- case "medium" :
553- budget = 8192
554- case "low" :
555- budget = 1024
556- case "minimal" :
557- budget = 512
558- default :
559- // Unknown level - remove it and let the API use defaults
539+ budget , ok := ThinkingLevelToBudget (res .String ())
540+ if ! ok {
560541 updated , _ := sjson .DeleteBytes (body , levelPath )
561542 return updated
562543 }
563544
564- // Set budget
565545 budgetPath := "request.generationConfig.thinkingConfig.thinkingBudget"
566546 updated , err := sjson .SetBytes (body , budgetPath , budget )
567547 if err != nil {
568548 return body
569549 }
570550
571- // Remove level
572551 updated , err = sjson .DeleteBytes (updated , levelPath )
573552 if err != nil {
574553 return body
0 commit comments