fix: use fetchAvailableModels for Antigravity quota instead of retrieveUserQuota

retrieveUserQuota only returns Gemini model quotas. fetchAvailableModels
returns all models (including Claude) with per-model quotaInfo.
This commit is contained in:
Chris Staley
2026-03-31 16:50:33 -06:00
parent fbd30dc4ee
commit 89eb5b7eb9
+43 -40
View File
@@ -657,34 +657,26 @@ function getAntigravityPlanLabel(subscriptionInfo) {
/**
* Antigravity Usage - Fetch quota from Google Cloud Code API
* Now calls loadCodeAssist ONCE (cached) and reuses for projectId + plan.
* Uses retrieveUserQuota API (same as Gemini CLI) for accurate quota data across all tiers.
* Uses fetchAvailableModels API which returns ALL models (including Claude)
* with per-model quotaInfo (remainingFraction, resetTime).
* retrieveUserQuota only returns Gemini models — not suitable for Antigravity.
*/
async function getAntigravityUsage(accessToken, providerSpecificData) {
try {
const subscriptionInfo = await getAntigravitySubscriptionInfoCached(accessToken);
const projectId = subscriptionInfo?.cloudaicompanionProject || null;
if (!projectId) {
return {
plan: getAntigravityPlanLabel(subscriptionInfo),
message: "Antigravity project ID not available.",
};
}
// Use retrieveUserQuota API (same as Gemini CLI) - works correctly for both Free and Pro tiers
const response = await fetch(
"https://cloudcode-pa.googleapis.com/v1internal:retrieveUserQuota",
{
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ project: projectId }),
signal: AbortSignal.timeout(10000),
}
);
// Fetch model list with quota info from fetchAvailableModels
const response = await fetch(ANTIGRAVITY_CONFIG.quotaApiUrl, {
method: "POST",
headers: {
Authorization: `Bearer ${accessToken}`,
"User-Agent": ANTIGRAVITY_CONFIG.userAgent,
"Content-Type": "application/json",
},
body: JSON.stringify(projectId ? { project: projectId } : {}),
signal: AbortSignal.timeout(10000),
});
if (response.status === 403) {
return { message: "Antigravity access forbidden. Check subscription." };
@@ -695,28 +687,39 @@ async function getAntigravityUsage(accessToken, providerSpecificData) {
}
const data = await response.json();
const dataObj = toRecord(data);
const modelEntries = toRecord(dataObj.models);
const quotas: Record<string, UsageQuota> = {};
// Parse buckets from retrieveUserQuota response (same format as Gemini CLI)
if (Array.isArray(data.buckets)) {
for (const bucket of data.buckets) {
if (!bucket.modelId || bucket.remainingFraction == null) continue;
// Parse per-model quota info from fetchAvailableModels response.
// Show all models that have quota data, excluding only internal models
// (tab-completion, chat placeholders, etc.).
for (const [modelKey, infoValue] of Object.entries(modelEntries)) {
const info = toRecord(infoValue);
const quotaInfo = toRecord(info.quotaInfo);
const remainingFraction = toNumber(bucket.remainingFraction, 0);
const remainingPercentage = remainingFraction * 100;
const QUOTA_NORMALIZED_BASE = 1000;
const total = QUOTA_NORMALIZED_BASE;
const remaining = Math.round(total * remainingFraction);
const used = Math.max(0, total - remaining);
quotas[bucket.modelId] = {
used,
total,
resetAt: parseResetTime(bucket.resetTime),
remainingPercentage,
unlimited: false,
};
// Skip internal models and models without quota info
if (info.isInternal === true || Object.keys(quotaInfo).length === 0) {
continue;
}
const remainingFraction = toNumber(quotaInfo.remainingFraction, 0);
const resetAt = parseResetTime(quotaInfo.resetTime);
// Models with no resetTime and full remaining are unlimited (e.g. tab-completion models)
const isUnlimited = !resetAt && remainingFraction >= 1;
const remainingPercentage = remainingFraction * 100;
const QUOTA_NORMALIZED_BASE = 1000;
const total = QUOTA_NORMALIZED_BASE;
const remaining = Math.round(total * remainingFraction);
const used = isUnlimited ? 0 : Math.max(0, total - remaining);
quotas[modelKey] = {
used,
total: isUnlimited ? 0 : total,
resetAt,
remainingPercentage: isUnlimited ? 100 : remainingPercentage,
unlimited: isUnlimited,
};
}
return {