From d64e2a4d2f262dd5ebb9928491a9d933a942f151 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sun, 31 May 2026 13:53:16 +0100 Subject: [PATCH] fix(auth): keep timeout expiry per profile --- ...-profiles.getsoonestcooldownexpiry.test.ts | 20 +++++++++++++++++++ src/agents/auth-profiles/usage-state.ts | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/agents/auth-profiles.getsoonestcooldownexpiry.test.ts b/src/agents/auth-profiles.getsoonestcooldownexpiry.test.ts index 3ccb6261da4..552b0b2e8ea 100644 --- a/src/agents/auth-profiles.getsoonestcooldownexpiry.test.ts +++ b/src/agents/auth-profiles.getsoonestcooldownexpiry.test.ts @@ -95,6 +95,26 @@ describe("getSoonestCooldownExpiry", () => { ).toBe(now + 30_000); }); + it("uses the earliest matching timeout cooldown for the requested model", () => { + const now = 1_700_000_000_000; + const store = makeStore({ + "openai:p1": { + cooldownUntil: now + 10_000, + cooldownReason: "timeout", + cooldownModel: "gpt-5.4", + }, + "openai:p2": { + cooldownUntil: now + 30_000, + cooldownReason: "timeout", + cooldownModel: "gpt-5.4", + }, + }); + + expect( + getSoonestCooldownExpiry(store, ["openai:p1", "openai:p2"], { now, forModel: "gpt-5.4" }), + ).toBe(now + 10_000); + }); + it("still counts profile-wide disables for other models", () => { const now = 1_700_000_000_000; const store = makeStore({ diff --git a/src/agents/auth-profiles/usage-state.ts b/src/agents/auth-profiles/usage-state.ts index e0b3f6123a7..6b6122d8329 100644 --- a/src/agents/auth-profiles/usage-state.ts +++ b/src/agents/auth-profiles/usage-state.ts @@ -104,7 +104,7 @@ export function getSoonestCooldownExpiry( } const matchingModelScopedCooldown = options?.forModel && - isModelScopedCooldownReason(stats.cooldownReason) && + stats.cooldownReason === "rate_limit" && stats.cooldownModel === options.forModel && !isActiveUnusableWindow(stats.blockedUntil, ts) && !isActiveUnusableWindow(stats.disabledUntil, ts);