feat: show provider usage limits with /usage-limits - #9875
Conversation
06d70f7 to
0884697
Compare
2d91b6d to
e560039
Compare
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This PR introduces a default-enabled, cross-platform Not approved because:
Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more. |
e560039 to
ea91dea
Compare
a9ce673 to
124fcf8
Compare
cb0a604 to
0674340
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d841ed6. Configure here.
| } | ||
| isPreparingWorktree={isPreparingWorktree} | ||
| bannerItems={composerBannerItems} | ||
| onUsageLimitsCommand={ |
There was a problem hiding this comment.
🟡 Medium components/ChatView.tsx:8097
When /usage-limits is selected while the composer has an attachment or terminal/element context, ChatComposer treats it as an action-only command, removes the command text, and opens the limits panel; the non-prompt content is therefore left unsent. onUsageLimitsCommand is passed whenever limits are offered, unlike the typed-command path, which excludes composerHasNonPromptContent. Only provide this action callback when the composer contains no non-prompt content so the command remains sendable with its attachment or context.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/web/src/components/ChatView.tsx around line 8097:
When `/usage-limits` is selected while the composer has an attachment or terminal/element context, `ChatComposer` treats it as an action-only command, removes the command text, and opens the limits panel; the non-prompt content is therefore left unsent. `onUsageLimitsCommand` is passed whenever limits are offered, unlike the typed-command path, which excludes `composerHasNonPromptContent`. Only provide this action callback when the composer contains no non-prompt content so the command remains sendable with its attachment or context.
2951d44 to
1898482
Compare
f42f194 to
b684981
Compare
Sending /usage-limits in a thread opens the current model's limits above the composer, built from the same snapshot as Usage > Limits. The command resolves in the client without starting a turn, so nothing is written to the thread; the panel closes on dismiss or the next send. Web renders it as a composer notice so it stacks under warnings and uses the standard dismiss. Mobile docks an opaque card in the approval slot. The server only advertises the command for providers present in Limits. Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
Review follow-ups for /usage-limits: drop the snapshot when the thread or model changes, keep it hidden rather than dropped while the provider list is unavailable, clear it only when a message actually leaves, clear it when a later request has nothing to show, let submissions carrying attachments or contexts send as prompts, and report a usage-limit source that failed to read even though it has no accounts left to match. Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
Seed the provider status stream with the current providers so a usage limit source refresh reaches clients before any provider change, with a test. Tie the /usage-limits snapshot to the turn and clear it once an approval or question is answered, since the agent then spends quota. Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
The /usage-limits panel now reads provider data at render, so a redeemed reset credit or refreshed probe shows through instead of a frozen snapshot. Mobile New Task no longer offers the command and refuses to send it, since only the thread composer can answer it. Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
Choosing /usage-limits from the composer menu opens the panel at once instead of leaving the command in the draft to be sent. Typing it out and sending still works as a fallback. Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
Compare provider status pairings against the snapshot the client holds instead of dropping the first one, so a refresh between snapshot and subscription still goes out. A usage-limit source that failed to read now counts for every driver, so its error reaches the panel. Only a successful approval or answer clears the panel, and New Task lets a prompt with attachments through. Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
Native accounts in the panel show their instance id when they share a driver and have no display name. A response that resolves after navigating away clears only the originating thread's panel. The catalog republish comparator now lives in shared, counts a failed source as covering every driver, and is tested. Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
A report with no accounts, such as a failed hub and no native windows, now renders its own heading row with the close control. Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
A send can outlast a navigation while attachments upload, so it clears only the originating thread's limits panel instead of whatever is open. Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
Only a delivered approval or answer resumes the agent, so a failed reply leaves the snapshot in place. Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
Source-backed rows showed only the hub kind, so two accounts from one hub were indistinguishable. They now carry the hub and account id. Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
Ownership was a prefix match on a composite key; thread ids may contain the delimiter, so the panel now stores its thread key and compares it. Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
A send that fails before the turn starts spends no quota, so it leaves the panel in place. Both the composer and plan follow-up paths clear after a successful start. Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
The command name is only T3's where Limits has data for the selected provider; elsewhere a provider's own command of that name is sent through untouched, on the menu, on send, and in New Task. The panel key now includes any pending approval or question, so an answer from any client closes it, which also retires the local response wrappers. The web key stays hidden rather than dropped while a server thread is not yet loaded. Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
Clients that handle the command locally say so on the config subscription; the server injects it into provider catalogs only for them. An older client, which would send the injected command to the provider as a prompt, never sees it. The one-shot config fetch stays without it. Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
The menu handler and the send intercept now require an available panel key, so a reconnect or loading thread leaves the text in the composer. Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
Picking /usage-limits with attachments or contexts aboard inserts the command text instead, so it sends as a prompt, matching the typed path. Model: Claude Fable 5.1. Harness: Claude Code in T3 Code.
b684981 to
f370809
Compare

What Changed
/usage-limitsslash command. It is offered only for providers that appear under Usage → Limits. Sending it opens the current model's limits above the composer, built from the same snapshot as the Usage page. Nothing is posted to the thread and no turn starts.Why
Checking how much quota is left meant leaving the thread for Usage → Limits. A limits snapshot goes stale as soon as the next turn runs, so it belongs in the transient slot above the composer rather than in durable thread history.
UI Changes
Note
Since producing the videos below, the feature has been changed to not require sending
/usage-limitsas a message. Clicking it in the slash command menu instantly displays the usage limits.Web, Claude:
claude_usage_web.webm
Web, Codex with a banked reset credit:
codex_usage_web.webm
iOS, Claude:
claude_usage_ios.mov
iOS, Codex with a banked reset credit:
codex_usage_ios.mov
Checklist
Built with Claude Fable 5.1 in Claude Code via T3 Code.
Note
Add
/usage-limitscommand to show provider usage limits in chat composerUsageLimitsReportcontract in providerUsageLimits.tssubscribeServerConfigstream in ws.ts injects the/usage-limitsslash command into provider catalogs only for clients that opt in via a new capability flag in the subscription payload/usage-limitsprompt and opens a local report panel instead of starting a turn/usage-limitsis selected from the menuComposerUsageLimitsdocked card and compact/dense modes forAccountLimits,ResetCredits, andWindowRow;WindowRowbar colors now use explicit red (≥90%) and amber (70–89%) instead of semantic classesWindowRowin UsageLimitsSection.tsx switches from semanticdestructive/warningcolor classes to hardcoded red/amber, which may not match theme overrides;LimitWindowsin UsageLimits.tsx no longer suppresses repeated reset countdowns for windows sharing a reset timeMacroscope summarized f370809.
Note
Medium Risk
Touches WebSocket server config streaming and capability-gated catalog mutation; incorrect opt-in handling could advertise or hide the command for the wrong clients, but auth and turn dispatch are unchanged.
Overview
Adds a
/usage-limitscomposer command that opens provider quota locally from the same snapshots as Usage → Limits—no agent turn and nothing posted to the thread. It is offered only when Limits has data for the selected provider.Server & clients: Subscribers opt in with
usageLimitsCommandonsubscribeServerConfig; the server then injects the slash command into provider catalogs via sharedwithUsageLimitsCommands, and republishes when limit-source coverage changes (not on every quota tick). Older clients that do not opt in keep unmodified catalogs so they would still send the command to the provider.Web & mobile: Thread composers intercept a standalone
/usage-limits(typed or from the menu) and show a docked panel above the composer; new task on mobile blocks with guidance to use a thread or Settings. Panels track live limit data, dismiss on close, and auto-close when the thread/model/turn changes or a message is sent. SharedcollectProviderUsageLimitsbuilds theUsageLimitsReport; usage UI pieces gain compact/dense variants and small fixes (per-window reset labels, mobile bar colors).Reviewed by Cursor Bugbot for commit f370809. Bugbot is set up for automated code reviews on this repo. Configure here.