-
-
Notifications
You must be signed in to change notification settings - Fork 299
fix(gemini): use thinkingLevel instead of thinkingBudget for Gemini 3… #359
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -48,16 +48,30 @@ func ConvertOpenAIRequestToAntigravity(modelName string, inputRawJSON []byte, _ | |
| out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.thinkingBudget", -1) | ||
| out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.include_thoughts", true) | ||
| case "low": | ||
| out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.thinkingBudget", util.NormalizeThinkingBudget(modelName, 1024)) | ||
| if util.IsGemini3Model(modelName) { | ||
| out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.thinkingLevel", "low") | ||
| } else { | ||
| out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.thinkingBudget", util.NormalizeThinkingBudget(modelName, 1024)) | ||
| } | ||
| out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.include_thoughts", true) | ||
| case "medium": | ||
| out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.thinkingBudget", util.NormalizeThinkingBudget(modelName, 8192)) | ||
| if !util.IsGemini3Model(modelName) { | ||
| out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.thinkingBudget", util.NormalizeThinkingBudget(modelName, 8192)) | ||
| } | ||
| // Gemini 3: no thinkingLevel for medium, uses dynamic thinking (auto) | ||
| out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.include_thoughts", true) | ||
| case "high": | ||
| out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.thinkingBudget", util.NormalizeThinkingBudget(modelName, 32768)) | ||
| if util.IsGemini3Model(modelName) { | ||
| out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.thinkingLevel", "high") | ||
| } else { | ||
| out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.thinkingBudget", util.NormalizeThinkingBudget(modelName, 32768)) | ||
| } | ||
| out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.include_thoughts", true) | ||
| default: | ||
| out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.thinkingBudget", -1) | ||
| if !util.IsGemini3Model(modelName) { | ||
| out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.thinkingBudget", -1) | ||
| } | ||
| // Gemini 3: no thinkingLevel for auto/default, uses dynamic thinking | ||
| out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.include_thoughts", true) | ||
| } | ||
|
Comment on lines
50
to
76
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The logic within these Consider extracting this duplicated logic into a shared helper function in a common package like |
||
| } | ||
|
|
@@ -88,12 +102,10 @@ 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) | ||
| // For Gemini 3 models, enable thought summaries when no thinkingConfig is specified. | ||
| // Don't set thinkingLevel - let API use dynamic thinking by default. | ||
| // See: https://ai.google.dev/gemini-api/docs/thinking#thinking-levels | ||
| if !gjson.GetBytes(out, "request.generationConfig.thinkingConfig").Exists() && util.IsGemini3Model(modelName) { | ||
| out, _ = sjson.SetBytes(out, "request.generationConfig.thinkingConfig.include_thoughts", true) | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -398,19 +398,37 @@ func ConvertOpenAIResponsesRequestToGemini(modelName string, inputRawJSON []byte | |
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingBudget", -1) | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.include_thoughts", true) | ||
| case "minimal": | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingBudget", util.NormalizeThinkingBudget(modelName, 1024)) | ||
| if util.IsGemini3Model(modelName) { | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingLevel", "low") | ||
| } else { | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingBudget", util.NormalizeThinkingBudget(modelName, 1024)) | ||
| } | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.include_thoughts", true) | ||
| case "low": | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingBudget", util.NormalizeThinkingBudget(modelName, 4096)) | ||
| if util.IsGemini3Model(modelName) { | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingLevel", "low") | ||
| } else { | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingBudget", util.NormalizeThinkingBudget(modelName, 4096)) | ||
| } | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.include_thoughts", true) | ||
|
Comment on lines
400
to
413
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The case "minimal", "low":
if util.IsGemini3Model(modelName) {
out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingLevel", "low")
} else {
budget := 1024
if reasoningEffort.String() == "low" {
budget = 4096
}
out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingBudget", util.NormalizeThinkingBudget(modelName, budget))
}
out, _ = sjson.Set(out, "generationConfig.thinkingConfig.include_thoughts", true) |
||
| case "medium": | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingBudget", util.NormalizeThinkingBudget(modelName, 8192)) | ||
| if !util.IsGemini3Model(modelName) { | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingBudget", util.NormalizeThinkingBudget(modelName, 8192)) | ||
| } | ||
| // Gemini 3: no thinkingLevel for medium, uses dynamic thinking (auto) | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.include_thoughts", true) | ||
| case "high": | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingBudget", util.NormalizeThinkingBudget(modelName, 32768)) | ||
| if util.IsGemini3Model(modelName) { | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingLevel", "high") | ||
| } else { | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingBudget", util.NormalizeThinkingBudget(modelName, 32768)) | ||
| } | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.include_thoughts", true) | ||
| default: | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingBudget", -1) | ||
| if !util.IsGemini3Model(modelName) { | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.thinkingBudget", -1) | ||
| } | ||
| // Gemini 3: no thinkingLevel for auto/default, uses dynamic thinking | ||
| out, _ = sjson.Set(out, "generationConfig.thinkingConfig.include_thoughts", true) | ||
| } | ||
| } | ||
|
|
@@ -435,14 +453,11 @@ 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) | ||
| // For Gemini 3 models, enable thought summaries when no thinkingConfig is specified. | ||
| // Don't set thinkingLevel - let API use dynamic thinking by default. | ||
| // See: https://ai.google.dev/gemini-api/docs/thinking#thinking-levels | ||
| if !gjson.Get(out, "generationConfig.thinkingConfig").Exists() && util.IsGemini3Model(modelName) { | ||
| 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) | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -259,3 +259,9 @@ func ConvertThinkingLevelToBudget(body []byte) []byte { | |||||
| } | ||||||
| return updated | ||||||
| } | ||||||
|
|
||||||
| // IsGemini3Model returns true if the model is a Gemini 3 model (uses thinkingLevel instead of thinkingBudget). | ||||||
| func IsGemini3Model(model string) bool { | ||||||
| lower := strings.ToLower(model) | ||||||
| return strings.HasPrefix(lower, "gemini-3-") | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The string literal Example: const Gemini3ModelPrefix = "gemini-3-"
Suggested change
|
||||||
| } | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The string literals
"low"(line 52) and"high"(line 65) forthinkingLevelare magic strings. It's good practice to define these as constants in a shared package (e.g.,util) to ensure consistency and prevent typos. This issue is also present in the other translator files modified in this PR.Example:
You could then use
util.ThinkingLevelLowandutil.ThinkingLevelHigh.