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
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,16 @@ function getProviderLetter(provider: ProviderRateLimits['provider']): string {
// Why: Gemini exposes extra experimental buckets that made the pre-existing verbose footer noisy.
const STATUS_BAR_BUCKET_NAMES = new Set(['Flash', 'Pro', '1.5 Pro'])

// Why: the allowlist above is Gemini's. Cursor's pools are its whole meter — filtering
// them out leaves a signed-in account with an icon and no number at all.
function isVisibleStatusBarBucket(name: string): boolean {
/**
* Why Antigravity is matched by provider and not by name: its pools are one per model group, and the
* group names come from the account's own tier ("Gemini Models", "Claude and GPT models" today), so
* there is no list to allow. Cursor stays name-matched on purpose — a pool Orca does not recognise
* is filtered so the segment can fall back to the plan total instead of showing an unlabelled row.
*/
function isVisibleStatusBarBucket(name: string, provider: ProviderRateLimits['provider']): boolean {
if (provider === 'antigravity') {
return true
}
return STATUS_BAR_BUCKET_NAMES.has(name) || isCursorUsageBucket(name)
}

Expand All @@ -179,10 +186,15 @@ function VerboseProviderUsage({
display: UsagePercentageDisplay
}): React.JSX.Element {
if (p.buckets && p.buckets.length > 0) {
const visibleBuckets = p.buckets.filter((bucket) => isVisibleStatusBarBucket(bucket.name))
const visibleBuckets = p.buckets.filter((bucket) =>
isVisibleStatusBarBucket(bucket.name, p.provider)
)
// Why: a provider whose buckets are all filtered out still has a headline
// window worth showing rather than rendering an empty segment.
const fallbackWindow = p.session ?? p.monthly ?? null
// Why weekly is in the chain: a tier metered weekly only (Antigravity reports no 5h pool on
// some tiers) has no session window, and omitting weekly rendered an empty segment for an
// account that does have a limit worth showing.
const fallbackWindow = p.session ?? p.monthly ?? p.weekly ?? null
return (
<>
{visibleBuckets.map((bucket, index) => (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
import { renderToStaticMarkup } from 'react-dom/server'
import { describe, expect, it, vi } from 'vitest'
import type { ProviderRateLimits, RateLimitWindow } from '../../../../shared/rate-limit-types'

vi.mock('@/i18n/i18n', () => ({
i18n: { language: 'en' },
translate: (_key: string, fallback: string, values?: Record<string, string>) => {
let result = fallback
for (const [key, value] of Object.entries(values ?? {})) {
result = result.replace(`{{${key}}}`, value)
}
return result
}
}))

vi.mock('@/lib/agent-catalog', () => ({
AgentIcon: () => null
}))

vi.mock('../../store', () => ({
useAppStore: (selector: (state: { usagePercentageDisplay: 'used' | 'remaining' }) => unknown) =>
selector({ usagePercentageDisplay: 'used' })
}))

const WEEKLY_MINUTES = 10_080

function weeklyWindow(usedPercent: number): RateLimitWindow {
return { usedPercent, windowMinutes: WEEKLY_MINUTES, resetsAt: null, resetDescription: null }
}

/**
* The record `agy -p "/usage"` produces for a tier metered weekly only, with the Gemini pool
* genuinely exhausted — captured from agy 1.2.11.
*/
function antigravityLimits(overrides: Partial<ProviderRateLimits> = {}): ProviderRateLimits {
return {
provider: 'antigravity',
session: null,
weekly: weeklyWindow(100),
buckets: [
{ name: 'Gemini Models', ...weeklyWindow(100) },
{ name: 'Claude and GPT models', ...weeklyWindow(0) }
],
updatedAt: Date.now(),
error: null,
status: 'ok',
...overrides
}
}

describe('Antigravity status-bar segment', () => {
it('renders both model-group pools by name', async () => {
// Why: the verbose bucket allowlist was written for Gemini's experimental models, so
// Antigravity's pools — whose names come from the account's tier and cannot be enumerated
// ahead of time — were filtered out and the segment showed no number at all.
const { ProviderSegment } = await import('./StatusBar')
const markup = renderToStaticMarkup(
<ProviderSegment p={antigravityLimits()} compact={false} display="used" mode="verbose" />
)

expect(markup).toContain('Gemini Models')
expect(markup).toContain('Claude and GPT models')
expect(markup).toContain('100%')
})

it('shows the weekly window when a tier reports no session pool', async () => {
// Why: the verbose fallback chain was `session ?? monthly`, so a weekly-only provider with a
// real limit rendered an empty segment.

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.

The rationale here doesn't match the code path this test takes. With buckets: [] (and buckets: undefined in the next test), VerboseProviderUsage skips the p.buckets.length > 0 branch and goes to the second branch, which already rendered p.weekly before this PR. I verified this: reverting the changed session ?? monthly ?? weekly line to session ?? monthly still leaves all four tests passing, so the new ?? p.weekly fallback has no coverage.

To actually pin it, a fixture needs buckets present but all filtered (e.g. an unrecognised name) with session and monthly null and weekly set — only then does execution reach the fallback line.

Technical details
# `weekly` fallback in the bucket branch is untested

## Affected sites
- `src/renderer/src/components/status-bar/status-bar-antigravity-segment.test.tsx:66` — "shows the weekly window when a tier reports no session pool" passes `buckets: []`, taking the `visibleWindows` branch.
- `src/renderer/src/components/status-bar/status-bar-antigravity-segment.test.tsx:82` — "still renders a reading when only the weekly window is known" passes `buckets: undefined`, same branch.
- `src/renderer/src/components/status-bar/StatusBarProviderSegment.tsx:197` — `session ?? monthly ?? weekly` is only reached when `p.buckets.length > 0` and every bucket is filtered out.

## Required outcome
- Either add a test that reaches the fallback line (buckets present but all filtered, `session`/`monthly` null, `weekly` set), or correct the comments to describe the path actually taken.

## Note
- After this PR's provider bypass, Antigravity buckets are always visible, so the fallback line is also unreachable for the provider it was added for in the first place.

const { ProviderSegment } = await import('./StatusBar')
const markup = renderToStaticMarkup(
<ProviderSegment
p={antigravityLimits({ buckets: [] })}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Weekly fallback remains untested The empty bucket list takes the no-buckets branch, so this test never reaches the new weekly fallback. The 100% assertion can also pass from the MiniBar’s width even if no percentage label is shown. Use nonempty buckets that are all filtered out and assert the visible label, so a fallback regression fails the test.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

compact={false}
display="used"
mode="verbose"
/>
)

expect(markup).toContain('100%')
})

it('still renders a reading when only the weekly window is known', async () => {
const { ProviderSegment } = await import('./StatusBar')
const markup = renderToStaticMarkup(
<ProviderSegment
p={antigravityLimits({ buckets: undefined })}
compact={false}
display="used"
mode="verbose"
/>
)

expect(markup).toContain('100%')
})

it('does not widen the allowlist for providers that rely on it', async () => {
// Why: Gemini's experimental buckets are still filtered; only providers whose buckets are the
// whole meter bypass the allowlist.
const { ProviderSegment } = await import('./StatusBar')
const markup = renderToStaticMarkup(
<ProviderSegment
p={{
provider: 'gemini',
session: weeklyWindow(12),
weekly: null,
buckets: [
{ name: 'Pro', ...weeklyWindow(30) },
{ name: 'Some Experimental Model', ...weeklyWindow(80) }
],
updatedAt: Date.now(),
error: null,
status: 'ok'
}}
compact={false}
display="used"
mode="verbose"
/>
)

expect(markup).toContain('Pro')
expect(markup).not.toContain('Some Experimental Model')
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,11 @@ function createPendingProviderSnapshot(providerId: UsageProviderId): ProviderRat
session: null,
weekly: null,
...(providerId === 'opencode-go' ? { monthly: null } : {}),
...(providerId === 'gemini' || providerId === 'cursor' ? { buckets: [] } : {}),
// Why antigravity joins these: it reports one pool per model group, so its pending skeleton
// has to be bucket-shaped too or the segment changes shape once the first reading lands.
...(providerId === 'gemini' || providerId === 'cursor' || providerId === 'antigravity'
? { buckets: [] }
: {}),
updatedAt: 0,
error: null,
status: 'fetching'
Expand Down
Loading