Skip to content

feat(app-server): expose rate-limit reset credits#28143

Merged
jayp-oai merged 11 commits into
mainfrom
codex/rate-limit-reset-app-server
Jun 15, 2026
Merged

feat(app-server): expose rate-limit reset credits#28143
jayp-oai merged 11 commits into
mainfrom
codex/rate-limit-reset-app-server

Conversation

@jayp-oai

@jayp-oai jayp-oai commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

Why

Codex users can earn personal rate-limit reset credits, but app-server clients do not currently have an API for reading or redeeming them. This adds the backend and protocol foundation used by the /usage TUI flow in #28154.

What changed

  • Extend account/rateLimits/read with a nullable rateLimitResetCredits summary sourced from the existing usage response.
  • Add backend-client and app-server support for consuming a reset with a caller-generated idempotency key. A UUID is recommended, and clients reuse the same key when retrying the same logical reset.
  • Return only the consume outcome; clients refetch account/rateLimits/read for updated window state.
  • Document the response field and each consume outcome, and regenerate the JSON and TypeScript schema fixtures.
  • Clarify in AGENTS.md that new app-server string enum values use camelCase on the wire.
  • Update the existing TUI response fixture for the expanded protocol shape.
  • Add coverage for authentication, response mapping, backend failures, consume outcomes, and request timeout behavior.

Validation

  • just test -p codex-app-server-protocol — 231 passed.
  • just test -p codex-backend-client — 14 passed.
  • Focused codex-app-server reset-credit tests — 5 passed.
  • Focused codex-tui protocol response fixture test — passed.
  • just fix -p codex-backend-client -p codex-app-server-protocol -p codex-app-server — passed.
  • just fmt — passed.

@jayp-oai jayp-oai marked this pull request as ready for review June 15, 2026 01:10

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3f8ed5c895

ℹ️ 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 codex-rs/app-server/README.md
Comment thread codex-rs/backend-client/src/client/rate_limit_resets.rs
Comment thread codex-rs/app-server/tests/suite/v2/rate_limit_reset_credits.rs

@owenlin0 owenlin0 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

just some API design nits

#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ConsumeAccountRateLimitResetCreditParams {
pub redeem_request_id: String,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

should we just call this idempotency_key? IMO it's a well-known term and conveys the expectation that the client should be using this to represent the same logical "reset".

also, worth documenting that we recommend a UUID for this field?

Reset,
NothingToReset,
NoCredit,
AlreadyRedeemed,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

this is for the idempotent case?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yup this is returned when the same id is retried after redemption is completed.

#[serde(rename_all = "camelCase")]
#[ts(export_to = "v2/")]
pub struct ConsumeAccountRateLimitResetCreditResponse {
pub code: ConsumeAccountRateLimitResetCreditCode,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

nit: can we call this result or outcome? and rename the struct accordingly? code kind of feels like it should be an int (like JSON-RPC or HTTP status code or something)

#[ts(export_to = "v2/")]
pub struct ConsumeAccountRateLimitResetCreditResponse {
pub code: ConsumeAccountRateLimitResetCreditCode,
pub windows_reset: i64,

@owenlin0 owenlin0 Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

hmm, do we need to return the number of rate limit windows reset? seems like a weird contract. IMO let's keep it simple and only return result / outcome? either way, the client still has to refetch the latest rate limits via account/rateLimits/read

#[ts(export_to = "v2/", rename_all = "snake_case")]
pub enum ConsumeAccountRateLimitResetCreditCode {
Reset,
NothingToReset,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

worth documenting when this would be returned? it's not obvious to me


#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, JsonSchema, TS)]
#[serde(rename_all = "snake_case")]
#[ts(export_to = "v2/", rename_all = "snake_case")]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

use camelCase for consistency with the rest of the app-server API (I thought our agents.md mentions this, but maybe not? 🤔 )

@owenlin0 owenlin0 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

let's make the camelCase update but pre-approving

@jayp-oai jayp-oai enabled auto-merge (squash) June 15, 2026 21:50
@jayp-oai jayp-oai self-assigned this Jun 15, 2026
@jayp-oai jayp-oai merged commit bef99f8 into main Jun 15, 2026
32 of 33 checks passed
@jayp-oai jayp-oai deleted the codex/rate-limit-reset-app-server branch June 15, 2026 21:54
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 15, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants