From 9ffff7458a4ddda8ecc4b8670331d515eabb6969 Mon Sep 17 00:00:00 2001 From: Ephraim-9 Date: Tue, 13 Oct 2026 15:02:14 +0000 Subject: [PATCH 1/2] fix(server): price Antigravity Gemini Flash effort variants at their base model --- .../Drivers/antigravityUsageReader.test.ts | 68 +++++++++++++++++++ .../Drivers/antigravityUsageReader.ts | 49 +++++++++---- 2 files changed, 105 insertions(+), 12 deletions(-) diff --git a/apps/server/src/provider/Drivers/antigravityUsageReader.test.ts b/apps/server/src/provider/Drivers/antigravityUsageReader.test.ts index 20c815fc9b325..af04bf1da36bb 100644 --- a/apps/server/src/provider/Drivers/antigravityUsageReader.test.ts +++ b/apps/server/src/provider/Drivers/antigravityUsageReader.test.ts @@ -164,6 +164,74 @@ describe("readAntigravityUsage", () => { }).pipe(Effect.provide(NodeServices.layer)), ); + it.effect("prices Antigravity effort variants at their base model", () => + Effect.gen(function* () { + const path = yield* Path.Path; + const dir = yield* tempDir; + yield* seedDatabase(path.join(dir, "variants.db"), (db) => + Effect.gen(function* () { + yield* createTables(db); + yield* db.run("INSERT INTO gen_metadata VALUES (?, ?)", [ + 0, + new Uint8Array(protoBytes(1, protoText(19, "Gemini 3.7 Flash Control"))), + ]); + yield* db.run("INSERT INTO steps VALUES (?, ?)", [ + 0, + new Uint8Array(protoBytes(9, protoNumber(2, 10))), + ]); + yield* db.run("INSERT INTO steps VALUES (?, ?)", [ + 1, + new Uint8Array(protoBytes(9, [...protoNumber(1, 1319), ...protoNumber(2, 11)])), + ]); + yield* db.run("INSERT INTO steps VALUES (?, ?)", [ + 2, + new Uint8Array(protoBytes(9, [...protoNumber(1, 1132), ...protoNumber(2, 12)])), + ]); + }), + ); + const result = yield* readAntigravityUsage(dir, 0); + assert.deepStrictEqual(result.errors, []); + assert.deepStrictEqual( + records(result).map((record) => [record.model, record.rateModel]), + [ + ["gemini-3.7-flash-control", "gemini-3.7-flash"], + ["gemini-3.8-flash-medium", "gemini-3.8-flash"], + ["gemini-3-flash-agent", "gemini-3-flash-preview"], + ], + ); + }).pipe(Effect.provide(NodeServices.layer)), + ); + + it.effect("prices a merged Antigravity alias by the model it adopts", () => + Effect.gen(function* () { + const path = yield* Path.Path; + const dir = yield* tempDir; + yield* seedDatabase(path.join(dir, "adopt.db"), (db) => + Effect.gen(function* () { + yield* createTables(db); + yield* db.run("INSERT INTO steps VALUES (?, ?)", [ + 5, + new Uint8Array(protoBytes(9, [...protoNumber(2, 100), ...protoText(11, "response")])), + ]); + yield* db.run("INSERT INTO gen_metadata VALUES (?, ?)", [ + 0, + new Uint8Array( + protoBytes(1, [ + ...protoText(19, "Gemini 3.8 Flash High"), + ...protoBytes(4, [...protoNumber(2, 100), ...protoText(11, "response")]), + ]), + ), + ]); + }), + ); + const result = yield* readAntigravityUsage(dir, 0); + assert.deepStrictEqual( + records(result).map((record) => [record.model, record.rateModel]), + [["gemini-3.8-flash-high", "gemini-3.8-flash"]], + ); + }).pipe(Effect.provide(NodeServices.layer)), + ); + it.effect("merges Antigravity aliases that bridge previously separate step records", () => Effect.gen(function* () { const path = yield* Path.Path; diff --git a/apps/server/src/provider/Drivers/antigravityUsageReader.ts b/apps/server/src/provider/Drivers/antigravityUsageReader.ts index e48609cf874d2..55c965e806d74 100644 --- a/apps/server/src/provider/Drivers/antigravityUsageReader.ts +++ b/apps/server/src/provider/Drivers/antigravityUsageReader.ts @@ -100,8 +100,29 @@ const MODEL_IDS: Record = { 1018: "gemini-3-flash-preview", 1084: "gemini-3-flash-preview", 1047: "gemini-3-flash-preview", + 342: "gpt-oss-120b-medium", + 1020: "gemini-3.5-flash-low", + 1072: "gemini-3.6-flash-medium", + 1073: "gemini-3.6-flash-low", + 1132: "gemini-3-flash-agent", + 1133: "gemini-3-flash-agent", + 1187: "gemini-3.5-flash-extra-low", + 1298: "gemini-3.7-flash-high", + 1299: "gemini-3.7-flash-medium", + 1301: "gemini-3.7-flash-tiered", + 1318: "gemini-3.8-flash-high", + 1319: "gemini-3.8-flash-medium", + 1320: "gemini-3.8-flash-low", + 1322: "gemini-3.8-flash-tiered", }; +/** Prices effort and routing variants such as `gemini-3.8-flash-high` at their base model. */ +function antigravityRateModel(model: string): string { + const base = model.replace(/-(?:extra-low|low|medium|high|tiered|control|thinking|agent)$/, ""); + // Rate tables only list Gemini 3 Flash under its preview name, as `MODEL_IDS` does. + return base === "gemini-3-flash" ? "gemini-3-flash-preview" : base; +} + function modelName(name: string, id: number): string { if (name) { const normalized = name @@ -267,16 +288,18 @@ function usageCandidates( const id = textAt(usage, key); return id ? [`antigravity:${key}:${id}`] : []; }); + const model = + MODEL_IDS[numberAt(usage, 1)] || + entry.model || + (source === "step" ? generationModels.get(idx) : "") || + modelName("", numberAt(usage, 1)) || + "antigravity-unknown"; const record: UsageRecord = { provider: "antigravity", sessionId, timestampMs: entry.timestampMs ?? trajectoryTimestamp ?? fallbackTimestamp, - model: - MODEL_IDS[numberAt(usage, 1)] || - entry.model || - (source === "step" ? generationModels.get(idx) : "") || - modelName("", numberAt(usage, 1)) || - "antigravity-unknown", + model, + rateModel: antigravityRateModel(model), totals, reportedCostUsd: null, speed: "standard", @@ -354,14 +377,16 @@ export const readAntigravityUsage = Effect.fn("readAntigravityUsage")(function* : target; const x = target.record.totals; const y = source.record.totals; + const model = + first.record.model === "antigravity-unknown" + ? first === target + ? source.record.model + : target.record.model + : first.record.model; target.record = { ...first.record, - model: - first.record.model === "antigravity-unknown" - ? first === target - ? source.record.model - : target.record.model - : first.record.model, + model, + rateModel: antigravityRateModel(model), timestampMs: bestTime.record.timestampMs, totals: { uncachedInputTokens: Math.max(x.uncachedInputTokens, y.uncachedInputTokens), From 7a83c6ca8fc3f3b41ce9aa6620c88ed2aa8ce075 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Mon, 19 Oct 2026 01:38:01 +0000 Subject: [PATCH 2/2] fix(server): derive the Antigravity rate model once at emission Fold the two rateModel computations into the final emission loop, where the post-merge model is settled, and collapse the two tests into one table. Co-Authored-By: Claude Fable 5.1 --- .../Drivers/antigravityUsageReader.test.ts | 35 +++++----------- .../Drivers/antigravityUsageReader.ts | 42 ++++++++++--------- 2 files changed, 33 insertions(+), 44 deletions(-) diff --git a/apps/server/src/provider/Drivers/antigravityUsageReader.test.ts b/apps/server/src/provider/Drivers/antigravityUsageReader.test.ts index 30250a54cbe20..f0fba79e36d54 100644 --- a/apps/server/src/provider/Drivers/antigravityUsageReader.test.ts +++ b/apps/server/src/provider/Drivers/antigravityUsageReader.test.ts @@ -164,7 +164,7 @@ describe("readAntigravityUsage", () => { }).pipe(Effect.provide(NodeServices.layer)), ); - it.effect("prices Antigravity effort variants at their base model", () => + it.effect("prices Antigravity effort and routing variants at their base model", () => Effect.gen(function* () { const path = yield* Path.Path; const dir = yield* tempDir; @@ -187,34 +187,13 @@ describe("readAntigravityUsage", () => { 2, new Uint8Array(protoBytes(9, [...protoNumber(1, 1132), ...protoNumber(2, 12)])), ]); - }), - ); - const result = yield* readAntigravityUsage(dir, 0); - assert.deepStrictEqual(result.errors, []); - assert.deepStrictEqual( - records(result).map((record) => [record.model, record.rateModel]), - [ - ["gemini-3.7-flash-control", "gemini-3.7-flash"], - ["gemini-3.8-flash-medium", "gemini-3.8-flash"], - ["gemini-3-flash-agent", "gemini-3-flash-preview"], - ], - ); - }).pipe(Effect.provide(NodeServices.layer)), - ); - - it.effect("prices a merged Antigravity alias by the model it adopts", () => - Effect.gen(function* () { - const path = yield* Path.Path; - const dir = yield* tempDir; - yield* seedDatabase(path.join(dir, "adopt.db"), (db) => - Effect.gen(function* () { - yield* createTables(db); + // A model-less step that only learns its model by merging with a named generation. yield* db.run("INSERT INTO steps VALUES (?, ?)", [ 5, new Uint8Array(protoBytes(9, [...protoNumber(2, 100), ...protoText(11, "response")])), ]); yield* db.run("INSERT INTO gen_metadata VALUES (?, ?)", [ - 0, + 3, new Uint8Array( protoBytes(1, [ ...protoText(19, "Gemini 3.8 Flash High"), @@ -225,9 +204,15 @@ describe("readAntigravityUsage", () => { }), ); const result = yield* readAntigravityUsage(dir, 0); + assert.deepStrictEqual(result.errors, []); assert.deepStrictEqual( records(result).map((record) => [record.model, record.rateModel]), - [["gemini-3.8-flash-high", "gemini-3.8-flash"]], + [ + ["gemini-3.7-flash-control", "gemini-3.7-flash"], + ["gemini-3.8-flash-medium", "gemini-3.8-flash"], + ["gemini-3-flash-agent", "gemini-3-flash-preview"], + ["gemini-3.8-flash-high", "gemini-3.8-flash"], + ], ); }).pipe(Effect.provide(NodeServices.layer)), ); diff --git a/apps/server/src/provider/Drivers/antigravityUsageReader.ts b/apps/server/src/provider/Drivers/antigravityUsageReader.ts index 3e711886fc15d..3dc2f4ce67d02 100644 --- a/apps/server/src/provider/Drivers/antigravityUsageReader.ts +++ b/apps/server/src/provider/Drivers/antigravityUsageReader.ts @@ -115,10 +115,13 @@ const MODEL_IDS: Record = { 1322: "gemini-3.8-flash-tiered", }; -/** Prices effort and routing variants such as `gemini-3.8-flash-high` at their base model. */ +/** + * Antigravity names effort and routing variants (`gemini-3.8-flash-high`, + * `gemini-3-flash-agent`) that the rate table only lists as the base model, and + * Gemini 3 Flash only under its preview name. + */ function antigravityRateModel(model: string): string { const base = model.replace(/-(?:extra-low|low|medium|high|tiered|control|thinking|agent)$/, ""); - // Rate tables only list Gemini 3 Flash under its preview name, as `MODEL_IDS` does. return base === "gemini-3-flash" ? "gemini-3-flash-preview" : base; } @@ -317,18 +320,16 @@ function usageCandidates( const id = textAt(usage, key); return id ? [`antigravity:${key}:${id}`] : []; }); - const model = - MODEL_IDS[numberAt(usage, 1)] || - entry.model || - (source === "step" ? generationModels.get(idx) : "") || - modelName("", numberAt(usage, 1)) || - "antigravity-unknown"; const record: UsageRecord = { provider: "antigravity", sessionId, timestampMs: entry.timestampMs ?? trajectoryTimestamp ?? fallbackTimestamp, - model, - rateModel: antigravityRateModel(model), + model: + MODEL_IDS[numberAt(usage, 1)] || + entry.model || + (source === "step" ? generationModels.get(idx) : "") || + modelName("", numberAt(usage, 1)) || + "antigravity-unknown", totals, reportedCostUsd: null, speed: "standard", @@ -401,16 +402,14 @@ export const readAntigravityUsage = Effect.fn("readAntigravityUsage")(function* : target; const x = target.record.totals; const y = source.record.totals; - const model = - first.record.model === "antigravity-unknown" - ? first === target - ? source.record.model - : target.record.model - : first.record.model; target.record = { ...first.record, - model, - rateModel: antigravityRateModel(model), + model: + first.record.model === "antigravity-unknown" + ? first === target + ? source.record.model + : target.record.model + : first.record.model, timestampMs: bestTime.record.timestampMs, totals: { uncachedInputTokens: Math.max(x.uncachedInputTokens, y.uncachedInputTokens), @@ -505,7 +504,12 @@ export const readAntigravityUsage = Effect.fn("readAntigravityUsage")(function* } for (const [index, group] of groups.entries()) { if (group.parent === index && group.record.timestampMs >= sinceMs) { - files[group.fileIndex]!.records.push(group.record); + // Merging may still swap an `antigravity-unknown` model for a named one, so price here. + const { record } = group; + files[group.fileIndex]!.records.push({ + ...record, + rateModel: antigravityRateModel(record.model), + }); } } return { files, errors };