Files
openclaw/src/plugins/wired-hooks-compaction.test.ts
Marc Gratch 75969ed5c4 fix(plugins): pass session context to before_compaction hook in subscribe handler
The handleAutoCompactionStart handler was calling runBeforeCompaction with
only messageCount and an empty hook context. Plugins receiving this hook
could not identify the session or snapshot the transcript during
auto-compaction.

The other call site in compact.ts already passes the full payload
(messages, sessionFile, sessionKey). This aligns the subscribe handler
to do the same using ctx.params.session and ctx.params.sessionKey.

(cherry picked from commit 318a19d1a1a428ff1be2e03f51777c3829c6e322)
2026-02-24 04:33:50 +00:00

126 lines
4.0 KiB
TypeScript

/**
* Test: before_compaction & after_compaction hook wiring
*/
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
const hookMocks = vi.hoisted(() => ({
runner: {
hasHooks: vi.fn(() => false),
runBeforeCompaction: vi.fn(async () => {}),
runAfterCompaction: vi.fn(async () => {}),
},
}));
vi.mock("../plugins/hook-runner-global.js", () => ({
getGlobalHookRunner: () => hookMocks.runner,
}));
vi.mock("../infra/agent-events.js", () => ({
emitAgentEvent: vi.fn(),
}));
describe("compaction hook wiring", () => {
let handleAutoCompactionStart: typeof import("../agents/pi-embedded-subscribe.handlers.compaction.js").handleAutoCompactionStart;
let handleAutoCompactionEnd: typeof import("../agents/pi-embedded-subscribe.handlers.compaction.js").handleAutoCompactionEnd;
beforeAll(async () => {
({ handleAutoCompactionStart, handleAutoCompactionEnd } =
await import("../agents/pi-embedded-subscribe.handlers.compaction.js"));
});
beforeEach(() => {
hookMocks.runner.hasHooks.mockClear();
hookMocks.runner.hasHooks.mockReturnValue(false);
hookMocks.runner.runBeforeCompaction.mockClear();
hookMocks.runner.runBeforeCompaction.mockResolvedValue(undefined);
hookMocks.runner.runAfterCompaction.mockClear();
hookMocks.runner.runAfterCompaction.mockResolvedValue(undefined);
});
it("calls runBeforeCompaction in handleAutoCompactionStart", () => {
hookMocks.runner.hasHooks.mockReturnValue(true);
const ctx = {
params: {
runId: "r1",
sessionKey: "agent:main:web-abc123",
session: { messages: [1, 2, 3], sessionFile: "/tmp/test.jsonl" },
},
state: { compactionInFlight: false },
log: { debug: vi.fn(), warn: vi.fn() },
incrementCompactionCount: vi.fn(),
ensureCompactionPromise: vi.fn(),
};
handleAutoCompactionStart(ctx as never);
expect(hookMocks.runner.runBeforeCompaction).toHaveBeenCalledTimes(1);
const beforeCalls = hookMocks.runner.runBeforeCompaction.mock.calls as unknown as Array<
[unknown, unknown]
>;
const event = beforeCalls[0]?.[0] as
| { messageCount?: number; messages?: unknown[]; sessionFile?: string }
| undefined;
expect(event?.messageCount).toBe(3);
expect(event?.messages).toEqual([1, 2, 3]);
expect(event?.sessionFile).toBe("/tmp/test.jsonl");
const hookCtx = beforeCalls[0]?.[1] as { sessionKey?: string } | undefined;
expect(hookCtx?.sessionKey).toBe("agent:main:web-abc123");
});
it("calls runAfterCompaction when willRetry is false", () => {
hookMocks.runner.hasHooks.mockReturnValue(true);
const ctx = {
params: { runId: "r2", session: { messages: [1, 2] } },
state: { compactionInFlight: true },
log: { debug: vi.fn(), warn: vi.fn() },
maybeResolveCompactionWait: vi.fn(),
getCompactionCount: () => 1,
};
handleAutoCompactionEnd(
ctx as never,
{
type: "auto_compaction_end",
willRetry: false,
} as never,
);
expect(hookMocks.runner.runAfterCompaction).toHaveBeenCalledTimes(1);
const afterCalls = hookMocks.runner.runAfterCompaction.mock.calls as unknown as Array<
[unknown]
>;
const event = afterCalls[0]?.[0] as
| { messageCount?: number; compactedCount?: number }
| undefined;
expect(event?.messageCount).toBe(2);
expect(event?.compactedCount).toBe(1);
});
it("does not call runAfterCompaction when willRetry is true", () => {
hookMocks.runner.hasHooks.mockReturnValue(true);
const ctx = {
params: { runId: "r3", session: { messages: [] } },
state: { compactionInFlight: true },
log: { debug: vi.fn(), warn: vi.fn() },
noteCompactionRetry: vi.fn(),
resetForCompactionRetry: vi.fn(),
getCompactionCount: () => 0,
};
handleAutoCompactionEnd(
ctx as never,
{
type: "auto_compaction_end",
willRetry: true,
} as never,
);
expect(hookMocks.runner.runAfterCompaction).not.toHaveBeenCalled();
});
});