mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-20 15:33:54 +00:00
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.
This commit is contained in:
parent
8582f35d96
commit
89bd0fba90
24 changed files with 579 additions and 7 deletions
49
cli.py
49
cli.py
|
|
@ -8722,7 +8722,7 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin):
|
|||
elif canonical == "compress":
|
||||
self._manual_compress(cmd_original)
|
||||
elif canonical == "usage":
|
||||
self._show_usage()
|
||||
self._handle_usage_command(cmd_original)
|
||||
elif canonical == "credits":
|
||||
self._show_credits()
|
||||
elif canonical == "billing":
|
||||
|
|
@ -9623,6 +9623,53 @@ class HermesCLI(CLIAgentSetupMixin, CLICommandsMixin):
|
|||
|
||||
|
||||
|
||||
def _handle_usage_command(self, cmd_original: str):
|
||||
"""Dispatch `/usage [reset [--force]]`.
|
||||
|
||||
Bare `/usage` keeps the classic display. `/usage reset` redeems one
|
||||
banked Codex rate-limit reset credit (guarded: refuses when limits
|
||||
aren't exhausted unless --force).
|
||||
"""
|
||||
parts = cmd_original.split()
|
||||
args = [p.lower() for p in parts[1:]]
|
||||
if args and args[0] == "reset":
|
||||
self._usage_reset(force="--force" in args[1:])
|
||||
return
|
||||
if args:
|
||||
print(f" Unknown /usage subcommand: {' '.join(parts[1:])}. Try /usage or /usage reset [--force].")
|
||||
return
|
||||
self._show_usage()
|
||||
|
||||
def _usage_reset(self, force: bool = False):
|
||||
"""`/usage reset [--force]` — redeem one banked Codex reset credit."""
|
||||
provider = (
|
||||
(getattr(self.agent, "provider", None) if self.agent else None)
|
||||
or getattr(self, "provider", None)
|
||||
)
|
||||
normalized = str(provider or "").strip().lower()
|
||||
if normalized != "openai-codex":
|
||||
print(" Banked usage resets are only available on the openai-codex provider.")
|
||||
print(" Switch with `/model` or `hermes auth` first.")
|
||||
return
|
||||
base_url = (getattr(self.agent, "base_url", None) if self.agent else None) or getattr(self, "base_url", None)
|
||||
api_key = (getattr(self.agent, "api_key", None) if self.agent else None) or getattr(self, "api_key", None)
|
||||
|
||||
from agent.account_usage import redeem_codex_reset_credit
|
||||
|
||||
print(" ⏳ Checking banked reset credits...")
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as _pool:
|
||||
try:
|
||||
result = _pool.submit(
|
||||
redeem_codex_reset_credit,
|
||||
base_url=base_url,
|
||||
api_key=api_key,
|
||||
force=force,
|
||||
).result(timeout=45.0)
|
||||
except concurrent.futures.TimeoutError:
|
||||
print(" ❌ Timed out talking to the Codex backend — try again shortly.")
|
||||
return
|
||||
print(f" {result.message}")
|
||||
|
||||
def _show_usage(self):
|
||||
"""Rate limits + session token usage (when a live agent exists) + Nous credits.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue