@@ -7,6 +7,7 @@
|
|||||||
- Memory: allow custom OpenAI-compatible embedding endpoints for memory search (remote baseUrl/apiKey/headers). (#819 — thanks @mukhtharcm)
|
- Memory: allow custom OpenAI-compatible embedding endpoints for memory search (remote baseUrl/apiKey/headers). (#819 — thanks @mukhtharcm)
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
|
- Cron: coerce enabled patches so disabling jobs persists correctly. (#205 — thanks @thewilloftheshadow)
|
||||||
- Control UI: keep chat scroll position unless user is near the bottom. (#217 — thanks @thewilloftheshadow)
|
- Control UI: keep chat scroll position unless user is near the bottom. (#217 — thanks @thewilloftheshadow)
|
||||||
- Fallback: treat credential validation failures ("no credentials found", "no API key found") as auth errors that trigger model fallback. (#822 — thanks @sebslight)
|
- Fallback: treat credential validation failures ("no credentials found", "no API key found") as auth errors that trigger model fallback. (#822 — thanks @sebslight)
|
||||||
- Telegram: preserve forum topic thread ids, including General topic replies. (#727 — thanks @thewilloftheshadow)
|
- Telegram: preserve forum topic thread ids, including General topic replies. (#727 — thanks @thewilloftheshadow)
|
||||||
|
|||||||
@@ -65,6 +65,17 @@ export function normalizeCronJobInput(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ("enabled" in base) {
|
||||||
|
const enabled = (base as UnknownRecord).enabled;
|
||||||
|
if (typeof enabled === "boolean") {
|
||||||
|
next.enabled = enabled;
|
||||||
|
} else if (typeof enabled === "string") {
|
||||||
|
const trimmed = enabled.trim().toLowerCase();
|
||||||
|
if (trimmed === "true") next.enabled = true;
|
||||||
|
if (trimmed === "false") next.enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (isRecord(base.schedule)) {
|
if (isRecord(base.schedule)) {
|
||||||
next.schedule = coerceSchedule(base.schedule);
|
next.schedule = coerceSchedule(base.schedule);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -221,6 +221,45 @@ describe("gateway server cron", () => {
|
|||||||
testState.cronStorePath = undefined;
|
testState.cronStorePath = undefined;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("disables cron jobs via enabled:false patches", async () => {
|
||||||
|
const dir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-gw-cron-"));
|
||||||
|
testState.cronStorePath = path.join(dir, "cron", "jobs.json");
|
||||||
|
await fs.mkdir(path.dirname(testState.cronStorePath), { recursive: true });
|
||||||
|
await fs.writeFile(
|
||||||
|
testState.cronStorePath,
|
||||||
|
JSON.stringify({ version: 1, jobs: [] }),
|
||||||
|
);
|
||||||
|
|
||||||
|
const { server, ws } = await startServerWithClient();
|
||||||
|
await connectOk(ws);
|
||||||
|
|
||||||
|
const addRes = await rpcReq(ws, "cron.add", {
|
||||||
|
name: "disable test",
|
||||||
|
enabled: true,
|
||||||
|
schedule: { kind: "every", everyMs: 60_000 },
|
||||||
|
sessionTarget: "main",
|
||||||
|
wakeMode: "next-heartbeat",
|
||||||
|
payload: { kind: "systemEvent", text: "hello" },
|
||||||
|
});
|
||||||
|
expect(addRes.ok).toBe(true);
|
||||||
|
const jobIdValue = (addRes.payload as { id?: unknown } | null)?.id;
|
||||||
|
const jobId = typeof jobIdValue === "string" ? jobIdValue : "";
|
||||||
|
expect(jobId.length > 0).toBe(true);
|
||||||
|
|
||||||
|
const updateRes = await rpcReq(ws, "cron.update", {
|
||||||
|
id: jobId,
|
||||||
|
patch: { enabled: false },
|
||||||
|
});
|
||||||
|
expect(updateRes.ok).toBe(true);
|
||||||
|
const updated = updateRes.payload as { enabled?: unknown } | undefined;
|
||||||
|
expect(updated?.enabled).toBe(false);
|
||||||
|
|
||||||
|
ws.close();
|
||||||
|
await server.close();
|
||||||
|
await fs.rm(dir, { recursive: true, force: true });
|
||||||
|
testState.cronStorePath = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
test("writes cron run history to runs/<jobId>.jsonl", async () => {
|
test("writes cron run history to runs/<jobId>.jsonl", async () => {
|
||||||
const dir = await fs.mkdtemp(
|
const dir = await fs.mkdtemp(
|
||||||
path.join(os.tmpdir(), "clawdbot-gw-cron-log-"),
|
path.join(os.tmpdir(), "clawdbot-gw-cron-log-"),
|
||||||
|
|||||||
Reference in New Issue
Block a user