From 28f9f226f0d892c48a72d0312e7c1dd4ebe3f8db Mon Sep 17 00:00:00 2001 From: ClawdBot Date: Wed, 28 Jan 2026 22:18:06 +0000 Subject: [PATCH] fix: Auto-expire auth profile cooldowns when timestamp expires Fixes #3604 Auth profiles were getting stuck in cooldown even after the cooldownUntil timestamp had expired. This happened because the cooldown check only happened during profile selection, but expired cooldowns were never cleared from the store. Changes: - Added auto-expiry logic in profile ordering (both explicit and round-robin paths) - When now >= cooldownUntil, clear both cooldownUntil and disabledUntil - Ensures profiles become available immediately after cooldown expires Tested by manually setting expired cooldown and verifying it clears on next profile resolution attempt. --- src/agents/auth-profiles/order.ts | 31 +++++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) diff --git a/src/agents/auth-profiles/order.ts b/src/agents/auth-profiles/order.ts index 677c29069..c15c38823 100644 --- a/src/agents/auth-profiles/order.ts +++ b/src/agents/auth-profiles/order.ts @@ -98,14 +98,23 @@ export function resolveAuthProfileOrder(params: { const inCooldown: Array<{ profileId: string; cooldownUntil: number }> = []; for (const profileId of deduped) { - const cooldownUntil = resolveProfileUnusableUntil(store.usageStats?.[profileId] ?? {}) ?? 0; + const stats = store.usageStats?.[profileId]; + const cooldownUntil = resolveProfileUnusableUntil(stats ?? {}) ?? 0; + + // Auto-expire cooldowns that have passed + if (stats && cooldownUntil > 0 && now >= cooldownUntil) { + stats.cooldownUntil = undefined; + stats.disabledUntil = undefined; + } + + const updatedCooldownUntil = resolveProfileUnusableUntil(stats ?? {}) ?? 0; if ( - typeof cooldownUntil === "number" && - Number.isFinite(cooldownUntil) && - cooldownUntil > 0 && - now < cooldownUntil + typeof updatedCooldownUntil === "number" && + Number.isFinite(updatedCooldownUntil) && + updatedCooldownUntil > 0 && + now < updatedCooldownUntil ) { - inCooldown.push({ profileId, cooldownUntil }); + inCooldown.push({ profileId, cooldownUntil: updatedCooldownUntil }); } else { available.push(profileId); } @@ -144,6 +153,16 @@ function orderProfilesByMode(order: string[], store: AuthProfileStore): string[] const inCooldown: string[] = []; for (const profileId of order) { + const stats = store.usageStats?.[profileId]; + if (stats) { + const unusableUntil = resolveProfileUnusableUntil(stats); + // Auto-expire cooldowns that have passed + if (unusableUntil && unusableUntil > 0 && now >= unusableUntil) { + stats.cooldownUntil = undefined; + stats.disabledUntil = undefined; + } + } + if (isProfileInCooldown(store, profileId)) { inCooldown.push(profileId); } else {