fix(gemini): switch thinking default logic (#50841)
Co-authored-by: Aiden Cline <aidenpcline@gmail.com>
This commit is contained in:
parent
7cb044ee89
commit
610df0b566
2 changed files with 131 additions and 12 deletions
|
|
@ -517,8 +517,11 @@ export function message(msgs: ModelMessage[], model: Provider.Model, options: Re
|
|||
return msgs
|
||||
}
|
||||
|
||||
const GEMINI_2_5_RE = /gemini-2[.-]5(?:[.-]|$)/i
|
||||
const GEMINI_LEGACY_RE = /gemini-(?:(?:flash|pro)-)?[12](?:[.-]|$)/i
|
||||
|
||||
const GEMINI_MODELS_WITH_SAMPLING_DEFAULTS = [
|
||||
/gemini-2[.-]5(?:[.-]|$)/,
|
||||
GEMINI_2_5_RE,
|
||||
/gemini-3-(?:flash|pro)(?:[.-]|$)/,
|
||||
/gemini-3[.-]1(?:[.-]|$)/,
|
||||
/gemini-3[.-]5-flash(?!-lite)(?:[.-]|$)/,
|
||||
|
|
@ -735,9 +738,19 @@ function anthropicBlockBinding(model: Provider.Model, options: { [x: string]: an
|
|||
return options
|
||||
}
|
||||
|
||||
function isLegacyGemini(apiId: string) {
|
||||
return GEMINI_LEGACY_RE.test(apiId)
|
||||
}
|
||||
|
||||
function isGemini25(apiId: string) {
|
||||
return GEMINI_2_5_RE.test(apiId)
|
||||
}
|
||||
|
||||
function googleThinkingLevelEfforts(apiId: string) {
|
||||
const id = apiId.toLowerCase()
|
||||
if (!id.includes("gemini-3")) return ["low", "high"]
|
||||
// Gemma 4 only toggles thinking: "minimal" disables it and "high" enables it.
|
||||
if (id.includes("gemma")) return ["minimal", "high"]
|
||||
if (isLegacyGemini(id)) return ["low", "high"]
|
||||
if (id.includes("flash-image")) return ["minimal", "high"]
|
||||
if (id.includes("pro-image")) return ["high"]
|
||||
if (id.includes("flash")) return ["minimal", "low", "medium", "high"]
|
||||
|
|
@ -746,7 +759,7 @@ function googleThinkingLevelEfforts(apiId: string) {
|
|||
|
||||
function googleThinkingBudgetMax(apiId: string) {
|
||||
const id = apiId.toLowerCase()
|
||||
if (id.includes("2.5") && id.includes("pro") && !id.includes("flash")) return 32_768
|
||||
if (isGemini25(id) && id.includes("pro") && !id.includes("flash")) return 32_768
|
||||
return 24_576
|
||||
}
|
||||
|
||||
|
|
@ -758,7 +771,7 @@ function wrapInSapModelParams(variants: Record<string, Record<string, any>>): Re
|
|||
|
||||
function googleThinkingVariants(model: Provider.Model): Record<string, Record<string, any>> {
|
||||
const id = model.api.id.toLowerCase()
|
||||
if (id.includes("2.5")) {
|
||||
if (isGemini25(id)) {
|
||||
return {
|
||||
high: { thinkingConfig: { includeThoughts: true, thinkingBudget: 16000 } },
|
||||
max: {
|
||||
|
|
@ -912,7 +925,7 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
|
|||
}
|
||||
}
|
||||
if (model.api.id.includes("google")) {
|
||||
if (model.api.id.includes("2.5")) {
|
||||
if (isGemini25(model.api.id)) {
|
||||
return {
|
||||
high: {
|
||||
thinkingConfig: {
|
||||
|
|
@ -1189,7 +1202,7 @@ export function variants(model: Provider.Model): Record<string, Record<string, a
|
|||
max: { thinking: { type: "enabled", budget_tokens: 31999 } },
|
||||
})
|
||||
}
|
||||
if (id.includes("gemini") && id.includes("2.5")) {
|
||||
if (isGemini25(id) || isGemini25(model.api.id)) {
|
||||
return wrapInSapModelParams(googleThinkingVariants(model))
|
||||
}
|
||||
if (id.includes("gpt") || /\bo[1-9]/.test(id)) {
|
||||
|
|
@ -1237,7 +1250,7 @@ export function options(input: {
|
|||
result["usage"] = {
|
||||
include: true,
|
||||
}
|
||||
if (input.model.api.id.includes("gemini-3")) {
|
||||
if (input.model.api.id.toLowerCase().includes("gemini") && !isLegacyGemini(input.model.api.id)) {
|
||||
result["reasoning"] = { effort: "high" }
|
||||
}
|
||||
}
|
||||
|
|
@ -1269,7 +1282,7 @@ export function options(input: {
|
|||
result["thinkingConfig"] = {
|
||||
includeThoughts: true,
|
||||
}
|
||||
if (input.model.api.id.includes("gemini-3")) {
|
||||
if (!isLegacyGemini(input.model.api.id)) {
|
||||
result["thinkingConfig"]["thinkingLevel"] = "high"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -393,16 +393,20 @@ describe("ProviderTransform.options - minimax m3 thinking", () => {
|
|||
describe("ProviderTransform.options - google thinkingConfig gating", () => {
|
||||
const sessionID = "test-session-123"
|
||||
|
||||
const createGoogleModel = (reasoning: boolean, npm: "@ai-sdk/google" | "@ai-sdk/google-vertex") =>
|
||||
const createGoogleModel = (
|
||||
reasoning: boolean,
|
||||
npm: "@ai-sdk/google" | "@ai-sdk/google-vertex",
|
||||
apiId = "gemini-2.0-flash",
|
||||
) =>
|
||||
({
|
||||
id: `${npm === "@ai-sdk/google" ? "google" : "google-vertex"}/gemini-2.0-flash`,
|
||||
id: `${npm === "@ai-sdk/google" ? "google" : "google-vertex"}/${apiId}`,
|
||||
providerID: npm === "@ai-sdk/google" ? "google" : "google-vertex",
|
||||
api: {
|
||||
id: "gemini-2.0-flash",
|
||||
id: apiId,
|
||||
url: npm === "@ai-sdk/google" ? "https://generativelanguage.googleapis.com" : "https://vertexai.googleapis.com",
|
||||
npm,
|
||||
},
|
||||
name: "Gemini 2.0 Flash",
|
||||
name: apiId,
|
||||
capabilities: {
|
||||
temperature: true,
|
||||
reasoning,
|
||||
|
|
@ -454,6 +458,73 @@ describe("ProviderTransform.options - google thinkingConfig gating", () => {
|
|||
})
|
||||
expect(result.thinkingConfig).toBeUndefined()
|
||||
})
|
||||
|
||||
test.each(["gemini-1.5-pro", "gemini-2.0-flash", "gemini-2.5-pro", "gemini-2.5-flash"])(
|
||||
"omits default thinkingLevel for legacy model %s",
|
||||
(apiId) => {
|
||||
for (const npm of ["@ai-sdk/google", "@ai-sdk/google-vertex"] as const) {
|
||||
const result = ProviderTransform.options({
|
||||
model: createGoogleModel(true, npm, apiId),
|
||||
sessionID,
|
||||
providerOptions: {},
|
||||
})
|
||||
expect(result.thinkingConfig).toEqual({
|
||||
includeThoughts: true,
|
||||
})
|
||||
}
|
||||
|
||||
const openrouterResult = ProviderTransform.options({
|
||||
model: {
|
||||
...createGoogleModel(true, "@ai-sdk/google", `google/${apiId}`),
|
||||
providerID: "openrouter",
|
||||
api: {
|
||||
id: `google/${apiId}`,
|
||||
url: "https://openrouter.ai/api/v1",
|
||||
npm: "@openrouter/ai-sdk-provider",
|
||||
},
|
||||
},
|
||||
sessionID,
|
||||
providerOptions: {},
|
||||
})
|
||||
expect(openrouterResult.reasoning).toBeUndefined()
|
||||
},
|
||||
)
|
||||
|
||||
test.each([
|
||||
"gemini-3-pro-preview",
|
||||
"gemini-3-flash-preview",
|
||||
"gemini-9-pro",
|
||||
"gemini-9-flash",
|
||||
"gemini-pro-latest",
|
||||
"gemini-flash-latest",
|
||||
])("sets default thinkingLevel=high and OpenRouter reasoning effort=high for %s", (apiId) => {
|
||||
for (const npm of ["@ai-sdk/google", "@ai-sdk/google-vertex"] as const) {
|
||||
const result = ProviderTransform.options({
|
||||
model: createGoogleModel(true, npm, apiId),
|
||||
sessionID,
|
||||
providerOptions: {},
|
||||
})
|
||||
expect(result.thinkingConfig).toEqual({
|
||||
includeThoughts: true,
|
||||
thinkingLevel: "high",
|
||||
})
|
||||
}
|
||||
|
||||
const openrouterResult = ProviderTransform.options({
|
||||
model: {
|
||||
...createGoogleModel(true, "@ai-sdk/google", `google/${apiId}`),
|
||||
providerID: "openrouter",
|
||||
api: {
|
||||
id: `google/${apiId}`,
|
||||
url: "https://openrouter.ai/api/v1",
|
||||
npm: "@openrouter/ai-sdk-provider",
|
||||
},
|
||||
},
|
||||
sessionID,
|
||||
providerOptions: {},
|
||||
})
|
||||
expect(openrouterResult.reasoning).toEqual({ effort: "high" })
|
||||
})
|
||||
})
|
||||
|
||||
describe("ProviderTransform.options - gpt-5 textVerbosity", () => {
|
||||
|
|
@ -5651,6 +5722,16 @@ describe("ProviderTransform.variants", () => {
|
|||
]) {
|
||||
describe(provider.name, () => {
|
||||
for (const testCase of [
|
||||
{
|
||||
apiId: "gemini-1.5-pro",
|
||||
efforts: ["low", "high"],
|
||||
expectedHigh: { thinkingConfig: { includeThoughts: true, thinkingLevel: "high" } },
|
||||
},
|
||||
{
|
||||
apiId: "gemini-2.0-flash",
|
||||
efforts: ["low", "high"],
|
||||
expectedHigh: { thinkingConfig: { includeThoughts: true, thinkingLevel: "high" } },
|
||||
},
|
||||
{
|
||||
apiId: "gemini-2.5-pro",
|
||||
efforts: ["high", "max"],
|
||||
|
|
@ -5693,6 +5774,31 @@ describe("ProviderTransform.variants", () => {
|
|||
efforts: ["high"],
|
||||
expectedHigh: { thinkingConfig: { includeThoughts: true, thinkingLevel: "high" } },
|
||||
},
|
||||
{
|
||||
apiId: "gemini-9-pro",
|
||||
efforts: ["low", "medium", "high"],
|
||||
expectedHigh: { thinkingConfig: { includeThoughts: true, thinkingLevel: "high" } },
|
||||
},
|
||||
{
|
||||
apiId: "gemini-9-flash",
|
||||
efforts: ["minimal", "low", "medium", "high"],
|
||||
expectedHigh: { thinkingConfig: { includeThoughts: true, thinkingLevel: "high" } },
|
||||
},
|
||||
{
|
||||
apiId: "gemini-pro-latest",
|
||||
efforts: ["low", "medium", "high"],
|
||||
expectedHigh: { thinkingConfig: { includeThoughts: true, thinkingLevel: "high" } },
|
||||
},
|
||||
{
|
||||
apiId: "gemini-flash-latest",
|
||||
efforts: ["minimal", "low", "medium", "high"],
|
||||
expectedHigh: { thinkingConfig: { includeThoughts: true, thinkingLevel: "high" } },
|
||||
},
|
||||
{
|
||||
apiId: "gemma-4-31b-it",
|
||||
efforts: ["minimal", "high"],
|
||||
expectedHigh: { thinkingConfig: { includeThoughts: true, thinkingLevel: "high" } },
|
||||
},
|
||||
]) {
|
||||
test(`${testCase.apiId} returns supported thinking controls`, () => {
|
||||
const result = ProviderTransform.variants(
|
||||
|
|
|
|||
Loading…
Reference in a new issue