refactor(agents): dedupe plugin hooks and test helpers

This commit is contained in:
Peter Steinberger
2026-02-22 07:38:24 +00:00
parent 75c1bfbae8
commit 185fba1d22
16 changed files with 661 additions and 579 deletions

View File

@@ -37,6 +37,15 @@ function makeEvent(overrides?: Partial<InternalHookEvent>): InternalHookEvent {
}
describe("boot-md handler", () => {
function setupTwoAgentBootConfig() {
const cfg = { agents: { list: [{ id: "main" }, { id: "ops" }] } };
listAgentIds.mockReturnValue(["main", "ops"]);
resolveAgentWorkspaceDir.mockImplementation((_cfg: unknown, id: string) =>
id === "main" ? MAIN_WORKSPACE_DIR : OPS_WORKSPACE_DIR,
);
return cfg;
}
beforeEach(() => {
vi.clearAllMocks();
logWarn.mockReset();
@@ -59,11 +68,7 @@ describe("boot-md handler", () => {
});
it("runs boot for each agent", async () => {
const cfg = { agents: { list: [{ id: "main" }, { id: "ops" }] } };
listAgentIds.mockReturnValue(["main", "ops"]);
resolveAgentWorkspaceDir.mockImplementation((_cfg: unknown, id: string) =>
id === "main" ? MAIN_WORKSPACE_DIR : OPS_WORKSPACE_DIR,
);
const cfg = setupTwoAgentBootConfig();
runBootOnce.mockResolvedValue({ status: "ran" });
await runBootChecklist(makeEvent({ context: { cfg } }));
@@ -93,11 +98,7 @@ describe("boot-md handler", () => {
});
it("logs warning details when a per-agent boot run fails", async () => {
const cfg = { agents: { list: [{ id: "main" }, { id: "ops" }] } };
listAgentIds.mockReturnValue(["main", "ops"]);
resolveAgentWorkspaceDir.mockImplementation((_cfg: unknown, id: string) =>
id === "main" ? MAIN_WORKSPACE_DIR : OPS_WORKSPACE_DIR,
);
const cfg = setupTwoAgentBootConfig();
runBootOnce
.mockResolvedValueOnce({ status: "ran" })
.mockResolvedValueOnce({ status: "failed", reason: "agent failed" });

View File

@@ -114,6 +114,25 @@ function makeSessionMemoryConfig(tempDir: string, messages?: number): OpenClawCo
} satisfies OpenClawConfig;
}
async function createSessionMemoryWorkspace(params?: {
activeSession?: { name: string; content: string };
}): Promise<{ tempDir: string; sessionsDir: string; activeSessionFile?: string }> {
const tempDir = await makeTempWorkspace("openclaw-session-memory-");
const sessionsDir = path.join(tempDir, "sessions");
await fs.mkdir(sessionsDir, { recursive: true });
if (!params?.activeSession) {
return { tempDir, sessionsDir };
}
const activeSessionFile = await writeWorkspaceFile({
dir: sessionsDir,
name: params.activeSession.name,
content: params.activeSession.content,
});
return { tempDir, sessionsDir, activeSessionFile };
}
describe("session-memory hook", () => {
it("skips non-command events", async () => {
const tempDir = await makeTempWorkspace("openclaw-session-memory-");
@@ -289,14 +308,8 @@ describe("session-memory hook", () => {
});
it("falls back to latest .jsonl.reset.* transcript when active file is empty", async () => {
const tempDir = await makeTempWorkspace("openclaw-session-memory-");
const sessionsDir = path.join(tempDir, "sessions");
await fs.mkdir(sessionsDir, { recursive: true });
const activeSessionFile = await writeWorkspaceFile({
dir: sessionsDir,
name: "test-session.jsonl",
content: "",
const { tempDir, sessionsDir, activeSessionFile } = await createSessionMemoryWorkspace({
activeSession: { name: "test-session.jsonl", content: "" },
});
// Simulate /new rotation where useful content is now in .reset.* file
@@ -314,7 +327,7 @@ describe("session-memory hook", () => {
tempDir,
previousSessionEntry: {
sessionId: "test-123",
sessionFile: activeSessionFile,
sessionFile: activeSessionFile!,
},
});
@@ -323,9 +336,7 @@ describe("session-memory hook", () => {
});
it("handles reset-path session pointers from previousSessionEntry", async () => {
const tempDir = await makeTempWorkspace("openclaw-session-memory-");
const sessionsDir = path.join(tempDir, "sessions");
await fs.mkdir(sessionsDir, { recursive: true });
const { tempDir, sessionsDir } = await createSessionMemoryWorkspace();
const sessionId = "reset-pointer-session";
const resetSessionFile = await writeWorkspaceFile({
@@ -352,9 +363,7 @@ describe("session-memory hook", () => {
});
it("recovers transcript when previousSessionEntry.sessionFile is missing", async () => {
const tempDir = await makeTempWorkspace("openclaw-session-memory-");
const sessionsDir = path.join(tempDir, "sessions");
await fs.mkdir(sessionsDir, { recursive: true });
const { tempDir, sessionsDir } = await createSessionMemoryWorkspace();
const sessionId = "missing-session-file";
await writeWorkspaceFile({
@@ -385,14 +394,8 @@ describe("session-memory hook", () => {
});
it("prefers the newest reset transcript when multiple reset candidates exist", async () => {
const tempDir = await makeTempWorkspace("openclaw-session-memory-");
const sessionsDir = path.join(tempDir, "sessions");
await fs.mkdir(sessionsDir, { recursive: true });
const activeSessionFile = await writeWorkspaceFile({
dir: sessionsDir,
name: "test-session.jsonl",
content: "",
const { tempDir, sessionsDir, activeSessionFile } = await createSessionMemoryWorkspace({
activeSession: { name: "test-session.jsonl", content: "" },
});
await writeWorkspaceFile({
@@ -416,7 +419,7 @@ describe("session-memory hook", () => {
tempDir,
previousSessionEntry: {
sessionId: "test-123",
sessionFile: activeSessionFile,
sessionFile: activeSessionFile!,
},
});
@@ -425,6 +428,39 @@ describe("session-memory hook", () => {
expect(memoryContent).not.toContain("Older rotated transcript");
});
it("prefers active transcript when it is non-empty even with reset candidates", async () => {
const { tempDir, sessionsDir, activeSessionFile } = await createSessionMemoryWorkspace({
activeSession: {
name: "test-session.jsonl",
content: createMockSessionContent([
{ role: "user", content: "Active transcript message" },
{ role: "assistant", content: "Active transcript summary" },
]),
},
});
await writeWorkspaceFile({
dir: sessionsDir,
name: "test-session.jsonl.reset.2026-02-16T22-26-34.000Z",
content: createMockSessionContent([
{ role: "user", content: "Reset fallback message" },
{ role: "assistant", content: "Reset fallback summary" },
]),
});
const { memoryContent } = await runNewWithPreviousSessionEntry({
tempDir,
previousSessionEntry: {
sessionId: "test-123",
sessionFile: activeSessionFile!,
},
});
expect(memoryContent).toContain("user: Active transcript message");
expect(memoryContent).toContain("assistant: Active transcript summary");
expect(memoryContent).not.toContain("Reset fallback message");
});
it("handles empty session files gracefully", async () => {
// Should not throw
const { files } = await runNewWithPreviousSession({ sessionContent: "" });