Heartbeat: inject cron-style current time into prompts (#13733)

* Heartbeat: inject cron-style current time into prompts

* Tests: fix type for web heartbeat timestamp test

* Infra: inline heartbeat current-time injection
This commit is contained in:
Tak Hoffman
2026-02-10 18:58:45 -06:00
committed by GitHub
parent a853ded782
commit d2c2f4185b
6 changed files with 98 additions and 17 deletions

View File

@@ -0,0 +1,45 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { describe, expect, it, vi } from "vitest";
import type { OpenClawConfig } from "../../config/config.js";
import { runWebHeartbeatOnce } from "./heartbeat-runner.js";
describe("runWebHeartbeatOnce (timestamp)", () => {
it("injects a cron-style Current time line into the heartbeat prompt", async () => {
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-web-hb-"));
const storePath = path.join(tmpDir, "sessions.json");
try {
await fs.writeFile(storePath, JSON.stringify({}, null, 2));
const replyResolver = vi.fn().mockResolvedValue([{ text: "HEARTBEAT_OK" }]);
const cfg = {
agents: {
defaults: {
heartbeat: { prompt: "Ops check", every: "5m" },
userTimezone: "America/Chicago",
timeFormat: "24",
},
},
session: { store: storePath },
channels: { whatsapp: { allowFrom: ["*"] } },
} as unknown as OpenClawConfig;
await runWebHeartbeatOnce({
cfg,
to: "+1555",
dryRun: true,
replyResolver,
sender: vi.fn(),
});
expect(replyResolver).toHaveBeenCalledTimes(1);
const ctx = replyResolver.mock.calls[0]?.[0];
expect(ctx?.Body).toMatch(/Ops check/);
expect(ctx?.Body).toMatch(/Current time: /);
expect(ctx?.Body).toMatch(/\(.+\)/);
} finally {
await fs.rm(tmpDir, { recursive: true, force: true });
}
});
});

View File

@@ -1,4 +1,5 @@
import type { ReplyPayload } from "../../auto-reply/types.js";
import { appendCronStyleCurrentTimeLine } from "../../agents/current-time.js";
import {
DEFAULT_HEARTBEAT_ACK_MAX_CHARS,
resolveHeartbeatPrompt,
@@ -159,7 +160,11 @@ export async function runWebHeartbeatOnce(opts: {
const replyResult = await replyResolver(
{
Body: resolveHeartbeatPrompt(cfg.agents?.defaults?.heartbeat?.prompt),
Body: appendCronStyleCurrentTimeLine(
resolveHeartbeatPrompt(cfg.agents?.defaults?.heartbeat?.prompt),
cfg,
Date.now(),
),
From: to,
To: to,
MessageSid: sessionId ?? sessionSnapshot.entry?.sessionId,