fix(omp): show Antigravity weekly usage limits

This commit is contained in:
Alexander Kirilin
2026-06-27 16:01:20 -04:00
parent 2708c1edb8
commit 600e712bc2
4 changed files with 199 additions and 39 deletions
+4
View File
@@ -6,6 +6,10 @@
- Default reasoning context to `all_turns` for all Codex requests
### Fixed
- Fixed Antigravity usage reporting to surface named daily and weekly quota windows from Cloud Code Assist model metadata, so `/usage` can show weekly Antigravity limits instead of collapsing them into the default bucket.
## [16.2.2] - 2026-06-27
### Added
+91 -39
View File
@@ -29,7 +29,13 @@ interface AntigravityModelInfo {
displayName?: string;
quotaInfo?: AntigravityQuotaInfo | AntigravityQuotaInfo[];
quotaInfos?: AntigravityQuotaInfo[];
dailyQuotaInfo?: AntigravityQuotaInfo | AntigravityQuotaInfo[];
dailyQuotaInfos?: AntigravityQuotaInfo[];
weeklyQuotaInfo?: AntigravityQuotaInfo | AntigravityQuotaInfo[];
weeklyQuotaInfos?: AntigravityQuotaInfo[];
quotaInfoByTier?: Record<string, AntigravityQuotaInfo | AntigravityQuotaInfo[]>;
quotaInfoByWindow?: Record<string, AntigravityQuotaInfo | AntigravityQuotaInfo[]>;
quotaInfosByWindow?: Record<string, AntigravityQuotaInfo | AntigravityQuotaInfo[]>;
apiProvider?: string;
modelProvider?: string;
}
@@ -41,6 +47,39 @@ interface AntigravityUsageResponse {
const DEFAULT_ENDPOINT = "https://daily-cloudcode-pa.googleapis.com";
const FETCH_AVAILABLE_MODELS_PATH = "/v1internal:fetchAvailableModels";
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
const ONE_WEEK_MS = 7 * ONE_DAY_MS;
interface AntigravityWindowDescriptor {
id: string;
label: string;
durationMs?: number;
}
function classifyWindow(id: string | undefined, label: string | undefined): AntigravityWindowDescriptor | undefined {
const source = `${id ?? ""} ${label ?? ""}`.toLowerCase();
if (source.includes("week") || source.includes("7d") || /7[\s_-]*day/.test(source)) {
return { id: "weekly", label: "Weekly", durationMs: ONE_WEEK_MS };
}
if (source.includes("day") || source.includes("daily") || source.includes("24h")) {
return { id: "daily", label: "Daily", durationMs: ONE_DAY_MS };
}
if (id || label) return { id: id ?? label ?? "default", label: label ?? id ?? "Default" };
return undefined;
}
function withWindowDescriptor(
info: AntigravityQuotaInfo,
descriptor: AntigravityWindowDescriptor | undefined,
): AntigravityQuotaInfo {
if (!descriptor) return info;
return {
...info,
windowId: info.windowId ?? descriptor.id,
windowLabel: info.windowLabel ?? descriptor.label,
};
}
function clampFraction(value: number | undefined): number | undefined {
if (value === undefined || !Number.isFinite(value)) return undefined;
if (value < 0) return 0;
@@ -56,13 +95,15 @@ function getUsageStatus(remainingFraction: number | undefined): UsageStatus | un
}
function parseWindow(info: AntigravityQuotaInfo): UsageWindow | undefined {
if (!info.resetTime) return undefined;
const resetAt = Date.parse(info.resetTime);
if (!Number.isFinite(resetAt)) return undefined;
const descriptor = classifyWindow(info.windowId, info.windowLabel);
const resetAt = info.resetTime ? Date.parse(info.resetTime) : undefined;
const hasResetAt = resetAt !== undefined && Number.isFinite(resetAt);
if (!descriptor && !hasResetAt) return undefined;
return {
id: info.windowId ?? "default",
label: info.windowLabel ?? "Default",
resetsAt: resetAt,
id: descriptor?.id ?? info.windowId ?? "default",
label: info.windowLabel ?? descriptor?.label ?? "Default",
...(descriptor?.durationMs !== undefined ? { durationMs: descriptor.durationMs } : {}),
...(hasResetAt ? { resetsAt: resetAt } : {}),
};
}
@@ -106,31 +147,44 @@ function normalizeQuotaInfos(info: AntigravityModelInfo): AntigravityQuotaInfo[]
...(info.apiProvider ? { apiProvider: info.apiProvider } : {}),
...(info.modelProvider ? { modelProvider: info.modelProvider } : {}),
};
const addInfo = (value: AntigravityQuotaInfo, tier?: string) => {
results.push({ ...source, ...value, ...(tier ? { tier } : {}) });
const addInfo = (value: AntigravityQuotaInfo, tier?: string, windowDescriptor?: AntigravityWindowDescriptor) => {
results.push({ ...source, ...withWindowDescriptor(value, windowDescriptor), ...(tier ? { tier } : {}) });
};
const addArray = (values?: AntigravityQuotaInfo[]) => {
if (!values) return;
for (const value of values) addInfo(value);
const addValue = (
value: AntigravityQuotaInfo | AntigravityQuotaInfo[] | undefined,
tier?: string,
windowDescriptor?: AntigravityWindowDescriptor,
) => {
if (!value) return;
if (Array.isArray(value)) {
for (const entry of value) addInfo(entry, tier, windowDescriptor);
return;
}
addInfo(value, tier, windowDescriptor);
};
if (Array.isArray(info.quotaInfo)) {
addArray(info.quotaInfo);
} else if (info.quotaInfo) {
addInfo(info.quotaInfo);
}
addArray(info.quotaInfos);
addValue(info.quotaInfo);
addValue(info.quotaInfos);
addValue(info.dailyQuotaInfo, undefined, classifyWindow("daily", "Daily"));
addValue(info.dailyQuotaInfos, undefined, classifyWindow("daily", "Daily"));
addValue(info.weeklyQuotaInfo, undefined, classifyWindow("weekly", "Weekly"));
addValue(info.weeklyQuotaInfos, undefined, classifyWindow("weekly", "Weekly"));
if (info.quotaInfoByTier) {
for (const [tier, value] of Object.entries(info.quotaInfoByTier)) {
if (Array.isArray(value)) {
for (const entry of value) addInfo(entry, tier);
} else if (value) {
addInfo(value, tier);
}
addValue(value, tier);
}
}
const addWindowMap = (values?: Record<string, AntigravityQuotaInfo | AntigravityQuotaInfo[]>) => {
if (!values) return;
for (const [windowId, value] of Object.entries(values)) {
addValue(value, undefined, classifyWindow(windowId, undefined));
}
};
addWindowMap(info.quotaInfoByWindow);
addWindowMap(info.quotaInfosByWindow);
return results;
}
@@ -231,9 +285,10 @@ async function fetchAntigravityUsage(params: UsageFetchParams, ctx: UsageFetchCo
const tierKey = (quotaInfo.tier ?? "default").toLowerCase();
const counterName = formatCounterName(quotaInfo);
const counterKey = counterName?.toLowerCase() ?? "default";
// Use quotaInfo.windowId even when parseWindow returns undefined
// (no resetTime) — separate windows must not collapse to "default".
const windowId = quotaInfo.windowId ?? window?.id ?? "default";
// Use the parsed window id when available so provider enum names like
// WINDOW_WEEKLY normalize into the same visible `/usage` group as
// weeklyQuotaInfo entries.
const windowId = window?.id ?? quotaInfo.windowId ?? "default";
const key = `${counterKey}|${tierKey}|${windowId}`;
const existing = deduped.get(key);
if (!existing) {
@@ -324,8 +379,6 @@ export const antigravityUsageProvider: UsageProvider = {
supports: params => params.provider === "google-antigravity",
};
const ONE_DAY_MS = 24 * 60 * 60 * 1000;
function getAntigravityCounterKeyForModel(context: CredentialRankingContext | undefined): string | undefined {
const modelId = context?.modelId?.toLowerCase();
if (!modelId) return undefined;
@@ -361,17 +414,16 @@ function rankAntigravityLimits(report: UsageReport, context: CredentialRankingCo
}
/**
* Antigravity quotas reset daily and are returned per backend counter
* (Anthropic / Google / OpenAI) without a fixed "primary vs secondary"
* split. `fetchAntigravityUsage` already sorts `limits` ascending by
* `remainingFraction`; after model-family scoping, the most-pressured
* relevant counter is index 0.
* Antigravity quotas are returned per backend counter (Anthropic / Google /
* OpenAI) and can include both daily and weekly windows. `fetchAntigravityUsage`
* sorts `limits` ascending by `remainingFraction`; after model-family scoping,
* the most-pressured relevant counter/window is index 0.
*
* Leave `secondary` unset: AuthStorage compares secondary metrics before
* primary metrics, which is correct for providers with explicit long-window
* limits but wrong here. Ranking Antigravity by the bottleneck counter first
* avoids preferring an account at 95% Gemini / 0% Claude over one at
* 80% Gemini / 70% Claude.
* primary metrics, which is correct for providers with a fixed short/long
* split but wrong here. Ranking Antigravity by the bottleneck counter first
* avoids preferring an account at 95% Gemini daily / 0% Claude weekly over one
* with healthier Gemini headroom.
*/
export const antigravityRankingStrategy: CredentialRankingStrategy = {
findWindowLimits(report, context) {
@@ -384,8 +436,8 @@ export const antigravityRankingStrategy: CredentialRankingStrategy = {
const counterKey = getAntigravityCounterKeyForModel(context);
return `counter:${counterKey ?? "unknown"}`;
},
// Antigravity windows omit `durationMs`; the endpoint is
// `daily-cloudcode-pa.googleapis.com`, so fall back to 24h when computing
// drain rate.
// Antigravity windows carry `durationMs` when the response identifies them
// as daily/weekly. Fall back to daily for legacy unlabelled quotaInfo
// entries from `daily-cloudcode-pa.googleapis.com`.
windowDefaults: { primaryMs: ONE_DAY_MS, secondaryMs: ONE_DAY_MS },
};
@@ -188,6 +188,60 @@ describe("antigravity usage provider", () => {
expect(report!.limits.length).toBe(2);
});
it("surfaces named daily and weekly quota windows as separate limits", async () => {
const now = Date.now();
const dailyReset = new Date(now + 12 * 3600_000).toISOString();
const weeklyReset = new Date(now + 6 * 24 * 3600_000).toISOString();
const payload = {
models: {
gemini: {
displayName: "Gemini",
modelProvider: "MODEL_PROVIDER_GOOGLE",
quotaInfo: { remainingFraction: 0.8, resetTime: dailyReset, windowId: "WINDOW_DAILY" },
weeklyQuotaInfo: { remainingFraction: 0.4, resetTime: weeklyReset },
},
},
};
const report = await antigravityUsageProvider.fetchUsage!(
{ provider: "google-antigravity", credential: makeCredential(), signal: undefined },
makeCtx(fakeFetch(payload)),
);
const daily = report!.limits.find(limit => limit.scope.windowId === "daily");
const weekly = report!.limits.find(limit => limit.scope.windowId === "weekly");
expect(report!.limits.length).toBe(2);
expect(daily?.label).toBe("Usage (Google)");
expect(daily?.window?.label).toBe("Daily");
expect(daily?.window?.durationMs).toBe(24 * 60 * 60 * 1000);
expect(daily?.amount.remainingFraction).toBe(0.8);
expect(weekly?.label).toBe("Usage (Google)");
expect(weekly?.window?.label).toBe("Weekly");
expect(weekly?.window?.durationMs).toBe(7 * 24 * 60 * 60 * 1000);
expect(weekly?.amount.remainingFraction).toBe(0.4);
});
it("normalizes 7 Day window ids to the weekly usage window", async () => {
const payload = {
models: {
gemini: {
displayName: "Gemini",
modelProvider: "MODEL_PROVIDER_GOOGLE",
quotaInfoByWindow: {
WINDOW_7_DAY: { remainingFraction: 0.6 },
},
},
},
};
const report = await antigravityUsageProvider.fetchUsage!(
{ provider: "google-antigravity", credential: makeCredential(), signal: undefined },
makeCtx(fakeFetch(payload)),
);
expect(report!.limits).toHaveLength(1);
expect(report!.limits[0]!.scope.windowId).toBe("weekly");
expect(report!.limits[0]!.window?.label).toBe("Weekly");
});
it("includes email and projectId in report metadata", async () => {
const payload = { models: { m: makeApiModel("M", { remainingFraction: 1 }) } };
const report = await antigravityUsageProvider.fetchUsage!(
@@ -274,6 +328,24 @@ describe("antigravity ranking strategy", () => {
expect(secondary).toBeUndefined();
});
it("lets a weekly Antigravity quota become the ranking bottleneck", () => {
const daily = makeLimit(0.8, "Google Daily");
const weekly = makeLimit(0.2, "Google Weekly");
daily.scope.windowId = "daily";
daily.window = { id: "daily", label: "Daily", durationMs: 24 * 60 * 60 * 1000 };
weekly.scope.windowId = "weekly";
weekly.window = { id: "weekly", label: "Weekly", durationMs: 7 * 24 * 60 * 60 * 1000 };
const report = {
provider: "google-antigravity" as const,
fetchedAt: Date.now(),
limits: [weekly, daily],
};
const { primary, secondary } = antigravityRankingStrategy.findWindowLimits(report);
expect(primary).toBe(weekly);
expect(secondary).toBeUndefined();
});
it("returns undefined windows when the credential has no usage limits", () => {
const report = {
provider: "google-antigravity" as const,
@@ -213,6 +213,38 @@ describe("formatUsageBreakdown", () => {
expect(disclaimerIdx).toBeLessThan(firstLimitIdx);
});
it("renders Antigravity weekly windows in the usage breakdown", () => {
const now = Date.parse("2026-01-01T00:00:00.000Z");
const reports: UsageReport[] = [
{
provider: "google-antigravity",
fetchedAt: now,
metadata: { email: "ag@example.test", projectId: "proj-1" },
limits: [
{
id: "google-antigravity:google:default:weekly",
label: "Usage (Google)",
scope: { provider: "google-antigravity", projectId: "proj-1", windowId: "weekly" },
window: {
id: "weekly",
label: "Weekly",
durationMs: SEVEN_DAYS,
resetsAt: now + SEVEN_DAYS,
},
amount: { unit: "percent", usedFraction: 0.6, remainingFraction: 0.4 },
status: "ok",
},
],
},
];
const text = stripVTControlCharacters(formatUsageBreakdown(reports, [], now));
expect(text).toContain("Google Antigravity");
expect(text).toContain("Usage (Google) (Weekly)");
expect(text).toContain("60.0% used");
expect(text).toContain("0.40× quota left");
});
it("renders saved reset expiry state for future and expired credits", () => {
const now = Date.parse("2026-01-01T00:00:00.000Z");
const reports: UsageReport[] = [