Skip to content

feat(codex): forward quota telemetry to the client - #127

Open
rikbrown wants to merge 2 commits into
raine:mainfrom
rikbrown:rik/forward-codex-rate-limit-headers
Open

feat(codex): forward quota telemetry to the client#127
rikbrown wants to merge 2 commits into
raine:mainfrom
rikbrown:rik/forward-codex-rate-limit-headers

Conversation

@rikbrown

Copy link
Copy Markdown

Problem

Codex reports how much of a ChatGPT subscription is spent in two places: x-codex-* headers on an HTTP response, and a codex.rate_limits event on the WebSocket transport. Neither reaches the client. The proxy answers in Anthropic's format, which has no equivalent field, so the event is classified as control and becomes a ping, and the response headers are dropped.

That leaves anything sitting in front of the proxy — a rotating multi-account gateway, a quota readout — unable to see the limit it is about to hit. The first sign of a spent window is a 429.

Change

A new providers/codex/rate_limits.rs keeps the newest snapshot and stamps it onto every Codex /v1/messages response, under the header names Codex itself uses, so a client that already parses them needs no second format. Both transports feed it: the HTTP response head, and the codex.rate_limits event.

Only quota headers are forwarded. x-codex-turn-state is continuation state, and a large opaque blob to put on every response.

Codex sends the event ahead of the first generated output and the response head is built from that output, so a response normally carries the numbers of the request it answers. One that arrives before any telemetry does carries the previous snapshot, or none.

Which window is which is left to the client, because it varies: a ChatGPT Pro subscription reports its weekly limit as primary and meters no secondary window at all, so the -window-minutes header is what identifies a bucket, not the position.

Testing

  • Six unit tests in the new module, covering both sources, the header filter, and the stamped response.
  • cargo test — 1033 pass. cargo clippy --all-targets and cargo fmt --check clean.
  • Checked against a live ChatGPT Pro subscription on both transports, streaming and buffered.

The HTTP API reference gains a paragraph describing the headers.

🤖 Generated with Claude Code

https://claude.ai/code/session_01S3HCmE8ZPT1o59UCGaoEeV

Rik Brown added 2 commits August 31, 2026 09:28
Codex reports how much of a ChatGPT subscription is spent twice: as
`x-codex-*` headers on an HTTP response, and as a `codex.rate_limits`
event on the WebSocket transport. The proxy answers in Anthropic's
format, which has no equivalent field, so neither reaches the client and
a tool in front of the proxy — a rotating multi-account gateway, a quota
readout — cannot see the limit it is about to hit.

Keep the newest snapshot and stamp it onto every Codex response under
the header names Codex itself uses, so a client that already reads them
needs no second format. The event precedes the first generated output on
both transports and the response head is built from that output, so a
response normally carries the numbers of the request it answers.

Only quota headers are forwarded: `x-codex-turn-state` is continuation
state, and a large opaque blob to put on every response.
@rikbrown rikbrown changed the title Forward Codex quota telemetry to the client feat: forward Codex quota telemetry to the client Aug 31, 2026
@rikbrown rikbrown changed the title feat: forward Codex quota telemetry to the client feat(codex): forwar quota telemetry to the client Aug 31, 2026
@rikbrown rikbrown changed the title feat(codex): forwar quota telemetry to the client feat(codex): forward quota telemetry to the client Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant