mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-19 04:40:52 +08:00
fix(executor): centralize default thinking config
This commit is contained in:
@@ -309,6 +309,7 @@ func (e *AIStudioExecutor) translateRequest(req cliproxyexecutor.Request, opts c
|
|||||||
to := sdktranslator.FromString("gemini")
|
to := sdktranslator.FromString("gemini")
|
||||||
payload := sdktranslator.TranslateRequest(from, to, req.Model, bytes.Clone(req.Payload), stream)
|
payload := sdktranslator.TranslateRequest(from, to, req.Model, bytes.Clone(req.Payload), stream)
|
||||||
payload = applyThinkingMetadata(payload, req.Metadata, req.Model)
|
payload = applyThinkingMetadata(payload, req.Metadata, req.Model)
|
||||||
|
payload = util.ApplyDefaultThinkingIfNeeded(req.Model, payload)
|
||||||
payload = util.ConvertThinkingLevelToBudget(payload)
|
payload = util.ConvertThinkingLevelToBudget(payload)
|
||||||
payload = util.NormalizeGeminiThinkingBudget(req.Model, payload)
|
payload = util.NormalizeGeminiThinkingBudget(req.Model, payload)
|
||||||
payload = util.StripThinkingConfigIfUnsupported(req.Model, payload)
|
payload = util.StripThinkingConfigIfUnsupported(req.Model, payload)
|
||||||
|
|||||||
@@ -77,6 +77,7 @@ func (e *AntigravityExecutor) Execute(ctx context.Context, auth *cliproxyauth.Au
|
|||||||
translated := sdktranslator.TranslateRequest(from, to, req.Model, bytes.Clone(req.Payload), false)
|
translated := sdktranslator.TranslateRequest(from, to, req.Model, bytes.Clone(req.Payload), false)
|
||||||
|
|
||||||
translated = applyThinkingMetadataCLI(translated, req.Metadata, req.Model)
|
translated = applyThinkingMetadataCLI(translated, req.Metadata, req.Model)
|
||||||
|
translated = util.ApplyDefaultThinkingIfNeededCLI(req.Model, translated)
|
||||||
translated = normalizeAntigravityThinking(req.Model, translated)
|
translated = normalizeAntigravityThinking(req.Model, translated)
|
||||||
|
|
||||||
baseURLs := antigravityBaseURLFallbackOrder(auth)
|
baseURLs := antigravityBaseURLFallbackOrder(auth)
|
||||||
@@ -171,6 +172,7 @@ func (e *AntigravityExecutor) ExecuteStream(ctx context.Context, auth *cliproxya
|
|||||||
translated := sdktranslator.TranslateRequest(from, to, req.Model, bytes.Clone(req.Payload), true)
|
translated := sdktranslator.TranslateRequest(from, to, req.Model, bytes.Clone(req.Payload), true)
|
||||||
|
|
||||||
translated = applyThinkingMetadataCLI(translated, req.Metadata, req.Model)
|
translated = applyThinkingMetadataCLI(translated, req.Metadata, req.Model)
|
||||||
|
translated = util.ApplyDefaultThinkingIfNeededCLI(req.Model, translated)
|
||||||
translated = normalizeAntigravityThinking(req.Model, translated)
|
translated = normalizeAntigravityThinking(req.Model, translated)
|
||||||
|
|
||||||
baseURLs := antigravityBaseURLFallbackOrder(auth)
|
baseURLs := antigravityBaseURLFallbackOrder(auth)
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ func (e *GeminiCLIExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth
|
|||||||
to := sdktranslator.FromString("gemini-cli")
|
to := sdktranslator.FromString("gemini-cli")
|
||||||
basePayload := sdktranslator.TranslateRequest(from, to, req.Model, bytes.Clone(req.Payload), false)
|
basePayload := sdktranslator.TranslateRequest(from, to, req.Model, bytes.Clone(req.Payload), false)
|
||||||
basePayload = applyThinkingMetadataCLI(basePayload, req.Metadata, req.Model)
|
basePayload = applyThinkingMetadataCLI(basePayload, req.Metadata, req.Model)
|
||||||
|
basePayload = util.ApplyDefaultThinkingIfNeededCLI(req.Model, basePayload)
|
||||||
basePayload = util.NormalizeGeminiCLIThinkingBudget(req.Model, basePayload)
|
basePayload = util.NormalizeGeminiCLIThinkingBudget(req.Model, basePayload)
|
||||||
basePayload = util.StripThinkingConfigIfUnsupported(req.Model, basePayload)
|
basePayload = util.StripThinkingConfigIfUnsupported(req.Model, basePayload)
|
||||||
basePayload = fixGeminiCLIImageAspectRatio(req.Model, basePayload)
|
basePayload = fixGeminiCLIImageAspectRatio(req.Model, basePayload)
|
||||||
@@ -200,6 +201,7 @@ func (e *GeminiCLIExecutor) ExecuteStream(ctx context.Context, auth *cliproxyaut
|
|||||||
to := sdktranslator.FromString("gemini-cli")
|
to := sdktranslator.FromString("gemini-cli")
|
||||||
basePayload := sdktranslator.TranslateRequest(from, to, req.Model, bytes.Clone(req.Payload), true)
|
basePayload := sdktranslator.TranslateRequest(from, to, req.Model, bytes.Clone(req.Payload), true)
|
||||||
basePayload = applyThinkingMetadataCLI(basePayload, req.Metadata, req.Model)
|
basePayload = applyThinkingMetadataCLI(basePayload, req.Metadata, req.Model)
|
||||||
|
basePayload = util.ApplyDefaultThinkingIfNeededCLI(req.Model, basePayload)
|
||||||
basePayload = util.NormalizeGeminiCLIThinkingBudget(req.Model, basePayload)
|
basePayload = util.NormalizeGeminiCLIThinkingBudget(req.Model, basePayload)
|
||||||
basePayload = util.StripThinkingConfigIfUnsupported(req.Model, basePayload)
|
basePayload = util.StripThinkingConfigIfUnsupported(req.Model, basePayload)
|
||||||
basePayload = fixGeminiCLIImageAspectRatio(req.Model, basePayload)
|
basePayload = fixGeminiCLIImageAspectRatio(req.Model, basePayload)
|
||||||
|
|||||||
@@ -80,6 +80,7 @@ func (e *GeminiExecutor) Execute(ctx context.Context, auth *cliproxyauth.Auth, r
|
|||||||
to := sdktranslator.FromString("gemini")
|
to := sdktranslator.FromString("gemini")
|
||||||
body := sdktranslator.TranslateRequest(from, to, req.Model, bytes.Clone(req.Payload), false)
|
body := sdktranslator.TranslateRequest(from, to, req.Model, bytes.Clone(req.Payload), false)
|
||||||
body = applyThinkingMetadata(body, req.Metadata, req.Model)
|
body = applyThinkingMetadata(body, req.Metadata, req.Model)
|
||||||
|
body = util.ApplyDefaultThinkingIfNeeded(req.Model, body)
|
||||||
body = util.NormalizeGeminiThinkingBudget(req.Model, body)
|
body = util.NormalizeGeminiThinkingBudget(req.Model, body)
|
||||||
body = util.StripThinkingConfigIfUnsupported(req.Model, body)
|
body = util.StripThinkingConfigIfUnsupported(req.Model, body)
|
||||||
body = fixGeminiImageAspectRatio(req.Model, body)
|
body = fixGeminiImageAspectRatio(req.Model, body)
|
||||||
@@ -170,6 +171,7 @@ func (e *GeminiExecutor) ExecuteStream(ctx context.Context, auth *cliproxyauth.A
|
|||||||
to := sdktranslator.FromString("gemini")
|
to := sdktranslator.FromString("gemini")
|
||||||
body := sdktranslator.TranslateRequest(from, to, req.Model, bytes.Clone(req.Payload), true)
|
body := sdktranslator.TranslateRequest(from, to, req.Model, bytes.Clone(req.Payload), true)
|
||||||
body = applyThinkingMetadata(body, req.Metadata, req.Model)
|
body = applyThinkingMetadata(body, req.Metadata, req.Model)
|
||||||
|
body = util.ApplyDefaultThinkingIfNeeded(req.Model, body)
|
||||||
body = util.NormalizeGeminiThinkingBudget(req.Model, body)
|
body = util.NormalizeGeminiThinkingBudget(req.Model, body)
|
||||||
body = util.StripThinkingConfigIfUnsupported(req.Model, body)
|
body = util.StripThinkingConfigIfUnsupported(req.Model, body)
|
||||||
body = fixGeminiImageAspectRatio(req.Model, body)
|
body = fixGeminiImageAspectRatio(req.Model, body)
|
||||||
|
|||||||
@@ -296,6 +296,7 @@ func (e *GeminiVertexExecutor) executeWithServiceAccount(ctx context.Context, au
|
|||||||
}
|
}
|
||||||
body = util.ApplyGeminiThinkingConfig(body, budgetOverride, includeOverride)
|
body = util.ApplyGeminiThinkingConfig(body, budgetOverride, includeOverride)
|
||||||
}
|
}
|
||||||
|
body = util.ApplyDefaultThinkingIfNeeded(req.Model, body)
|
||||||
body = util.NormalizeGeminiThinkingBudget(req.Model, body)
|
body = util.NormalizeGeminiThinkingBudget(req.Model, body)
|
||||||
body = util.StripThinkingConfigIfUnsupported(req.Model, body)
|
body = util.StripThinkingConfigIfUnsupported(req.Model, body)
|
||||||
body = fixGeminiImageAspectRatio(req.Model, body)
|
body = fixGeminiImageAspectRatio(req.Model, body)
|
||||||
@@ -392,6 +393,7 @@ func (e *GeminiVertexExecutor) executeWithAPIKey(ctx context.Context, auth *clip
|
|||||||
}
|
}
|
||||||
body = util.ApplyGeminiThinkingConfig(body, budgetOverride, includeOverride)
|
body = util.ApplyGeminiThinkingConfig(body, budgetOverride, includeOverride)
|
||||||
}
|
}
|
||||||
|
body = util.ApplyDefaultThinkingIfNeeded(req.Model, body)
|
||||||
body = util.NormalizeGeminiThinkingBudget(req.Model, body)
|
body = util.NormalizeGeminiThinkingBudget(req.Model, body)
|
||||||
body = util.StripThinkingConfigIfUnsupported(req.Model, body)
|
body = util.StripThinkingConfigIfUnsupported(req.Model, body)
|
||||||
body = fixGeminiImageAspectRatio(req.Model, body)
|
body = fixGeminiImageAspectRatio(req.Model, body)
|
||||||
@@ -489,6 +491,7 @@ func (e *GeminiVertexExecutor) executeStreamWithServiceAccount(ctx context.Conte
|
|||||||
}
|
}
|
||||||
body = util.ApplyGeminiThinkingConfig(body, budgetOverride, includeOverride)
|
body = util.ApplyGeminiThinkingConfig(body, budgetOverride, includeOverride)
|
||||||
}
|
}
|
||||||
|
body = util.ApplyDefaultThinkingIfNeeded(req.Model, body)
|
||||||
body = util.NormalizeGeminiThinkingBudget(req.Model, body)
|
body = util.NormalizeGeminiThinkingBudget(req.Model, body)
|
||||||
body = util.StripThinkingConfigIfUnsupported(req.Model, body)
|
body = util.StripThinkingConfigIfUnsupported(req.Model, body)
|
||||||
body = fixGeminiImageAspectRatio(req.Model, body)
|
body = fixGeminiImageAspectRatio(req.Model, body)
|
||||||
@@ -602,6 +605,7 @@ func (e *GeminiVertexExecutor) executeStreamWithAPIKey(ctx context.Context, auth
|
|||||||
}
|
}
|
||||||
body = util.ApplyGeminiThinkingConfig(body, budgetOverride, includeOverride)
|
body = util.ApplyGeminiThinkingConfig(body, budgetOverride, includeOverride)
|
||||||
}
|
}
|
||||||
|
body = util.ApplyDefaultThinkingIfNeeded(req.Model, body)
|
||||||
body = util.NormalizeGeminiThinkingBudget(req.Model, body)
|
body = util.NormalizeGeminiThinkingBudget(req.Model, body)
|
||||||
body = util.StripThinkingConfigIfUnsupported(req.Model, body)
|
body = util.StripThinkingConfigIfUnsupported(req.Model, body)
|
||||||
body = fixGeminiImageAspectRatio(req.Model, body)
|
body = fixGeminiImageAspectRatio(req.Model, body)
|
||||||
|
|||||||
@@ -102,15 +102,6 @@ func ConvertOpenAIRequestToAntigravity(modelName string, inputRawJSON []byte, _
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For gemini-3-pro-preview, always send default thinkingConfig when none specified.
|
|
||||||
// This matches the official Gemini CLI behavior which always sends:
|
|
||||||
// { thinkingBudget: -1, includeThoughts: true }
|
|
||||||
// See: ai-gemini-cli/packages/core/src/config/defaultModelConfigs.ts
|
|
||||||
if !gjson.GetBytes(out, "request.generationConfig.thinkingConfig").Exists() && modelName == "gemini-3-pro-preview" {
|
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.thinkingBudget", -1)
|
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.include_thoughts", true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temperature/top_p/top_k/max_tokens
|
// Temperature/top_p/top_k/max_tokens
|
||||||
if tr := gjson.GetBytes(rawJSON, "temperature"); tr.Exists() && tr.Type == gjson.Number {
|
if tr := gjson.GetBytes(rawJSON, "temperature"); tr.Exists() && tr.Type == gjson.Number {
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.temperature", tr.Num)
|
out, _ = sjson.SetBytes(out, "request.generationConfig.temperature", tr.Num)
|
||||||
|
|||||||
@@ -88,15 +88,6 @@ func ConvertOpenAIRequestToGeminiCLI(modelName string, inputRawJSON []byte, _ bo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For gemini-3-pro-preview, always send default thinkingConfig when none specified.
|
|
||||||
// This matches the official Gemini CLI behavior which always sends:
|
|
||||||
// { thinkingBudget: -1, includeThoughts: true }
|
|
||||||
// See: ai-gemini-cli/packages/core/src/config/defaultModelConfigs.ts
|
|
||||||
if !gjson.GetBytes(out, "request.generationConfig.thinkingConfig").Exists() && modelName == "gemini-3-pro-preview" {
|
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.thinkingBudget", -1)
|
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.include_thoughts", true)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Temperature/top_p/top_k
|
// Temperature/top_p/top_k
|
||||||
if tr := gjson.GetBytes(rawJSON, "temperature"); tr.Exists() && tr.Type == gjson.Number {
|
if tr := gjson.GetBytes(rawJSON, "temperature"); tr.Exists() && tr.Type == gjson.Number {
|
||||||
out, _ = sjson.SetBytes(out, "request.generationConfig.temperature", tr.Num)
|
out, _ = sjson.SetBytes(out, "request.generationConfig.temperature", tr.Num)
|
||||||
|
|||||||
@@ -437,16 +437,6 @@ func ConvertOpenAIResponsesRequestToGemini(modelName string, inputRawJSON []byte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For gemini-3-pro-preview, always send default thinkingConfig when none specified.
|
|
||||||
// This matches the official Gemini CLI behavior which always sends:
|
|
||||||
// { thinkingBudget: -1, includeThoughts: true }
|
|
||||||
// See: ai-gemini-cli/packages/core/src/config/defaultModelConfigs.ts
|
|
||||||
if !gjson.Get(out, "generationConfig.thinkingConfig").Exists() && modelName == "gemini-3-pro-preview" {
|
|
||||||
out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingBudget", -1)
|
|
||||||
out, _ = sjson.Set(out, "generationConfig.thinkingConfig.include_thoughts", true)
|
|
||||||
// log.Debugf("Applied default thinkingConfig for gemini-3-pro-preview (matches Gemini CLI): thinkingBudget=-1, include_thoughts=true")
|
|
||||||
}
|
|
||||||
|
|
||||||
result := []byte(out)
|
result := []byte(out)
|
||||||
result = common.AttachDefaultSafetySettings(result, "safetySettings")
|
result = common.AttachDefaultSafetySettings(result, "safetySettings")
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -207,6 +207,47 @@ func GeminiThinkingFromMetadata(metadata map[string]any) (*int, *bool, bool) {
|
|||||||
return budgetPtr, includePtr, matched
|
return budgetPtr, includePtr, matched
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// modelsWithDefaultThinking lists models that should have thinking enabled by default
|
||||||
|
// when no explicit thinkingConfig is provided.
|
||||||
|
var modelsWithDefaultThinking = map[string]bool{
|
||||||
|
"gemini-3-pro-preview": true,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModelHasDefaultThinking returns true if the model should have thinking enabled by default.
|
||||||
|
func ModelHasDefaultThinking(model string) bool {
|
||||||
|
return modelsWithDefaultThinking[model]
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyDefaultThinkingIfNeeded injects default thinkingConfig for models that require it.
|
||||||
|
// For standard Gemini API format (generationConfig.thinkingConfig path).
|
||||||
|
// Returns the modified body if thinkingConfig was added, otherwise returns the original.
|
||||||
|
func ApplyDefaultThinkingIfNeeded(model string, body []byte) []byte {
|
||||||
|
if !ModelHasDefaultThinking(model) {
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
if gjson.GetBytes(body, "generationConfig.thinkingConfig").Exists() {
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
updated, _ := sjson.SetBytes(body, "generationConfig.thinkingConfig.thinkingBudget", -1)
|
||||||
|
updated, _ = sjson.SetBytes(updated, "generationConfig.thinkingConfig.include_thoughts", true)
|
||||||
|
return updated
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApplyDefaultThinkingIfNeededCLI injects default thinkingConfig for models that require it.
|
||||||
|
// For Gemini CLI API format (request.generationConfig.thinkingConfig path).
|
||||||
|
// Returns the modified body if thinkingConfig was added, otherwise returns the original.
|
||||||
|
func ApplyDefaultThinkingIfNeededCLI(model string, body []byte) []byte {
|
||||||
|
if !ModelHasDefaultThinking(model) {
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
if gjson.GetBytes(body, "request.generationConfig.thinkingConfig").Exists() {
|
||||||
|
return body
|
||||||
|
}
|
||||||
|
updated, _ := sjson.SetBytes(body, "request.generationConfig.thinkingConfig.thinkingBudget", -1)
|
||||||
|
updated, _ = sjson.SetBytes(updated, "request.generationConfig.thinkingConfig.include_thoughts", true)
|
||||||
|
return updated
|
||||||
|
}
|
||||||
|
|
||||||
// StripThinkingConfigIfUnsupported removes thinkingConfig from the request body
|
// StripThinkingConfigIfUnsupported removes thinkingConfig from the request body
|
||||||
// when the target model does not advertise Thinking capability. It cleans both
|
// when the target model does not advertise Thinking capability. It cleans both
|
||||||
// standard Gemini and Gemini CLI JSON envelopes. This acts as a final safety net
|
// standard Gemini and Gemini CLI JSON envelopes. This acts as a final safety net
|
||||||
|
|||||||
Reference in New Issue
Block a user