Compare commits

...

2 Commits

Author SHA1 Message Date
Peter Steinberger
c50b64e298 docs: add changelog entry for cron tool fix 2026-01-04 16:16:20 +00:00
Clawd
a471f2debe 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).
2026-01-04 16:15:28 +00:00
3 changed files with 51 additions and 8 deletions

View File

@ -2,6 +2,12 @@
**Why this looks different:** the project was renamed from **Clawdis → Clawdbot**. To make the transition clear, releases now use **date-based versions** (`YYYY.M.D`) and the changelog is **compressed** into milestone summaries. Full detail still lives in git history and the docs.
## Unreleased
### Fixes
- Cron tool passes `id` to the gateway for update/remove/run/runs (keeps `jobId` input). (#180) — thanks @adamgall
## 2026.1.4
### Highlights

View File

@ -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);
});
});

View File

@ -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": {