mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-06 07:12:12 +03:00
fix(codex): preserve quota window duration (#9222)
Validated in local merge-train (devbox-vm-06-dev002) @ combined-tip (FAST gates — only pre-existing audit.test.ts flake).
This commit is contained in:
committed by
GitHub
parent
348e1b1921
commit
bfd2d5603c
1
changelog.d/fixes/9222-codex-quota-window-duration.md
Normal file
1
changelog.d/fixes/9222-codex-quota-window-duration.md
Normal file
@@ -0,0 +1 @@
|
||||
- **fix(codex):** preserve quota window duration in usage shape. (thanks @HectorBernstorff)
|
||||
@@ -13,6 +13,7 @@ export type CodexUsageQuota = {
|
||||
remaining?: number;
|
||||
resetAt: string | null;
|
||||
unlimited: boolean;
|
||||
windowSeconds: number | null;
|
||||
displayName?: string;
|
||||
};
|
||||
|
||||
@@ -38,6 +39,15 @@ function toNumber(value: unknown, fallback = 0): number {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
function toNullableNumber(value: unknown): number | null {
|
||||
if (typeof value === "number" && Number.isFinite(value)) return value;
|
||||
if (typeof value === "string" && value.trim().length > 0) {
|
||||
const parsed = Number(value);
|
||||
return Number.isFinite(parsed) ? parsed : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function parseResetTime(resetValue: unknown): string | null {
|
||||
if (!resetValue) return null;
|
||||
try {
|
||||
@@ -81,6 +91,15 @@ function buildPercentageQuota(window: JsonRecord, displayName?: string): CodexUs
|
||||
remaining: 100 - usedPercent,
|
||||
resetAt: parseWindowReset(window),
|
||||
unlimited: false,
|
||||
windowSeconds: toNullableNumber(
|
||||
getFieldValue(
|
||||
window,
|
||||
"limit_window_seconds",
|
||||
"limitWindowSeconds",
|
||||
"window_seconds",
|
||||
"windowSeconds"
|
||||
)
|
||||
),
|
||||
...(displayName ? { displayName } : {}),
|
||||
};
|
||||
}
|
||||
@@ -105,10 +124,7 @@ function isLatentWindow(window: JsonRecord): boolean {
|
||||
getFieldValue(window, "limit_window_seconds", "limitWindowSeconds"),
|
||||
0
|
||||
);
|
||||
const resetAfter = toNumber(
|
||||
getFieldValue(window, "reset_after_seconds", "resetAfterSeconds"),
|
||||
0
|
||||
);
|
||||
const resetAfter = toNumber(getFieldValue(window, "reset_after_seconds", "resetAfterSeconds"), 0);
|
||||
return usedPercent === 0 && limitWindow > 0 && resetAfter >= limitWindow;
|
||||
}
|
||||
|
||||
@@ -225,7 +241,9 @@ function findCodexReviewRateLimit(data: JsonRecord): JsonRecord {
|
||||
* (issue #5199).
|
||||
*/
|
||||
function parseBankedResetCredits(data: JsonRecord): number | undefined {
|
||||
const resetCredits = toRecord(getFieldValue(data, "rate_limit_reset_credits", "rateLimitResetCredits"));
|
||||
const resetCredits = toRecord(
|
||||
getFieldValue(data, "rate_limit_reset_credits", "rateLimitResetCredits")
|
||||
);
|
||||
const availableCount = getFieldValue(resetCredits, "available_count", "availableCount");
|
||||
const count = toNumber(availableCount, NaN);
|
||||
return Number.isFinite(count) ? count : undefined;
|
||||
|
||||
52
tests/unit/codex-usage-windows.test.ts
Normal file
52
tests/unit/codex-usage-windows.test.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { describe, it } from "node:test";
|
||||
|
||||
import { buildCodexUsageQuotas } from "../../open-sse/services/codexUsageQuotas";
|
||||
|
||||
describe("Codex usage windows", () => {
|
||||
it("preserves upstream durations for session and weekly windows", () => {
|
||||
const { quotas } = buildCodexUsageQuotas({
|
||||
rate_limit: {
|
||||
primary_window: {
|
||||
used_percent: 7,
|
||||
limit_window_seconds: 18_000,
|
||||
reset_at: 1_785_623_016,
|
||||
},
|
||||
secondary_window: {
|
||||
used_percent: 19,
|
||||
limit_window_seconds: 604_800,
|
||||
reset_at: 1_785_678_428,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepEqual(quotas.session, {
|
||||
used: 7,
|
||||
total: 100,
|
||||
remaining: 93,
|
||||
resetAt: new Date(1_785_623_016_000).toISOString(),
|
||||
unlimited: false,
|
||||
windowSeconds: 18_000,
|
||||
});
|
||||
assert.deepEqual(quotas.weekly, {
|
||||
used: 19,
|
||||
total: 100,
|
||||
remaining: 81,
|
||||
resetAt: new Date(1_785_678_428_000).toISOString(),
|
||||
unlimited: false,
|
||||
windowSeconds: 604_800,
|
||||
});
|
||||
});
|
||||
|
||||
it("accepts camelCase duration variants and nulls invalid values", () => {
|
||||
const { quotas } = buildCodexUsageQuotas({
|
||||
rateLimit: {
|
||||
primaryWindow: { usedPercent: 3, windowSeconds: "18000" },
|
||||
secondaryWindow: { usedPercent: 4, windowSeconds: "not-a-number" },
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(quotas.session.windowSeconds, 18_000);
|
||||
assert.equal(quotas.weekly.windowSeconds, null);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user