Repository navigation
feat(codex): keep GPT slots in rotation on spendable ChatGPT credits - #508
Merged
dofastted merged 2 commits intoOct 17, 2026
Merged
Conversation
A slot whose 5h/7d window is spent but whose ChatGPT credits are still spendable now stays schedulable instead of parking until the window reset. - Parse `credits` from /wham/usage and `x-codex-credits-*` reply headers (same contract as the Codex CLI; balance kept as a string) into vm.codex.credits, separate from reset_credits, and project it to the pool summary (`codex_credits`) and panel responses. - One predicate, hasSpendableCodexCredits (fresh within 10 min and has_credits or unlimited), waives only window caps in every quota gate: codexQuotaPark, evaluateOpenAIQuotaGate, codexQuotaWindowReason, evaluateCodexQuotaSchedule, and the park derived on successful replies. - An upstream 429 still parks the slot and drops the credits reading; an explicit park, operator disable, auth and proxy blocks are unchanged.
Co-authored-by: ted <kuhlmangarry24@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Once a GPT slot's 5h/7d window hits 100%, ChatGPT can keep serving it by spending account credits. Until now vm2api parked the slot until the window reset, even when credits were available. With this PR, a fresh reading that credits are spendable keeps the slot schedulable. The upstream 429 stays the authority on real exhaustion.
Credit snapshot
/wham/usagecreditsand from thex-codex-credits-has-credits/-unlimited/-balanceheaders on every Responses reply. This is the same contract as the official Codex CLI (codex-rs/codex-api/src/rate_limits.rs): both flags are required,true/false/1/0are accepted, and the balance is trimmed.vm.codex.credits = { has_credits, unlimited, balance, fetched_at }, separate fromreset_creditsbecause the two mean different things.balancestays a string, so long decimals keep full precision.credits), on the pool summary (codex_credits), and on the panel VM list (codex_credits).One predicate in every quota gate
hasSpendableCodexCredits(vm)is true when the reading is withinCODEX_CREDITS_TTL_MS(10 min) andhas_credits || unlimited. A hiddenbalance: nullstill counts. When it holds, only the window caps are waived, in:codexQuotaPark(newwaiveWindowCapsoption) →isCodexSlotParked/parkUntilevaluateOpenAIQuotaGate(locallimit_5h/limit_7d)codexQuotaWindowReasonandcodexRestrictionUntil→evaluateCodexQuotaSchedule, so notemp_unschedulableis written and an existing quota restriction is clearedpersistCodexUsage: a successful reply past the cap no longer derives acodex_limited_untilfrom the spent windowStill blocks
limitedUntilpath and drops the credits reading, so the window caps apply again until a newer reading arrives.codex_limited_untiloutranks credits.has_credits=false && unlimited=false): parking is exactly as before.Behavior notes for review
/wham/usagerefresh that reports spendable credits clears an oldercodex_limited_until. If upstream refuses again, the next 429 re-parks.limit_5h/limit_7dbelow 1, as the original proposal specifies. A follow-up could add an opt-out switch if operators want those limits to reserve headroom even when credits are available.Tests
New
test/unit/codex-credits.test.mjs(13 tests). It covers balance parsing, long-decimal precision,unlimited,has_creditswithbalance=null,has_credits=falsenot bypassing the weekly cap, TTL expiry, every local gate passing at 7d=100% with fresh credits, operator/credential blocks, the protocol path keeping the slot on a successful reply, an upstream 429 parking and dropping credits, and reset credits being unaffected. Nine of these fail with the gate wiring reverted.node --test test/unit/*codex*.test.mjs test/unit/openai*.test.mjs: 212/212 pass (199 existing + 13 new)npm run test:uniton macOS: 7 files fail (egress, oauth-binary, session-oauth-seam, slot-shell-rc, slot-recovery, host-path, guest-identity-reader). All 7 fail identically on the untouched base; they need Linux binaries or paths.biome format: clean.git diff --check: clean.Not run: a live ChatGPT account with real credits, the web UI (no frontend change), or the Go tests.