mirror of https://github.com/openclaw/openclaw.git
refactor(agent): extract tested compaction safety timeout
This commit is contained in:
parent
2baa4fe668
commit
8aad43681b
|
|
@ -0,0 +1,45 @@
|
|||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
compactWithSafetyTimeout,
|
||||
EMBEDDED_COMPACTION_TIMEOUT_MS,
|
||||
} from "./pi-embedded-runner/compaction-safety-timeout.js";
|
||||
|
||||
describe("compactWithSafetyTimeout", () => {
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
});
|
||||
|
||||
it("rejects with timeout when compaction never settles", async () => {
|
||||
vi.useFakeTimers();
|
||||
const compactPromise = compactWithSafetyTimeout(() => new Promise<never>(() => {}));
|
||||
const timeoutAssertion = expect(compactPromise).rejects.toThrow("Compaction timed out");
|
||||
|
||||
await vi.advanceTimersByTimeAsync(EMBEDDED_COMPACTION_TIMEOUT_MS);
|
||||
await timeoutAssertion;
|
||||
expect(vi.getTimerCount()).toBe(0);
|
||||
});
|
||||
|
||||
it("returns result and clears timer when compaction settles first", async () => {
|
||||
vi.useFakeTimers();
|
||||
const compactPromise = compactWithSafetyTimeout(
|
||||
() => new Promise<string>((resolve) => setTimeout(() => resolve("ok"), 10)),
|
||||
30,
|
||||
);
|
||||
|
||||
await vi.advanceTimersByTimeAsync(10);
|
||||
await expect(compactPromise).resolves.toBe("ok");
|
||||
expect(vi.getTimerCount()).toBe(0);
|
||||
});
|
||||
|
||||
it("preserves compaction errors and clears timer", async () => {
|
||||
vi.useFakeTimers();
|
||||
const error = new Error("provider exploded");
|
||||
|
||||
await expect(
|
||||
compactWithSafetyTimeout(async () => {
|
||||
throw error;
|
||||
}, 30),
|
||||
).rejects.toBe(error);
|
||||
expect(vi.getTimerCount()).toBe(0);
|
||||
});
|
||||
});
|
||||
|
|
@ -57,6 +57,7 @@ import {
|
|||
type SkillSnapshot,
|
||||
} from "../skills.js";
|
||||
import { resolveTranscriptPolicy } from "../transcript-policy.js";
|
||||
import { compactWithSafetyTimeout } from "./compaction-safety-timeout.js";
|
||||
import { buildEmbeddedExtensionPaths } from "./extensions.js";
|
||||
import {
|
||||
logToolSchemasForGoogle,
|
||||
|
|
@ -632,22 +633,9 @@ export async function compactEmbeddedPiSessionDirect(
|
|||
}
|
||||
|
||||
const compactStartedAt = Date.now();
|
||||
const COMPACT_TIMEOUT_MS = 300_000; // 5 minutes safety timeout
|
||||
let compactTimer: ReturnType<typeof setTimeout> | undefined;
|
||||
const result = await Promise.race([
|
||||
const result = await compactWithSafetyTimeout(() =>
|
||||
session.compact(params.customInstructions),
|
||||
new Promise<never>((_, reject) => {
|
||||
compactTimer = setTimeout(
|
||||
() => reject(new Error("Compaction timed out")),
|
||||
COMPACT_TIMEOUT_MS,
|
||||
);
|
||||
compactTimer.unref?.();
|
||||
}),
|
||||
]).finally(() => {
|
||||
if (compactTimer) {
|
||||
clearTimeout(compactTimer);
|
||||
}
|
||||
});
|
||||
);
|
||||
// Estimate tokens after compaction by summing token estimates for remaining messages
|
||||
let tokensAfter: number | undefined;
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
import { withTimeout } from "../../node-host/with-timeout.js";
|
||||
|
||||
export const EMBEDDED_COMPACTION_TIMEOUT_MS = 300_000;
|
||||
|
||||
export async function compactWithSafetyTimeout<T>(
|
||||
compact: () => Promise<T>,
|
||||
timeoutMs: number = EMBEDDED_COMPACTION_TIMEOUT_MS,
|
||||
): Promise<T> {
|
||||
return await withTimeout(() => compact(), timeoutMs, "Compaction");
|
||||
}
|
||||
|
|
@ -14,6 +14,7 @@ export async function withTimeout<T>(
|
|||
const abortCtrl = new AbortController();
|
||||
const timeoutError = new Error(`${label ?? "request"} timed out`);
|
||||
const timer = setTimeout(() => abortCtrl.abort(timeoutError), resolved);
|
||||
timer.unref?.();
|
||||
|
||||
let abortListener: (() => void) | undefined;
|
||||
const abortPromise: Promise<never> = abortCtrl.signal.aborted
|
||||
|
|
|
|||
Loading…
Reference in New Issue