Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions app/Sources/MenuBarCore/ProxyModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ public struct UsageAccountRow: Decodable, Equatable, Sendable {
}

public struct QuotaWindow: Decodable, Equatable, Sendable {
public let modelId: String?
public let label: String?
public let percent: Double?
public let resetAt: Double?
Expand All @@ -188,6 +189,7 @@ public struct QuotaReport: Decodable, Equatable, Sendable {

/// A provider-agnostic view of quota, since the window key differs per provider.
public struct NormalizedQuota: Equatable, Sendable {
public let modelId: String?
public let provider: String
public let providerLabel: String
public let percent: Double?
Expand Down Expand Up @@ -219,10 +221,10 @@ public extension QuotaReport {
let name = label ?? provider
var windows: [NormalizedQuota] = []

func append(_ percent: Double?, _ windowLabel: String, _ resetAt: Double?) {
func append(_ percent: Double?, _ windowLabel: String, _ resetAt: Double?, _ modelId: String? = nil) {
guard percent != nil || resetAt != nil else { return }
windows.append(NormalizedQuota(
provider: provider, providerLabel: name, percent: percent,
modelId: modelId, provider: provider, providerLabel: name, percent: percent,
windowLabel: windowLabel, resetAt: Self.date(from: resetAt)
))
}
Expand All @@ -232,15 +234,16 @@ public extension QuotaReport {
append(quota?.monthlyPercent, "month", quota?.monthlyResetAt)

for window in quota?.customWindows ?? [] {
append(window.percent, window.label ?? "window", window.resetAt)
append(window.percent, window.label ?? "window", window.resetAt, window.modelId)
}

return windows
}

/// The single window that best represents current pressure, for the compact row.
///
/// Selection is **highest reported usage**, not longest horizon. Every window can
/// Diagnostic model rows are retained in details and excluded here. Selection is
/// **highest reported usage**, not longest horizon. Every aggregate window can
/// stop work: a provider at 99% of a five-hour limit and 10% of its monthly limit is
/// blocked right now, and showing the monthly 10% would paint that row green while
/// the user cannot make a request. Ties break toward the longer horizon, since that
Expand All @@ -250,7 +253,7 @@ public extension QuotaReport {
/// em dash rather than a misleading zero.
func normalized() -> NormalizedQuota {
let name = label ?? provider
let windows = normalizedWindows()
let windows = normalizedWindows().filter { $0.modelId == nil }

// Longer horizons rank higher only as a tie-breaker.
func horizonRank(_ label: String) -> Int {
Expand All @@ -271,7 +274,7 @@ public extension QuotaReport {
} ?? windows.first

return preferred ?? NormalizedQuota(
provider: provider, providerLabel: name, percent: nil,
modelId: nil, provider: provider, providerLabel: name, percent: nil,
windowLabel: "—", resetAt: nil
)
}
Expand Down
17 changes: 17 additions & 0 deletions app/Sources/MenuBarCoreTests/ModelDecodingSuite.swift
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,23 @@ enum ModelDecodingSuite {
t.equal(report.normalized().percent, 12)
}

t.test("quotas: model diagnostics stay detailed and cannot become compact pressure") {
let json = """
{"provider":"google-antigravity","quota":{"customWindows":[
{"label":"aux","modelId":"aux","percent":100},
{"label":"Gem","percent":20}]}}
"""
let report = try decode(QuotaReport.self, json)
t.equal(report.normalized().percent, 20)
t.equal(report.normalized().windowLabel, "Gem")
t.equal(report.normalizedWindows().count, 2)
t.equal(report.quota?.customWindows?.first?.modelId, "aux")
t.equal(report.normalizedWindows().first?.modelId, "aux")
let onlyModel = try decode(QuotaReport.self,
#"{"provider":"p","quota":{"customWindows":[{"label":"aux","modelId":"aux","percent":100}]}}"#)
t.isNil(onlyModel.normalized().percent, "model-only compact percent")
}

t.test("quotas: an absent quota normalizes to a nil percent") {
let normalized = try decode(QuotaReport.self, #"{"provider":"p","label":"P"}"#).normalized()
t.isNil(normalized.percent, "percent")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,9 @@ from that account's own credential and Cloud Code Assist project id. The per-acc
talks to Google's Cloud Code Assist host through the pinned outbound transport, regardless of a
configured `baseUrl`: a custom base URL is a routing choice for requests, not a second source of
Google's accounting for a stored credential. An account without a project id, or one whose probe
is redirected or fails, shows `unavailable`.
is redirected or fails, shows `unavailable`. When fallback model discovery supplies quota readings,
detailed displays retain up to 256 model diagnostics with distinct bounded labels. These rows do not
affect provider summary headlines, severity, account ranking, routing, or reset notifications.

Devin rows come from Cognition's `GetUserStatus` for that account's own key, sent to its
allowlisted api-server host. If an older credential has no host, the probe uses the configured
Expand Down
4 changes: 4 additions & 0 deletions docs-site/src/content/docs/reference/management-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,10 @@ also preserves an omitted setting, including the latest stored `false`; an expli
boolean wins. See [Context windows on custom providers](/reference/configuration/providers/#context-windows-on-custom-providers)
for its default-off, custom-provider-only behavior.

When Antigravity's quota-summary endpoint has no usable response, quota reports may also include
per-model Cloud Code Assist usage windows when the model-discovery response provides them. These
measurements are diagnostic; an absent model window does not establish that the model is unavailable.

The provider context-cap response includes `caps` (active limits) and `values` (last selected
values, retained while disabled). Enabling a provider without `value` restores its selection,
or uses the global `contextCapValue` on first enable. This also applies to OpenAI: the switch
Expand Down
2 changes: 1 addition & 1 deletion gui/src/codex-quota-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export interface AccountQuota {
shortObservedAt?: number;
shortWindowSeconds?: number;
monthlyResetAt?: number;
customWindows?: { label: string; percent: number; resetAt?: number }[];
customWindows?: { label: string; percent: number; resetAt?: number; modelId?: string }[];
creditsUsd?: {
used: number;
limit: number;
Expand Down
21 changes: 15 additions & 6 deletions gui/src/components/QuotaBars.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { type AccountQuota, normalizeQuotaForPlan } from "../codex-quota-utils";

export type QuotaWindowKey = "fiveHour" | "weekly" | "monthly";
export type QuotaBarRow = {
id: string;
windowKey?: QuotaWindowKey;
customLabel?: string;
label: string;
Expand Down Expand Up @@ -69,7 +70,7 @@ export function buildQuotaRows(quota: AccountQuota | null, plan: string | null |
const displayQuota = normalizeQuotaForPlan(quota, plan);
if (!displayQuota) return [];
// Intrinsic ranks for the standard slots; custom windows rank on their RAW labels.
const ranked: Array<{ rank: number; row: QuotaBarRow }> = [];
const ranked: Array<{ rank: number; row: Omit<QuotaBarRow, "id"> & { id?: string } }> = [];
if (typeof displayQuota.fiveHourPercent === "number") {
ranked.push({
rank: 0,
Expand Down Expand Up @@ -112,6 +113,7 @@ export function buildQuotaRows(quota: AccountQuota | null, plan: string | null |
ranked.push({
rank: rawCustomWindowRank(customLabel),
row: {
id: JSON.stringify([w.modelId ?? null, w.label, w.resetAt ?? null]),
customLabel,
label: localized,
limitLabel: localized,
Expand All @@ -122,7 +124,7 @@ export function buildQuotaRows(quota: AccountQuota | null, plan: string | null |
}
if (displayQuota.creditsUsd && typeof displayQuota.creditsUsd.percent === "number") {
const hasSubscriptionCreditsCustom = displayQuota.customWindows?.some(
w => canonicalCustomWindowLabel(w.label) === SUBSCRIPTION_CREDITS_LABEL,
w => w.modelId === undefined && canonicalCustomWindowLabel(w.label) === SUBSCRIPTION_CREDITS_LABEL,
);
if (!hasSubscriptionCreditsCustom) {
const localized = localizeCustomQuotaLabel(SUBSCRIPTION_CREDITS_LABEL, t);
Expand All @@ -138,7 +140,13 @@ export function buildQuotaRows(quota: AccountQuota | null, plan: string | null |
});
}
}
return ranked.sort((a, b) => a.rank - b.rank).map(entry => entry.row);
const identities = new Map<string, number>();
return ranked.sort((a, b) => a.rank - b.rank).map(({ row }) => {
const identity = row.id ?? row.windowKey ?? row.customLabel!;
const ordinal = identities.get(identity) ?? 0;
identities.set(identity, ordinal + 1);
return { ...row, id: JSON.stringify([identity, ordinal]) };
});
}

/** Max utilisation across known windows (for sorting providers by urgency). */
Expand All @@ -147,10 +155,11 @@ export function maxQuotaUtilisation(quota: AccountQuota | null): number {
const vals = [quota.fiveHourPercent, quota.weeklyPercent, quota.monthlyPercent]
.filter((n): n is number => typeof n === "number");
for (const w of quota.customWindows ?? []) {
if (w.modelId !== undefined) continue;
if (typeof w.percent === "number") vals.push(w.percent);
}
const hasSubscriptionCreditsCustom = quota.customWindows?.some(
w => canonicalCustomWindowLabel(w.label) === SUBSCRIPTION_CREDITS_LABEL,
w => w.modelId === undefined && canonicalCustomWindowLabel(w.label) === SUBSCRIPTION_CREDITS_LABEL,
);
if (!hasSubscriptionCreditsCustom && typeof quota.creditsUsd?.percent === "number") {
vals.push(quota.creditsUsd.percent);
Expand Down Expand Up @@ -329,7 +338,7 @@ export default function QuotaBars({
{observedLine}
{rows.map(row => (
<StackedQuotaRow
key={row.limitLabel}
key={row.id}
row={row}
threshold={threshold}
t={t}
Expand All @@ -346,7 +355,7 @@ export default function QuotaBars({
<div className={`codex-account-quota-slot quota-compact${className ? ` ${className}` : ""}`}>
{observedLine}
{rows.map(row => (
<Fragment key={row.label}>
<Fragment key={row.id}>
<QuotaRow
credits={row.customLabel === SUBSCRIPTION_CREDITS_LABEL}
label={row.label}
Expand Down
2 changes: 1 addition & 1 deletion gui/src/pages/tray-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export function quotaWindows(quota: AccountQuota | null) {
{ id: 'quota.monthlyLimit', key: 'quota.monthlyLimit' as const, percent: quota.monthlyPercent, reset: quota.monthlyResetAt },
// A provider-named window is identified by its own label; the de-duplication below is what
// keeps that unique, including against the fixed keys above.
...(Array.isArray(quota.customWindows) ? quota.customWindows.filter(w => w && typeof w.label === 'string').map(w => ({ id: w.label, label: w.label, percent: w.percent, reset: w.resetAt })) : []),
...(Array.isArray(quota.customWindows) ? quota.customWindows.filter(w => w && typeof w.label === 'string').map(w => ({ id: w.label, label: w.label, modelId: w.modelId, percent: w.percent, reset: w.resetAt })) : []),
];
// A window is listed only when it reports a percentage (zero included) or a reset time. Plans
// differ in which windows they have: a weekly-only account has no 5-hour window, and showing a
Expand Down
1 change: 1 addition & 0 deletions gui/src/provider-workspace/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ function quotaFromUnknown(quota: unknown, fallbackUpdatedAt?: number): AccountQu
label: row.label,
percent: row.percent as number,
...(finite(row.resetAt) !== undefined ? { resetAt: row.resetAt as number } : {}),
...(typeof row.modelId === "string" && row.modelId.length <= 128 ? { modelId: row.modelId } : {}),
}];
})
: [];
Expand Down
7 changes: 5 additions & 2 deletions gui/src/quota-summary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export type QuotaSummarySeverity = "normal" | "warn" | "critical";

export interface QuotaSummaryWindow {
id: string;
modelId?: string;
/** Fixed window label (5h / weekly / monthly / credits). */
labelKey?: TKey;
/** Provider-named window label, shown verbatim. */
Expand Down Expand Up @@ -57,13 +58,15 @@ function summaryWindows(quota: AccountQuota): QuotaSummaryWindow[] {
const windows: QuotaSummaryWindow[] = quotaWindows(quota).map(window => {
const percent = finite(window.percent) ? window.percent : undefined;
const resetMs = resetTimestamp(window.reset);
const modelId = "modelId" in window ? window.modelId : undefined;
return {
id: window.id,
...(modelId !== undefined ? { modelId } : {}),
...("key" in window && window.key ? { labelKey: window.key } : {}),
...("label" in window && typeof window.label === "string" ? { label: window.label } : {}),
...(percent !== undefined ? { percent } : {}),
...(resetMs !== null ? { resetAt: resetMs } : {}),
severity: quotaSeverity(percent),
severity: modelId === undefined ? quotaSeverity(percent) : "normal",
};
});
const credits = quota.creditsUsd;
Expand All @@ -81,7 +84,7 @@ function summaryWindows(quota: AccountQuota): QuotaSummaryWindow[] {
}

function pickHeadline(windows: QuotaSummaryWindow[]): QuotaSummaryWindow | undefined {
const measured = windows.filter(window => window.percent !== undefined);
const measured = windows.filter(window => window.modelId === undefined && window.percent !== undefined);
const byId = new Map(measured.map(window => [window.id, window]));
for (const id of HEADLINE_ORDER) {
const hit = byId.get(id);
Expand Down
72 changes: 72 additions & 0 deletions gui/tests/provider-quota-model-id.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { buildQuotaSummary } from "../src/quota-summary";
import { quotaWindows } from "../src/pages/tray-data";
import { expect, test } from "bun:test";
import { accountQuotaFromReport } from "../src/provider-workspace/report";
import { buildQuotaRows, maxQuotaUtilisation } from "../src/components/QuotaBars";

test("provider quota projection preserves bounded exact Antigravity model IDs", () => {
expect(accountQuotaFromReport({
updatedAt: 123,
quota: {
updatedAt: 123,
customWindows: [
{ label: "gemini-3.8-flash-high", modelId: "gemini-3.8-flash-high", percent: 24 },
{ label: "legacy", modelId: "x".repeat(129), percent: 12 },
],
},
})?.customWindows).toEqual([
{ label: "gemini-3.8-flash-high", modelId: "gemini-3.8-flash-high", percent: 24 },
{ label: "legacy", percent: 12 },
]);
});

test("model diagnostic bars do not change provider urgency sorting", () => {
expect(maxQuotaUtilisation({
updatedAt: 123,
customWindows: [
{ label: "Gem", percent: 36 },
{ label: "gemini-3.8-flash-high", modelId: "gemini-3.8-flash-high", percent: 100 },
],
})).toBe(36);
});

test("diagnostic labels cannot suppress subscription credit urgency", () => {
expect(maxQuotaUtilisation({
updatedAt: 123,
customWindows: [{ label: "Total subscription credits", modelId: "Total subscription credits", percent: 0 }],
creditsUsd: { used: 90, limit: 100, remaining: 10, percent: 90 },
})).toBe(90);
});


test("summary preserves model diagnostics without selecting them for headline or severity", () => {
const quota = { updatedAt: 123, customWindows: [
{ label: "aux", modelId: "aux", percent: 100 },
{ label: "Gem", percent: 20 },
] };
const windows = quotaWindows(quota);
const rows = buildQuotaSummary({ google: { updatedAt: 123, quota } }, id => id);
expect(rows[0]?.headline.label).toBe("Gem");
expect(windows[0]).toMatchObject({ modelId: "aux", percent: 100 });
expect(rows[0]?.severity).toBe("normal");
expect(rows[0]?.windows[0]).toMatchObject({ modelId: "aux", percent: 100, severity: "normal" });
expect(buildQuotaSummary({ google: { updatedAt: 123, quota: { ...quota, customWindows: [quota.customWindows[0]!] } } }, id => id)).toEqual([]);
});

test("quota bars have unique stable identities for repeated labels", () => {
const customWindows = [
{ label: "same", modelId: "aux", percent: 10, resetAt: 123 },
{ label: "same", modelId: "aux", percent: 20, resetAt: 456 },
{ label: "same", modelId: "other", percent: 30 },
];
const t = ((key: string) => key) as Parameters<typeof buildQuotaRows>[2];
const rows = buildQuotaRows({ updatedAt: 123, customWindows }, null, t);
expect(rows).toHaveLength(3);
expect(new Set(rows.map(row => row.id)).size).toBe(3);
const reversed = buildQuotaRows({ updatedAt: 123, customWindows: [...customWindows].reverse() }, null, t);
expect(reversed.map(row => row.id)).toEqual(rows.map(row => row.id).reverse());
const repeated = buildQuotaRows({ updatedAt: 123, customWindows: [...customWindows, customWindows[0]!] }, null, t);
expect(new Set(repeated.map(row => row.id)).size).toBe(4);
const refreshed = buildQuotaRows({ updatedAt: 456, customWindows: customWindows.map(row => ({ ...row, percent: 99 })) }, null, t);
expect(refreshed.map(row => row.id)).toEqual(rows.map(row => row.id));
});
1 change: 1 addition & 0 deletions scripts/test-layout/layout.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"gui-pair-delivery.test.ts": "gui",
"usage-antigravity-55.test.ts": "usage",
"provider-antigravity-wire-snapshot.test.ts": "providers",
"provider-antigravity-model-quota.test.ts": "providers",
"antigravity-discovered-families.test.ts": "adapters/google",
"provider-antigravity-effort-families.test.ts": "providers",
"provider-antigravity-family-catalog.test.ts": "providers",
Expand Down
1 change: 1 addition & 0 deletions src/cli/account-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,7 @@ export interface ProviderQuotaWindowDto {
label: string;
percent: number;
resetAt?: number;
modelId?: string;
}

export interface ProviderQuotaDto extends CodexQuotaDto {
Expand Down
3 changes: 3 additions & 0 deletions src/combos/resolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ function quotaWindowExhausted(percent: number | undefined, resetAt: number | und
const MODEL_FAMILY_WINDOW_LABELS = new Set(["fable", "opus", "sonnet"]);

function customWindowAppliesToModel(window: ProviderQuotaWindow, model: string | undefined): boolean {
// Exact Antigravity model readings are diagnostic only. They are not permission or
// provider-wide exhaustion evidence until a separate eligibility contract consumes them.
if (window.modelId !== undefined) return false;
if (window.scope !== "model" || model === undefined) return true;
const family = window.label.trim().toLowerCase();
if (!MODEL_FAMILY_WINDOW_LABELS.has(family)) return true;
Expand Down
4 changes: 2 additions & 2 deletions src/oauth/account-quota-rank.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ function headroomOf(provider: string, accountId: string, requestedModelId?: stri
const family = classifyModelFamilyForQuota(provider, requestedModelId);
if (family) {
const percents = (quota.customWindows ?? [])
.filter(window => windowMatchesFamily(window.label, family))
.filter(window => window.modelId === undefined && windowMatchesFamily(window.label, family))
.map(window => window.percent)
.filter((value): value is number => typeof value === "number");
if (percents.length === 0) return null;
Expand All @@ -106,7 +106,7 @@ function headroomOf(provider: string, accountId: string, requestedModelId?: stri
quota.fiveHourPercent,
quota.weeklyPercent,
quota.monthlyPercent,
...(quota.customWindows ?? []).map(window => window.percent),
...(quota.customWindows ?? []).filter(window => window.modelId === undefined).map(window => window.percent),
].filter((value): value is number => typeof value === "number");
if (percents.length === 0) return null;
return 100 - Math.max(...percents);
Expand Down
2 changes: 2 additions & 0 deletions src/providers/quota-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export interface ProviderQuotaWindow {
label: string;
percent: number;
resetAt?: number;
/** Exact CCA wire model measured by this window; display evidence only, not eligibility. */
modelId?: string;
/**
* Set only when the PRODUCER proved this window covers one model family, structurally rather
* than by reading its label: an Anthropic `seven_day_<family>` body key, or a limit with
Expand Down
Loading
Loading