mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 19:28:28 +00:00
fix: align cron prompt content with filtered reminder events
This commit is contained in:
committed by
Vignesh
parent
7a8a57b573
commit
54513f4240
@@ -11,6 +11,8 @@ describe("isCronSystemEvent", () => {
|
||||
expect(isCronSystemEvent("HEARTBEAT_OK")).toBe(false);
|
||||
expect(isCronSystemEvent("HEARTBEAT_OK 🦞")).toBe(false);
|
||||
expect(isCronSystemEvent("heartbeat_ok")).toBe(false);
|
||||
expect(isCronSystemEvent("HEARTBEAT_OK:")).toBe(false);
|
||||
expect(isCronSystemEvent("HEARTBEAT_OK, continue")).toBe(false);
|
||||
});
|
||||
|
||||
it("returns false for heartbeat poll and wake noise", () => {
|
||||
|
||||
@@ -135,6 +135,9 @@ describe("Ghost reminder bug (issue #13317)", () => {
|
||||
const calledCtx = getReplySpy.mock.calls[0]?.[0];
|
||||
expect(calledCtx?.Provider).toBe("cron-event");
|
||||
expect(calledCtx?.Body).toContain("scheduled reminder has been triggered");
|
||||
expect(calledCtx?.Body).toContain("Reminder: Check Base Scout results");
|
||||
expect(calledCtx?.Body).not.toContain("HEARTBEAT_OK");
|
||||
expect(calledCtx?.Body).not.toContain("heartbeat poll");
|
||||
expect(sendTelegram).toHaveBeenCalled();
|
||||
} finally {
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
@@ -170,6 +173,9 @@ describe("Ghost reminder bug (issue #13317)", () => {
|
||||
const calledCtx = getReplySpy.mock.calls[0]?.[0];
|
||||
expect(calledCtx?.Provider).toBe("cron-event");
|
||||
expect(calledCtx?.Body).toContain("scheduled reminder has been triggered");
|
||||
expect(calledCtx?.Body).toContain("Reminder: Check Base Scout results");
|
||||
expect(calledCtx?.Body).not.toContain("HEARTBEAT_OK");
|
||||
expect(calledCtx?.Body).not.toContain("heartbeat poll");
|
||||
expect(sendTelegram).toHaveBeenCalled();
|
||||
} finally {
|
||||
await fs.rm(tmpDir, { recursive: true, force: true });
|
||||
|
||||
@@ -114,26 +114,47 @@ function buildCronEventPrompt(pendingEvents: string[]): string {
|
||||
);
|
||||
}
|
||||
|
||||
// Returns true when a system event should be treated as real cron reminder content.
|
||||
export function isCronSystemEvent(evt: string) {
|
||||
const HEARTBEAT_OK_PREFIX = HEARTBEAT_TOKEN.toLowerCase();
|
||||
|
||||
// Detect heartbeat-specific noise so cron reminders don't trigger on non-reminder events.
|
||||
function isHeartbeatAckEvent(evt: string): boolean {
|
||||
const trimmed = evt.trim();
|
||||
if (!trimmed) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const lower = trimmed.toLowerCase();
|
||||
const heartbeatOk = HEARTBEAT_TOKEN.toLowerCase();
|
||||
if (lower === heartbeatOk || lower.startsWith(`${heartbeatOk} `)) {
|
||||
if (!lower.startsWith(HEARTBEAT_OK_PREFIX)) {
|
||||
return false;
|
||||
}
|
||||
if (lower.includes("heartbeat poll") || lower.includes("heartbeat wake")) {
|
||||
return false;
|
||||
}
|
||||
if (lower.includes("exec finished")) {
|
||||
return false;
|
||||
const suffix = lower.slice(HEARTBEAT_OK_PREFIX.length);
|
||||
if (suffix.length === 0) {
|
||||
return true;
|
||||
}
|
||||
return !/[a-z0-9_]/.test(suffix[0]);
|
||||
}
|
||||
|
||||
return true;
|
||||
function isHeartbeatNoiseEvent(evt: string): boolean {
|
||||
const lower = evt.trim().toLowerCase();
|
||||
if (!lower) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
isHeartbeatAckEvent(lower) ||
|
||||
lower.includes("heartbeat poll") ||
|
||||
lower.includes("heartbeat wake")
|
||||
);
|
||||
}
|
||||
|
||||
function isExecCompletionEvent(evt: string): boolean {
|
||||
return evt.toLowerCase().includes("exec finished");
|
||||
}
|
||||
|
||||
// Returns true when a system event should be treated as real cron reminder content.
|
||||
export function isCronSystemEvent(evt: string) {
|
||||
if (!evt.trim()) {
|
||||
return false;
|
||||
}
|
||||
return !isHeartbeatNoiseEvent(evt) && !isExecCompletionEvent(evt);
|
||||
}
|
||||
|
||||
type HeartbeatAgentState = {
|
||||
@@ -521,12 +542,13 @@ export async function runHeartbeatOnce(opts: {
|
||||
const isExecEvent = opts.reason === "exec-event";
|
||||
const isCronEvent = Boolean(opts.reason?.startsWith("cron:"));
|
||||
const pendingEvents = isExecEvent || isCronEvent ? peekSystemEvents(sessionKey) : [];
|
||||
const hasExecCompletion = pendingEvents.some((evt) => evt.includes("Exec finished"));
|
||||
const hasCronEvents = isCronEvent && pendingEvents.some((evt) => isCronSystemEvent(evt));
|
||||
const cronEvents = pendingEvents.filter((evt) => isCronSystemEvent(evt));
|
||||
const hasExecCompletion = pendingEvents.some(isExecCompletionEvent);
|
||||
const hasCronEvents = isCronEvent && cronEvents.length > 0;
|
||||
const prompt = hasExecCompletion
|
||||
? EXEC_EVENT_PROMPT
|
||||
: hasCronEvents
|
||||
? buildCronEventPrompt(pendingEvents)
|
||||
? buildCronEventPrompt(cronEvents)
|
||||
: resolveHeartbeatPrompt(cfg, heartbeat);
|
||||
const ctx = {
|
||||
Body: appendCronStyleCurrentTimeLine(prompt, cfg, startedAt),
|
||||
|
||||
Reference in New Issue
Block a user