From 86694ed8d048b1355c81068a12f45651c2f43434 Mon Sep 17 00:00:00 2001 From: Azriel Akbar Ferry Ardiansyah Kusumawardhana Date: Fri, 14 Aug 2026 16:26:45 +0700 Subject: [PATCH] feat(antigravity): add Gemini 3.7 Flash models (#3286, #3281) 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 --- cli/src/cli/menus/providers.js | 3 + open-sse/providers/capabilities.js | 1 + open-sse/providers/pricing.js | 4 ++ open-sse/providers/registry/antigravity.js | 3 + open-sse/providers/registry/gemini.js | 1 + open-sse/services/usage/google.js | 3 + src/mitm/config.js | 9 ++- src/shared/constants/cliTools.js | 2 +- .../unit/antigravity-quota-gemini-3.7.test.js | 61 +++++++++++++++++++ tests/unit/gemini-3.7-antigravity.test.js | 36 +++++++++++ 10 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 tests/unit/antigravity-quota-gemini-3.7.test.js create mode 100644 tests/unit/gemini-3.7-antigravity.test.js diff --git a/cli/src/cli/menus/providers.js b/cli/src/cli/menus/providers.js index 7e28ec64..92d10a04 100644 --- a/cli/src/cli/menus/providers.js +++ b/cli/src/cli/menus/providers.js @@ -53,6 +53,9 @@ const PROVIDER_MODELS = { { id: "glm-4.7" }, ], 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-medium" }, { id: "gemini-3.6-flash-low" }, diff --git a/open-sse/providers/capabilities.js b/open-sse/providers/capabilities.js index e91ad1f2..24a03b04 100644 --- a/open-sse/providers/capabilities.js +++ b/open-sse/providers/capabilities.js @@ -205,6 +205,7 @@ export const PATTERN_CAPABILITIES = [ // ── Gemini (all 2.0+ multimodal + google_search grounding, 1M ctx) ─ { 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*", 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 } }, diff --git a/open-sse/providers/pricing.js b/open-sse/providers/pricing.js index e9f2b612..cf6ffd55 100644 --- a/open-sse/providers/pricing.js +++ b/open-sse/providers/pricing.js @@ -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 }, // === 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-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 }, diff --git a/open-sse/providers/registry/antigravity.js b/open-sse/providers/registry/antigravity.js index 1a7c4347..2666552b 100644 --- a/open-sse/providers/registry/antigravity.js +++ b/open-sse/providers/registry/antigravity.js @@ -45,6 +45,9 @@ export default { clientSecret: "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", }, 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-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)" }, diff --git a/open-sse/providers/registry/gemini.js b/open-sse/providers/registry/gemini.js index c9b0de9b..df643556 100644 --- a/open-sse/providers/registry/gemini.js +++ b/open-sse/providers/registry/gemini.js @@ -36,6 +36,7 @@ export default { }, }, models: [ + { id: "gemini-3.7-flash", name: "Gemini 3.7 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.1-pro-preview", name: "Gemini 3.1 Pro Preview" }, diff --git a/open-sse/services/usage/google.js b/open-sse/services/usage/google.js index e79c018e..c7564c00 100644 --- a/open-sse/services/usage/google.js +++ b/open-sse/services/usage/google.js @@ -161,6 +161,9 @@ export async function getAntigravityUsage(accessToken, providerSpecificData, pro if (data.models) { // Filter only recommended/important models (must match PROVIDER_MODELS ag ids) 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-medium', 'gemini-3.6-flash-low', diff --git a/src/mitm/config.js b/src/mitm/config.js index 93c19ad0..73653a3c 100644 --- a/src/mitm/config.js +++ b/src/mitm/config.js @@ -55,6 +55,9 @@ const MODEL_SYNONYMS = { "gemini-3.5-flash-high": "gemini-3-flash-agent", "gemini-3.5-flash-medium": "gemini-3.5-flash-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-pro-high": "gemini-pro-agent", "gemini-3-pro-low": "gemini-3.1-pro-low", @@ -131,13 +134,15 @@ function extractModel(url, body) { return parsed.conversationState.currentMessage?.userInputMessage?.modelId || 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 || parsed.generationConfig?.thinkingConfig?.thinkingLevel; const level = ["high", "medium", "low"].includes(String(rawLevel).toLowerCase()) ? String(rawLevel).toLowerCase() : "medium"; - return `gemini-3.6-flash-${level}`; + return `gemini-${ver}-flash-${level}`; } return model; } catch { diff --git a/src/shared/constants/cliTools.js b/src/shared/constants/cliTools.js index bfe853c3..1e58918a 100644 --- a/src/shared/constants/cliTools.js +++ b/src/shared/constants/cliTools.js @@ -8,7 +8,7 @@ export const MITM_TOOLS = { description: "Google Antigravity IDE with MITM", configType: "mitm", 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: [ { 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" }, diff --git a/tests/unit/antigravity-quota-gemini-3.7.test.js b/tests/unit/antigravity-quota-gemini-3.7.test.js new file mode 100644 index 00000000..e172be31 --- /dev/null +++ b/tests/unit/antigravity-quota-gemini-3.7.test.js @@ -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, + }); + }); +}); diff --git a/tests/unit/gemini-3.7-antigravity.test.js b/tests/unit/gemini-3.7-antigravity.test.js new file mode 100644 index 00000000..d188d1f9 --- /dev/null +++ b/tests/unit/gemini-3.7-antigravity.test.js @@ -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"]); + }); +});