Clarify and localize provider usage limits#2215
Conversation
|
| Filename | Overview |
|---|---|
| packages/app/src/provider-usage/format.ts | Refactored to use Intl.NumberFormat for locale-aware percent/currency/number formatting; timing helpers now use i18n singleton for translated strings; new formatRunsOutLabel export replacing the old string-manipulation hack in window-bar. |
| packages/app/src/provider-usage/format.test.ts | New test file verifying locale-aware formatting for both English and Japanese; uses vi.spyOn(Date, "now") to patch a global for deterministic time — a banned test pattern per the style guide. |
| packages/app/src/provider-usage/window-bar.tsx | Replaces the fragile "resets X".replace("resets ", "") hack for the at-risk case with the new formatRunsOutLabel; adds i18n "{{percentage}} used" wrapper via t(); also fixes a pre-existing bug where the "runs out now" label would have rendered as "runs out resetting now". |
| packages/app/src/provider-usage/active-provider.ts | New helper extracting provider matching and session-window detection from tooltip-section; findSessionWindow matches by known IDs ("session", "five_hour") first, then falls back to label text "session" for unrecognised providers. |
| packages/app/src/provider-usage/tooltip-section.tsx | Removes inline matchProvider helper (now active-provider.ts); adds new ProviderUsageMobileSession component that renders the active session window inline for compact mobile layouts; copy.ts dependency fully removed. |
| packages/app/src/components/context-window-meter.tsx | Adds shouldFetchProviderUsage flag so mobile showPercentage+provider mode pre-fetches usage without waiting for the tooltip; wraps the trigger and new ProviderUsageMobileSession in a flex column when showPercentage is true. |
| packages/app/src/provider-usage/copy.ts | Deleted; all English-only copy has been migrated to i18n resource keys across all 8 supported locales. |
| packages/app/src/provider-usage/use-provider-usage.ts | Replaces providerUsageCopy with t(); t added to useMemo deps so error messages recompute on language change; queryFn guard also updated but is unreachable in practice since canFetch is false when client is null. |
| packages/app/src/i18n/resources/en.ts | Adds providerUsage namespace with 18 keys covering loading/error/empty states, status labels, value templates, duration abbreviations, and timing copy; serves as canonical source for other locales. |
| packages/app/e2e/provider-usage-tooltip.spec.ts | Updated E2E tests to reflect new mobile session display (testID provider-usage-mobile-session, "42% used") and changed trigger from hover to click for the refresh test; assertions tightened with exact match and toContainText. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
CWM["ContextWindowMeter\n(context-window-meter.tsx)"]
SFPU{"shouldFetchProviderUsage\nisTooltipOpen ||\nshowPercentage && provider != null"}
UPU["useProviderUsage\n(use-provider-usage.ts)"]
VIEW["ProviderUsageView\n{ kind: loading | error | ready }"]
CWM --> SFPU
SFPU -->|enabled| UPU
UPU --> VIEW
VIEW -->|desktop: tooltip open| TTS["ProviderUsageTooltipSection\n→ ProviderUsageCard\n→ window/balance bars"]
VIEW -->|mobile: showPercentage| PMS["ProviderUsageMobileSession\n(tooltip-section.tsx)"]
PMS --> APU["findActiveProviderSessionWindow\n(active-provider.ts)\nmatches by id: session, five_hour\nor label: 'session'"]
APU --> WB["ProviderUsageWindowBar\n→ t('providerUsage.values.used', { percentage: formatPct(usedPct, locale) })\n→ formatRunsOutLabel / formatResetLabel"]
TTS --> CARD["ProviderUsageCard\n→ statusText(t)\n→ footerText(t)\n→ ProviderUsageWindowBar\n→ ProviderUsageBalanceBar"]
WB --> FMT["format.ts\nIntl.NumberFormat for % and currency\ni18n singleton for timing strings"]
CARD --> FMT
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
CWM["ContextWindowMeter\n(context-window-meter.tsx)"]
SFPU{"shouldFetchProviderUsage\nisTooltipOpen ||\nshowPercentage && provider != null"}
UPU["useProviderUsage\n(use-provider-usage.ts)"]
VIEW["ProviderUsageView\n{ kind: loading | error | ready }"]
CWM --> SFPU
SFPU -->|enabled| UPU
UPU --> VIEW
VIEW -->|desktop: tooltip open| TTS["ProviderUsageTooltipSection\n→ ProviderUsageCard\n→ window/balance bars"]
VIEW -->|mobile: showPercentage| PMS["ProviderUsageMobileSession\n(tooltip-section.tsx)"]
PMS --> APU["findActiveProviderSessionWindow\n(active-provider.ts)\nmatches by id: session, five_hour\nor label: 'session'"]
APU --> WB["ProviderUsageWindowBar\n→ t('providerUsage.values.used', { percentage: formatPct(usedPct, locale) })\n→ formatRunsOutLabel / formatResetLabel"]
TTS --> CARD["ProviderUsageCard\n→ statusText(t)\n→ footerText(t)\n→ ProviderUsageWindowBar\n→ ProviderUsageBalanceBar"]
WB --> FMT["format.ts\nIntl.NumberFormat for % and currency\ni18n singleton for timing strings"]
CARD --> FMT
Reviews (3): Last reviewed commit: "Show session usage in mobile composer" | Re-trigger Greptile
|
Hopefully okay to bundle the i18n changes into this one |




Summary
Why
The percentage displayed beside session limits matched the consumed portion of the progress bar, but the number alone did not say whether it represented usage or remaining capacity. On mobile, provider usage was only available after opening the context meter, leaving the composer footer with context usage but no session-limit counterpart. The provider-usage feature also still used a temporary English-only copy object, so adding
useddirectly would have left mixed-language UI.Impact
Users can now immediately read values such as
7% usedwithout inferring the meaning from the bar direction. On mobile, an active provider’s Session usage is displayed beneath Context window usage and refreshes when the meter is opened. The Usage tab and compact usage tooltip render the same semantics in the app’s selected language.Provider names, plan labels, usage-window labels, balance/detail labels, source labels, and raw provider errors remain provider-owned runtime values and are intentionally not translated.
Validation
npx vitest run packages/app/src/provider-usage/format.test.ts packages/app/src/i18n/resources.test.ts --bail=1npx vitest run packages/app/src/provider-usage/active-provider.test.ts --bail=1npm run lint -- packages/app/src/components/context-window-meter.tsx packages/app/src/provider-usage packages/app/e2e/provider-usage-tooltip.spec.tsnpm run typecheck