Fix Gemini 3 Flash Preview thinking levels (#212)

* use the correct Gemini 3 Flash Preview thinking levels

* fix a build error

* add changelog entry

* regenerate models

* make less assumptions about future models
This commit is contained in:
Markus Ylisiurunen 2025-12-18 14:03:28 +02:00 committed by GitHub
parent a8b58335c3
commit d690310587
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 35 additions and 11 deletions

10
package-lock.json generated
View file

@ -675,9 +675,9 @@
} }
}, },
"node_modules/@google/genai": { "node_modules/@google/genai": {
"version": "1.31.0", "version": "1.34.0",
"resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.31.0.tgz", "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.34.0.tgz",
"integrity": "sha512-rK0RKXxNkbK35eDl+G651SxtxwHNEOogjyeZJUJe+Ed4yxu3xy5ufCiU0+QLT7xo4M9Spey8OAYfD8LPRlYBKw==", "integrity": "sha512-vu53UMPvjmb7PGzlYu6Tzxso8Dfhn+a7eQFaS2uNemVtDZKwzSpJ5+ikqBbXplF7RGB1STcVDqCkPvquiwb2sw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"google-auth-library": "^10.3.0", "google-auth-library": "^10.3.0",
@ -687,7 +687,7 @@
"node": ">=20.0.0" "node": ">=20.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"@modelcontextprotocol/sdk": "^1.20.1" "@modelcontextprotocol/sdk": "^1.24.0"
}, },
"peerDependenciesMeta": { "peerDependenciesMeta": {
"@modelcontextprotocol/sdk": { "@modelcontextprotocol/sdk": {
@ -6197,7 +6197,7 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@anthropic-ai/sdk": "0.71.2", "@anthropic-ai/sdk": "0.71.2",
"@google/genai": "1.31.0", "@google/genai": "1.34.0",
"@mistralai/mistralai": "1.10.0", "@mistralai/mistralai": "1.10.0",
"@sinclair/typebox": "^0.34.41", "@sinclair/typebox": "^0.34.41",
"ajv": "^8.17.1", "ajv": "^8.17.1",

View file

@ -2,6 +2,10 @@
## [Unreleased] ## [Unreleased]
### Added
- **Gemini 3 Flash thinking support**: Extended thinking level support for Gemini 3 Flash models (MINIMAL, LOW, MEDIUM, HIGH) to match Pro models' capabilities. ([#212](https://github.com/badlogic/pi-mono/pull/212) by [@markusylisiurunen](https://github.com/markusylisiurunen))
## [0.22.3] - 2025-12-16 ## [0.22.3] - 2025-12-16
### Added ### Added

View file

@ -21,7 +21,7 @@
}, },
"dependencies": { "dependencies": {
"@anthropic-ai/sdk": "0.71.2", "@anthropic-ai/sdk": "0.71.2",
"@google/genai": "1.31.0", "@google/genai": "1.34.0",
"@mistralai/mistralai": "1.10.0", "@mistralai/mistralai": "1.10.0",
"@sinclair/typebox": "^0.34.41", "@sinclair/typebox": "^0.34.41",
"ajv": "^8.17.1", "ajv": "^8.17.1",

View file

@ -468,6 +468,8 @@ function mapStopReason(reason: FinishReason): StopReason {
case FinishReason.SAFETY: case FinishReason.SAFETY:
case FinishReason.IMAGE_SAFETY: case FinishReason.IMAGE_SAFETY:
case FinishReason.IMAGE_PROHIBITED_CONTENT: case FinishReason.IMAGE_PROHIBITED_CONTENT:
case FinishReason.IMAGE_RECITATION:
case FinishReason.IMAGE_OTHER:
case FinishReason.RECITATION: case FinishReason.RECITATION:
case FinishReason.FINISH_REASON_UNSPECIFIED: case FinishReason.FINISH_REASON_UNSPECIFIED:
case FinishReason.OTHER: case FinishReason.OTHER:

View file

@ -174,14 +174,14 @@ function mapOptionsForApi<TApi extends Api>(
const googleModel = model as Model<"google-generative-ai">; const googleModel = model as Model<"google-generative-ai">;
const effort = clampReasoning(options.reasoning)!; const effort = clampReasoning(options.reasoning)!;
// Gemini 3 Pro models use thinkingLevel exclusively instead of thinkingBudget. // Gemini 3 models use thinkingLevel exclusively instead of thinkingBudget.
// https://ai.google.dev/gemini-api/docs/thinking#set-budget // https://ai.google.dev/gemini-api/docs/thinking#set-budget
if (isGemini3ProModel(googleModel)) { if (isGemini3ProModel(googleModel) || isGemini3FlashModel(googleModel)) {
return { return {
...base, ...base,
thinking: { thinking: {
enabled: true, enabled: true,
level: getGoogleThinkingLevel(effort), level: getGemini3ThinkingLevel(effort, googleModel),
}, },
} satisfies GoogleOptions; } satisfies GoogleOptions;
} }
@ -210,13 +210,31 @@ function isGemini3ProModel(model: Model<"google-generative-ai">): boolean {
return model.id.includes("3-pro"); return model.id.includes("3-pro");
} }
function getGoogleThinkingLevel(effort: ClampedReasoningEffort): ThinkingLevel { function isGemini3FlashModel(model: Model<"google-generative-ai">): boolean {
// Gemini 3 Pro only supports LOW/HIGH (for now) // Covers gemini-3-flash, gemini-3-flash-preview, and possible other prefixed ids in the future
return model.id.includes("3-flash");
}
function getGemini3ThinkingLevel(effort: ClampedReasoningEffort, model: Model<"google-generative-ai">): ThinkingLevel {
if (isGemini3ProModel(model)) {
// Gemini 3 Pro only supports LOW/HIGH (for now)
switch (effort) {
case "minimal":
case "low":
return ThinkingLevel.LOW;
case "medium":
case "high":
return ThinkingLevel.HIGH;
}
}
// Gemini 3 Flash supports all four levels
switch (effort) { switch (effort) {
case "minimal": case "minimal":
return ThinkingLevel.MINIMAL;
case "low": case "low":
return ThinkingLevel.LOW; return ThinkingLevel.LOW;
case "medium": case "medium":
return ThinkingLevel.MEDIUM;
case "high": case "high":
return ThinkingLevel.HIGH; return ThinkingLevel.HIGH;
} }