Commit graph

4 commits

Author SHA1 Message Date
Teknium
89bd0fba90
feat(codex): redeem banked usage-limit resets via /usage reset (#64280)
OpenAI lets ChatGPT-plan Codex users bank rate-limit reset credits, but
until now they could only be redeemed from the Codex CLI/app or the
website. This wires the same backend API into Hermes:

- /usage on the openai-codex provider now shows "You have N resets
  banked - use /usage reset to activate" (parsed from the
  rate_limit_reset_credits field the /usage endpoint already returns).
- New /usage reset subcommand (CLI + gateway) redeems one banked
  credit via POST .../rate-limit-reset-credits/consume with a UUID
  idempotency key, mirroring codex-rs backend-client semantics
  (PathStyle /wham vs /api/codex, ChatGPT-Account-Id header,
  reset/nothing_to_reset/no_credit/already_redeemed outcomes).
- Guard: redemption is refused while no rate-limit window is fully
  exhausted, since a banked reset restores the FULL 5h + weekly
  allowance and spending it early wastes it. /usage reset --force
  overrides. Zero banked credits and non-codex providers are refused
  with clear messages; nothing_to_reset reports the credit was NOT
  spent.
- i18n: new gateway.usage.unknown_subcommand / reset_wrong_provider
  keys across all 16 locales; docs updated (cli.md, messaging index).

Tested with unit tests plus a real-socket E2E against a local fake
Codex backend exercising redeem/guard/force and the /usage hint.
2026-07-14 03:23:19 -07:00
kshitijk4poor
130e2337c2 fix(usage): scope Codex usage pool fallback to AuthError, keep singleton token on account_id read failure
Follow-up hardening on the cherry-picked pool-fallback fix. The original
_resolve_codex_usage_credentials wrapped BOTH resolve_codex_runtime_credentials()
and the separate _read_codex_tokens() account_id read in one broad
'except Exception: pass', which had three problems:

1. A transient refresh/network failure (non-AuthError) from the resolver was
   silently swallowed and downgraded to pool.select(), which could report
   /usage limits for a DIFFERENT pool account than the one actually running.
   On main that error surfaced. This is a real behavior regression for the
   multi-account/pool case.
2. If the resolver succeeded but only the account_id read raised, the whole
   singleton tier was abandoned in favor of a pool token that carries no
   ChatGPT-Account-Id header (PooledCredential has no account_id concept),
   risking a wrong-account read or 401.
3. 'except Exception' masked genuine programming errors.

Fix: narrow the outer catch to AuthError (the documented 'no creds' failure
mode of both functions), and read account_id in a best-effort inner try so a
partial/missing singleton store can't sink an otherwise-usable credential.
Transient errors now propagate and fail open via the outer fetch_account_usage
guard rather than mis-routing to the wrong account. Adds debug breadcrumbs and
a comment characterizing when the tier-3 pool path actually fires.

Guard tests: a non-AuthError resolver failure must NOT swap to the pool
(fail-open, no snapshot); an account_id read failure keeps the singleton token.
Updated the existing pool-fallback test to use AuthError (the real failure
mode) instead of a generic RuntimeError.
2026-07-07 12:01:33 +05:30
spiky02plateau
c59b300865 test: lock Codex usage percent polarity 2026-07-07 12:01:33 +05:30
spiky02plateau
b2213ba870 fix: fetch Codex quota from credential pool 2026-07-07 12:01:33 +05:30