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

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

Conversation

@rikbrown

Copy link
Copy Markdown
Contributor

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

@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
Rik Brown added 2 commits September 5, 2026 10:52
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 force-pushed the rik/forward-codex-rate-limit-headers branch 2 times, most recently from 42aed13 to dd66fed Compare September 13, 2026 14:10
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