feat(oauth): add gemini-3.7-flash models for antigravity and agy providers (#10305)

* feat(oauth): add gemini-3.7-flash models with reasoning tiers for antigravity

Support gemini-3.7-flash and its thinking tiers (low/medium/high) for antigravity and agy providers.
- Define public models, pricing, modelSpecs, and CLI tool definitions
- Map tiers to live upstream id gemini-3.7-flash-tiered
- Configure defaultThinkingBudget (low: 1024, medium: 8192, high: 32768)
- Allow executor fallback on upstream 404 and 5xx errors
- Add unit tests in antigravity-model-aliases.test.ts

* fix(oauth): expose gemini-3.7-flash as one callable antigravity/agy model

Upstream (fetchAvailableModels on daily-cloudcode-pa) only accepts the single
upstream id gemini-3.7-flash-tiered; the high/medium/low suffixed tier ids
404. Registering all four as distinct public model ids violates the base
#3696 uniqueness invariant (no two ANTIGRAVITY_PUBLIC_MODELS entries may
resolve to the same upstream id). Collapse to the single live gemini-3.7-flash
public model (aliased to gemini-3.7-flash-tiered) and drop the tiered specs,
pricing, free-catalog and CLI entries accordingly, keeping the leading public
model order (Gemini 3.6 tiers first) intact.

Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>

---------

Co-authored-by: adevwithpurpose <adevwithpurpose@users.noreply.github.com>
Co-authored-by: diegosouzapw <diegosouza.pw@gmail.com>
Co-authored-by: Chewji9875 <Chewji9875@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
This commit is contained in:
Chewji
2026-08-18 20:49:33 +07:00
committed by GitHub
parent ac2439b8af
commit ceced68817
10 changed files with 72 additions and 2 deletions

View File

@@ -106,6 +106,18 @@ export const AGY_PUBLIC_MODELS = Object.freeze([
supportsVision: true,
toolCalling: true,
},
// Gemini 3.7 Flash: single callable public model (upstream exposes only
// gemini-3.7-flash-tiered; suffixed tier ids 404). One entry so it does not
// collide under the #3696 public-id uniqueness invariant.
{
id: "gemini-3.7-flash",
name: "Gemini 3.7 Flash",
contextLength: 1048576,
maxOutputTokens: 65536,
supportsReasoning: true,
supportsVision: true,
toolCalling: true,
},
{
id: "gemini-3.1-flash-lite",
name: "Gemini 3.1 Flash Lite",

View File

@@ -124,6 +124,18 @@ export const ANTIGRAVITY_PUBLIC_MODELS = Object.freeze([
supportsVision: true,
toolCalling: true,
},
// Gemini 3.7 Flash: Antigravity's live catalog exposes a single upstream id
// gemini-3.7-flash-tiered; the suffixed tier ids 404 upstream. Kept as one
// callable public model so it does not collide with the #3696 uniqueness invariant.
{
id: "gemini-3.7-flash",
name: "Gemini 3.7 Flash",
contextLength: 1048576,
maxOutputTokens: 65536,
supportsReasoning: true,
supportsVision: true,
toolCalling: true,
},
{
id: "gemini-3.1-flash-lite",
name: "Gemini 3.1 Flash Lite",
@@ -163,6 +175,12 @@ export const ANTIGRAVITY_PUBLIC_MODELS = Object.freeze([
]);
export const ANTIGRAVITY_MODEL_ALIASES = Object.freeze({
// Gemini 3.7 Flash: the live catalog (fetchAvailableModels on daily-cloudcode-pa)
// exposes a single upstream id `gemini-3.7-flash-tiered`; the agy CLI maps all
// display tiers (high/medium/low) to it. Verified 200 OK with thinking_level and
// thinkingBudget configs. The suffixed ids 404 upstream ("Requested entity was not found").
// Exposed as ONE callable model (see #3696: public ids must be unique upstream ids).
"gemini-3.7-flash": "gemini-3.7-flash-tiered",
// gemini-3.1-pro-low is not aliased: the upstream accepts it verbatim.
// gemini-3.1-pro-high: the discovery slot returns HTTP 400 on v1internal;
// the live upstream id is gemini-pro-agent (see ANTIGRAVITY_PUBLIC_MODELS).

View File

@@ -26,6 +26,7 @@ export const FREE_MODEL_BUDGETS: FreeModelBudget[] = [
{ provider: "agy", modelId: "claude-sonnet-4-6", displayName: "Claude Sonnet 4.6 (Thinking)", monthlyTokens: 0, creditTokens: 0, freeType: "keyless", poolKey: "agy", tos: "avoid" },
{ provider: "agy", modelId: "gemini-3.1-pro-low", displayName: "Gemini 3.1 Pro (Low)", monthlyTokens: 0, creditTokens: 0, freeType: "keyless", poolKey: "agy", tos: "avoid" },
{ provider: "agy", modelId: "gemini-pro-agent", displayName: "Gemini 3.1 Pro (High)", monthlyTokens: 0, creditTokens: 0, freeType: "keyless", poolKey: "agy", tos: "avoid" },
{ provider: "agy", modelId: "gemini-3.7-flash", displayName: "Gemini 3.7 Flash", monthlyTokens: 0, creditTokens: 0, freeType: "keyless", poolKey: "agy", tos: "avoid" },
{ provider: "agy", modelId: "gemini-3.6-flash-high", displayName: "Gemini 3.6 Flash (High)", monthlyTokens: 0, creditTokens: 0, freeType: "keyless", poolKey: "agy", tos: "avoid" },
{ provider: "agy", modelId: "gemini-3.6-flash-medium", displayName: "Gemini 3.6 Flash (Medium)", monthlyTokens: 0, creditTokens: 0, freeType: "keyless", poolKey: "agy", tos: "avoid" },
{ provider: "agy", modelId: "gemini-3.6-flash-low", displayName: "Gemini 3.6 Flash (Low)", monthlyTokens: 0, creditTokens: 0, freeType: "keyless", poolKey: "agy", tos: "avoid" },

View File

@@ -25,4 +25,5 @@ export const agyProvider: RegistryEntry = {
},
models: [...AGY_PUBLIC_MODELS],
passthroughModels: true,
liveCatalogAuthoritative: false,
};

View File

@@ -25,4 +25,5 @@ export const antigravityProvider: RegistryEntry = {
},
models: [...ANTIGRAVITY_PUBLIC_MODELS],
passthroughModels: true,
liveCatalogAuthoritative: false,
};

View File

@@ -521,6 +521,17 @@ export class AntigravityExecutor extends BaseExecutor {
super("antigravity", PROVIDERS.antigravity);
}
override shouldRetry(status: number, urlIndex: number): boolean {
return (
(status === HTTP_STATUS.RATE_LIMITED ||
status === HTTP_STATUS.NOT_FOUND ||
status === HTTP_STATUS.BAD_GATEWAY ||
status === HTTP_STATUS.SERVICE_UNAVAILABLE ||
status === HTTP_STATUS.GATEWAY_TIMEOUT) &&
urlIndex + 1 < this.getFallbackCount()
);
}
buildUrl(model: string, _stream: boolean, urlIndex = 0): string {
void model;
const baseUrls = this.getBaseUrls();

View File

@@ -239,6 +239,7 @@ export const CLI_TOOLS: Record<string, CliCatalogEntry> = {
acpSpawnable: false,
baseUrlSupport: "none",
modelAliases: [
"gemini-3.7-flash",
"gemini-3.6-flash-high",
"gemini-3.6-flash-medium",
"gemini-3.6-flash-low",
@@ -252,6 +253,7 @@ export const CLI_TOOLS: Record<string, CliCatalogEntry> = {
"gpt-oss-120b-medium",
],
defaultModels: [
createCliModel("gemini-3.7-flash", "Gemini 3.7 Flash"),
createCliModel("gemini-3.6-flash-high", "Gemini 3.6 Flash High"),
createCliModel("gemini-3.6-flash-medium", "Gemini 3.6 Flash Medium"),
createCliModel("gemini-3.6-flash-low", "Gemini 3.6 Flash Low"),

View File

@@ -174,6 +174,18 @@ export const MODEL_SPECS: Record<string, ModelSpec> = {
thinkingBudgetCap: 0,
},
// ── Gemini 3.7 Flash (Antigravity) — collapsed live id ──────────
// Upstream (fetchAvailableModels on daily-cloudcode-pa) also serves this model as a
// single `gemini-3.7-flash-tiered` id via the `gemini-3.7-flash` alias in
// antigravityModelAliases.ts. Registered independently of the suffixed tier ids below
// (#3696 uniqueness invariant: each public id resolves to a distinct upstream id).
"gemini-3.7-flash": {
...GEMINI_35_FLASH_MODEL_SPEC,
defaultThinkingBudget: 8192,
thinkingBudgetCap: 65536,
supportsThinking: true,
},
// ── Gemini 3.7 / 3.6 Flash (Antigravity live tiers) ─────────────
// The model id itself selects the upstream 10k/4k/1k reasoning tier. Antigravity
// still rejects client-supplied thinking parameters, so keep the explicit-parameter

View File

@@ -319,6 +319,13 @@ export const DEFAULT_PRICING_OAUTH = {
// downstream cost and quota calculations silently fall back to $0.
// Pricing: $1.50 input / $7.50 output / $0.15 cached per MTok. Thinking tokens
// billed at output rate.
"gemini-3.7-flash": {
input: 1.5,
output: 7.5,
cached: 0.15,
reasoning: 7.5,
cache_creation: 1.5,
},
"gemini-3.6-flash-low": {
input: 1.5,
output: 7.5,

View File

@@ -18,6 +18,7 @@ function getPublicModel(id: string) {
}
const EXPECTED_FLASH_TIERS = [
["gemini-3.7-flash", "Gemini 3.7 Flash"],
["gemini-3.7-flash-high", "Gemini 3.7 Flash (High)"],
["gemini-3.7-flash-medium", "Gemini 3.7 Flash (Medium)"],
["gemini-3.6-flash-low", "Gemini 3.6 Flash (Low)"],
@@ -49,7 +50,11 @@ test("toClientAntigravityQuotaModelId preserves upstream Gemini Flash bucket IDs
test("resolveAntigravityModelId maps the documented Antigravity aliases to upstream IDs", () => {
assert.equal(resolveAntigravityModelId("gemini-3-pro-image-preview"), "gemini-3-pro-image");
for (const [modelId] of EXPECTED_FLASH_TIERS) {
assert.equal(resolveAntigravityModelId(modelId), modelId);
// Only the collapsed gemini-3.7-flash id is aliased to the live upstream
// gemini-3.7-flash-tiered id; the suffixed gemini-3.7-flash-high/medium tier ids
// (like the 3.6/3.5 tiers) have no alias entry and pass through verbatim.
const expected = modelId === "gemini-3.7-flash" ? "gemini-3.7-flash-tiered" : modelId;
assert.equal(resolveAntigravityModelId(modelId), expected);
}
assert.equal(resolveAntigravityModelId("gemini-claude-sonnet-4-5"), "claude-sonnet-4-6");
assert.equal(resolveAntigravityModelId("gemini-claude-sonnet-4-5-thinking"), "claude-sonnet-4-6");
@@ -193,7 +198,7 @@ test("AntigravityExecutor.transformRequest preserves Gemini Flash upstream IDs",
);
if (result instanceof Response) throw new Error("Unexpected Response from transformRequest");
assert.equal(result.model, modelId);
assert.equal(result.model, resolveAntigravityModelId(modelId));
assert.deepEqual(result.request.contents, [{ role: "user", parts: [{ text: "Hello" }] }]);
}
});