fix(auth): clear all usage stats fields in clearAuthProfileCooldown (openclaw#19211) thanks @nabbilkhan

Verified:
- pnpm install --frozen-lockfile
- pnpm build
- pnpm check
- pnpm test:macmini

Co-authored-by: nabbilkhan <203121263+nabbilkhan@users.noreply.github.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
Nabbil Khan
2026-02-19 22:21:37 -06:00
committed by GitHub
parent dece0fa146
commit f91034aa6b
3 changed files with 70 additions and 1 deletions

View File

@@ -1,11 +1,21 @@
import { describe, expect, it } from "vitest";
import { describe, expect, it, vi } from "vitest";
import type { AuthProfileStore } from "./types.js";
import {
clearAuthProfileCooldown,
clearExpiredCooldowns,
isProfileInCooldown,
resolveProfileUnusableUntil,
} from "./usage.js";
vi.mock("./store.js", async (importOriginal) => {
const original = await importOriginal<typeof import("./store.js")>();
return {
...original,
updateAuthProfileStoreWithLock: vi.fn().mockResolvedValue(null),
saveAuthProfileStore: vi.fn(),
};
});
function makeStore(usageStats: AuthProfileStore["usageStats"]): AuthProfileStore {
return {
version: 1,
@@ -283,3 +293,55 @@ describe("clearExpiredCooldowns", () => {
expect(clearExpiredCooldowns(store)).toBe(false);
});
});
// ---------------------------------------------------------------------------
// clearAuthProfileCooldown
// ---------------------------------------------------------------------------
describe("clearAuthProfileCooldown", () => {
it("clears all error state fields including disabledUntil and failureCounts", async () => {
const store = makeStore({
"anthropic:default": {
cooldownUntil: Date.now() + 60_000,
disabledUntil: Date.now() + 3_600_000,
disabledReason: "billing",
errorCount: 5,
failureCounts: { billing: 3, rate_limit: 2 },
},
});
await clearAuthProfileCooldown({ store, profileId: "anthropic:default" });
const stats = store.usageStats?.["anthropic:default"];
expect(stats?.cooldownUntil).toBeUndefined();
expect(stats?.disabledUntil).toBeUndefined();
expect(stats?.disabledReason).toBeUndefined();
expect(stats?.errorCount).toBe(0);
expect(stats?.failureCounts).toBeUndefined();
});
it("preserves lastUsed and lastFailureAt timestamps", async () => {
const lastUsed = Date.now() - 10_000;
const lastFailureAt = Date.now() - 5_000;
const store = makeStore({
"anthropic:default": {
cooldownUntil: Date.now() + 60_000,
errorCount: 3,
lastUsed,
lastFailureAt,
},
});
await clearAuthProfileCooldown({ store, profileId: "anthropic:default" });
const stats = store.usageStats?.["anthropic:default"];
expect(stats?.lastUsed).toBe(lastUsed);
expect(stats?.lastFailureAt).toBe(lastFailureAt);
});
it("no-ops for unknown profile id", async () => {
const store = makeStore(undefined);
await clearAuthProfileCooldown({ store, profileId: "nonexistent" });
expect(store.usageStats).toBeUndefined();
});
});

View File

@@ -400,6 +400,9 @@ export async function clearAuthProfileCooldown(params: {
...freshStore.usageStats[profileId],
errorCount: 0,
cooldownUntil: undefined,
disabledUntil: undefined,
disabledReason: undefined,
failureCounts: undefined,
};
return true;
},
@@ -416,6 +419,9 @@ export async function clearAuthProfileCooldown(params: {
...store.usageStats[profileId],
errorCount: 0,
cooldownUntil: undefined,
disabledUntil: undefined,
disabledReason: undefined,
failureCounts: undefined,
};
saveAuthProfileStore(store, agentDir);
}