mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-18 12:20:52 +08:00
Merge pull request #1429 from neavo/fix/gemini-python-sdk-thinking-fields
fix(gemini): support snake_case thinking config fields from Python SDK
This commit is contained in:
@@ -388,7 +388,12 @@ func extractGeminiConfig(body []byte, provider string) ThinkingConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check thinkingLevel first (Gemini 3 format takes precedence)
|
// Check thinkingLevel first (Gemini 3 format takes precedence)
|
||||||
if level := gjson.GetBytes(body, prefix+".thinkingLevel"); level.Exists() {
|
level := gjson.GetBytes(body, prefix+".thinkingLevel")
|
||||||
|
if !level.Exists() {
|
||||||
|
// Google official Gemini Python SDK sends snake_case field names
|
||||||
|
level = gjson.GetBytes(body, prefix+".thinking_level")
|
||||||
|
}
|
||||||
|
if level.Exists() {
|
||||||
value := level.String()
|
value := level.String()
|
||||||
switch value {
|
switch value {
|
||||||
case "none":
|
case "none":
|
||||||
@@ -401,7 +406,12 @@ func extractGeminiConfig(body []byte, provider string) ThinkingConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check thinkingBudget (Gemini 2.5 format)
|
// Check thinkingBudget (Gemini 2.5 format)
|
||||||
if budget := gjson.GetBytes(body, prefix+".thinkingBudget"); budget.Exists() {
|
budget := gjson.GetBytes(body, prefix+".thinkingBudget")
|
||||||
|
if !budget.Exists() {
|
||||||
|
// Google official Gemini Python SDK sends snake_case field names
|
||||||
|
budget = gjson.GetBytes(body, prefix+".thinking_budget")
|
||||||
|
}
|
||||||
|
if budget.Exists() {
|
||||||
value := int(budget.Int())
|
value := int(budget.Int())
|
||||||
switch value {
|
switch value {
|
||||||
case 0:
|
case 0:
|
||||||
|
|||||||
@@ -94,8 +94,10 @@ func (a *Applier) applyCompatible(body []byte, config thinking.ThinkingConfig, m
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *Applier) applyLevelFormat(body []byte, config thinking.ThinkingConfig) ([]byte, error) {
|
func (a *Applier) applyLevelFormat(body []byte, config thinking.ThinkingConfig) ([]byte, error) {
|
||||||
// Remove conflicting field to avoid both thinkingLevel and thinkingBudget in output
|
// Remove conflicting fields to avoid both thinkingLevel and thinkingBudget in output
|
||||||
result, _ := sjson.DeleteBytes(body, "request.generationConfig.thinkingConfig.thinkingBudget")
|
result, _ := sjson.DeleteBytes(body, "request.generationConfig.thinkingConfig.thinkingBudget")
|
||||||
|
result, _ = sjson.DeleteBytes(result, "request.generationConfig.thinkingConfig.thinking_budget")
|
||||||
|
result, _ = sjson.DeleteBytes(result, "request.generationConfig.thinkingConfig.thinking_level")
|
||||||
// Normalize includeThoughts field name to avoid oneof conflicts in upstream JSON parsing.
|
// Normalize includeThoughts field name to avoid oneof conflicts in upstream JSON parsing.
|
||||||
result, _ = sjson.DeleteBytes(result, "request.generationConfig.thinkingConfig.include_thoughts")
|
result, _ = sjson.DeleteBytes(result, "request.generationConfig.thinkingConfig.include_thoughts")
|
||||||
|
|
||||||
@@ -114,28 +116,30 @@ func (a *Applier) applyLevelFormat(body []byte, config thinking.ThinkingConfig)
|
|||||||
|
|
||||||
level := string(config.Level)
|
level := string(config.Level)
|
||||||
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.thinkingLevel", level)
|
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.thinkingLevel", level)
|
||||||
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.includeThoughts", true)
|
|
||||||
|
// Respect user's explicit includeThoughts setting from original body; default to true if not set
|
||||||
|
// Support both camelCase and snake_case variants
|
||||||
|
includeThoughts := true
|
||||||
|
if inc := gjson.GetBytes(body, "request.generationConfig.thinkingConfig.includeThoughts"); inc.Exists() {
|
||||||
|
includeThoughts = inc.Bool()
|
||||||
|
} else if inc := gjson.GetBytes(body, "request.generationConfig.thinkingConfig.include_thoughts"); inc.Exists() {
|
||||||
|
includeThoughts = inc.Bool()
|
||||||
|
}
|
||||||
|
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.includeThoughts", includeThoughts)
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Applier) applyBudgetFormat(body []byte, config thinking.ThinkingConfig, modelInfo *registry.ModelInfo, isClaude bool) ([]byte, error) {
|
func (a *Applier) applyBudgetFormat(body []byte, config thinking.ThinkingConfig, modelInfo *registry.ModelInfo, isClaude bool) ([]byte, error) {
|
||||||
// Remove conflicting field to avoid both thinkingLevel and thinkingBudget in output
|
// Remove conflicting fields to avoid both thinkingLevel and thinkingBudget in output
|
||||||
result, _ := sjson.DeleteBytes(body, "request.generationConfig.thinkingConfig.thinkingLevel")
|
result, _ := sjson.DeleteBytes(body, "request.generationConfig.thinkingConfig.thinkingLevel")
|
||||||
|
result, _ = sjson.DeleteBytes(result, "request.generationConfig.thinkingConfig.thinking_level")
|
||||||
|
result, _ = sjson.DeleteBytes(result, "request.generationConfig.thinkingConfig.thinking_budget")
|
||||||
// Normalize includeThoughts field name to avoid oneof conflicts in upstream JSON parsing.
|
// Normalize includeThoughts field name to avoid oneof conflicts in upstream JSON parsing.
|
||||||
result, _ = sjson.DeleteBytes(result, "request.generationConfig.thinkingConfig.include_thoughts")
|
result, _ = sjson.DeleteBytes(result, "request.generationConfig.thinkingConfig.include_thoughts")
|
||||||
|
|
||||||
budget := config.Budget
|
budget := config.Budget
|
||||||
includeThoughts := false
|
|
||||||
switch config.Mode {
|
|
||||||
case thinking.ModeNone:
|
|
||||||
includeThoughts = false
|
|
||||||
case thinking.ModeAuto:
|
|
||||||
includeThoughts = true
|
|
||||||
default:
|
|
||||||
includeThoughts = budget > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply Claude-specific constraints
|
// Apply Claude-specific constraints first to get the final budget value
|
||||||
if isClaude && modelInfo != nil {
|
if isClaude && modelInfo != nil {
|
||||||
budget, result = a.normalizeClaudeBudget(budget, result, modelInfo)
|
budget, result = a.normalizeClaudeBudget(budget, result, modelInfo)
|
||||||
// Check if budget was removed entirely
|
// Check if budget was removed entirely
|
||||||
@@ -144,6 +148,37 @@ func (a *Applier) applyBudgetFormat(body []byte, config thinking.ThinkingConfig,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// For ModeNone, always set includeThoughts to false regardless of user setting.
|
||||||
|
// This ensures that when user requests budget=0 (disable thinking output),
|
||||||
|
// the includeThoughts is correctly set to false even if budget is clamped to min.
|
||||||
|
if config.Mode == thinking.ModeNone {
|
||||||
|
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.thinkingBudget", budget)
|
||||||
|
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.includeThoughts", false)
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine includeThoughts: respect user's explicit setting from original body if provided
|
||||||
|
// Support both camelCase and snake_case variants
|
||||||
|
var includeThoughts bool
|
||||||
|
var userSetIncludeThoughts bool
|
||||||
|
if inc := gjson.GetBytes(body, "request.generationConfig.thinkingConfig.includeThoughts"); inc.Exists() {
|
||||||
|
includeThoughts = inc.Bool()
|
||||||
|
userSetIncludeThoughts = true
|
||||||
|
} else if inc := gjson.GetBytes(body, "request.generationConfig.thinkingConfig.include_thoughts"); inc.Exists() {
|
||||||
|
includeThoughts = inc.Bool()
|
||||||
|
userSetIncludeThoughts = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !userSetIncludeThoughts {
|
||||||
|
// No explicit setting, use default logic based on mode
|
||||||
|
switch config.Mode {
|
||||||
|
case thinking.ModeAuto:
|
||||||
|
includeThoughts = true
|
||||||
|
default:
|
||||||
|
includeThoughts = budget > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.thinkingBudget", budget)
|
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.thinkingBudget", budget)
|
||||||
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.includeThoughts", includeThoughts)
|
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.includeThoughts", includeThoughts)
|
||||||
return result, nil
|
return result, nil
|
||||||
|
|||||||
@@ -118,8 +118,10 @@ func (a *Applier) applyLevelFormat(body []byte, config thinking.ThinkingConfig)
|
|||||||
// - ModeNone + Budget>0: forced to think but hide output (includeThoughts=false)
|
// - ModeNone + Budget>0: forced to think but hide output (includeThoughts=false)
|
||||||
// ValidateConfig sets config.Level to the lowest level when ModeNone + Budget > 0.
|
// ValidateConfig sets config.Level to the lowest level when ModeNone + Budget > 0.
|
||||||
|
|
||||||
// Remove conflicting field to avoid both thinkingLevel and thinkingBudget in output
|
// Remove conflicting fields to avoid both thinkingLevel and thinkingBudget in output
|
||||||
result, _ := sjson.DeleteBytes(body, "generationConfig.thinkingConfig.thinkingBudget")
|
result, _ := sjson.DeleteBytes(body, "generationConfig.thinkingConfig.thinkingBudget")
|
||||||
|
result, _ = sjson.DeleteBytes(result, "generationConfig.thinkingConfig.thinking_budget")
|
||||||
|
result, _ = sjson.DeleteBytes(result, "generationConfig.thinkingConfig.thinking_level")
|
||||||
// Normalize includeThoughts field name to avoid oneof conflicts in upstream JSON parsing.
|
// Normalize includeThoughts field name to avoid oneof conflicts in upstream JSON parsing.
|
||||||
result, _ = sjson.DeleteBytes(result, "generationConfig.thinkingConfig.include_thoughts")
|
result, _ = sjson.DeleteBytes(result, "generationConfig.thinkingConfig.include_thoughts")
|
||||||
|
|
||||||
@@ -138,29 +140,58 @@ func (a *Applier) applyLevelFormat(body []byte, config thinking.ThinkingConfig)
|
|||||||
|
|
||||||
level := string(config.Level)
|
level := string(config.Level)
|
||||||
result, _ = sjson.SetBytes(result, "generationConfig.thinkingConfig.thinkingLevel", level)
|
result, _ = sjson.SetBytes(result, "generationConfig.thinkingConfig.thinkingLevel", level)
|
||||||
result, _ = sjson.SetBytes(result, "generationConfig.thinkingConfig.includeThoughts", true)
|
|
||||||
|
// Respect user's explicit includeThoughts setting from original body; default to true if not set
|
||||||
|
// Support both camelCase and snake_case variants
|
||||||
|
includeThoughts := true
|
||||||
|
if inc := gjson.GetBytes(body, "generationConfig.thinkingConfig.includeThoughts"); inc.Exists() {
|
||||||
|
includeThoughts = inc.Bool()
|
||||||
|
} else if inc := gjson.GetBytes(body, "generationConfig.thinkingConfig.include_thoughts"); inc.Exists() {
|
||||||
|
includeThoughts = inc.Bool()
|
||||||
|
}
|
||||||
|
result, _ = sjson.SetBytes(result, "generationConfig.thinkingConfig.includeThoughts", includeThoughts)
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Applier) applyBudgetFormat(body []byte, config thinking.ThinkingConfig) ([]byte, error) {
|
func (a *Applier) applyBudgetFormat(body []byte, config thinking.ThinkingConfig) ([]byte, error) {
|
||||||
// Remove conflicting field to avoid both thinkingLevel and thinkingBudget in output
|
// Remove conflicting fields to avoid both thinkingLevel and thinkingBudget in output
|
||||||
result, _ := sjson.DeleteBytes(body, "generationConfig.thinkingConfig.thinkingLevel")
|
result, _ := sjson.DeleteBytes(body, "generationConfig.thinkingConfig.thinkingLevel")
|
||||||
|
result, _ = sjson.DeleteBytes(result, "generationConfig.thinkingConfig.thinking_level")
|
||||||
|
result, _ = sjson.DeleteBytes(result, "generationConfig.thinkingConfig.thinking_budget")
|
||||||
// Normalize includeThoughts field name to avoid oneof conflicts in upstream JSON parsing.
|
// Normalize includeThoughts field name to avoid oneof conflicts in upstream JSON parsing.
|
||||||
result, _ = sjson.DeleteBytes(result, "generationConfig.thinkingConfig.include_thoughts")
|
result, _ = sjson.DeleteBytes(result, "generationConfig.thinkingConfig.include_thoughts")
|
||||||
|
|
||||||
budget := config.Budget
|
budget := config.Budget
|
||||||
// ModeNone semantics:
|
|
||||||
// - ModeNone + Budget=0: completely disable thinking
|
// For ModeNone, always set includeThoughts to false regardless of user setting.
|
||||||
// - ModeNone + Budget>0: forced to think but hide output (includeThoughts=false)
|
// This ensures that when user requests budget=0 (disable thinking output),
|
||||||
// When ZeroAllowed=false, ValidateConfig clamps Budget to Min while preserving ModeNone.
|
// the includeThoughts is correctly set to false even if budget is clamped to min.
|
||||||
includeThoughts := false
|
if config.Mode == thinking.ModeNone {
|
||||||
switch config.Mode {
|
result, _ = sjson.SetBytes(result, "generationConfig.thinkingConfig.thinkingBudget", budget)
|
||||||
case thinking.ModeNone:
|
result, _ = sjson.SetBytes(result, "generationConfig.thinkingConfig.includeThoughts", false)
|
||||||
includeThoughts = false
|
return result, nil
|
||||||
case thinking.ModeAuto:
|
}
|
||||||
includeThoughts = true
|
|
||||||
default:
|
// Determine includeThoughts: respect user's explicit setting from original body if provided
|
||||||
includeThoughts = budget > 0
|
// Support both camelCase and snake_case variants
|
||||||
|
var includeThoughts bool
|
||||||
|
var userSetIncludeThoughts bool
|
||||||
|
if inc := gjson.GetBytes(body, "generationConfig.thinkingConfig.includeThoughts"); inc.Exists() {
|
||||||
|
includeThoughts = inc.Bool()
|
||||||
|
userSetIncludeThoughts = true
|
||||||
|
} else if inc := gjson.GetBytes(body, "generationConfig.thinkingConfig.include_thoughts"); inc.Exists() {
|
||||||
|
includeThoughts = inc.Bool()
|
||||||
|
userSetIncludeThoughts = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !userSetIncludeThoughts {
|
||||||
|
// No explicit setting, use default logic based on mode
|
||||||
|
switch config.Mode {
|
||||||
|
case thinking.ModeAuto:
|
||||||
|
includeThoughts = true
|
||||||
|
default:
|
||||||
|
includeThoughts = budget > 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result, _ = sjson.SetBytes(result, "generationConfig.thinkingConfig.thinkingBudget", budget)
|
result, _ = sjson.SetBytes(result, "generationConfig.thinkingConfig.thinkingBudget", budget)
|
||||||
|
|||||||
@@ -79,8 +79,10 @@ func (a *Applier) applyCompatible(body []byte, config thinking.ThinkingConfig) (
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *Applier) applyLevelFormat(body []byte, config thinking.ThinkingConfig) ([]byte, error) {
|
func (a *Applier) applyLevelFormat(body []byte, config thinking.ThinkingConfig) ([]byte, error) {
|
||||||
// Remove conflicting field to avoid both thinkingLevel and thinkingBudget in output
|
// Remove conflicting fields to avoid both thinkingLevel and thinkingBudget in output
|
||||||
result, _ := sjson.DeleteBytes(body, "request.generationConfig.thinkingConfig.thinkingBudget")
|
result, _ := sjson.DeleteBytes(body, "request.generationConfig.thinkingConfig.thinkingBudget")
|
||||||
|
result, _ = sjson.DeleteBytes(result, "request.generationConfig.thinkingConfig.thinking_budget")
|
||||||
|
result, _ = sjson.DeleteBytes(result, "request.generationConfig.thinkingConfig.thinking_level")
|
||||||
// Normalize includeThoughts field name to avoid oneof conflicts in upstream JSON parsing.
|
// Normalize includeThoughts field name to avoid oneof conflicts in upstream JSON parsing.
|
||||||
result, _ = sjson.DeleteBytes(result, "request.generationConfig.thinkingConfig.include_thoughts")
|
result, _ = sjson.DeleteBytes(result, "request.generationConfig.thinkingConfig.include_thoughts")
|
||||||
|
|
||||||
@@ -99,25 +101,58 @@ func (a *Applier) applyLevelFormat(body []byte, config thinking.ThinkingConfig)
|
|||||||
|
|
||||||
level := string(config.Level)
|
level := string(config.Level)
|
||||||
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.thinkingLevel", level)
|
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.thinkingLevel", level)
|
||||||
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.includeThoughts", true)
|
|
||||||
|
// Respect user's explicit includeThoughts setting from original body; default to true if not set
|
||||||
|
// Support both camelCase and snake_case variants
|
||||||
|
includeThoughts := true
|
||||||
|
if inc := gjson.GetBytes(body, "request.generationConfig.thinkingConfig.includeThoughts"); inc.Exists() {
|
||||||
|
includeThoughts = inc.Bool()
|
||||||
|
} else if inc := gjson.GetBytes(body, "request.generationConfig.thinkingConfig.include_thoughts"); inc.Exists() {
|
||||||
|
includeThoughts = inc.Bool()
|
||||||
|
}
|
||||||
|
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.includeThoughts", includeThoughts)
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *Applier) applyBudgetFormat(body []byte, config thinking.ThinkingConfig) ([]byte, error) {
|
func (a *Applier) applyBudgetFormat(body []byte, config thinking.ThinkingConfig) ([]byte, error) {
|
||||||
// Remove conflicting field to avoid both thinkingLevel and thinkingBudget in output
|
// Remove conflicting fields to avoid both thinkingLevel and thinkingBudget in output
|
||||||
result, _ := sjson.DeleteBytes(body, "request.generationConfig.thinkingConfig.thinkingLevel")
|
result, _ := sjson.DeleteBytes(body, "request.generationConfig.thinkingConfig.thinkingLevel")
|
||||||
|
result, _ = sjson.DeleteBytes(result, "request.generationConfig.thinkingConfig.thinking_level")
|
||||||
|
result, _ = sjson.DeleteBytes(result, "request.generationConfig.thinkingConfig.thinking_budget")
|
||||||
// Normalize includeThoughts field name to avoid oneof conflicts in upstream JSON parsing.
|
// Normalize includeThoughts field name to avoid oneof conflicts in upstream JSON parsing.
|
||||||
result, _ = sjson.DeleteBytes(result, "request.generationConfig.thinkingConfig.include_thoughts")
|
result, _ = sjson.DeleteBytes(result, "request.generationConfig.thinkingConfig.include_thoughts")
|
||||||
|
|
||||||
budget := config.Budget
|
budget := config.Budget
|
||||||
includeThoughts := false
|
|
||||||
switch config.Mode {
|
// For ModeNone, always set includeThoughts to false regardless of user setting.
|
||||||
case thinking.ModeNone:
|
// This ensures that when user requests budget=0 (disable thinking output),
|
||||||
includeThoughts = false
|
// the includeThoughts is correctly set to false even if budget is clamped to min.
|
||||||
case thinking.ModeAuto:
|
if config.Mode == thinking.ModeNone {
|
||||||
includeThoughts = true
|
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.thinkingBudget", budget)
|
||||||
default:
|
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.includeThoughts", false)
|
||||||
includeThoughts = budget > 0
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine includeThoughts: respect user's explicit setting from original body if provided
|
||||||
|
// Support both camelCase and snake_case variants
|
||||||
|
var includeThoughts bool
|
||||||
|
var userSetIncludeThoughts bool
|
||||||
|
if inc := gjson.GetBytes(body, "request.generationConfig.thinkingConfig.includeThoughts"); inc.Exists() {
|
||||||
|
includeThoughts = inc.Bool()
|
||||||
|
userSetIncludeThoughts = true
|
||||||
|
} else if inc := gjson.GetBytes(body, "request.generationConfig.thinkingConfig.include_thoughts"); inc.Exists() {
|
||||||
|
includeThoughts = inc.Bool()
|
||||||
|
userSetIncludeThoughts = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if !userSetIncludeThoughts {
|
||||||
|
// No explicit setting, use default logic based on mode
|
||||||
|
switch config.Mode {
|
||||||
|
case thinking.ModeAuto:
|
||||||
|
includeThoughts = true
|
||||||
|
default:
|
||||||
|
includeThoughts = budget > 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.thinkingBudget", budget)
|
result, _ = sjson.SetBytes(result, "request.generationConfig.thinkingConfig.thinkingBudget", budget)
|
||||||
|
|||||||
@@ -116,7 +116,11 @@ func ConvertGeminiRequestToClaude(modelName string, inputRawJSON []byte, stream
|
|||||||
// Include thoughts configuration for reasoning process visibility
|
// Include thoughts configuration for reasoning process visibility
|
||||||
// Translator only does format conversion, ApplyThinking handles model capability validation.
|
// Translator only does format conversion, ApplyThinking handles model capability validation.
|
||||||
if thinkingConfig := genConfig.Get("thinkingConfig"); thinkingConfig.Exists() && thinkingConfig.IsObject() {
|
if thinkingConfig := genConfig.Get("thinkingConfig"); thinkingConfig.Exists() && thinkingConfig.IsObject() {
|
||||||
if thinkingLevel := thinkingConfig.Get("thinkingLevel"); thinkingLevel.Exists() {
|
thinkingLevel := thinkingConfig.Get("thinkingLevel")
|
||||||
|
if !thinkingLevel.Exists() {
|
||||||
|
thinkingLevel = thinkingConfig.Get("thinking_level")
|
||||||
|
}
|
||||||
|
if thinkingLevel.Exists() {
|
||||||
level := strings.ToLower(strings.TrimSpace(thinkingLevel.String()))
|
level := strings.ToLower(strings.TrimSpace(thinkingLevel.String()))
|
||||||
switch level {
|
switch level {
|
||||||
case "":
|
case "":
|
||||||
@@ -132,23 +136,29 @@ func ConvertGeminiRequestToClaude(modelName string, inputRawJSON []byte, stream
|
|||||||
out, _ = sjson.Set(out, "thinking.budget_tokens", budget)
|
out, _ = sjson.Set(out, "thinking.budget_tokens", budget)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if thinkingBudget := thinkingConfig.Get("thinkingBudget"); thinkingBudget.Exists() {
|
} else {
|
||||||
budget := int(thinkingBudget.Int())
|
thinkingBudget := thinkingConfig.Get("thinkingBudget")
|
||||||
switch budget {
|
if !thinkingBudget.Exists() {
|
||||||
case 0:
|
thinkingBudget = thinkingConfig.Get("thinking_budget")
|
||||||
out, _ = sjson.Set(out, "thinking.type", "disabled")
|
}
|
||||||
out, _ = sjson.Delete(out, "thinking.budget_tokens")
|
if thinkingBudget.Exists() {
|
||||||
case -1:
|
budget := int(thinkingBudget.Int())
|
||||||
out, _ = sjson.Set(out, "thinking.type", "enabled")
|
switch budget {
|
||||||
out, _ = sjson.Delete(out, "thinking.budget_tokens")
|
case 0:
|
||||||
default:
|
out, _ = sjson.Set(out, "thinking.type", "disabled")
|
||||||
out, _ = sjson.Set(out, "thinking.type", "enabled")
|
out, _ = sjson.Delete(out, "thinking.budget_tokens")
|
||||||
out, _ = sjson.Set(out, "thinking.budget_tokens", budget)
|
case -1:
|
||||||
|
out, _ = sjson.Set(out, "thinking.type", "enabled")
|
||||||
|
out, _ = sjson.Delete(out, "thinking.budget_tokens")
|
||||||
|
default:
|
||||||
|
out, _ = sjson.Set(out, "thinking.type", "enabled")
|
||||||
|
out, _ = sjson.Set(out, "thinking.budget_tokens", budget)
|
||||||
|
}
|
||||||
|
} else if includeThoughts := thinkingConfig.Get("includeThoughts"); includeThoughts.Exists() && includeThoughts.Type == gjson.True {
|
||||||
|
out, _ = sjson.Set(out, "thinking.type", "enabled")
|
||||||
|
} else if includeThoughts := thinkingConfig.Get("include_thoughts"); includeThoughts.Exists() && includeThoughts.Type == gjson.True {
|
||||||
|
out, _ = sjson.Set(out, "thinking.type", "enabled")
|
||||||
}
|
}
|
||||||
} else if includeThoughts := thinkingConfig.Get("includeThoughts"); includeThoughts.Exists() && includeThoughts.Type == gjson.True {
|
|
||||||
out, _ = sjson.Set(out, "thinking.type", "enabled")
|
|
||||||
} else if includeThoughts := thinkingConfig.Get("include_thoughts"); includeThoughts.Exists() && includeThoughts.Type == gjson.True {
|
|
||||||
out, _ = sjson.Set(out, "thinking.type", "enabled")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -243,19 +243,30 @@ func ConvertGeminiRequestToCodex(modelName string, inputRawJSON []byte, _ bool)
|
|||||||
out, _ = sjson.Set(out, "parallel_tool_calls", true)
|
out, _ = sjson.Set(out, "parallel_tool_calls", true)
|
||||||
|
|
||||||
// Convert Gemini thinkingConfig to Codex reasoning.effort.
|
// Convert Gemini thinkingConfig to Codex reasoning.effort.
|
||||||
|
// Note: Google official Python SDK sends snake_case fields (thinking_level/thinking_budget).
|
||||||
effortSet := false
|
effortSet := false
|
||||||
if genConfig := root.Get("generationConfig"); genConfig.Exists() {
|
if genConfig := root.Get("generationConfig"); genConfig.Exists() {
|
||||||
if thinkingConfig := genConfig.Get("thinkingConfig"); thinkingConfig.Exists() && thinkingConfig.IsObject() {
|
if thinkingConfig := genConfig.Get("thinkingConfig"); thinkingConfig.Exists() && thinkingConfig.IsObject() {
|
||||||
if thinkingLevel := thinkingConfig.Get("thinkingLevel"); thinkingLevel.Exists() {
|
thinkingLevel := thinkingConfig.Get("thinkingLevel")
|
||||||
|
if !thinkingLevel.Exists() {
|
||||||
|
thinkingLevel = thinkingConfig.Get("thinking_level")
|
||||||
|
}
|
||||||
|
if thinkingLevel.Exists() {
|
||||||
effort := strings.ToLower(strings.TrimSpace(thinkingLevel.String()))
|
effort := strings.ToLower(strings.TrimSpace(thinkingLevel.String()))
|
||||||
if effort != "" {
|
if effort != "" {
|
||||||
out, _ = sjson.Set(out, "reasoning.effort", effort)
|
out, _ = sjson.Set(out, "reasoning.effort", effort)
|
||||||
effortSet = true
|
effortSet = true
|
||||||
}
|
}
|
||||||
} else if thinkingBudget := thinkingConfig.Get("thinkingBudget"); thinkingBudget.Exists() {
|
} else {
|
||||||
if effort, ok := thinking.ConvertBudgetToLevel(int(thinkingBudget.Int())); ok {
|
thinkingBudget := thinkingConfig.Get("thinkingBudget")
|
||||||
out, _ = sjson.Set(out, "reasoning.effort", effort)
|
if !thinkingBudget.Exists() {
|
||||||
effortSet = true
|
thinkingBudget = thinkingConfig.Get("thinking_budget")
|
||||||
|
}
|
||||||
|
if thinkingBudget.Exists() {
|
||||||
|
if effort, ok := thinking.ConvertBudgetToLevel(int(thinkingBudget.Int())); ok {
|
||||||
|
out, _ = sjson.Set(out, "reasoning.effort", effort)
|
||||||
|
effortSet = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,16 +83,27 @@ func ConvertGeminiRequestToOpenAI(modelName string, inputRawJSON []byte, stream
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Map Gemini thinkingConfig to OpenAI reasoning_effort.
|
// Map Gemini thinkingConfig to OpenAI reasoning_effort.
|
||||||
// Always perform conversion to support allowCompat models that may not be in registry
|
// Always perform conversion to support allowCompat models that may not be in registry.
|
||||||
|
// Note: Google official Python SDK sends snake_case fields (thinking_level/thinking_budget).
|
||||||
if thinkingConfig := genConfig.Get("thinkingConfig"); thinkingConfig.Exists() && thinkingConfig.IsObject() {
|
if thinkingConfig := genConfig.Get("thinkingConfig"); thinkingConfig.Exists() && thinkingConfig.IsObject() {
|
||||||
if thinkingLevel := thinkingConfig.Get("thinkingLevel"); thinkingLevel.Exists() {
|
thinkingLevel := thinkingConfig.Get("thinkingLevel")
|
||||||
|
if !thinkingLevel.Exists() {
|
||||||
|
thinkingLevel = thinkingConfig.Get("thinking_level")
|
||||||
|
}
|
||||||
|
if thinkingLevel.Exists() {
|
||||||
effort := strings.ToLower(strings.TrimSpace(thinkingLevel.String()))
|
effort := strings.ToLower(strings.TrimSpace(thinkingLevel.String()))
|
||||||
if effort != "" {
|
if effort != "" {
|
||||||
out, _ = sjson.Set(out, "reasoning_effort", effort)
|
out, _ = sjson.Set(out, "reasoning_effort", effort)
|
||||||
}
|
}
|
||||||
} else if thinkingBudget := thinkingConfig.Get("thinkingBudget"); thinkingBudget.Exists() {
|
} else {
|
||||||
if effort, ok := thinking.ConvertBudgetToLevel(int(thinkingBudget.Int())); ok {
|
thinkingBudget := thinkingConfig.Get("thinkingBudget")
|
||||||
out, _ = sjson.Set(out, "reasoning_effort", effort)
|
if !thinkingBudget.Exists() {
|
||||||
|
thinkingBudget = thinkingConfig.Get("thinking_budget")
|
||||||
|
}
|
||||||
|
if thinkingBudget.Exists() {
|
||||||
|
if effort, ok := thinking.ConvertBudgetToLevel(int(thinkingBudget.Int())); ok {
|
||||||
|
out, _ = sjson.Set(out, "reasoning_effort", effort)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user