-
Notifications
You must be signed in to change notification settings - Fork 7.9k
feat: support multiple rate limits #11260
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
f0abfb0 to
5a1de97
Compare
There was a problem hiding this comment.
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: 5a1de97fb3
ℹ️ 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".
| .find(|snapshot| snapshot.limit_name.as_deref() == Some("codex")) | ||
| .cloned() | ||
| .unwrap_or_else(|| snapshots[0].clone()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fall back when codex snapshot has no limit data
This selection always prefers the "codex" entry, but get_rate_limits_many now always includes a synthetic codex snapshot even when /usage returns rate_limit: null and only non-codex buckets have real window data. In that case rate_limits in GetAccountRateLimitsResponse is returned empty while rate_limits_by_name has populated limits, which regresses legacy clients that still read only rate_limits. Prefer codex only when it actually contains window/credit data, otherwise fall back to a populated snapshot.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rate_limits is intentionally the canonical codex bucket for legacy clients; falling back to additional buckets would change its semantics and misrepresent what legacy clients are actually able to interpret.
| HeaderValue::from_static("1704074400"), | ||
| ); | ||
|
|
||
| let snapshot = parse_rate_limit_for_limit(&headers, Some("codex_other")).expect("snapshot"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use matching limit name in secondary-header parser test
This test sets x-codex-secondary-* headers but calls parse_rate_limit_for_limit(..., Some("codex_other")), so the parser looks for x-codex-other-* keys and cannot populate primary, making the subsequent expect("primary") fail. The limit name and header prefix need to match (for example codex_secondary with x-codex-secondary-*).
Useful? React with 👍 / 👎.
9f74d29 to
dd06980
Compare
|
@codex review |
There was a problem hiding this comment.
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: dd069802d6
ℹ️ 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".
| self.rate_limit_snapshots_by_limit_id | ||
| .insert(limit_id, display); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prune stale limit buckets when applying updates
This path only upserts a single bucket into rate_limit_snapshots_by_limit_id, and buckets are cleared only when snapshot is None. With the new multi-limit polling flow, snapshots are emitted one-by-one from /usage, so if a bucket disappears from a later response (for example, codex_other is no longer returned), there is no tombstone and the old entry remains in memory, causing /status to keep rendering stale limits indefinitely.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is OK for now.
| let suffix = "-primary-used-percent"; | ||
| let prefix = header_name.strip_suffix(suffix)?; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Detect non-default limit ids beyond primary headers
parse_rate_limit_updates discovers additional buckets via header_name_to_limit_id, but this helper only matches headers ending in -primary-used-percent. If a non-default bucket is reported with only secondary-window headers, that bucket is never discovered, so no snapshot is emitted and consumers miss the update entirely. Limit-id discovery should include secondary header families (or use a broader prefix-based detection) to avoid dropping valid buckets.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should no happen.
| limit_id: None, | ||
| limit_name: None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are the core rate limits name/idless?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok i see you store them rate_limits
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can update the test with a real value of limit_id/name.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we still update v1 schemas?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Must be auto-generated from some command I run. Let me revert.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just write-app-server-schema actually it will still generate v1 (otherwise C1 will fail).
dd06980 to
7c81f7e
Compare
codex-rs/core/src/error.rs
Outdated
| impl std::fmt::Display for UsageLimitReachedError { | ||
| fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
| // Pro users might hit a non-standard codex metered bucket. | ||
| if matches!(self.plan_type, Some(PlanType::Known(KnownPlan::Pro))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does it have to gate to pro or can it be more general?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call!
7c81f7e to
b494b5b
Compare
Added multi-limit support end-to-end by carrying limit_name in rate-limit snapshots and handling multiple buckets instead of only codex.
Extended /usage client parsing to consume additional_rate_limits
Updated TUI /status and in-memory state to store/render per-limit snapshots
Extended app-server rate-limit read response: kept rate_limits and added rate_limits_by_name.
Adjusted usage-limit error messaging for non-default codex limit buckets