mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-03 20:04:05 +00:00
fix(commitments): bound terminal failure cooldown expiry
This commit is contained in:
@@ -293,6 +293,49 @@ describe("commitment extraction runtime", () => {
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("uses the queued item timestamp for terminal failure cooldowns", async () => {
|
||||
const cfg = await createConfig();
|
||||
const extractBatch = vi.fn(async () => {
|
||||
throw new Error("OAuth token refresh failed");
|
||||
});
|
||||
const dateNow = vi.spyOn(Date, "now").mockReturnValue(Number.NaN);
|
||||
configureCommitmentExtractionRuntime({
|
||||
forceInTests: true,
|
||||
extractBatch,
|
||||
setTimer: () => ({ unref() {} }) as ReturnType<typeof setTimeout>,
|
||||
clearTimer: () => undefined,
|
||||
});
|
||||
|
||||
expect(
|
||||
enqueueCommitmentExtraction({
|
||||
cfg,
|
||||
nowMs,
|
||||
agentId: "main",
|
||||
sessionKey: "agent:main:discord:channel-1",
|
||||
channel: "discord",
|
||||
userText: "I have an interview tomorrow.",
|
||||
assistantText: "Good luck.",
|
||||
}),
|
||||
).toBe(true);
|
||||
|
||||
try {
|
||||
await expect(drainCommitmentExtractionQueue()).rejects.toThrow("OAuth token refresh failed");
|
||||
expect(
|
||||
enqueueCommitmentExtraction({
|
||||
cfg,
|
||||
nowMs: nowMs + 1,
|
||||
agentId: "main",
|
||||
sessionKey: "agent:main:discord:channel-1",
|
||||
channel: "discord",
|
||||
userText: "The interview is tomorrow.",
|
||||
assistantText: "I hope it goes well.",
|
||||
}),
|
||||
).toBe(false);
|
||||
} finally {
|
||||
dateNow.mockRestore();
|
||||
}
|
||||
});
|
||||
|
||||
it("bounds hidden extraction queue growth before spending extractor tokens", async () => {
|
||||
const cfg = await createConfig();
|
||||
const extractBatch = vi.fn(
|
||||
|
||||
@@ -4,6 +4,7 @@ import { resolveAgentWorkspaceDir } from "../agents/agent-scope.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { resolveStateDir } from "../config/paths.js";
|
||||
import { createSubsystemLogger } from "../logging/subsystem.js";
|
||||
import { resolveExpiresAtMsFromDurationMs } from "../shared/number-coercion.js";
|
||||
import { normalizeOptionalString } from "../shared/string-coerce.js";
|
||||
import { resolveCommitmentTimezone, resolveCommitmentsConfig } from "./config.js";
|
||||
import {
|
||||
@@ -168,11 +169,20 @@ function isTerminalExtractionError(error: unknown): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
function openTerminalFailureCooldown(agentId: string, error: unknown): void {
|
||||
terminalFailureCooldownUntilByAgent.set(
|
||||
agentId,
|
||||
Date.now() + TERMINAL_EXTRACTION_FAILURE_COOLDOWN_MS,
|
||||
);
|
||||
function openTerminalFailureCooldown(
|
||||
agentId: string,
|
||||
error: unknown,
|
||||
nowMs: number,
|
||||
fallbackNowMs: number,
|
||||
): void {
|
||||
const cooldownUntil =
|
||||
resolveExpiresAtMsFromDurationMs(TERMINAL_EXTRACTION_FAILURE_COOLDOWN_MS, { nowMs }) ??
|
||||
resolveExpiresAtMsFromDurationMs(TERMINAL_EXTRACTION_FAILURE_COOLDOWN_MS, {
|
||||
nowMs: fallbackNowMs,
|
||||
});
|
||||
if (cooldownUntil !== undefined) {
|
||||
terminalFailureCooldownUntilByAgent.set(agentId, cooldownUntil);
|
||||
}
|
||||
queue = queue.filter((item) => item.agentId !== agentId);
|
||||
log.warn("commitment extraction disabled temporarily after terminal model/auth failure", {
|
||||
agentId,
|
||||
@@ -281,7 +291,12 @@ export async function drainCommitmentExtractionQueue(): Promise<number> {
|
||||
result = await extractor({ cfg: firstCfg, items });
|
||||
} catch (error) {
|
||||
if (isTerminalExtractionError(error)) {
|
||||
openTerminalFailureCooldown(items[0]?.agentId ?? "", error);
|
||||
openTerminalFailureCooldown(
|
||||
items[0]?.agentId ?? "",
|
||||
error,
|
||||
Date.now(),
|
||||
items[0]?.nowMs ?? Date.now(),
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user