Skip to content

fix(antigravity): align subscription tier detection with Antigravity Manager#2496

Merged
diegosouzapw merged 3 commits into
diegosouzapw:release/v3.8.2from
Gi99lin:fix/antigravity-subscription-tier
May 21, 2026
Merged

fix(antigravity): align subscription tier detection with Antigravity Manager#2496
diegosouzapw merged 3 commits into
diegosouzapw:release/v3.8.2from
Gi99lin:fix/antigravity-subscription-tier

Conversation

@Gi99lin
Copy link
Copy Markdown
Contributor

@Gi99lin Gi99lin commented May 21, 2026

Summary

  • Add shared loadCodeAssist tier extraction (paidTiercurrentTier → restricted allowedTiers default), matching Antigravity Manager.
  • Fix loadCodeAssist metadata on Linux/Docker: send only { ideType: "ANTIGRAVITY" } (Google rejects platform: "LINUX").
  • Bust subscription cache on manual quota refresh and persist tier / subscriptionTier / plan back to connections.
  • Prefer live usage plan over stale persisted tier in Provider Limits UI.

Test plan

  • tests/unit/code-assist-subscription.test.ts
  • tests/unit/antigravity-headers.test.ts
  • tests/unit/oauth-providers-config.test.ts (Antigravity OAuth)
  • tests/unit/usage-service-hardening.test.ts (Antigravity plan labels + refresh cache)
  • Manual: connect Antigravity Pro account on Linux Docker, refresh quotas → plan shows Pro without re-auth

…Manager

Extract paid/current/restricted tiers from loadCodeAssist (shared module), fix invalid LINUX metadata on Docker, refresh tier on quota update without re-auth, and persist tier fields back to connections.

Co-authored-by: Cursor <cursoragent@cursor.com>
@Gi99lin Gi99lin requested a review from diegosouzapw as a code owner May 21, 2026 14:24
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors Antigravity subscription and plan label extraction logic to align with Antigravity Manager, introducing a centralized extraction service and a synchronization mechanism to persist live subscription data during quota refreshes. It also simplifies metadata headers and improves error handling within the usage service. Feedback from the review focuses on simplifying the tier ID extraction logic to remove redundant checks and optimizing the usage service to avoid duplicate cached data lookups during error scenarios.

Comment on lines +70 to +92
if (!isIneligible(subscription)) {
const currentId = pickTierField(subscription.currentTier, "id");
if (currentId) return currentId;
} else {
const defaultTier = findDefaultAllowedTier(subscription);
const defaultId = defaultTier ? pickTierField(defaultTier, "id") : null;
if (defaultId) return defaultId;
}

if (Array.isArray(subscription.allowedTiers)) {
for (const tierValue of subscription.allowedTiers) {
const tier = toRecord(tierValue);
if (tier.isDefault) {
const id = pickTierField(tier, "id");
if (id) return id;
}
}
}

const currentId = pickTierField(subscription.currentTier, "id");
if (currentId) return currentId;

return "legacy-tier";
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic for extracting the tier ID can be simplified. The loop over allowedTiers (lines 79-87) is redundant because it performs the same check as findDefaultAllowedTier (called at line 74). Additionally, the fallback to currentTier at line 89 can be unified with the initial check to improve readability and maintainability.

  if (!isIneligible(subscription)) {
    const currentId = pickTierField(subscription.currentTier, "id");
    if (currentId) return currentId;
  }

  const defaultTier = findDefaultAllowedTier(subscription);
  const defaultId = defaultTier ? pickTierField(defaultTier, "id") : null;
  if (defaultId) return defaultId;

  const currentId = pickTierField(subscription.currentTier, "id");
  if (currentId) return currentId;

  return "legacy-tier";

Comment thread open-sse/services/usage.ts Outdated
Comment on lines +1911 to +1920
let subscriptionInfo: unknown = null;
try {
subscriptionInfo = await getAntigravitySubscriptionInfoCached(
accessToken,
providerSpecificData,
options
);
} catch {
subscriptionInfo = null;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block performs a redundant call to getAntigravitySubscriptionInfoCached. Since this function was already called at the beginning of the getAntigravityUsage function (line 1813), you can reuse the result by declaring subscriptionInfo outside the try block. This avoids unnecessary overhead and potential duplicate network requests in error scenarios, especially when forceRefresh is enabled, as it would trigger another network attempt if the first one failed.

… cache

Simplify onboard tier ID fallback and reuse subscription lookup in error path.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread open-sse/services/usage.ts Outdated
*/
function getAntigravityPlanLabel(subscriptionInfo: unknown, fallbackInfo?: unknown): string {
const plan = mapCodeAssistSubscriptionToPlanLabel(subscriptionInfo);
if (plan !== "Free") return plan;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: getAntigravityPlanLabel returns immediately when live plan is not "Free", skipping the fallback to providerSpecificData. If the live subscription produces an unrecognized non-"Free" tier (e.g., a new tier type not yet in the mapping), the fallback to persisted data is never tried. This aligns with the PR goal to prefer live data, but could miss a better tier label when live data returns an unmapped value like a raw tier ID. Consider checking whether the mapped plan is a known tier before deciding to skip the fallback.

Comment thread open-sse/services/usage.ts Outdated
if (tierId === "legacy-tier") return "";
const upper = tierId.toUpperCase();
if (mapCodeAssistTierIdToLabel(upper)) return upper;
return upper;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SUGGESTION: extractCodeAssistTierId returns upper even when mapCodeAssistTierIdToLabel(upper) returns null, meaning it can return arbitrary uppercase strings like "TIER_UNKNOWN_CUSTOM". While the caller (mapCodeAssistSubscriptionToPlanLabel) handles this by re-checking against mapCodeAssistTierIdToLabel, the function name suggests it extracts a valid tier ID rather than an uppercased raw value. Consider returning "" or null when no known mapping exists, to make the contract clearer.

@kilo-code-bot
Copy link
Copy Markdown

kilo-code-bot Bot commented May 21, 2026

Code Review Summary

Status: 2 SUGGESTIONs Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 0
SUGGESTION 2
Issue Details (click to expand)

SUGGESTION

File Line Issue
open-sse/services/usage.ts 1644 getAntigravityPlanLabel returns immediately when live plan is not "Free", skipping fallback to persisted data. Unrecognized non-"Free" tiers would bypass the fallback even when persisted data might have a better mapped label.
open-sse/services/usage.ts 1566 extractCodeAssistTierId returns arbitrary uppercase strings (e.g. "TIER_UNKNOWN") when no mapping exists, which is semantically misleading given the function name. Caller handles this, but contract could be clearer.
Other Observations (not in diff)

Issues found in unchanged code that cannot receive inline comments:

File Line Issue
open-sse/services/usage.ts 1854-1855 Forbidden response (__antigravityForbidden) returns only { message } without plan or subscriptionInfo. When this path is hit, syncAntigravitySubscriptionIfNeeded in providerLimits.ts will skip persisting tier data entirely since it checks if (!subscriptionInfo) return connection;. Consider including subscriptionInfo (which was already fetched at this point) so tier data can still be persisted even when access is forbidden.
Files Reviewed (10 files)
  • open-sse/services/codeAssistSubscription.ts - New module, clean tier extraction logic, 2 inline comments
  • open-sse/services/antigravityHeaders.ts - Simplified metadata (removed platform/pluginType), no issues
  • open-sse/services/usage.ts - Refactored plan label mapping, 2 inline comments + 1 summary observation
  • src/app/(dashboard)/dashboard/usage/components/ProviderLimits/utils.tsx - Prefer live plan logic, no issues
  • src/lib/oauth/providers/antigravity.ts - Uses shared extraction, adds tier to providerSpecificData, no issues
  • src/lib/oauth/services/antigravity.ts - Uses shared extraction, no issues
  • src/lib/usage/providerLimits.ts - New syncAntigravitySubscriptionIfNeeded function, no issues
  • tests/unit/antigravity-headers.test.ts - New test file, validates simplified metadata, no issues
  • tests/unit/code-assist-subscription.test.ts - New test file, 6 test cases covering main scenarios
  • tests/unit/usage-service-hardening.test.ts - Updated to track loadCodeAssist calls, adds plan label tests

Reviewed by qwen3.6-plus · 616,050 tokens

Prefer persisted tier when live subscription maps to an unknown label,
and only return mapped tier IDs from extractCodeAssistTierId. Add
regression test for fallback from providerSpecificData.

Co-authored-by: Cursor <cursoragent@cursor.com>
@kilo-code-bot
Copy link
Copy Markdown

kilo-code-bot Bot commented May 21, 2026

Kilo Code Review could not run — your account is out of credits.

Add credits or switch to a free model to enable reviews on this change.

@diegosouzapw diegosouzapw changed the base branch from main to release/v3.8.2 May 21, 2026 18:46
@diegosouzapw diegosouzapw merged commit 7cbb51d into diegosouzapw:release/v3.8.2 May 21, 2026
55 of 72 checks passed
@diegosouzapw
Copy link
Copy Markdown
Owner

Thank you for this contribution! 🎉 Your fix has been integrated into the release/v3.8.2 branch via local merge (conflicts resolved). Will ship with v3.8.2.

@diegosouzapw diegosouzapw mentioned this pull request May 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants