fix(codex): normalize rate limit window labels

Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
Jinwoo-H
2026-05-16 17:08:13 -04:00
co-authored by Orca
parent 37e2be4064
commit a5dd98d58a
4 changed files with 57 additions and 9 deletions
@@ -109,4 +109,47 @@ describe('fetchCodexRateLimits', () => {
error: null
})
})
it('normalizes Codex RPC remaining-minute windows to fixed display durations', async () => {
const rpcChild = makeRpcChild()
childSpawnMock.mockReturnValue(rpcChild)
rpcChild.stdin.write.mockImplementation((line: string) => {
const msg = JSON.parse(line) as { id?: number; method?: string }
if (msg.method === 'initialize') {
setTimeout(() => {
rpcChild.stdout.emit(
'data',
Buffer.from(`${JSON.stringify({ jsonrpc: '2.0', id: msg.id, result: {} })}\n`)
)
}, 0)
}
if (msg.method === 'account/rateLimits/read') {
setTimeout(() => {
rpcChild.stdout.emit(
'data',
Buffer.from(
`${JSON.stringify({
jsonrpc: '2.0',
id: msg.id,
result: {
rateLimits: {
primary: { usedPercent: 0, windowDurationMins: 299 },
secondary: { usedPercent: 0, windowDurationMins: 10079 }
}
}
})}\n`
)
)
}, 0)
}
})
const resultPromise = fetchCodexRateLimits()
await vi.advanceTimersByTimeAsync(1)
await vi.advanceTimersByTimeAsync(1)
const result = await resultPromise
expect(result.session?.windowMinutes).toBe(300)
expect(result.weekly?.windowMinutes).toBe(10080)
})
})
+9 -4
View File
@@ -44,7 +44,10 @@ function buildRpcMessage(id: number, method: string, params?: unknown): string {
return `${JSON.stringify({ jsonrpc: '2.0', id, method, params: params ?? {} })}\n`
}
function mapRpcWindow(raw: RpcRateWindow | undefined): RateLimitWindow | null {
function mapRpcWindow(
raw: RpcRateWindow | undefined,
expectedWindowMinutes: number
): RateLimitWindow | null {
if (!raw || typeof raw.usedPercent !== 'number') {
return null
}
@@ -70,7 +73,9 @@ function mapRpcWindow(raw: RpcRateWindow | undefined): RateLimitWindow | null {
return {
usedPercent: Math.min(100, Math.max(0, raw.usedPercent)),
windowMinutes: raw.windowDurationMins ?? 300,
// Why: Codex currently reports remaining minutes in `windowDurationMins`.
// Orca's UI needs the fixed bucket duration so labels stay "5h" / "7d".
windowMinutes: expectedWindowMinutes,
resetsAt,
resetDescription
}
@@ -199,8 +204,8 @@ async function fetchViaRpc(options?: FetchCodexRateLimitsOptions): Promise<Provi
const wrapper = msg.result as RpcRateLimitsResponse | undefined
const result = wrapper?.rateLimits
const session = mapRpcWindow(result?.primary)
const weekly = mapRpcWindow(result?.secondary)
const session = mapRpcWindow(result?.primary, 300)
const weekly = mapRpcWindow(result?.secondary, 10080)
resolve({
provider: 'codex',
@@ -10,8 +10,8 @@ describe('formatWindowLabel', () => {
expect(formatWindowLabel(60)).toBe('1h')
})
it('returns "wk" for 10080 minutes (7 days)', () => {
expect(formatWindowLabel(10080)).toBe('wk')
it('returns "7d" for 10080 minutes (7 days)', () => {
expect(formatWindowLabel(10080)).toBe('7d')
})
it('returns "1d" for 1440 minutes (1 day)', () => {
@@ -1,12 +1,12 @@
/**
* Returns a short human-readable label for a usage window duration.
*
* Why: 10080 minutes (7 days) is hard-coded as "wk" for backward
* compatibility with the original StatusBar implementation.
* Why: the status bar uses duration labels, so the weekly bucket is shown as
* "7d" instead of a calendar-period label like "wk".
*/
export function formatWindowLabel(windowMinutes: number): string {
if (windowMinutes === 10080) {
return 'wk'
return '7d'
}
if (windowMinutes === 300) {
return '5h'