Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions packages/opencode/src/provider/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1347,18 +1347,27 @@ export namespace ProviderTransform {
) {
return mergeDeep({ store: false }, small)
}
// altimate_change start — upstream_fix: restore Google minimal thinking for small calls only on reasoning models
// altimate_change start — upstream_fix: use generation-supported Google thinking controls for small reasoning calls
if (
(model.providerID === "google" ||
model.api.npm === "@ai-sdk/google" ||
model.api.npm === "@ai-sdk/google-vertex") &&
model.capabilities.reasoning
) {
const id = model.api.id.toLowerCase()
if (id.includes("gemini-3")) {
// Leading digits after "gemini-", wherever it appears (prefixed, concatenated or dated ids).
const generation = Number(/gemini-(\d+)/.exec(id)?.[1])
if (generation === 3) {
return { thinkingConfig: { thinkingLevel: "minimal" } }
}
return { thinkingConfig: { thinkingBudget: 0 } }
// Gemini 2.x and unversioned aliases (e.g. gemini-flash-latest) keep the budget control.
if (!(generation >= 4)) {
return { thinkingConfig: { thinkingBudget: 0 } }
}
// Gemini 4+ rejects budgets and "minimal"; prefer the lowest configured supported level.
const levels = Object.values(model.variants ?? {}).map((variant) => variant.thinkingConfig?.thinkingLevel)
const thinkingLevel = WIDELY_SUPPORTED_EFFORTS.find((level) => levels.includes(level)) ?? "low"
return { thinkingConfig: { thinkingLevel } }
}
// altimate_change end
if (model.providerID === "openrouter" || model.providerID === "llmgateway") {
Expand Down
49 changes: 49 additions & 0 deletions packages/opencode/test/provider/transform.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,55 @@ describe("ProviderTransform.smallOptions - google thinking", () => {
variants: overrides.variants ?? {},
}) as any

// altimate_change start — small calls must use thinking controls supported by each Gemini generation
for (const provider of [
{ providerID: "google", npm: "@ai-sdk/google" },
{ providerID: "google-vertex", npm: "@ai-sdk/google-vertex" },
] as const) {
for (const testCase of [
{ id: "gemini-2.0-flash", thinkingConfig: { thinkingBudget: 0 } },
{ id: "gemini-2.5-flash", thinkingConfig: { thinkingBudget: 0 } },
{ id: "gemini-3-pro", thinkingConfig: { thinkingLevel: "minimal" } },
{ id: "gemini-3.1-pro", thinkingConfig: { thinkingLevel: "minimal" } },
{ id: "models/gemini-3-pro-preview", thinkingConfig: { thinkingLevel: "minimal" } },
{ id: "vertex_gemini-3pro", thinkingConfig: { thinkingLevel: "minimal" } },
{ id: "vertex_gemini-4argon", thinkingConfig: { thinkingLevel: "low" } },
{ id: "publishers/google/models/gemini-4-argon", thinkingConfig: { thinkingLevel: "low" } },
{ id: "gemini-2.5-flash-lite-preview-06-17", thinkingConfig: { thinkingBudget: 0 } },
{ id: "gemini-4-argon", thinkingConfig: { thinkingLevel: "low" } },
{ id: "gemini-5-pro", thinkingConfig: { thinkingLevel: "low" } },
{ id: "gemini-30-pro", thinkingConfig: { thinkingLevel: "low" } },
{ id: "gemini-flash-latest", thinkingConfig: { thinkingBudget: 0 } },
]) {
for (const configured of [false, true]) {
test(`${provider.providerID} ${testCase.id} uses supported small thinking controls with ${configured ? "generated" : "empty"} variants`, () => {
const model = createGoogleModel(testCase.id, provider)
if (configured) model.variants = ProviderTransform.variants(model)

const result = ProviderTransform.smallOptions(model)

expect(result).toEqual({ thinkingConfig: testCase.thinkingConfig })
if (testCase.thinkingConfig.thinkingLevel) {
expect(result.thinkingConfig).not.toHaveProperty("thinkingBudget")
}
})
}
}

test(`${provider.providerID} uses the lowest configured Gemini 4 thinking level regardless of variant names or order`, () => {
const model = createGoogleModel("gemini-4-argon", {
...provider,
variants: {
detailed: { thinkingConfig: { includeThoughts: true, thinkingLevel: "high" } },
balanced: { thinkingConfig: { includeThoughts: true, thinkingLevel: "medium" } },
},
})

expect(ProviderTransform.smallOptions(model)).toEqual({ thinkingConfig: { thinkingLevel: "medium" } })
})
}
// altimate_change end

test("disables Gemini 2.5 thinking budget for small calls even when high is the first variant", () => {
const result = ProviderTransform.smallOptions(
createGoogleModel("gemini-2.5-pro", {
Expand Down
Loading