From b20b16965c7663e2a9d861b1ebea84a7946cb9a3 Mon Sep 17 00:00:00 2001 From: Rai Butera Date: Sun, 8 Mar 2026 13:40:30 +0000 Subject: [PATCH] test(hooks): cover reset hook agent id edge cases Add regression coverage for the before_reset hook context when the session key is undefined and when it targets the main agent session. This documents the fallback contract around resolveAgentIdFromSessionKey and protects the reset hook path from future regressions. --- src/auto-reply/reply/commands-core.test.ts | 51 ++++++++++++++++------ 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/src/auto-reply/reply/commands-core.test.ts b/src/auto-reply/reply/commands-core.test.ts index 76aa4c9e827..226037f957a 100644 --- a/src/auto-reply/reply/commands-core.test.ts +++ b/src/auto-reply/reply/commands-core.test.ts @@ -18,18 +18,7 @@ vi.mock("../../plugins/hook-runner-global.js", () => ({ const { emitResetCommandHooks } = await import("./commands-core.js"); describe("emitResetCommandHooks", () => { - beforeEach(() => { - hookRunnerMocks.hasHooks.mockReset(); - hookRunnerMocks.runBeforeReset.mockReset(); - hookRunnerMocks.hasHooks.mockImplementation((hookName) => hookName === "before_reset"); - hookRunnerMocks.runBeforeReset.mockResolvedValue(undefined); - }); - - afterEach(() => { - vi.restoreAllMocks(); - }); - - it("passes the bound agent id to before_reset hooks for multi-agent session keys", async () => { + async function runBeforeResetContext(sessionKey?: string) { const command = { surface: "discord", senderId: "rai", @@ -44,7 +33,7 @@ describe("emitResetCommandHooks", () => { ctx: {} as HandleCommandsParams["ctx"], cfg: {} as HandleCommandsParams["cfg"], command, - sessionKey: "agent:navi:main", + sessionKey, previousSessionEntry: { sessionId: "prev-session", } as HandleCommandsParams["previousSessionEntry"], @@ -53,6 +42,22 @@ describe("emitResetCommandHooks", () => { await vi.waitFor(() => expect(hookRunnerMocks.runBeforeReset).toHaveBeenCalledTimes(1)); const [, ctx] = hookRunnerMocks.runBeforeReset.mock.calls[0] ?? []; + return ctx; + } + + beforeEach(() => { + hookRunnerMocks.hasHooks.mockReset(); + hookRunnerMocks.runBeforeReset.mockReset(); + hookRunnerMocks.hasHooks.mockImplementation((hookName) => hookName === "before_reset"); + hookRunnerMocks.runBeforeReset.mockResolvedValue(undefined); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("passes the bound agent id to before_reset hooks for multi-agent session keys", async () => { + const ctx = await runBeforeResetContext("agent:navi:main"); expect(ctx).toMatchObject({ agentId: "navi", sessionKey: "agent:navi:main", @@ -60,4 +65,24 @@ describe("emitResetCommandHooks", () => { workspaceDir: "/tmp/openclaw-workspace", }); }); + + it("falls back to main when the reset hook has no session key", async () => { + const ctx = await runBeforeResetContext(undefined); + expect(ctx).toMatchObject({ + agentId: "main", + sessionKey: undefined, + sessionId: "prev-session", + workspaceDir: "/tmp/openclaw-workspace", + }); + }); + + it("keeps the main-agent path on the main agent workspace", async () => { + const ctx = await runBeforeResetContext("agent:main:main"); + expect(ctx).toMatchObject({ + agentId: "main", + sessionKey: "agent:main:main", + sessionId: "prev-session", + workspaceDir: "/tmp/openclaw-workspace", + }); + }); });