From c6cfd12228b35ef6eb7626a48abf1925129cc281 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 12 May 2026 09:11:08 +0100 Subject: [PATCH] test: guard before tool call mock calls --- .../run.before-agent-reply-cron.test.ts | 4 ++-- ...dded-subscribe.handlers.tools.media.test.ts | 4 ++-- ...efore-tool-execution-start-preserve.test.ts | 4 ++-- .../pi-tool-definition-adapter.logging.test.ts | 4 ++-- .../pi-tools.before-tool-call.e2e.test.ts | 4 ++-- src/agents/pi-tools.before-tool-call.ts | 18 ++++++++++-------- 6 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/agents/pi-embedded-runner/run.before-agent-reply-cron.test.ts b/src/agents/pi-embedded-runner/run.before-agent-reply-cron.test.ts index e3bda1360ef..1a5aa3ea88f 100644 --- a/src/agents/pi-embedded-runner/run.before-agent-reply-cron.test.ts +++ b/src/agents/pi-embedded-runner/run.before-agent-reply-cron.test.ts @@ -38,7 +38,7 @@ describe("runEmbeddedPiAgent cron before_agent_reply seam", () => { expect(mockedGlobalHookRunner.runBeforeAgentReply).toHaveBeenCalledTimes(1); const [hookPayload, hookContext] = - mockedGlobalHookRunner.runBeforeAgentReply.mock.calls[0] ?? []; + mockedGlobalHookRunner.runBeforeAgentReply.mock.calls.at(0) ?? []; expect(hookPayload).toEqual({ cleanedBody: "__openclaw_memory_core_short_term_promotion_dream__", }); @@ -94,7 +94,7 @@ describe("runEmbeddedPiAgent cron before_agent_reply seam", () => { promptMode: "none", }); - const [attemptParams] = (mockedRunEmbeddedAttempt.mock.calls[0] ?? []) as [ + const [attemptParams] = (mockedRunEmbeddedAttempt.mock.calls.at(0) ?? []) as [ { modelRun?: boolean; promptMode?: string }?, ]; expect(attemptParams?.modelRun).toBe(true); diff --git a/src/agents/pi-embedded-subscribe.handlers.tools.media.test.ts b/src/agents/pi-embedded-subscribe.handlers.tools.media.test.ts index 1dd4341edfc..9df6fb1e7bd 100644 --- a/src/agents/pi-embedded-subscribe.handlers.tools.media.test.ts +++ b/src/agents/pi-embedded-subscribe.handlers.tools.media.test.ts @@ -410,7 +410,7 @@ describe("handleToolExecutionEnd media emission", () => { expect(ctx.emitToolOutput).toHaveBeenCalledTimes(1); const emitToolOutput = vi.mocked(ctx.emitToolOutput); - const [toolName, summary, output, options] = emitToolOutput.mock.calls[0] ?? []; + const [toolName, summary, output, options] = emitToolOutput.mock.calls.at(0) ?? []; expect(toolName).toBe("tts"); expect(summary).toBeUndefined(); expect(output).toBe("remote tool output"); @@ -486,7 +486,7 @@ describe("handleToolExecutionEnd media emission", () => { expect(ctx.emitToolOutput).toHaveBeenCalledTimes(1); const emitToolOutput = vi.mocked(ctx.emitToolOutput); - const [calledToolName, summary, output, options] = emitToolOutput.mock.calls[0] ?? []; + const [calledToolName, summary, output, options] = emitToolOutput.mock.calls.at(0) ?? []; expect(calledToolName).toBe(toolName); expect(summary).toBeUndefined(); expect(output).toBe(providerInventoryText); diff --git a/src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.calls-onblockreplyflush-before-tool-execution-start-preserve.test.ts b/src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.calls-onblockreplyflush-before-tool-execution-start-preserve.test.ts index cdfb7ae1301..e20e3adef2a 100644 --- a/src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.calls-onblockreplyflush-before-tool-execution-start-preserve.test.ts +++ b/src/agents/pi-embedded-subscribe.subscribe-embedded-pi-session.calls-onblockreplyflush-before-tool-execution-start-preserve.test.ts @@ -83,7 +83,7 @@ describe("subscribeEmbeddedPiSession", () => { await Promise.resolve(); expect(onBlockReply).toHaveBeenCalledTimes(1); - expect(onBlockReply.mock.calls[0]?.[0]?.text).toBe("Short chunk."); + expect(onBlockReply.mock.calls.at(0)?.[0]?.text).toBe("Short chunk."); expect(onBlockReplyFlush).toHaveBeenCalledTimes(1); }); @@ -157,7 +157,7 @@ describe("subscribeEmbeddedPiSession", () => { await Promise.resolve(); expect(onBlockReply).toHaveBeenCalledTimes(1); - expect(onBlockReply.mock.calls[0]?.[0]?.text).toBe("Final reply before lifecycle end."); + expect(onBlockReply.mock.calls.at(0)?.[0]?.text).toBe("Final reply before lifecycle end."); expect(onBlockReplyFlush).toHaveBeenCalledTimes(1); }); diff --git a/src/agents/pi-tool-definition-adapter.logging.test.ts b/src/agents/pi-tool-definition-adapter.logging.test.ts index 3750c4d56a5..4c02f234314 100644 --- a/src/agents/pi-tool-definition-adapter.logging.test.ts +++ b/src/agents/pi-tool-definition-adapter.logging.test.ts @@ -64,7 +64,7 @@ describe("pi tool definition adapter logging", () => { await def.execute("call-edit-1", { path: "notes.txt" }, undefined, undefined, extensionContext); - expect(vi.mocked(logError).mock.calls[0]?.[0]).toContain( + expect(vi.mocked(logError).mock.calls.at(0)?.[0]).toContain( '[tools] edit failed: Missing required parameter: edits (received: path). Supply correct parameters before retrying. raw_params={"path":"notes.txt"}', ); }); @@ -139,7 +139,7 @@ describe("pi tool definition adapter logging", () => { expect(details?.status).toBe("error"); expect(details?.tool).toBe("web_search"); expect(details?.error).toBe("This operation was aborted"); - expect(vi.mocked(logError).mock.calls[0]?.[0]).toContain( + expect(vi.mocked(logError).mock.calls.at(0)?.[0]).toContain( "[tools] web_search failed: This operation was aborted", ); }); diff --git a/src/agents/pi-tools.before-tool-call.e2e.test.ts b/src/agents/pi-tools.before-tool-call.e2e.test.ts index 6486a0487e0..68ef1b19ce4 100644 --- a/src/agents/pi-tools.before-tool-call.e2e.test.ts +++ b/src/agents/pi-tools.before-tool-call.e2e.test.ts @@ -1009,12 +1009,12 @@ describe("before_tool_call requireApproval handling", () => { expect(result.blocked).toBe(false); expect(mockCallGateway).toHaveBeenCalledTimes(2); - const requestCall = mockCallGateway.mock.calls[0]; + const requestCall = mockCallGateway.mock.calls.at(0); expect(requestCall?.[0]).toBe("plugin.approval.request"); requireRecord(requestCall?.[1], "approval request gateway client"); expect(requireRecord(requestCall?.[2], "approval request params").twoPhase).toBe(true); expect(requestCall?.[3]).toEqual({ expectFinal: false }); - const waitCall = mockCallGateway.mock.calls[1]; + const waitCall = mockCallGateway.mock.calls.at(1); expect(waitCall?.[0]).toBe("plugin.approval.waitDecision"); requireRecord(waitCall?.[1], "approval wait gateway client"); expect(waitCall?.[2]).toEqual({ id: "server-id-1" }); diff --git a/src/agents/pi-tools.before-tool-call.ts b/src/agents/pi-tools.before-tool-call.ts index d77f499d04e..399e603e7d8 100644 --- a/src/agents/pi-tools.before-tool-call.ts +++ b/src/agents/pi-tools.before-tool-call.ts @@ -490,14 +490,16 @@ export async function runBeforeToolCallHook(args: { } } - recordToolCall( - sessionState, - toolName, - params, - args.toolCallId, - args.ctx.loopDetection, - loopScope, - ); + if (args.ctx.loopDetection?.enabled !== false) { + recordToolCall( + sessionState, + toolName, + params, + args.toolCallId, + args.ctx.loopDetection, + loopScope, + ); + } } const hookRunner = getGlobalHookRunner();