Spaces:
Running
Running
Codex usage: label quota windows by length, not slot position
Browse filesThe Usage card assumed codex reports the 5-hour window as 'primary'
and the weekly as 'secondary', but codex doesn't always order them
that way — so a block that led with the weekly got shown as '5-hour'
(and the real 5-hour vanished). Classify each window by its
window_minutes instead (<=6h is the 5-hour bucket, longer is weekly),
scanning newest lines first to fill both. Verified against normal,
reversed, and weekly-only blocks.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- server/src/usage.js +13 -3
server/src/usage.js
CHANGED
|
@@ -146,17 +146,27 @@ async function tailOf(p, bytes = 262_144) {
|
|
| 146 |
function codexQuota() {
|
| 147 |
return cached('codexq', async () => {
|
| 148 |
const win = (w) => (w ? { usedPercent: w.used_percent, windowMinutes: w.window_minutes, resetsAt: toEpochSec(w.resets_at) } : null);
|
| 149 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
for (const f of (await codexRollouts()).slice(0, 20)) {
|
| 151 |
let lines;
|
| 152 |
try { lines = (await tailOf(f.p)).split('\n'); } catch { continue; }
|
| 153 |
-
for (let i = lines.length - 1; i >= 0; i--) {
|
| 154 |
const ln = lines[i];
|
| 155 |
if (!ln) continue;
|
| 156 |
let j; try { j = JSON.parse(ln); } catch { continue; }
|
| 157 |
const r = findRateLimits(j);
|
| 158 |
-
if (r)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
}
|
|
|
|
| 160 |
}
|
| 161 |
return null;
|
| 162 |
});
|
|
|
|
| 146 |
function codexQuota() {
|
| 147 |
return cached('codexq', async () => {
|
| 148 |
const win = (w) => (w ? { usedPercent: w.used_percent, windowMinutes: w.window_minutes, resetsAt: toEpochSec(w.resets_at) } : null);
|
| 149 |
+
// Classify each window by its length, NOT by primary/secondary position:
|
| 150 |
+
// codex doesn't always report the 5-hour window first, so trusting the
|
| 151 |
+
// slot mislabeled the weekly as "5-hour" (and hid the real 5-hour). A
|
| 152 |
+
// window <= 6h is the 5-hour bucket; anything longer is the weekly.
|
| 153 |
+
let fiveHour = null, weekly = null;
|
| 154 |
for (const f of (await codexRollouts()).slice(0, 20)) {
|
| 155 |
let lines;
|
| 156 |
try { lines = (await tailOf(f.p)).split('\n'); } catch { continue; }
|
| 157 |
+
for (let i = lines.length - 1; i >= 0 && !(fiveHour && weekly); i--) {
|
| 158 |
const ln = lines[i];
|
| 159 |
if (!ln) continue;
|
| 160 |
let j; try { j = JSON.parse(ln); } catch { continue; }
|
| 161 |
const r = findRateLimits(j);
|
| 162 |
+
if (!r) continue;
|
| 163 |
+
for (const w of [r.primary, r.secondary]) {
|
| 164 |
+
if (!w || w.window_minutes == null) continue;
|
| 165 |
+
if (w.window_minutes <= 360) { if (!fiveHour) fiveHour = win(w); }
|
| 166 |
+
else if (!weekly) weekly = win(w);
|
| 167 |
+
}
|
| 168 |
}
|
| 169 |
+
if (fiveHour || weekly) return { fiveHour, weekly };
|
| 170 |
}
|
| 171 |
return null;
|
| 172 |
});
|