Repository navigation
fix(antigravity): default includeThoughts for modern Gemini models - #4180
Conversation
Gemini 2.5+ models always have thinking capability, but the translator only set includeThoughts when the client explicitly requested it via reasoning_effort or thinking.type. Without this flag, the upstream does not mark thought parts with thought:true, so the response translator cannot route reasoning to reasoning_content — the model's internal reasoning leaks into visible content instead. This is especially problematic for smaller models (e.g. gemini-3.5-flash) that tend to reason extensively about tool names and instructions when their reasoning has no separate channel. Fix: set thinkingConfig with includeThoughts:true by default for all Gemini models except legacy 1.x and 2.0 (which lack thinking). Uses getDefaultThinkingBudget(model) with a 24576 fallback.
There was a problem hiding this comment.
Code Review
This pull request introduces default thinking capability configuration for modern Gemini models (2.5+) in open-sse/translator/request/openai-to-gemini.ts to prevent reasoning leakage. The review feedback highlights a style guide violation for missing tests, an issue with the exclusion logic that incorrectly filters out gemini-2.0-flash-thinking-exp, and a recommendation to wrap the fallback thinking budget in capThinkingBudget to prevent potential API errors.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| // 3. Default: all modern Gemini models (2.5+) have thinking capability. | ||
| // If the client didn't explicitly request thinking (via reasoning_effort or | ||
| // thinking.type), still set includeThoughts so the upstream marks thought | ||
| // parts with thought:true. Without this, the model's reasoning leaks into | ||
| // visible content instead of being routed to reasoning_content by the | ||
| // response translator. (#4170) |
There was a problem hiding this comment.
According to the Repository Style Guide (Rule 2.9), tests must always be included when changing production code under open-sse/. Since this PR modifies open-sse/translator/request/openai-to-gemini.ts but does not include any test changes, it violates this rule.
Please add a test case to tests/fixtures/translation/openai-to-gemini.json to verify that the default thinkingConfig is correctly applied to modern Gemini models. For example:
{
"name": "openai-to-gemini/modern-gemini-default-thinking",
"sourceFormat": "openai",
"targetFormat": "gemini",
"input": {
"model": "gemini-2.5-flash",
"messages": [{ "role": "user", "content": "Hello Gemini!" }]
}
}References
- Always include tests when changing production code (src/, open-sse/, electron/, bin/). (link)
| if ( | ||
| modelLower.includes("gemini") && | ||
| !modelLower.includes("gemini-1") && | ||
| !modelLower.includes("gemini-2.0") | ||
| ) { |
There was a problem hiding this comment.
The current exclusion logic !modelLower.includes("gemini-2.0") will incorrectly exclude gemini-2.0-flash-thinking-exp, which is a valid thinking model and should have includeThoughts: true enabled by default to prevent reasoning leakage.
We should update the condition to allow models that explicitly contain thinking even if they are in the gemini-2.0 family.
| if ( | |
| modelLower.includes("gemini") && | |
| !modelLower.includes("gemini-1") && | |
| !modelLower.includes("gemini-2.0") | |
| ) { | |
| if ( | |
| modelLower.includes("gemini") && | |
| !modelLower.includes("gemini-1") && | |
| (!modelLower.includes("gemini-2.0") || modelLower.includes("thinking")) | |
| ) { |
| result.generationConfig.thinkingConfig = { | ||
| thinkingBudget: getDefaultThinkingBudget(model) || 24576, | ||
| includeThoughts: true, | ||
| }; |
There was a problem hiding this comment.
To prevent potential 400 Bad Request errors from the Gemini API if a model has a lower thinking budget cap than 24576, we should wrap the fallback budget in capThinkingBudget(model, 24576). This ensures the fallback budget is always safe and within the model's capabilities.
| result.generationConfig.thinkingConfig = { | |
| thinkingBudget: getDefaultThinkingBudget(model) || 24576, | |
| includeThoughts: true, | |
| }; | |
| result.generationConfig.thinkingConfig = { | |
| thinkingBudget: getDefaultThinkingBudget(model) || capThinkingBudget(model, 24576), | |
| includeThoughts: true, | |
| }; |
…ion, test - Wrap fallback budget in capThinkingBudget(model, 24576) to prevent 400 errors for models with lower caps - Allow gemini-2.0-flash-thinking-exp (and similar) through the exclusion by checking for 'thinking' in the model name - Add test fixture for default thinkingConfig on modern Gemini models
|
Hi @gemini-code-assist, thanks for the review. All three points addressed in
|
|
Thanks for the updates, @dhaern. These changes look excellent and correctly address the points raised. The inclusion of the test fixture and the refinement of the thinking budget logic ensure both correctness and robustness for modern Gemini models. The PR is in great shape. |
…ludeThoughts The default-includeThoughts change for modern Gemini (2.5+) alters the openai->gemini output, so the existing golden snapshots basic-chat (gemini-2.5-flash) and with-system (gemini-2.5-pro) now carry the injected thinkingConfig, and the new modern-gemini-default-thinking snapshot (its fixture case was added but its snapshot was not committed) is included. 61/61 translator + golden tests pass. Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
89cd954
into
cheaper-inference:release/v3.8.29
|
Merged into |
…iscovery (#3931 bug 3, #3737) (#4185) Integrated into release/v3.8.29 — add moonshotai/kimi-k2.7-code to the kmca (kimi-coding-apikey) catalog (KIMI_CODING_SHARED.models), requested in discussion #3737. On resync: the PR's qwen-web PROVIDER_MODELS_CONFIG addition (issue #3931 bug #3) was already shipped by #4172 — dropped the duplicate, kept release's entry (which has the Array.isArray guard); kept #4183's KIMI_K27_MODELS spread + added the moonshotai-prefixed entry (union). Also reconciled the file-size baseline for openai-to-gemini.ts (#4180 merged without its +20 bump). Validated: 13/13 tests (kmca catalog + qwen-web parse + kimi registration) + file-size green.
…heaper-inference#4180) Integrated into release/v3.8.29 — default includeThoughts for modern Gemini (2.5+) in the openai->gemini translator, so the model's reasoning is marked thought:true and routed to reasoning_content instead of leaking into visible content (cheaper-inference#4170). Thanks @dhaern! On review we regenerated the gemini golden snapshots (basic-chat/with-system) and committed the new modern-gemini-default-thinking snapshot. 61/61 translator + golden tests pass; eslint clean. Respects explicit client thinking config (only applies when none is set) and excludes gemini-1.x / non-thinking 2.0.
…iscovery (cheaper-inference#3931 bug 3, cheaper-inference#3737) (cheaper-inference#4185) Integrated into release/v3.8.29 — add moonshotai/kimi-k2.7-code to the kmca (kimi-coding-apikey) catalog (KIMI_CODING_SHARED.models), requested in discussion cheaper-inference#3737. On resync: the PR's qwen-web PROVIDER_MODELS_CONFIG addition (issue cheaper-inference#3931 bug cheaper-inference#3) was already shipped by cheaper-inference#4172 — dropped the duplicate, kept release's entry (which has the Array.isArray guard); kept cheaper-inference#4183's KIMI_K27_MODELS spread + added the moonshotai-prefixed entry (union). Also reconciled the file-size baseline for openai-to-gemini.ts (cheaper-inference#4180 merged without its +20 bump). Validated: 13/13 tests (kmca catalog + qwen-web parse + kimi registration) + file-size green.
Problem
Gemini 2.5+ models always have thinking capability, but the translator only set
includeThoughts: truewhen the client explicitly requested it viareasoning_effortorthinking.type.Without this flag, the upstream does not mark thought parts with
thought: truein its response. The response translator (gemini-to-openai.ts) checkspart.thought === trueto route text toreasoning_content— so without the flag, the model's internal reasoning leaks into visiblecontentinstead of being separated intoreasoning_content.This is especially problematic for smaller models (e.g.
gemini-3.5-flash-low) that tend to reason extensively about tool names, instructions, and internal logic when their reasoning has no separate channel. Users see the model's internal deliberation (including echoed system prompt fragments) as regular assistant output.Root Cause
In
openai-to-gemini.ts,thinkingConfigis only set in two cases:reasoning_effort(OpenAI format) → maps to a budget +includeThoughts: truethinking.type: "enabled"(Claude format) → sets budget +includeThoughts: trueIf neither is present (the common case for clients that don't explicitly request thinking), no
thinkingConfigis sent at all, and the upstream treats all output as regular content.Fix
Add a default
thinkingConfigwithincludeThoughts: truefor all modern Gemini models (2.5+) when the client hasn't explicitly requested thinking.Design decisions
gemini-1.x,gemini-2.0) that lack thinking capability. All other Gemini models (2.5+, 3.x, future 4.x) are included automatically.getDefaultThinkingBudget(model)when available, falling back to24576(the highest budget from the 2.5 era). This respects per-model caps while ensuring a sensible default.if (!result.generationConfig.thinkingConfig)ensures thatreasoning_effortandthinking.typestill take precedence.Files changed
open-sse/translator/request/openai-to-gemini.ts(+20 lines)Validation
gemini-3.5-flash-lowandgemini-3.5-flash-highvia Antigravity.tokens.reasoningis now non-zero in call logs (e.g. 483 reasoning tokens for flash-low), indicating the upstream is generating and returning thought parts.glob,grep,read) execute correctly without_idesuffix leaks.<internal_reminder>or internal reasoning echoed in visible content.Compatibility
No breaking changes. Models that previously received no
thinkingConfignow receive a default one, which only affects how the upstream marks thought parts — it does not change the model's behavior or capabilities. Clients that explicitly request thinking are unaffected.