diff --git a/src/agents/bootstrap-files.e2e.test.ts b/src/agents/bootstrap-files.e2e.test.ts index 938d728d7..676030ad5 100644 --- a/src/agents/bootstrap-files.e2e.test.ts +++ b/src/agents/bootstrap-files.e2e.test.ts @@ -9,23 +9,27 @@ import { makeTempWorkspace } from "../test-helpers/workspace.js"; import { resolveBootstrapContextForRun, resolveBootstrapFilesForRun } from "./bootstrap-files.js"; import type { WorkspaceBootstrapFile } from "./workspace.js"; +function registerExtraBootstrapFileHook() { + registerInternalHook("agent:bootstrap", (event) => { + const context = event.context as AgentBootstrapHookContext; + context.bootstrapFiles = [ + ...context.bootstrapFiles, + { + name: "EXTRA.md", + path: path.join(context.workspaceDir, "EXTRA.md"), + content: "extra", + missing: false, + } as unknown as WorkspaceBootstrapFile, + ]; + }); +} + describe("resolveBootstrapFilesForRun", () => { beforeEach(() => clearInternalHooks()); afterEach(() => clearInternalHooks()); it("applies bootstrap hook overrides", async () => { - registerInternalHook("agent:bootstrap", (event) => { - const context = event.context as AgentBootstrapHookContext; - context.bootstrapFiles = [ - ...context.bootstrapFiles, - { - name: "EXTRA.md", - path: path.join(context.workspaceDir, "EXTRA.md"), - content: "extra", - missing: false, - } as unknown as WorkspaceBootstrapFile, - ]; - }); + registerExtraBootstrapFileHook(); const workspaceDir = await makeTempWorkspace("openclaw-bootstrap-"); const files = await resolveBootstrapFilesForRun({ workspaceDir }); @@ -39,18 +43,7 @@ describe("resolveBootstrapContextForRun", () => { afterEach(() => clearInternalHooks()); it("returns context files for hook-adjusted bootstrap files", async () => { - registerInternalHook("agent:bootstrap", (event) => { - const context = event.context as AgentBootstrapHookContext; - context.bootstrapFiles = [ - ...context.bootstrapFiles, - { - name: "EXTRA.md", - path: path.join(context.workspaceDir, "EXTRA.md"), - content: "extra", - missing: false, - } as unknown as WorkspaceBootstrapFile, - ]; - }); + registerExtraBootstrapFileHook(); const workspaceDir = await makeTempWorkspace("openclaw-bootstrap-"); const result = await resolveBootstrapContextForRun({ workspaceDir }); diff --git a/src/agents/pi-tool-definition-adapter.e2e.test.ts b/src/agents/pi-tool-definition-adapter.e2e.test.ts index cc15e71e1..1b11bbf49 100644 --- a/src/agents/pi-tool-definition-adapter.e2e.test.ts +++ b/src/agents/pi-tool-definition-adapter.e2e.test.ts @@ -6,25 +6,28 @@ import { toToolDefinitions } from "./pi-tool-definition-adapter.js"; type ToolExecute = ReturnType[number]["execute"]; const extensionContext = {} as Parameters[4]; +async function executeThrowingTool(name: string, callId: string) { + const tool = { + name, + label: name === "bash" ? "Bash" : "Boom", + description: "throws", + parameters: Type.Object({}), + execute: async () => { + throw new Error("nope"); + }, + } satisfies AgentTool; + + const defs = toToolDefinitions([tool]); + const def = defs[0]; + if (!def) { + throw new Error("missing tool definition"); + } + return await def.execute(callId, {}, undefined, undefined, extensionContext); +} + describe("pi tool definition adapter", () => { it("wraps tool errors into a tool result", async () => { - const tool = { - name: "boom", - label: "Boom", - description: "throws", - parameters: Type.Object({}), - execute: async () => { - throw new Error("nope"); - }, - } satisfies AgentTool; - - const defs = toToolDefinitions([tool]); - const def = defs[0]; - if (!def) { - throw new Error("missing tool definition"); - } - const execute = (...args: Parameters<(typeof defs)[0]["execute"]>) => def.execute(...args); - const result = await execute("call1", {}, undefined, undefined, extensionContext); + const result = await executeThrowingTool("boom", "call1"); expect(result.details).toMatchObject({ status: "error", @@ -35,23 +38,7 @@ describe("pi tool definition adapter", () => { }); it("normalizes exec tool aliases in error results", async () => { - const tool = { - name: "bash", - label: "Bash", - description: "throws", - parameters: Type.Object({}), - execute: async () => { - throw new Error("nope"); - }, - } satisfies AgentTool; - - const defs = toToolDefinitions([tool]); - const def = defs[0]; - if (!def) { - throw new Error("missing tool definition"); - } - const execute = (...args: Parameters<(typeof defs)[0]["execute"]>) => def.execute(...args); - const result = await execute("call2", {}, undefined, undefined, extensionContext); + const result = await executeThrowingTool("bash", "call2"); expect(result.details).toMatchObject({ status: "error", diff --git a/src/agents/tool-call-id.e2e.test.ts b/src/agents/tool-call-id.e2e.test.ts index 30ae90fe1..ce4e5dd61 100644 --- a/src/agents/tool-call-id.e2e.test.ts +++ b/src/agents/tool-call-id.e2e.test.ts @@ -129,22 +129,9 @@ describe("sanitizeToolCallIdsForCloudCodeAssist", () => { ] as unknown as AgentMessage[]; const out = sanitizeToolCallIdsForCloudCodeAssist(input); - const assistant = out[0] as Extract; - const a = assistant.content?.[0] as { id?: string }; - const b = assistant.content?.[1] as { id?: string }; - - expect(typeof a.id).toBe("string"); - expect(typeof b.id).toBe("string"); - expect(a.id).not.toBe(b.id); - expect(a.id?.length).toBeLessThanOrEqual(40); - expect(b.id?.length).toBeLessThanOrEqual(40); - expect(isValidCloudCodeAssistToolId(a.id as string, "strict")).toBe(true); - expect(isValidCloudCodeAssistToolId(b.id as string, "strict")).toBe(true); - - const r1 = out[1] as Extract; - const r2 = out[2] as Extract; - expect(r1.toolCallId).toBe(a.id); - expect(r2.toolCallId).toBe(b.id); + const { aId, bId } = expectCollisionIdsRemainDistinct(out, "strict"); + expect(aId.length).toBeLessThanOrEqual(40); + expect(bId.length).toBeLessThanOrEqual(40); }); }); @@ -221,23 +208,9 @@ describe("sanitizeToolCallIdsForCloudCodeAssist", () => { const out = sanitizeToolCallIdsForCloudCodeAssist(input, "strict9"); expect(out).not.toBe(input); - - const assistant = out[0] as Extract; - const a = assistant.content?.[0] as { id?: string }; - const b = assistant.content?.[1] as { id?: string }; - - expect(typeof a.id).toBe("string"); - expect(typeof b.id).toBe("string"); - expect(a.id).not.toBe(b.id); - expect(a.id?.length).toBe(9); - expect(b.id?.length).toBe(9); - expect(isValidCloudCodeAssistToolId(a.id as string, "strict9")).toBe(true); - expect(isValidCloudCodeAssistToolId(b.id as string, "strict9")).toBe(true); - - const r1 = out[1] as Extract; - const r2 = out[2] as Extract; - expect(r1.toolCallId).toBe(a.id); - expect(r2.toolCallId).toBe(b.id); + const { aId, bId } = expectCollisionIdsRemainDistinct(out, "strict9"); + expect(aId.length).toBe(9); + expect(bId.length).toBe(9); }); }); });