mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 08:02:28 +00:00
fix(codex): cache weekly-only accounts when switching Codex accounts (#10467)
* fix(codex): cache weekly-only accounts when switching Codex accounts refreshForCodexAccountChange snapshotted the outgoing account only when this.state.codex.session was populated. Weekly-only plans report no session window, so their snapshot was dropped and the account switcher's inline bars rendered empty for exactly those accounts. Accept a populated weekly window as well. #10136 made this reachable: before duration-based classification, a weekly-only quota landed in the session slot, so the gate happened to pass. Claude is intentionally untouched; it has no weekly-only plan shape. * test(rate-limits): pin that a windowless outgoing Codex account is not cached The widened weekly-only gate had no test for its lower bound: replacing it with a bare truthy check on state.codex passed all 70 tests, which would cache an empty fetching placeholder and render a blank inline bar row in the switcher.
This commit is contained in:
@@ -1751,6 +1751,60 @@ describe('RateLimitService', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('caches an outgoing weekly-only Codex account so the switcher keeps its inline bars', async () => {
|
||||
const service = new RateLimitService()
|
||||
service.setInactiveCodexAccountsResolver(() => [
|
||||
{ id: 'account-weekly', managedHomePath: '/tmp/account-weekly/home' }
|
||||
])
|
||||
|
||||
const weeklyOnly: ProviderRateLimits = {
|
||||
provider: 'codex',
|
||||
session: null,
|
||||
weekly: { usedPercent: 76, windowMinutes: 10080, resetsAt: null, resetDescription: null },
|
||||
updatedAt: Date.now(),
|
||||
error: null,
|
||||
status: 'ok'
|
||||
}
|
||||
vi.mocked(fetchClaudeRateLimits).mockResolvedValueOnce(okProvider('claude', 10, Date.now()))
|
||||
vi.mocked(fetchCodexRateLimits)
|
||||
.mockResolvedValueOnce(weeklyOnly)
|
||||
.mockResolvedValueOnce(okProvider('codex', 40, Date.now()))
|
||||
|
||||
await service.refresh()
|
||||
await service.refreshForCodexAccountChange('account-weekly')
|
||||
|
||||
expect(service.getState().inactiveCodexAccounts).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
accountId: 'account-weekly',
|
||||
rateLimits: expect.objectContaining({
|
||||
session: null,
|
||||
weekly: expect.objectContaining({ usedPercent: 76 })
|
||||
})
|
||||
})
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it('does not cache an outgoing Codex account that has no usage windows', async () => {
|
||||
const service = new RateLimitService()
|
||||
service.setInactiveCodexAccountsResolver(() => [
|
||||
{ id: 'account-empty', managedHomePath: '/tmp/account-empty/home' }
|
||||
])
|
||||
|
||||
vi.mocked(fetchClaudeRateLimits).mockResolvedValueOnce(okProvider('claude', 10, Date.now()))
|
||||
vi.mocked(fetchCodexRateLimits)
|
||||
.mockResolvedValueOnce(errorProvider('codex', 'codex not signed in'))
|
||||
.mockResolvedValueOnce(okProvider('codex', 40, Date.now()))
|
||||
|
||||
await service.refresh()
|
||||
await service.refreshForCodexAccountChange('account-empty')
|
||||
|
||||
expect(service.getState().inactiveCodexAccounts).not.toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ accountId: 'account-empty' })])
|
||||
)
|
||||
})
|
||||
|
||||
it('does not cache host Claude usage under an outgoing WSL account', async () => {
|
||||
const service = new RateLimitService()
|
||||
service.setInactiveClaudeAccountsResolver(() => [
|
||||
|
||||
@@ -378,9 +378,11 @@ export class RateLimitService {
|
||||
target?: CodexAccountSelectionTarget
|
||||
): Promise<RateLimitState> {
|
||||
const nextTarget = normalizeCodexAccountSelectionTarget(target)
|
||||
// Why: weekly-only plans report no session window, so gating on session alone
|
||||
// dropped their snapshot and left the switcher's inline bars empty.
|
||||
if (
|
||||
outgoingAccountId &&
|
||||
this.state.codex?.session &&
|
||||
(this.state.codex?.session || this.state.codex?.weekly) &&
|
||||
this.isSameCodexTarget(this.codexFetchTarget, nextTarget)
|
||||
) {
|
||||
this.inactiveCodexCache.set(outgoingAccountId, this.state.codex)
|
||||
|
||||
Reference in New Issue
Block a user