Skip to content

feat: display provider usage limits in settings - #1732

Open
Aditya190803 wants to merge 16 commits into
pingdotgg:mainfrom
Aditya190803:feat/provider-usage-limits
Open

feat: display provider usage limits in settings#1732
Aditya190803 wants to merge 16 commits into
pingdotgg:mainfrom
Aditya190803:feat/provider-usage-limits

Conversation

@Aditya190803

@Aditya190803 Aditya190803 commented Apr 4, 2026

Copy link
Copy Markdown
Contributor

Fixes #228.

What Changed

Added provider usage limits to the settings flow end to end for all 4 providers (Codex, Claude, Cursor, OpenCode):

  • the shared contract now includes the usage-limits schema
  • the server persists and exposes provider usage limits
  • the web app renders the limits in Settings

Note: For OpenCode, only the official OpenCode-managed providers (OpenCode Go, OpenCode Zen) are shown.

Why

Users need a visible place to confirm provider usage limits without digging through logs or backend state. This keeps the value available across sessions and makes the current limits easy to inspect from the UI.

UI Changes

The Settings panel now shows provider usage limits in the provider section.

Checklist

  • This PR is small and focused
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Medium Risk
Spawns PTY processes and parses CLI output during provider health checks, which can affect probe latency and reliability; live usage merge logic changes snapshot refresh behavior for quota fields.

Overview
Adds end-to-end provider usage limits: server status probes populate usageLimits on provider snapshots, live session events can refresh them without a full re-probe, and the mobile Usage screen shows a Provider limits section with progress bars and reset dates.

Server probing attaches quota data per driver: Claude/Cursor/Grok via optional PTY CLI scraping (claude --print /usage, Cursor/Grok /usage TUI flows), Codex via a bounded account/rateLimits/read app-server call (with API-key/Bedrock marked unavailable), OpenCode Go/Zen from managed inventory usage fields, and Grok auth/subscription via ACP before TUI usage on paid tiers. Drivers thread PtyAdapter from the registry context when present; missing PTY degrades to explicit “unavailable in this runtime” reasons.

Snapshot lifecycle extends managed providers with applyUsageLimits, merges live account.rate-limits.updated ingestion, and preserves in-flight live patches when enrichment or refresh completes so quota bars do not snap back to stale probe values.

Mobile groups limits by environment when multiple servers are connected, hides OpenCode from this section, and surfaces notices (e.g. Grok free tier, missing data).

Also ignores .claude-work-test/ in gitignore so Claude usage probe tests do not commit session files.

Reviewed by Cursor Bugbot for commit e6ed20c. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add provider usage limits display to settings and usage pages

  • Introduces ServerProviderUsageLimits and ServerProviderUsageWindow schemas in server.ts, constraining window kinds to session and weekly, percent to [0, 100], and dropping invalid windows during decode via ForwardCompatibleArray
  • Adds per-provider usage probes: PTY-driven TUI scraping for Claude, Cursor, and Grok in claudeUsageProbe.ts, cursorUsageProbe.ts, and grokTuiUsageProbe.ts; ACP-based rate-limit reads for Codex and Grok auth checks in CodexProvider.ts and grokUsageProbe.ts; and inventory-derived limits for OpenCode managed providers in openCodeUsageLimits.ts
  • Adds ProviderUsageLimitsIngestionLive in ProviderUsageLimitsIngestion.ts which subscribes to account.rate-limits.updated events and folds live usage patches into provider snapshots via applyUsageLimits on makeManagedServerProvider
  • Renders usage bars with severity colors, reset dates, and contextual notices on web in ProviderQuotaLimits.tsx and UsagePage.tsx, and on mobile in UsageRouteScreen.tsx
  • Improves PTY adapters in NodePtyAdapter.ts and BunPtyAdapter.ts to kill the full process tree on Windows via taskkill /T /F and replay exit events to listeners registered after process exit
  • Risk: makeManagedServerProvider enrichment publish path now early-returns if enrichmentGeneration changed and preserves current snapshot.usageLimits when enrichment yields a different reference — stale enrichment no longer reverts live patches; callers relying on enrichment to overwrite live usage updates will see different behavior

Macroscope summarized e6ed20c.


Open in Devin Review

@coderabbitai

coderabbitai Bot commented Apr 4, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 35ffc15f-1bb1-4639-a8ea-977f6703b1f8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:XL 500-999 changed lines (additions + deletions). labels Apr 4, 2026
@Aditya190803

Copy link
Copy Markdown
Contributor Author

For now, I’ve added two images to illustrate the UI:

1. Free tier view

This screenshot reflects my current setup. I don’t have subscriptions to Codex or Claude Code, I’m using Copilot Pro (available to me as a student). It shows how the weekly usage limit appears in the interface.

Free Tier Screenshot

2. Pro tier (mocked example)

This second screenshot uses dummy data to demonstrate how the UI could look for users on a Pro plan (Codex or Claude Code). It includes both session-based limits and weekly limits for clarity.

Pro Tier Mock Screenshot

Comment thread apps/server/src/persistence/Layers/ProviderUsageLimits.ts Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 80515efa38

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread apps/server/src/provider/Layers/CodexProvider.ts Outdated
Comment thread apps/server/src/provider/Layers/CodexProvider.ts Outdated
@macroscopeapp

macroscopeapp Bot commented Apr 4, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR introduces a broad provider-usage capability with new cross-platform probes, live telemetry ingestion, contract changes, and shared PTY lifecycle behavior on existing provider paths. An unresolved concrete issue can also leave empty provider tiles when usage windows are discarded.

You can add or adjust custom eligibility rules. Learn more.

Comment thread apps/server/src/provider/codexAppServer.ts Outdated
@Aditya190803

Copy link
Copy Markdown
Contributor Author

Hey @juliusmarminge, could you take a look at this PR when you get a moment? Thanks!

@Marve10s

Marve10s commented Apr 6, 2026

Copy link
Copy Markdown
Contributor

Randomly found this PR because wanted to add usage to T3. I think this is great as a user but also I think the UI should match the Codex App usage,it's minimal and clean, would be better than AI tabs
image

You would need to redo the settings button though,something Julius needs to approve. I genuinely think settings button should match Codex App, would love to open PR for that.

@Marve10s

Marve10s commented Apr 6, 2026

Copy link
Copy Markdown
Contributor

A few concerns after checking the code:

  1. Codex can prefer stale persisted usage over freshly probed usage in the same refresh path.
    checkCodexProviderStatus() reads cachedUsageLimits first, then later resolves account state, but ultimately uses cachedUsageLimits ?? accountUsageLimits. That means a refresh can still emit an older persisted value even when the same refresh just fetched newer limits from the provider probe. If the goal is to show the freshest available snapshot, I think the precedence likely needs to be reversed, or persisted data should only be used when no fresh usage was fetched.
  2. The persisted cache looks too coarse-grained for account/config changes.
    The new table is keyed only by provider_name, and the repo API is also getByProvider only. That seems risky if the user changes auth state, swaps Codex homePath, changes binary path, or otherwise changes the effective account behind a provider. In those cases we can still surface previously persisted usage for the provider even though it may belong to a different account/config. Is that safe, or should this cache be scoped more tightly (for example by provider + account/config fingerprint) or suppressed when provider health/auth no longer matches the cached source?
  3. A usage-limit update currently looks like it can trigger full provider refresh work.
    ProviderService persists account.rate-limits.updated, then ProviderRegistry listens to repository changes and calls refresh(change.provider). That refresh path eventually reruns the provider's checkProvider flow rather than just updating already-known snapshot state. For a quota-bar style UI update, this feels heavier than necessary and could add extra CLI churn to a hot path. Would it be simpler to keep usage attached to the provider snapshot/update flow directly instead of going through persistence -> repository stream -> provider refresh?

I can test further and commit to this PR if you're okay with it, @Aditya190803. Genuinely want to see this merged - it would be super useful

@juliusmarminge

Copy link
Copy Markdown
Member

this is on my list to review still! Just dealing with some larger prep work so haven't had time yet.

As for the "it must be more visible and sjhould be 1:1 like codex app":

How often do you guys check your limits to warrant it being one click ??? I check it at most a few times a week, so hiding it in settings next to the provider status is fine!

@Marve10s

Marve10s commented Apr 6, 2026

Copy link
Copy Markdown
Contributor

this is on my list to review still! Just dealing with some larger prep work so haven't had time yet.

As for the "it must be more visible and sjhould be 1:1 like codex app":

How often do you guys check your limits to warrant it being one click ??? I check it at most a few times a week, so hiding it in settings next to the provider status is fine!

I've been checking usage a lot in Codex - a couple of times daily since I was on the $20 plan with 2x limits till April, so I was curious how it was going. My take is that the current settings are genuinely fine, but I think it'll get crowded soon. With usage, OpenCode and Cursor support, and I'm sure there are PRs that extend the settings further it's going to contain a lot of content before long.
Codex shows a small tab with everything you need: usage, general info, and language (something I'd tuck away in settings). I think the Cursor settings approach is a good reference here too.

image

@juliusmarminge

Copy link
Copy Markdown
Member

Yes when the single settings page gets too large we'll split it to subpages. We already did the work adding the sidebar when adding the archive

@juliusmarminge

Copy link
Copy Markdown
Member

can't see claude limits:
CleanShot 2026-04-06 at 15 21 34@2x

@juliusmarminge juliusmarminge left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

implementation seems way overcomplicated.

why cache the data? the provider check runs once per minute. we can get fresh data on every tick?

how i imaagined this working:

  • extend the checkProvider probe in ServerProvider to include a new usageLimits property.
  • on the auth check probes (app server / claude), extract usage data
  • stream it down to client as part of the normal provider snapshot
  • render the UI on settings page

given i haven't looked into exactly what's possible to probe and not, why is this PR so much more than that?

@github-actions github-actions Bot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Apr 7, 2026
Comment thread apps/server/src/provider/Layers/ClaudeProvider.ts
Comment thread apps/server/src/server.ts
@Aditya190803
Aditya190803 force-pushed the feat/provider-usage-limits branch from f9aabcd to 171df70 Compare April 17, 2026 06:07
@github-actions github-actions Bot added size:XL 500-999 changed lines (additions + deletions). and removed size:XXL 1,000+ changed lines (additions + deletions). labels Apr 17, 2026
Comment thread apps/server/src/provider/Layers/ClaudeProvider.ts Outdated
Comment thread apps/server/src/provider/providerUsageLimits.ts Outdated
@github-actions github-actions Bot added size:XXL 1,000+ changed lines (additions + deletions). and removed size:XL 500-999 changed lines (additions + deletions). labels Apr 17, 2026
Comment thread apps/server/src/provider/codexAppServer.ts Outdated
Comment thread apps/server/src/provider/Layers/ClaudeProvider.ts Outdated
@Aditya190803
Aditya190803 force-pushed the feat/provider-usage-limits branch from 036a9b9 to ed12bb8 Compare April 17, 2026 07:18
@Aditya190803

Copy link
Copy Markdown
Contributor Author

Wth
It has everything Implemented and is being closed by a pr that just has 2 providers

I have implemented for all 4 providers

Well done @t3dotgg

@juliusmarminge @maria-rcks

@greyxp1

greyxp1 commented Aug 23, 2026

Copy link
Copy Markdown

That's actually so sad I was following this for quite a while omg

@Aditya190803

Copy link
Copy Markdown
Contributor Author

That's actually so sad I was following this for quite a while omg

I even modified It to work properly with the new usage page
Because this is one thing I wanted for sooo fucking long

@juliusmarminge

Copy link
Copy Markdown
Member

Hey I'm OOO but raised this to the team. I've been in support of your implementation over Theo's. I think his agent might have been a bit of a yes-man and just favored their own implementation blindly.

@syrok0010

Copy link
Copy Markdown

That's actually so sad I was following this for quite a while omg

I even modified It to work properly with the new usage page
Because this is one thing I wanted for sooo fucking long

Your implementation is great. I've been using it for ages it seems. Although the idea to display the limits on hover seems useful, so you don't have to click anything. It would be great if you add it too.

@t3dotgg

t3dotgg commented Aug 23, 2026

Copy link
Copy Markdown
Member

My bad

@t3dotgg t3dotgg reopened this Aug 23, 2026
…provider-usage-limits

# Conflicts:
#	apps/server/src/provider/Layers/ProviderRegistry.test.ts
@juliusmarminge

Copy link
Copy Markdown
Member

I'll get this over the finish line when i get back 🫡

@macroscopeapp macroscopeapp Bot left a comment

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.

Reviewed the web UI added by this PR (apps/web/src/components/usage/**, timestampFormat.ts, UsagePage.tsx). The bar geometry, role="progressbar" semantics and motion-reduce transition now match ContextWindowMeter, and the reset formatters both go through the host-locale formatters in timestampFormat.ts. Two findings inline: a provider tile that can render with a heading and no body, and a copy-pasted badge-geometry override that is now on its third call site.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/usage/ProviderQuotaLimits.tsx Outdated
Comment thread apps/web/src/components/usage/ProviderQuotaLimits.tsx

@macroscopeapp macroscopeapp Bot left a comment

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.

Reviewed the web UI added by this PR (apps/web/src/components/usage/**, timestampFormat.ts, UsagePage.tsx). The bar geometry, role="progressbar" semantics and motion-reduce transition now match ContextWindowMeter, and the reset formatters both go through the host-locale formatters in timestampFormat.ts. Two findings inline: a provider tile that can render with a heading and no body, and a copy-pasted badge-geometry override that is now on its third call site.

Posted via Macroscope — UI Consistency

Comment thread apps/web/src/components/usage/ProviderQuotaLimits.tsx Outdated
Comment thread apps/web/src/components/usage/ProviderQuotaLimits.tsx
…provider-usage-limits

# Conflicts:
#	apps/server/src/provider/Layers/GrokProvider.ts
#	apps/web/src/components/usage/UsagePage.tsx
#	docs/user/usage.md

@macroscopeapp macroscopeapp Bot left a comment

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.

Reviewed the changed Effect service code (usage probes, provider layers, ingestion layer, drivers). The earlier findings about threading PtyAdapter["Service"] through value parameters are resolved — the probes now acquire the tag from the environment via Effect.serviceOption. One issue remains in GrokDriver.ts.

Posted via Macroscope — Effect Service Conventions

Comment thread apps/server/src/provider/Drivers/GrokDriver.ts Outdated
Comment thread apps/server/src/provider/Layers/GrokProvider.ts
Comment thread apps/server/src/provider/Layers/GrokProvider.ts
Keep probes from hanging the rest of status checks, preserve last-good quota bars, and stop empty usage tiles from rendering without an explanation.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread apps/server/src/terminal/BunPtyAdapter.ts
Comment thread apps/server/src/terminal/NodePtyAdapter.ts
Comment thread apps/server/src/terminal/NodePtyAdapter.ts Outdated
Replay last-exit on a microtask so Terminal Manager can assign session.process first. On Windows, kill the PTY tree with taskkill so cmd.exe-launched CLI children do not leak.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread apps/server/src/terminal/NodePtyAdapter.ts
Co-authored-by: macroscopeapp[bot] <170038800+macroscopeapp[bot]@users.noreply.github.com>
if (isGrokFreeTier(provider)) {
return GROK_FREE_TIER_USAGE_MESSAGE;
}
if (!provider.usageLimits) return "Usage data unavailable";

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.

Dropped usage windows leave empty tiles

Low Severity

Forward-compatible decoding now drops invalid or unknown usage windows instead of failing the provider, which can leave usageLimits.available true with an empty windows array. providerQuotaNotice only fills the tile body when usageLimits is missing, so those snapshots render a title with no bars and no message on web and mobile.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit fdc78fb. Configure here.

return {
models,
...(auth ? { auth } : {}),
} satisfies GrokAcpDiscoveryResult;

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.

Grok auth probe can discard models

Medium Severity

The Grok auth subscription probe still runs inside the outer ACP discovery timeout, so a slow acp.start() can leave too little budget for auth/check_subscription. When that outer timer fires, the already-built model catalog is thrown away and the provider is reported as a startup timeout instead of ready with unknown auth.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 574252c. Configure here.

Effect.catchCause((cause) =>
Cause.hasInterrupts(cause) ? Effect.failCause(cause) : Effect.succeed(Option.none()),
),
);

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.

Codex rate-limit interrupt drops snapshot

Medium Severity

The Codex rate-limit read rethrows interrupts, so an outer probe timeout that fires during account/rateLimits/read can still fail the whole app-server snapshot. Account, models, and skills that were already fetched are then discarded as a provider timeout instead of publishing with usage degraded.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 574252c. Configure here.

@Aditya190803

Copy link
Copy Markdown
Contributor Author

Follow-up stacked on this PR: remaining session/weekly usage in the chat box, current provider only.

Stacked PR: #8445

  • Opt-in via Settings → General → Show usage in chat (default off)
  • Hidden until the thread has sent its first message
  • Bars go in the context-window hover when that ring exists; otherwise a compact percent next to send
  • Does not mix quota into the context-window ring number

Settings

Show usage in chat setting

Chat hover

Session and weekly usage in the context-window hover

@cursor cursor Bot left a comment

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.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

There are 31 total unresolved issues (including 30 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e6ed20c. Configure here.

? window.windowDurationMins
: reported.length > 1 && index === 0
? CODEX_SESSION_WINDOW_DURATION_MINS
: CODEX_WEEKLY_WINDOW_DURATION_MINS;

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.

Codex partials mislabeled as weekly

Medium Severity

Live Codex account.rate-limits.updated payloads reuse the full-snapshot resolver, which treats a lone duration-less primary window as weekly. Codex notifications are documented as partial, and mergeUsageLimitWindows upserts by kind, so a session-only patch can overwrite the weekly bar and leave the session bar stale during a turn.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e6ed20c. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add usage / quota visibility for Codex sessions and accounts

10 participants