Files
clawdmeter/daemon/tests/test_openai_codex.py
T
wenilandClaude Opus 4.8 b63a6a62ae v3 M2: OpenAI Codex provider — real rate-limit % from local Codex rollouts
OpenAICodexProvider replaces the openai stub. It reads the rate-limit snapshot
the Codex CLI already records locally (no second auth): each turn Codex writes a
token_count event into $CODEX_HOME/sessions/**/rollout-*.jsonl whose
payload.rate_limits mirrors Claude's model — primary (5h) + secondary (weekly),
each with used_percent + resets_at + plan_type. The provider surfaces the
freshest such snapshot; a window whose reset time has passed is reported as a
fresh 0% (local read, so current in-session and self-heals between sessions).

primary -> s/sr, secondary -> w/wr, plan_type -> status ("Plus"/…),
rate_limit_reached_type -> "limited". No per-token cost (subscription), so the
two rate-limit bars are the metric, per the locked v3 decision.

Verified against the real ~/.codex: full daemon payload with openai active =
{pv:openai, pnm:"OpenAI Codex", ac:0x10a37f, st:"Plus", ok:true, weekly reset}.
registry test updated (openai now real, zai still stub); +7 provider tests.
113 passed, 2 Linux-only failures (baseline). spec: hiddenimport added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 07:14:15 +03:00

106 lines
4.1 KiB
Python

"""v3 M2 — OpenAI Codex provider: read rate-limit % from the Codex session rollouts.
Codex writes a token_count event per turn whose payload.rate_limits mirrors
Claude's model (primary=5h, secondary=weekly). The provider surfaces the freshest
such snapshot; a window whose reset time has passed is reported as a fresh 0%.
"""
import asyncio
import json
import os
import time
from daemon.providers.openai_codex import OpenAICodexProvider
def _run(coro):
return asyncio.get_event_loop().run_until_complete(coro)
def _write_rollout(home, name, rate_limits_list, mtime=None):
"""Write a rollout JSONL with one token_count event per rate_limits dict."""
d = home / "sessions" / "2026" / "07" / "10"
d.mkdir(parents=True, exist_ok=True)
p = d / f"rollout-{name}.jsonl"
lines = []
for i, rl in enumerate(rate_limits_list):
lines.append(json.dumps({
"timestamp": f"2026-07-10T00:00:0{i}Z",
"type": "event_msg",
"payload": {"type": "token_count",
"info": {"total_token_usage": {"total_tokens": 1}},
"rate_limits": rl},
}))
p.write_text("\n".join(lines), encoding="utf-8")
if mtime is not None:
os.utime(p, (mtime, mtime))
return p
def _rl(pri_used, pri_reset, sec_used, sec_reset, plan="plus", reached=None):
return {"limit_id": "codex",
"primary": {"used_percent": pri_used, "window_minutes": 300, "resets_at": pri_reset},
"secondary": {"used_percent": sec_used, "window_minutes": 10080, "resets_at": sec_reset},
"plan_type": plan, "rate_limit_reached_type": reached}
def test_maps_windows_with_future_reset(tmp_path):
now = time.time()
_write_rollout(tmp_path, "a", [_rl(42.0, now + 3600, 10.0, now + 7200)])
st = _run(OpenAICodexProvider(codex_home=str(tmp_path)).poll())
assert st.ok is True
assert st.s == 42.0 and 58 <= st.sr <= 60
assert st.w == 10.0 and 118 <= st.wr <= 120
assert st.st == "Plus"
def test_past_reset_is_fresh_zero(tmp_path):
now = time.time()
# primary window already elapsed => 0% fresh, unknown reset; secondary still open
_write_rollout(tmp_path, "a", [_rl(99.0, now - 100, 55.0, now + 600)])
st = _run(OpenAICodexProvider(codex_home=str(tmp_path)).poll())
assert st.s == 0.0 and st.sr == -1
assert st.w == 55.0 and 8 <= st.wr <= 10
def test_rate_limit_reached_marks_limited(tmp_path):
now = time.time()
_write_rollout(tmp_path, "a", [_rl(100.0, now + 60, 80.0, now + 600, reached="primary")])
st = _run(OpenAICodexProvider(codex_home=str(tmp_path)).poll())
assert st.st == "limited" and st.ok is True
def test_last_snapshot_in_file_wins(tmp_path):
now = time.time()
_write_rollout(tmp_path, "a", [_rl(10.0, now + 600, 1.0, now + 600),
_rl(73.0, now + 600, 2.0, now + 600)])
st = _run(OpenAICodexProvider(codex_home=str(tmp_path)).poll())
assert st.s == 73.0 # the later event, not the first
def test_newest_file_wins(tmp_path):
now = time.time()
_write_rollout(tmp_path, "old", [_rl(11.0, now + 600, 0.0, now + 600)], mtime=now - 500)
_write_rollout(tmp_path, "new", [_rl(88.0, now + 600, 0.0, now + 600)], mtime=now)
st = _run(OpenAICodexProvider(codex_home=str(tmp_path)).poll())
assert st.s == 88.0
def test_skips_file_without_rate_limits(tmp_path):
now = time.time()
# newest file has a token_count with null rate_limits; older file has the data
_write_rollout(tmp_path, "older", [_rl(64.0, now + 600, 0.0, now + 600)], mtime=now - 500)
p = _write_rollout(tmp_path, "newer", [], mtime=now)
p.write_text(json.dumps({
"timestamp": "2026-07-10T01:00:00Z", "type": "event_msg",
"payload": {"type": "token_count", "info": {}, "rate_limits": None},
}), encoding="utf-8")
os.utime(p, (now, now))
st = _run(OpenAICodexProvider(codex_home=str(tmp_path)).poll())
assert st.ok is True and st.s == 64.0
def test_no_sessions_dir_reports_no_data(tmp_path):
st = _run(OpenAICodexProvider(codex_home=str(tmp_path)).poll())
assert st.ok is False and st.st == "no data"