Skip to content

Commit 843316e

Browse files
authored
Merge branch 'router-for-me:main' into main
2 parents 44f66d2 + f607231 commit 843316e

File tree

3 files changed

+49
-42
lines changed

3 files changed

+49
-42
lines changed

internal/runtime/executor/aistudio_executor.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,8 @@ func (e *AIStudioExecutor) translateRequest(req cliproxyexecutor.Request, opts c
325325
payload = ApplyThinkingMetadata(payload, req.Metadata, req.Model)
326326
payload = util.ApplyGemini3ThinkingLevelFromMetadata(req.Model, req.Metadata, payload)
327327
payload = util.ApplyDefaultThinkingIfNeeded(req.Model, payload)
328-
payload = util.ConvertThinkingLevelToBudget(payload, req.Model)
329-
payload = util.NormalizeGeminiThinkingBudget(req.Model, payload)
328+
payload = util.ConvertThinkingLevelToBudget(payload, req.Model, true)
329+
payload = util.NormalizeGeminiThinkingBudget(req.Model, payload, true)
330330
payload = util.StripThinkingConfigIfUnsupported(req.Model, payload)
331331
payload = fixGeminiImageAspectRatio(req.Model, payload)
332332
payload = applyPayloadConfig(e.cfg, req.Model, payload)

internal/util/gemini_thinking.go

Lines changed: 19 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -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

internal/util/thinking.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,34 @@ func ThinkingEffortToBudget(model, effort string) (int, bool) {
160160
}
161161
}
162162

163+
// ThinkingLevelToBudget maps a Gemini thinkingLevel to a numeric thinking budget (tokens).
164+
//
165+
// Mappings:
166+
// - "minimal" -> 512
167+
// - "low" -> 1024
168+
// - "medium" -> 8192
169+
// - "high" -> 32768
170+
//
171+
// Returns false when the level is empty or unsupported.
172+
func ThinkingLevelToBudget(level string) (int, bool) {
173+
if level == "" {
174+
return 0, false
175+
}
176+
normalized := strings.ToLower(strings.TrimSpace(level))
177+
switch normalized {
178+
case "minimal":
179+
return 512, true
180+
case "low":
181+
return 1024, true
182+
case "medium":
183+
return 8192, true
184+
case "high":
185+
return 32768, true
186+
default:
187+
return 0, false
188+
}
189+
}
190+
163191
// ThinkingBudgetToEffort maps a numeric thinking budget (tokens)
164192
// to a reasoning effort level for level-based models.
165193
//

0 commit comments

Comments
 (0)