fix(ai): send thinkingLevel for Gemini 4 models

Gemini 4 Argon rejected thinkingBudget on Vertex and ignored the selected
thinking level on the Gemini API.

fixes #10890
This commit is contained in:
David Brailovsky 2026-10-14 12:38:28 +02:00
parent 63035734f2
commit 1692bba634
3 changed files with 10 additions and 0 deletions

View file

@ -14,6 +14,7 @@
- Fixed OpenCode Go MiniMax M2.7 failing with "Model does not support this protocol" by using the Anthropic Messages API
- Fixed automatic retry not triggering for gateway `Unable to forward upstream stream` errors ([#10920](https://github.com/earendil-works/pi/issues/10920))
- Fixed OpenAI-compatible responses showing thinking after the answer when a proxy such as LiteLLM sends reasoning and content in the same stream chunk ([#10926](https://github.com/earendil-works/pi/issues/10926))
- Fixed Gemini 4 Argon requests on Google Vertex failing with "Thinking budget is not supported", and its thinking level being ignored on the Gemini API, by sending `thinkingLevel` for Gemini 4 and later models ([#10890](https://github.com/earendil-works/pi/issues/10890))
## [1.2.0] - 2026-10-12

View file

@ -75,6 +75,8 @@ export function usesGoogleThinkingLevel<T extends GoogleApiType>(model: Model<T>
// Match Gemini 3 Pro/Flash IDs with or without a minor version, such as
// gemini-3-flash-preview, gemini-3.1-pro-preview, and gemini-3.8-flash.
/gemini-3(?:\.\d+)?-(?:pro|flash)/.test(id) ||
// Match Gemini 4 and later, such as gemini-4-argon (#10890).
/gemini-(?:[4-9]|[1-9]\d)/.test(id) ||
id === "gemini-flash-latest" ||
id === "gemini-flash-lite-latest" ||
// Match both hosted Gemma 4 naming forms: gemma-4-* and gemma4-*.

View file

@ -166,6 +166,13 @@ describe("Google thinking level maps", () => {
expect(payload.config?.thinkingConfig).toEqual({ thinkingBudget: 0 });
});
// Regression test for https://github.com/earendil-works/pi/issues/10890
it.each(googleAdapters)("uses thinking levels for Gemini 4 models on $name", async ({ capture }) => {
const payload = await capture("gemini-4-argon", {}, "medium");
expect(payload.config?.thinkingConfig).toEqual({ includeThoughts: true, thinkingLevel: "MEDIUM" });
});
it.each(["xhigh", "max"] as const)("maps Google Generative AI %s to a supported level", async (reasoning) => {
const payload = await captureGooglePayload(
googleModel("gemini-3.7-flash", { xhigh: "high", max: "high" }),