mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 19:04:58 +00:00
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:
@@ -175,6 +175,7 @@ Docs: https://docs.openclaw.ai
|
|||||||
|
|
||||||
- Tests/Telegram: add regression coverage for command-menu sync that asserts all `setMyCommands` entries are Telegram-safe and hyphen-normalized across native/custom/plugin command sources. (#19703) Thanks @obviyus.
|
- Tests/Telegram: add regression coverage for command-menu sync that asserts all `setMyCommands` entries are Telegram-safe and hyphen-normalized across native/custom/plugin command sources. (#19703) Thanks @obviyus.
|
||||||
- Agents/Image: collapse resize diagnostics to one line per image and include visible pixel/byte size details in the log message for faster triage.
|
- Agents/Image: collapse resize diagnostics to one line per image and include visible pixel/byte size details in the log message for faster triage.
|
||||||
|
- Auth/Cooldowns: clear all usage stats fields (`disabledUntil`, `disabledReason`, `failureCounts`) in `clearAuthProfileCooldown` so manual cooldown resets fully recover billing-disabled profiles without requiring direct file edits. (#19211) Thanks @nabbilkhan.
|
||||||
- Agents/Subagents: preemptively guard accumulated tool-result context before model calls by truncating oversized outputs and compacting oldest tool-result messages to avoid context-window overflow crashes. Thanks @tyler6204.
|
- Agents/Subagents: preemptively guard accumulated tool-result context before model calls by truncating oversized outputs and compacting oldest tool-result messages to avoid context-window overflow crashes. Thanks @tyler6204.
|
||||||
- Agents/Subagents/CLI: fail `sessions_spawn` when subagent model patching is rejected, allow subagent model patch defaults from `subagents.model`, and keep `sessions list`/`status` model reporting aligned to runtime model resolution. (#18660) Thanks @robbyczgw-cla.
|
- Agents/Subagents/CLI: fail `sessions_spawn` when subagent model patching is rejected, allow subagent model patch defaults from `subagents.model`, and keep `sessions list`/`status` model reporting aligned to runtime model resolution. (#18660) Thanks @robbyczgw-cla.
|
||||||
- Agents/Subagents: add explicit subagent guidance to recover from `[compacted: tool output removed to free context]` / `[truncated: output exceeded context limit]` markers by re-reading with smaller chunks instead of full-file `cat`. Thanks @tyler6204.
|
- Agents/Subagents: add explicit subagent guidance to recover from `[compacted: tool output removed to free context]` / `[truncated: output exceeded context limit]` markers by re-reading with smaller chunks instead of full-file `cat`. Thanks @tyler6204.
|
||||||
|
|||||||
@@ -1,11 +1,21 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it, vi } from "vitest";
|
||||||
import type { AuthProfileStore } from "./types.js";
|
import type { AuthProfileStore } from "./types.js";
|
||||||
import {
|
import {
|
||||||
|
clearAuthProfileCooldown,
|
||||||
clearExpiredCooldowns,
|
clearExpiredCooldowns,
|
||||||
isProfileInCooldown,
|
isProfileInCooldown,
|
||||||
resolveProfileUnusableUntil,
|
resolveProfileUnusableUntil,
|
||||||
} from "./usage.js";
|
} 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 {
|
function makeStore(usageStats: AuthProfileStore["usageStats"]): AuthProfileStore {
|
||||||
return {
|
return {
|
||||||
version: 1,
|
version: 1,
|
||||||
@@ -283,3 +293,55 @@ describe("clearExpiredCooldowns", () => {
|
|||||||
expect(clearExpiredCooldowns(store)).toBe(false);
|
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();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -400,6 +400,9 @@ export async function clearAuthProfileCooldown(params: {
|
|||||||
...freshStore.usageStats[profileId],
|
...freshStore.usageStats[profileId],
|
||||||
errorCount: 0,
|
errorCount: 0,
|
||||||
cooldownUntil: undefined,
|
cooldownUntil: undefined,
|
||||||
|
disabledUntil: undefined,
|
||||||
|
disabledReason: undefined,
|
||||||
|
failureCounts: undefined,
|
||||||
};
|
};
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
@@ -416,6 +419,9 @@ export async function clearAuthProfileCooldown(params: {
|
|||||||
...store.usageStats[profileId],
|
...store.usageStats[profileId],
|
||||||
errorCount: 0,
|
errorCount: 0,
|
||||||
cooldownUntil: undefined,
|
cooldownUntil: undefined,
|
||||||
|
disabledUntil: undefined,
|
||||||
|
disabledReason: undefined,
|
||||||
|
failureCounts: undefined,
|
||||||
};
|
};
|
||||||
saveAuthProfileStore(store, agentDir);
|
saveAuthProfileStore(store, agentDir);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user