Add gemini-3.7-flash and its tiered high/medium/low variants to the Antigravity and Gemini registries, with matching capabilities, pricing and Antigravity quota tracking. extractModel now recognises gemini-3.7-flash-tiered alongside 3.6 and derives the version from the request, so thinkingLevel still maps to the right tiered alias. Closes #3286 Closes #3281
This commit is contained in:
parent
8af5e752da
commit
86694ed8d0
10 changed files with 120 additions and 3 deletions
|
|
@ -53,6 +53,9 @@ const PROVIDER_MODELS = {
|
||||||
{ id: "glm-4.7" },
|
{ id: "glm-4.7" },
|
||||||
],
|
],
|
||||||
ag: [
|
ag: [
|
||||||
|
{ id: "gemini-3.7-flash-high" },
|
||||||
|
{ id: "gemini-3.7-flash-medium" },
|
||||||
|
{ id: "gemini-3.7-flash-low" },
|
||||||
{ id: "gemini-3.6-flash-high" },
|
{ id: "gemini-3.6-flash-high" },
|
||||||
{ id: "gemini-3.6-flash-medium" },
|
{ id: "gemini-3.6-flash-medium" },
|
||||||
{ id: "gemini-3.6-flash-low" },
|
{ id: "gemini-3.6-flash-low" },
|
||||||
|
|
|
||||||
|
|
@ -205,6 +205,7 @@ export const PATTERN_CAPABILITIES = [
|
||||||
|
|
||||||
// ── Gemini (all 2.0+ multimodal + google_search grounding, 1M ctx) ─
|
// ── Gemini (all 2.0+ multimodal + google_search grounding, 1M ctx) ─
|
||||||
{ pattern: "*gemini*image*", caps: { vision: true, imageOutput: true, contextWindow: 1048576 } },
|
{ pattern: "*gemini*image*", caps: { vision: true, imageOutput: true, contextWindow: 1048576 } },
|
||||||
|
{ pattern: "*gemini-3.7*", caps: { vision: true, audioInput: true, videoInput: true, reasoning: true, search: true, thinkingFormat: "gemini-level", thinkingCanDisable: false, contextWindow: 1048576, maxOutput: 65536 } },
|
||||||
{ pattern: "*gemini-3*pro*", caps: { vision: true, audioInput: true, videoInput: true, reasoning: true, search: true, thinkingFormat: "gemini-level", thinkingCanDisable: false, contextWindow: 1048576, maxOutput: 65535 } },
|
{ pattern: "*gemini-3*pro*", caps: { vision: true, audioInput: true, videoInput: true, reasoning: true, search: true, thinkingFormat: "gemini-level", thinkingCanDisable: false, contextWindow: 1048576, maxOutput: 65535 } },
|
||||||
{ pattern: "*gemini-3*", caps: { vision: true, audioInput: true, videoInput: true, reasoning: true, search: true, thinkingFormat: "gemini-level", thinkingCanDisable: false, contextWindow: 1048576, maxOutput: 65536 } },
|
{ pattern: "*gemini-3*", caps: { vision: true, audioInput: true, videoInput: true, reasoning: true, search: true, thinkingFormat: "gemini-level", thinkingCanDisable: false, contextWindow: 1048576, maxOutput: 65536 } },
|
||||||
{ pattern: "*gemini-2.5*", caps: { vision: true, audioInput: true, videoInput: true, reasoning: true, search: true, thinkingFormat: "gemini-budget", thinkingRange: { min: 0, max: 24576 }, contextWindow: 1048576, maxOutput: 65536 } },
|
{ pattern: "*gemini-2.5*", caps: { vision: true, audioInput: true, videoInput: true, reasoning: true, search: true, thinkingFormat: "gemini-budget", thinkingRange: { min: 0, max: 24576 }, contextWindow: 1048576, maxOutput: 65536 } },
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,10 @@ export const MODEL_PRICING = {
|
||||||
"o1-mini": { input: 3.00, output: 12.00, cached: 1.50, reasoning: 18.00, cache_creation: 3.00 },
|
"o1-mini": { input: 3.00, output: 12.00, cached: 1.50, reasoning: 18.00, cache_creation: 3.00 },
|
||||||
|
|
||||||
// === Gemini ===
|
// === Gemini ===
|
||||||
|
"gemini-3.7-flash": { input: 1.50, output: 7.50, cached: 0.15, reasoning: 11.25, cache_creation: 1.875 },
|
||||||
|
"gemini-3.7-flash-high": { input: 1.50, output: 7.50, cached: 0.15, reasoning: 11.25, cache_creation: 1.875 },
|
||||||
|
"gemini-3.7-flash-medium": { input: 1.50, output: 7.50, cached: 0.15, reasoning: 11.25, cache_creation: 1.875 },
|
||||||
|
"gemini-3.7-flash-low": { input: 1.50, output: 7.50, cached: 0.15, reasoning: 11.25, cache_creation: 1.875 },
|
||||||
"gemini-3.6-flash": { input: 1.50, output: 7.50, cached: 0.15, reasoning: 11.25, cache_creation: 1.875 },
|
"gemini-3.6-flash": { input: 1.50, output: 7.50, cached: 0.15, reasoning: 11.25, cache_creation: 1.875 },
|
||||||
"gemini-3.6-flash-high": { input: 1.50, output: 7.50, cached: 0.15, reasoning: 11.25, cache_creation: 1.875 },
|
"gemini-3.6-flash-high": { input: 1.50, output: 7.50, cached: 0.15, reasoning: 11.25, cache_creation: 1.875 },
|
||||||
"gemini-3.6-flash-medium": { input: 1.50, output: 7.50, cached: 0.15, reasoning: 11.25, cache_creation: 1.875 },
|
"gemini-3.6-flash-medium": { input: 1.50, output: 7.50, cached: 0.15, reasoning: 11.25, cache_creation: 1.875 },
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,9 @@ export default {
|
||||||
clientSecret: "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",
|
clientSecret: "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",
|
||||||
},
|
},
|
||||||
models: [
|
models: [
|
||||||
|
{ id: "gemini-3.7-flash-high", name: "Gemini 3.7 Flash (High)", upstreamModelId: "gemini-3.7-flash-tiered(high)" },
|
||||||
|
{ id: "gemini-3.7-flash-medium", name: "Gemini 3.7 Flash (Medium)", upstreamModelId: "gemini-3.7-flash-tiered(medium)" },
|
||||||
|
{ id: "gemini-3.7-flash-low", name: "Gemini 3.7 Flash (Low)", upstreamModelId: "gemini-3.7-flash-tiered(low)" },
|
||||||
{ id: "gemini-3.6-flash-high", name: "Gemini 3.6 Flash (High)", upstreamModelId: "gemini-3.6-flash-tiered(high)" },
|
{ id: "gemini-3.6-flash-high", name: "Gemini 3.6 Flash (High)", upstreamModelId: "gemini-3.6-flash-tiered(high)" },
|
||||||
{ id: "gemini-3.6-flash-medium", name: "Gemini 3.6 Flash (Medium)", upstreamModelId: "gemini-3.6-flash-tiered(medium)" },
|
{ id: "gemini-3.6-flash-medium", name: "Gemini 3.6 Flash (Medium)", upstreamModelId: "gemini-3.6-flash-tiered(medium)" },
|
||||||
{ id: "gemini-3.6-flash-low", name: "Gemini 3.6 Flash (Low)", upstreamModelId: "gemini-3.6-flash-tiered(low)" },
|
{ id: "gemini-3.6-flash-low", name: "Gemini 3.6 Flash (Low)", upstreamModelId: "gemini-3.6-flash-tiered(low)" },
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,7 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
models: [
|
models: [
|
||||||
|
{ id: "gemini-3.7-flash", name: "Gemini 3.7 Flash" },
|
||||||
{ id: "gemini-3.6-flash", name: "Gemini 3.6 Flash" },
|
{ id: "gemini-3.6-flash", name: "Gemini 3.6 Flash" },
|
||||||
{ id: "gemini-3.5-flash-lite", name: "Gemini 3.5 Flash Lite" },
|
{ id: "gemini-3.5-flash-lite", name: "Gemini 3.5 Flash Lite" },
|
||||||
{ id: "gemini-3.1-pro-preview", name: "Gemini 3.1 Pro Preview" },
|
{ id: "gemini-3.1-pro-preview", name: "Gemini 3.1 Pro Preview" },
|
||||||
|
|
|
||||||
|
|
@ -161,6 +161,9 @@ export async function getAntigravityUsage(accessToken, providerSpecificData, pro
|
||||||
if (data.models) {
|
if (data.models) {
|
||||||
// Filter only recommended/important models (must match PROVIDER_MODELS ag ids)
|
// Filter only recommended/important models (must match PROVIDER_MODELS ag ids)
|
||||||
const importantModels = [
|
const importantModels = [
|
||||||
|
'gemini-3.7-flash-high',
|
||||||
|
'gemini-3.7-flash-medium',
|
||||||
|
'gemini-3.7-flash-low',
|
||||||
'gemini-3.6-flash-high',
|
'gemini-3.6-flash-high',
|
||||||
'gemini-3.6-flash-medium',
|
'gemini-3.6-flash-medium',
|
||||||
'gemini-3.6-flash-low',
|
'gemini-3.6-flash-low',
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,9 @@ const MODEL_SYNONYMS = {
|
||||||
"gemini-3.5-flash-high": "gemini-3-flash-agent",
|
"gemini-3.5-flash-high": "gemini-3-flash-agent",
|
||||||
"gemini-3.5-flash-medium": "gemini-3.5-flash-low",
|
"gemini-3.5-flash-medium": "gemini-3.5-flash-low",
|
||||||
"gemini-3.5-flash-extra-low": "gemini-3.5-flash-extra-low",
|
"gemini-3.5-flash-extra-low": "gemini-3.5-flash-extra-low",
|
||||||
|
"gemini-3.7-flash-high": "gemini-3.7-flash-high",
|
||||||
|
"gemini-3.7-flash-medium": "gemini-3.7-flash-medium",
|
||||||
|
"gemini-3.7-flash-low": "gemini-3.7-flash-low",
|
||||||
"gemini-3.1-pro-high": "gemini-pro-agent",
|
"gemini-3.1-pro-high": "gemini-pro-agent",
|
||||||
"gemini-3-pro-high": "gemini-pro-agent",
|
"gemini-3-pro-high": "gemini-pro-agent",
|
||||||
"gemini-3-pro-low": "gemini-3.1-pro-low",
|
"gemini-3-pro-low": "gemini-3.1-pro-low",
|
||||||
|
|
@ -131,13 +134,15 @@ function extractModel(url, body) {
|
||||||
return parsed.conversationState.currentMessage?.userInputMessage?.modelId || null;
|
return parsed.conversationState.currentMessage?.userInputMessage?.modelId || null;
|
||||||
}
|
}
|
||||||
const model = urlModel || parsed.model || null;
|
const model = urlModel || parsed.model || null;
|
||||||
if (String(model).replace(/^models\//, "") === "gemini-3.6-flash-tiered") {
|
const cleanModelName = String(model).replace(/^models\//, "");
|
||||||
|
if (cleanModelName === "gemini-3.6-flash-tiered" || cleanModelName === "gemini-3.7-flash-tiered") {
|
||||||
|
const ver = cleanModelName.includes("3.7") ? "3.7" : "3.6";
|
||||||
const rawLevel = parsed.request?.generationConfig?.thinkingConfig?.thinkingLevel
|
const rawLevel = parsed.request?.generationConfig?.thinkingConfig?.thinkingLevel
|
||||||
|| parsed.generationConfig?.thinkingConfig?.thinkingLevel;
|
|| parsed.generationConfig?.thinkingConfig?.thinkingLevel;
|
||||||
const level = ["high", "medium", "low"].includes(String(rawLevel).toLowerCase())
|
const level = ["high", "medium", "low"].includes(String(rawLevel).toLowerCase())
|
||||||
? String(rawLevel).toLowerCase()
|
? String(rawLevel).toLowerCase()
|
||||||
: "medium";
|
: "medium";
|
||||||
return `gemini-3.6-flash-${level}`;
|
return `gemini-${ver}-flash-${level}`;
|
||||||
}
|
}
|
||||||
return model;
|
return model;
|
||||||
} catch {
|
} catch {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ export const MITM_TOOLS = {
|
||||||
description: "Google Antigravity IDE with MITM",
|
description: "Google Antigravity IDE with MITM",
|
||||||
configType: "mitm",
|
configType: "mitm",
|
||||||
mitmDomain: "daily-cloudcode-pa.googleapis.com",
|
mitmDomain: "daily-cloudcode-pa.googleapis.com",
|
||||||
modelAliases: ["gemini-3.6-flash-high", "gemini-3.6-flash-medium", "gemini-3.6-flash-low", "gemini-3.5-flash-low", "gemini-3-flash-agent", "gemini-3.5-flash-extra-low", "gemini-3.1-pro-low", "gemini-pro-agent", "claude-sonnet-4-6", "claude-opus-4-6-thinking", "gpt-oss-120b-medium", "gemini-3-flash"],
|
modelAliases: ["gemini-3.7-flash-high", "gemini-3.7-flash-medium", "gemini-3.7-flash-low", "gemini-3.6-flash-high", "gemini-3.6-flash-medium", "gemini-3.6-flash-low", "gemini-3.5-flash-low", "gemini-3-flash-agent", "gemini-3.5-flash-extra-low", "gemini-3.1-pro-low", "gemini-pro-agent", "claude-sonnet-4-6", "claude-opus-4-6-thinking", "gpt-oss-120b-medium", "gemini-3-flash"],
|
||||||
defaultModels: [
|
defaultModels: [
|
||||||
{ id: "gemini-3.6-flash-high", name: "Gemini 3.6 Flash (High)", alias: "gemini-3.6-flash-high" },
|
{ id: "gemini-3.6-flash-high", name: "Gemini 3.6 Flash (High)", alias: "gemini-3.6-flash-high" },
|
||||||
{ id: "gemini-3.6-flash-medium", name: "Gemini 3.6 Flash (Medium)", alias: "gemini-3.6-flash-medium" },
|
{ id: "gemini-3.6-flash-medium", name: "Gemini 3.6 Flash (Medium)", alias: "gemini-3.6-flash-medium" },
|
||||||
|
|
|
||||||
61
tests/unit/antigravity-quota-gemini-3.7.test.js
Normal file
61
tests/unit/antigravity-quota-gemini-3.7.test.js
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
import { describe, expect, it, vi, beforeEach } from "vitest";
|
||||||
|
|
||||||
|
const proxyAwareFetch = vi.fn(async (url) => ({
|
||||||
|
ok: true,
|
||||||
|
status: 200,
|
||||||
|
json: async () => url.includes(":loadCodeAssist")
|
||||||
|
? { cloudaicompanionProject: "project-1", currentTier: { name: "Pro" } }
|
||||||
|
: {
|
||||||
|
models: {
|
||||||
|
"gemini-3.7-flash-high": {
|
||||||
|
displayName: "Gemini 3.7 Flash (High)",
|
||||||
|
quotaInfo: { remainingFraction: 0.85, resetTime: "2026-08-25T12:00:00Z" },
|
||||||
|
},
|
||||||
|
"gemini-3.7-flash-medium": {
|
||||||
|
displayName: "Gemini 3.7 Flash (Medium)",
|
||||||
|
quotaInfo: { remainingFraction: 0.6, resetTime: "2026-08-25T12:00:00Z" },
|
||||||
|
},
|
||||||
|
"gemini-3.7-flash-low": {
|
||||||
|
displayName: "Gemini 3.7 Flash (Low)",
|
||||||
|
quotaInfo: { remainingFraction: 0.35, resetTime: "2026-08-25T12:00:00Z" },
|
||||||
|
},
|
||||||
|
"internal-model": {
|
||||||
|
displayName: "Internal",
|
||||||
|
isInternal: true,
|
||||||
|
quotaInfo: { remainingFraction: 0.5 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
text: async () => "{}",
|
||||||
|
}));
|
||||||
|
|
||||||
|
vi.mock("../../open-sse/utils/proxyFetch.js", () => ({
|
||||||
|
proxyAwareFetch,
|
||||||
|
}));
|
||||||
|
|
||||||
|
describe("Antigravity quota tracker: Gemini 3.7 Flash usage bars", () => {
|
||||||
|
beforeEach(() => proxyAwareFetch.mockClear());
|
||||||
|
|
||||||
|
it("returns Gemini 3.7 Flash tier quotas so the dashboard can render usage bars", async () => {
|
||||||
|
const { getAntigravityUsage } = await import("../../open-sse/services/usage/google.js");
|
||||||
|
|
||||||
|
const usage = await getAntigravityUsage("access-token", {});
|
||||||
|
|
||||||
|
expect(usage.quotas["gemini-3.7-flash-high"]).toMatchObject({
|
||||||
|
used: 150,
|
||||||
|
total: 1000,
|
||||||
|
remainingPercentage: 85,
|
||||||
|
displayName: "Gemini 3.7 Flash (High)",
|
||||||
|
});
|
||||||
|
expect(usage.quotas["gemini-3.7-flash-medium"]).toMatchObject({
|
||||||
|
used: 400,
|
||||||
|
total: 1000,
|
||||||
|
remainingPercentage: 60,
|
||||||
|
});
|
||||||
|
expect(usage.quotas["gemini-3.7-flash-low"]).toMatchObject({
|
||||||
|
used: 650,
|
||||||
|
total: 1000,
|
||||||
|
remainingPercentage: 35,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
36
tests/unit/gemini-3.7-antigravity.test.js
Normal file
36
tests/unit/gemini-3.7-antigravity.test.js
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
import { describe, it, expect } from "vitest";
|
||||||
|
import { getCapabilitiesForModel } from "../../open-sse/providers/capabilities.js";
|
||||||
|
import antigravityRegistry from "../../open-sse/providers/registry/antigravity.js";
|
||||||
|
import geminiRegistry from "../../open-sse/providers/registry/gemini.js";
|
||||||
|
import { MODEL_PRICING } from "../../open-sse/providers/pricing.js";
|
||||||
|
|
||||||
|
describe("Gemini 3.7 Flash Support & Config (#3286, #3281)", () => {
|
||||||
|
it("registers gemini-3.7-flash tiered models in antigravity provider registry", () => {
|
||||||
|
const agIds = antigravityRegistry.models.map(m => m.id);
|
||||||
|
expect(agIds).toContain("gemini-3.7-flash-high");
|
||||||
|
expect(agIds).toContain("gemini-3.7-flash-medium");
|
||||||
|
expect(agIds).toContain("gemini-3.7-flash-low");
|
||||||
|
expect(agIds).not.toContain("gemini-3.7-flash");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("registers gemini-3.7-flash in gemini provider registry", () => {
|
||||||
|
const geminiIds = geminiRegistry.models.map(m => m.id);
|
||||||
|
expect(geminiIds).toContain("gemini-3.7-flash");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("resolves capabilities correctly for gemini-3.7 models with official limits", () => {
|
||||||
|
const caps = getCapabilitiesForModel("antigravity", "gemini-3.7-flash-high");
|
||||||
|
expect(caps.vision).toBe(true);
|
||||||
|
expect(caps.reasoning).toBe(true);
|
||||||
|
expect(caps.thinkingFormat).toBe("gemini-level");
|
||||||
|
expect(caps.contextWindow).toBe(1048576);
|
||||||
|
expect(caps.maxOutput).toBe(65536);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("defines pricing matching gemini-3.6-flash baseline", () => {
|
||||||
|
expect(MODEL_PRICING["gemini-3.7-flash"]).toEqual(MODEL_PRICING["gemini-3.6-flash"]);
|
||||||
|
expect(MODEL_PRICING["gemini-3.7-flash-high"]).toEqual(MODEL_PRICING["gemini-3.6-flash-high"]);
|
||||||
|
expect(MODEL_PRICING["gemini-3.7-flash-medium"]).toEqual(MODEL_PRICING["gemini-3.6-flash-medium"]);
|
||||||
|
expect(MODEL_PRICING["gemini-3.7-flash-low"]).toEqual(MODEL_PRICING["gemini-3.6-flash-low"]);
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue