From 17665d17328ff77ff0bf9f761aa8c5a2a558c3ad Mon Sep 17 00:00:00 2001 From: Clawd Date: Sun, 4 Jan 2026 14:57:26 +0000 Subject: [PATCH] fix(cron): pass 'id' instead of 'jobId' to gateway The cron tool was passing { jobId } to the gateway for update/remove/run/runs actions, but the gateway protocol schema expects { id }. This caused validation errors when trying to update or remove cron jobs via the tool. Fixes the parameter name while keeping the external tool API unchanged (still accepts 'jobId' from callers). --- src/agents/tools/cron-tool.test.ts | 37 ++++++++++++++++++++++++++++++ src/agents/tools/cron-tool.ts | 16 ++++++------- 2 files changed, 45 insertions(+), 8 deletions(-) create mode 100644 src/agents/tools/cron-tool.test.ts diff --git a/src/agents/tools/cron-tool.test.ts b/src/agents/tools/cron-tool.test.ts new file mode 100644 index 000000000..6a31a3e44 --- /dev/null +++ b/src/agents/tools/cron-tool.test.ts @@ -0,0 +1,37 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const callGatewayMock = vi.fn(); +vi.mock("../../gateway/call.js", () => ({ + callGateway: (opts: unknown) => callGatewayMock(opts), +})); + +import { createCronTool } from "./cron-tool.js"; + +describe("cron tool", () => { + beforeEach(() => { + callGatewayMock.mockReset(); + callGatewayMock.mockResolvedValue({ ok: true }); + }); + + it.each([ + [ + "update", + { action: "update", jobId: "job-1", patch: { foo: "bar" } }, + { id: "job-1", patch: { foo: "bar" } }, + ], + ["remove", { action: "remove", jobId: "job-1" }, { id: "job-1" }], + ["run", { action: "run", jobId: "job-1" }, { id: "job-1" }], + ["runs", { action: "runs", jobId: "job-1" }, { id: "job-1" }], + ])("%s sends id to gateway", async (action, args, expectedParams) => { + const tool = createCronTool(); + await tool.execute("call1", args); + + expect(callGatewayMock).toHaveBeenCalledTimes(1); + const call = callGatewayMock.mock.calls[0]?.[0] as { + method?: string; + params?: unknown; + }; + expect(call.method).toBe(`cron.${action}`); + expect(call.params).toEqual(expectedParams); + }); +}); diff --git a/src/agents/tools/cron-tool.ts b/src/agents/tools/cron-tool.ts index 0d4bcce43..f043de4cd 100644 --- a/src/agents/tools/cron-tool.ts +++ b/src/agents/tools/cron-tool.ts @@ -102,33 +102,33 @@ export function createCronTool(): AnyAgentTool { ); } case "update": { - const jobId = readStringParam(params, "jobId", { required: true }); + const id = readStringParam(params, "jobId", { required: true }); if (!params.patch || typeof params.patch !== "object") { throw new Error("patch required"); } return jsonResult( await callGatewayTool("cron.update", gatewayOpts, { - jobId, + id, patch: params.patch, }), ); } case "remove": { - const jobId = readStringParam(params, "jobId", { required: true }); + const id = readStringParam(params, "jobId", { required: true }); return jsonResult( - await callGatewayTool("cron.remove", gatewayOpts, { jobId }), + await callGatewayTool("cron.remove", gatewayOpts, { id }), ); } case "run": { - const jobId = readStringParam(params, "jobId", { required: true }); + const id = readStringParam(params, "jobId", { required: true }); return jsonResult( - await callGatewayTool("cron.run", gatewayOpts, { jobId }), + await callGatewayTool("cron.run", gatewayOpts, { id }), ); } case "runs": { - const jobId = readStringParam(params, "jobId", { required: true }); + const id = readStringParam(params, "jobId", { required: true }); return jsonResult( - await callGatewayTool("cron.runs", gatewayOpts, { jobId }), + await callGatewayTool("cron.runs", gatewayOpts, { id }), ); } case "wake": {