mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 18:24:57 +00:00
refactor(agent): dedupe harness and command workflows
This commit is contained in:
@@ -25,6 +25,36 @@ vi.mock("./pi-tools.before-tool-call.js", () => ({
|
||||
runBeforeToolCallHook: hookMocks.runBeforeToolCallHook,
|
||||
}));
|
||||
|
||||
function createReadTool() {
|
||||
return {
|
||||
name: "read",
|
||||
label: "Read",
|
||||
description: "reads",
|
||||
parameters: {},
|
||||
execute: vi.fn(async () => ({ content: [], details: { ok: true } })),
|
||||
} satisfies AgentTool<unknown, unknown>;
|
||||
}
|
||||
|
||||
function enableAfterToolCallHook() {
|
||||
hookMocks.runner.hasHooks.mockImplementation((name: string) => name === "after_tool_call");
|
||||
}
|
||||
|
||||
async function executeReadTool(callId: string) {
|
||||
const defs = toToolDefinitions([createReadTool()]);
|
||||
return await defs[0].execute(callId, { path: "/tmp/file" }, undefined, undefined);
|
||||
}
|
||||
|
||||
function expectReadAfterToolCallPayload(result: Awaited<ReturnType<typeof executeReadTool>>) {
|
||||
expect(hookMocks.runner.runAfterToolCall).toHaveBeenCalledWith(
|
||||
{
|
||||
toolName: "read",
|
||||
params: { mode: "safe" },
|
||||
result,
|
||||
},
|
||||
{ toolName: "read" },
|
||||
);
|
||||
}
|
||||
|
||||
describe("pi tool definition adapter after_tool_call", () => {
|
||||
beforeEach(() => {
|
||||
hookMocks.runner.hasHooks.mockReset();
|
||||
@@ -42,68 +72,31 @@ describe("pi tool definition adapter after_tool_call", () => {
|
||||
});
|
||||
|
||||
it("dispatches after_tool_call once on successful adapter execution", async () => {
|
||||
hookMocks.runner.hasHooks.mockImplementation((name: string) => name === "after_tool_call");
|
||||
enableAfterToolCallHook();
|
||||
hookMocks.runBeforeToolCallHook.mockResolvedValue({
|
||||
blocked: false,
|
||||
params: { mode: "safe" },
|
||||
});
|
||||
const tool = {
|
||||
name: "read",
|
||||
label: "Read",
|
||||
description: "reads",
|
||||
parameters: {},
|
||||
execute: vi.fn(async () => ({ content: [], details: { ok: true } })),
|
||||
} satisfies AgentTool<unknown, unknown>;
|
||||
|
||||
const defs = toToolDefinitions([tool]);
|
||||
const result = await defs[0].execute("call-ok", { path: "/tmp/file" }, undefined, undefined);
|
||||
const result = await executeReadTool("call-ok");
|
||||
|
||||
expect(result.details).toMatchObject({ ok: true });
|
||||
expect(hookMocks.runner.runAfterToolCall).toHaveBeenCalledTimes(1);
|
||||
expect(hookMocks.runner.runAfterToolCall).toHaveBeenCalledWith(
|
||||
{
|
||||
toolName: "read",
|
||||
params: { mode: "safe" },
|
||||
result,
|
||||
},
|
||||
{ toolName: "read" },
|
||||
);
|
||||
expectReadAfterToolCallPayload(result);
|
||||
});
|
||||
|
||||
it("uses wrapped-tool adjusted params for after_tool_call payload", async () => {
|
||||
hookMocks.runner.hasHooks.mockImplementation((name: string) => name === "after_tool_call");
|
||||
enableAfterToolCallHook();
|
||||
hookMocks.isToolWrappedWithBeforeToolCallHook.mockReturnValue(true);
|
||||
hookMocks.consumeAdjustedParamsForToolCall.mockReturnValue({ mode: "safe" });
|
||||
const tool = {
|
||||
name: "read",
|
||||
label: "Read",
|
||||
description: "reads",
|
||||
parameters: {},
|
||||
execute: vi.fn(async () => ({ content: [], details: { ok: true } })),
|
||||
} satisfies AgentTool<unknown, unknown>;
|
||||
|
||||
const defs = toToolDefinitions([tool]);
|
||||
const result = await defs[0].execute(
|
||||
"call-ok-wrapped",
|
||||
{ path: "/tmp/file" },
|
||||
undefined,
|
||||
undefined,
|
||||
);
|
||||
const result = await executeReadTool("call-ok-wrapped");
|
||||
|
||||
expect(result.details).toMatchObject({ ok: true });
|
||||
expect(hookMocks.runBeforeToolCallHook).not.toHaveBeenCalled();
|
||||
expect(hookMocks.runner.runAfterToolCall).toHaveBeenCalledWith(
|
||||
{
|
||||
toolName: "read",
|
||||
params: { mode: "safe" },
|
||||
result,
|
||||
},
|
||||
{ toolName: "read" },
|
||||
);
|
||||
expectReadAfterToolCallPayload(result);
|
||||
});
|
||||
|
||||
it("dispatches after_tool_call once on adapter error with normalized tool name", async () => {
|
||||
hookMocks.runner.hasHooks.mockImplementation((name: string) => name === "after_tool_call");
|
||||
enableAfterToolCallHook();
|
||||
const tool = {
|
||||
name: "bash",
|
||||
label: "Bash",
|
||||
@@ -134,18 +127,9 @@ describe("pi tool definition adapter after_tool_call", () => {
|
||||
});
|
||||
|
||||
it("does not break execution when after_tool_call hook throws", async () => {
|
||||
hookMocks.runner.hasHooks.mockImplementation((name: string) => name === "after_tool_call");
|
||||
enableAfterToolCallHook();
|
||||
hookMocks.runner.runAfterToolCall.mockRejectedValue(new Error("hook failed"));
|
||||
const tool = {
|
||||
name: "read",
|
||||
label: "Read",
|
||||
description: "reads",
|
||||
parameters: {},
|
||||
execute: vi.fn(async () => ({ content: [], details: { ok: true } })),
|
||||
} satisfies AgentTool<unknown, unknown>;
|
||||
|
||||
const defs = toToolDefinitions([tool]);
|
||||
const result = await defs[0].execute("call-ok2", { path: "/tmp/file" }, undefined, undefined);
|
||||
const result = await executeReadTool("call-ok2");
|
||||
|
||||
expect(result.details).toMatchObject({ ok: true });
|
||||
expect(hookMocks.runner.runAfterToolCall).toHaveBeenCalledTimes(1);
|
||||
|
||||
Reference in New Issue
Block a user