fix(catalog): map aliased Gemini Flash minimal to LOW on Cloud Code Assist
When a collapsed Gemini 3.6/3.7 Flash family routes user minimal onto the same Cloud Code Assist wire id as low, emit thinkingLevel LOW. Those -low SKUs reject MINIMAL with HTTP 400.
This commit is contained in:
@@ -2,6 +2,11 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
|
||||
### Fixed
|
||||
|
||||
- Cloud Code Assist Gemini 3.6/3.7 Flash requests at `minimal` now send `thinkingLevel: LOW` on the aliased `-low` SKU instead of `MINIMAL`, which the API rejects with HTTP 400.
|
||||
|
||||
## [17.3.7] - 2026-08-17
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -2149,7 +2149,7 @@ function mapOptionsForApi<TApi extends Api>(
|
||||
serviceTier: options?.serviceTier,
|
||||
thinking: {
|
||||
enabled: true,
|
||||
level: mapEffortToGoogleThinkingLevel(effort),
|
||||
level: mapEffortToGoogleThinkingLevel(effort, googleModel),
|
||||
},
|
||||
hideThinkingSummary: options?.hideThinkingSummary,
|
||||
toolChoice: mapGoogleToolChoice(options?.toolChoice),
|
||||
@@ -2182,7 +2182,7 @@ function mapOptionsForApi<TApi extends Api>(
|
||||
requestModelId: resolveWireModelId(model, effort),
|
||||
thinking: {
|
||||
enabled: true,
|
||||
level: mapEffortToGoogleThinkingLevel(effort),
|
||||
level: mapEffortToGoogleThinkingLevel(effort, model),
|
||||
},
|
||||
hideThinkingSummary: options?.hideThinkingSummary,
|
||||
toolChoice,
|
||||
@@ -2254,7 +2254,7 @@ function mapOptionsForApi<TApi extends Api>(
|
||||
serviceTier: options?.serviceTier,
|
||||
thinking: {
|
||||
enabled: true,
|
||||
level: mapEffortToGoogleThinkingLevel(effort),
|
||||
level: mapEffortToGoogleThinkingLevel(effort, model),
|
||||
},
|
||||
hideThinkingSummary: options?.hideThinkingSummary,
|
||||
toolChoice: mapGoogleToolChoice(options?.toolChoice),
|
||||
|
||||
@@ -11,6 +11,7 @@ interface GeminiCliThinkingConfig {
|
||||
}
|
||||
|
||||
interface CapturedRequestBody {
|
||||
model?: string;
|
||||
request?: {
|
||||
generationConfig?: {
|
||||
thinkingConfig?: GeminiCliThinkingConfig;
|
||||
@@ -138,4 +139,47 @@ describe("google-gemini-cli Gemini 3.x thinking mapping", () => {
|
||||
expect(thinking?.thinkingLevel).toBeUndefined();
|
||||
expect(thinking?.thinkingBudget).toBeDefined();
|
||||
});
|
||||
|
||||
it("sends LOW not MINIMAL when gemini-3.7-flash minimal aliases the -low SKU", async () => {
|
||||
let requestBody: string | undefined;
|
||||
const fetchMock = createFetchMock(body => {
|
||||
requestBody = body;
|
||||
});
|
||||
|
||||
const model = buildModel({
|
||||
id: "gemini-3.7-flash",
|
||||
name: "Gemini 3.7 Flash",
|
||||
api: "google-gemini-cli",
|
||||
provider: "google-antigravity",
|
||||
baseUrl: "https://daily-cloudcode-pa.googleapis.com",
|
||||
reasoning: true,
|
||||
thinking: {
|
||||
mode: "google-level",
|
||||
efforts: [Effort.Minimal, Effort.Low, Effort.Medium, Effort.High],
|
||||
requiresEffort: true,
|
||||
effortRouting: {
|
||||
[Effort.Minimal]: "gemini-3.7-flash-low",
|
||||
[Effort.Low]: "gemini-3.7-flash-low",
|
||||
[Effort.Medium]: "gemini-3.7-flash-medium",
|
||||
[Effort.High]: "gemini-3.7-flash-high",
|
||||
},
|
||||
},
|
||||
input: ["text", "image"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 1_048_576,
|
||||
maxTokens: 65_536,
|
||||
});
|
||||
|
||||
const stream = streamSimple(model, context, {
|
||||
apiKey: JSON.stringify({ token: "token", projectId: "proj-123" }),
|
||||
reasoning: Effort.Minimal,
|
||||
fetch: fetchMock,
|
||||
});
|
||||
await stream.result();
|
||||
|
||||
const parsed = JSON.parse(requestBody ?? "{}") as CapturedRequestBody;
|
||||
expect(parsed.model).toBe("gemini-3.7-flash-low");
|
||||
expect(parsed.request?.generationConfig?.thinkingConfig?.thinkingLevel).toBe("LOW");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
|
||||
### Fixed
|
||||
|
||||
- Cloud Code Assist Gemini 3.6/3.7 Flash no longer maps user `minimal` to wire `thinkingLevel: MINIMAL` when that effort is aliased onto the `-low` SKU. The request now sends `LOW`, which those SKUs accept.
|
||||
|
||||
## [17.3.6] - 2026-08-17
|
||||
|
||||
### Changed
|
||||
|
||||
@@ -796,11 +796,22 @@ export function requireSupportedEffort<TApi extends Api>(model: ApiModel<TApi>,
|
||||
return effort;
|
||||
}
|
||||
|
||||
/** Maps a normalized thinking effort to Google's `thinkingLevel` enum values. */
|
||||
export function mapEffortToGoogleThinkingLevel(effort: Effort): "MINIMAL" | "LOW" | "MEDIUM" | "HIGH" {
|
||||
/** Maps a normalized thinking effort to Google's `thinkingLevel` enum values.
|
||||
* When a collapsed family routes `minimal` onto the same wire id as `low`
|
||||
* (Antigravity Gemini 3.6/3.7 Flash), emit `LOW` — Cloud Code Assist rejects
|
||||
* `MINIMAL` on those `-low` SKUs. */
|
||||
export function mapEffortToGoogleThinkingLevel<TApi extends Api>(
|
||||
effort: Effort,
|
||||
model?: ApiModel<TApi>,
|
||||
): "MINIMAL" | "LOW" | "MEDIUM" | "HIGH" {
|
||||
if (effort === Effort.Minimal) {
|
||||
const routing = model?.thinking?.effortRouting;
|
||||
if (routing?.[Effort.Minimal] && routing[Effort.Minimal] === routing[Effort.Low]) {
|
||||
return "LOW";
|
||||
}
|
||||
return "MINIMAL";
|
||||
}
|
||||
switch (effort) {
|
||||
case Effort.Minimal:
|
||||
return "MINIMAL";
|
||||
case Effort.Low:
|
||||
return "LOW";
|
||||
case Effort.Medium:
|
||||
|
||||
@@ -360,6 +360,29 @@ describe("model thinking derivation", () => {
|
||||
expect(() => requireSupportedEffort(model, Effort.Medium)).toThrow(/not supported/);
|
||||
});
|
||||
|
||||
it("maps minimal to LOW when a collapsed family aliases it onto the low wire id", () => {
|
||||
const model = createModel({
|
||||
id: "gemini-3.7-flash",
|
||||
api: "google-gemini-cli",
|
||||
provider: "google-antigravity",
|
||||
thinking: {
|
||||
mode: "google-level",
|
||||
efforts: [Effort.Minimal, Effort.Low, Effort.Medium, Effort.High],
|
||||
requiresEffort: true,
|
||||
effortRouting: {
|
||||
[Effort.Minimal]: "gemini-3.7-flash-low",
|
||||
[Effort.Low]: "gemini-3.7-flash-low",
|
||||
[Effort.Medium]: "gemini-3.7-flash-medium",
|
||||
[Effort.High]: "gemini-3.7-flash-high",
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(mapEffortToGoogleThinkingLevel(Effort.Minimal, model)).toBe("LOW");
|
||||
expect(mapEffortToGoogleThinkingLevel(Effort.Low, model)).toBe("LOW");
|
||||
expect(mapEffortToGoogleThinkingLevel(Effort.Minimal)).toBe("MINIMAL");
|
||||
});
|
||||
|
||||
|
||||
it("bakes requiresEffort for Gemini 3.x on any provider and backfills explicit metadata", () => {
|
||||
// Derivation: aggregator-hosted Gemini 3.5 gets the flag, 2.5 does not.
|
||||
const openRouterFlash = createModel({
|
||||
|
||||
Reference in New Issue
Block a user