diff --git a/src/agents/auth-profiles/order.ts b/src/agents/auth-profiles/order.ts index 571f61f7020..1f7e1439907 100644 --- a/src/agents/auth-profiles/order.ts +++ b/src/agents/auth-profiles/order.ts @@ -2,20 +2,11 @@ import type { OpenClawConfig } from "../../config/config.js"; import { findNormalizedProviderValue, normalizeProviderId } from "../model-selection.js"; import { dedupeProfileIds, listProfilesForProvider } from "./profiles.js"; import type { AuthProfileStore } from "./types.js"; -import { clearExpiredCooldowns, isProfileInCooldown } from "./usage.js"; - -function resolveProfileUnusableUntil(stats: { - cooldownUntil?: number; - disabledUntil?: number; -}): number | null { - const values = [stats.cooldownUntil, stats.disabledUntil] - .filter((value): value is number => typeof value === "number") - .filter((value) => Number.isFinite(value) && value > 0); - if (values.length === 0) { - return null; - } - return Math.max(...values); -} +import { + clearExpiredCooldowns, + isProfileInCooldown, + resolveProfileUnusableUntil, +} from "./usage.js"; export function resolveAuthProfileOrder(params: { cfg?: OpenClawConfig; diff --git a/src/agents/auth-profiles/usage.test.ts b/src/agents/auth-profiles/usage.test.ts index af45781813b..a4f3f5261ae 100644 --- a/src/agents/auth-profiles/usage.test.ts +++ b/src/agents/auth-profiles/usage.test.ts @@ -1,6 +1,10 @@ import { describe, expect, it } from "vitest"; import type { AuthProfileStore } from "./types.js"; -import { clearExpiredCooldowns, isProfileInCooldown } from "./usage.js"; +import { + clearExpiredCooldowns, + isProfileInCooldown, + resolveProfileUnusableUntil, +} from "./usage.js"; function makeStore(usageStats: AuthProfileStore["usageStats"]): AuthProfileStore { return { @@ -13,6 +17,18 @@ function makeStore(usageStats: AuthProfileStore["usageStats"]): AuthProfileStore }; } +describe("resolveProfileUnusableUntil", () => { + it("returns null when both values are missing or invalid", () => { + expect(resolveProfileUnusableUntil({})).toBeNull(); + expect(resolveProfileUnusableUntil({ cooldownUntil: 0, disabledUntil: Number.NaN })).toBeNull(); + }); + + it("returns the latest active timestamp", () => { + expect(resolveProfileUnusableUntil({ cooldownUntil: 100, disabledUntil: 200 })).toBe(200); + expect(resolveProfileUnusableUntil({ cooldownUntil: 300 })).toBe(300); + }); +}); + // --------------------------------------------------------------------------- // isProfileInCooldown // --------------------------------------------------------------------------- diff --git a/src/agents/auth-profiles/usage.ts b/src/agents/auth-profiles/usage.ts index 6c4ecf52e21..20c5b3b0e14 100644 --- a/src/agents/auth-profiles/usage.ts +++ b/src/agents/auth-profiles/usage.ts @@ -3,7 +3,9 @@ import { normalizeProviderId } from "../model-selection.js"; import { saveAuthProfileStore, updateAuthProfileStoreWithLock } from "./store.js"; import type { AuthProfileFailureReason, AuthProfileStore, ProfileUsageStats } from "./types.js"; -function resolveProfileUnusableUntil(stats: ProfileUsageStats): number | null { +export function resolveProfileUnusableUntil( + stats: Pick, +): number | null { const values = [stats.cooldownUntil, stats.disabledUntil] .filter((value): value is number => typeof value === "number") .filter((value) => Number.isFinite(value) && value > 0);