Cron: route reminders by session namespace

This commit is contained in:
Vignesh Natarajan
2026-02-16 14:29:21 -08:00
committed by Peter Steinberger
parent f452a7a60b
commit f988abf202
19 changed files with 530 additions and 32 deletions

View File

@@ -721,6 +721,81 @@ describe("runHeartbeatOnce", () => {
}
});
it("runs heartbeats in forced session key overrides passed at call time", async () => {
const tmpDir = await createCaseDir("hb-forced-session-override");
const storePath = path.join(tmpDir, "sessions.json");
const replySpy = vi.spyOn(replyModule, "getReplyFromConfig");
try {
const cfg: OpenClawConfig = {
agents: {
defaults: {
workspace: tmpDir,
heartbeat: {
every: "5m",
target: "last",
},
},
},
channels: { whatsapp: { allowFrom: ["*"] } },
session: { store: storePath },
};
const mainSessionKey = resolveMainSessionKey(cfg);
const agentId = resolveAgentIdFromSessionKey(mainSessionKey);
const forcedSessionKey = buildAgentPeerSessionKey({
agentId,
channel: "whatsapp",
peerKind: "dm",
peerId: "+15559990000",
});
await fs.writeFile(
storePath,
JSON.stringify({
[mainSessionKey]: {
sessionId: "sid-main",
updatedAt: Date.now(),
lastChannel: "whatsapp",
lastTo: "+1555",
},
[forcedSessionKey]: {
sessionId: "sid-forced",
updatedAt: Date.now() + 10_000,
lastChannel: "whatsapp",
lastTo: "+15559990000",
},
}),
);
replySpy.mockResolvedValue([{ text: "Forced alert" }]);
const sendWhatsApp = vi.fn().mockResolvedValue({
messageId: "m1",
toJid: "jid",
});
await runHeartbeatOnce({
cfg,
sessionKey: forcedSessionKey,
deps: {
sendWhatsApp,
getQueueSize: () => 0,
nowMs: () => 0,
webAuthExists: async () => true,
hasActiveWebListener: () => true,
},
});
expect(sendWhatsApp).toHaveBeenCalledTimes(1);
expect(sendWhatsApp).toHaveBeenCalledWith("+15559990000", "Forced alert", expect.any(Object));
expect(replySpy).toHaveBeenCalledWith(
expect.objectContaining({ SessionKey: forcedSessionKey }),
expect.objectContaining({ isHeartbeat: true }),
cfg,
);
} finally {
replySpy.mockRestore();
}
});
it("suppresses duplicate heartbeat payloads within 24h", async () => {
const tmpDir = await createCaseDir("hb-dup-suppress");
const storePath = path.join(tmpDir, "sessions.json");