fix: Make cron systemEvents trigger autonomous agent action
Fixes #4107 Problem: - Cron jobs with systemEvent payloads enqueue events as passive text - Agent sees events but doesn't autonomously process them - Expected behavior: agent should execute complex tasks (spawn subagents, etc.) Root Cause: - systemEvents are injected as 'System: [timestamp] text' messages - Standard heartbeat prompt is passive: 'Read HEARTBEAT.md... reply HEARTBEAT_OK' - No explicit instruction to process and act on systemEvents - Exec completion events already had directive prompt, but generic events didn't Solution: - Added SYSTEM_EVENT_PROMPT constant with directive language - Modified heartbeat runner to detect generic (non-exec) systemEvents - When generic events are present, use directive prompt instead of passive one - Directive prompt explicitly instructs agent to: 1. Check HEARTBEAT.md for event-specific handling 2. Execute required actions (spawn subagent, perform task, etc.) 3. Reply HEARTBEAT_OK only if no action needed Changes: - src/infra/heartbeat-runner.ts: - Added SYSTEM_EVENT_PROMPT constant (lines 100-105) - Modified prompt selection logic to detect generic systemEvents (lines 510-523) - Updated Provider field to reflect 'system-event' context Testing: - Build passes (TypeScript compilation successful) - Pattern follows existing exec-event precedent - Backward compatible (only affects sessions with pending systemEvents) Follow-up: - Add integration test for cron → subagent spawn workflow - Update documentation on systemEvent best practices
This commit is contained in:
parent
a39811caca
commit
cc2f8e3351
@ -97,6 +97,14 @@ const EXEC_EVENT_PROMPT =
|
||||
"Please relay the command output to the user in a helpful way. If the command succeeded, share the relevant output. " +
|
||||
"If it failed, explain what went wrong.";
|
||||
|
||||
// This prompt is used when generic system events (e.g., from cron jobs) are pending.
|
||||
// It explicitly instructs the agent to process the events rather than just acknowledging them.
|
||||
const SYSTEM_EVENT_PROMPT =
|
||||
"You have received one or more system events (shown in the system messages above). " +
|
||||
"Read HEARTBEAT.md if it exists for instructions on how to handle specific event types. " +
|
||||
"If an event requires action (e.g., spawning a subagent, performing a task), execute that action now. " +
|
||||
"If no action is needed, reply HEARTBEAT_OK.";
|
||||
|
||||
function resolveActiveHoursTimezone(cfg: OpenClawConfig, raw?: string): string {
|
||||
const trimmed = raw?.trim();
|
||||
if (!trimmed || trimmed === "user") {
|
||||
@ -499,15 +507,26 @@ export async function runHeartbeatOnce(opts: {
|
||||
// If so, use a specialized prompt that instructs the model to relay the result
|
||||
// instead of the standard heartbeat prompt with "reply HEARTBEAT_OK".
|
||||
const isExecEvent = opts.reason === "exec-event";
|
||||
const pendingEvents = isExecEvent ? peekSystemEvents(sessionKey) : [];
|
||||
const pendingEvents = peekSystemEvents(sessionKey);
|
||||
const hasExecCompletion = pendingEvents.some((evt) => evt.includes("Exec finished"));
|
||||
// Check for generic (non-exec) system events that may require action (e.g., from cron jobs).
|
||||
// Use a directive prompt to ensure the agent processes them rather than just acknowledging.
|
||||
const hasGenericSystemEvents = pendingEvents.length > 0 && !hasExecCompletion;
|
||||
|
||||
const prompt = hasExecCompletion ? EXEC_EVENT_PROMPT : resolveHeartbeatPrompt(cfg, heartbeat);
|
||||
const prompt = hasExecCompletion
|
||||
? EXEC_EVENT_PROMPT
|
||||
: hasGenericSystemEvents
|
||||
? SYSTEM_EVENT_PROMPT
|
||||
: resolveHeartbeatPrompt(cfg, heartbeat);
|
||||
const ctx = {
|
||||
Body: prompt,
|
||||
From: sender,
|
||||
To: sender,
|
||||
Provider: hasExecCompletion ? "exec-event" : "heartbeat",
|
||||
Provider: hasExecCompletion
|
||||
? "exec-event"
|
||||
: hasGenericSystemEvents
|
||||
? "system-event"
|
||||
: "heartbeat",
|
||||
SessionKey: sessionKey,
|
||||
};
|
||||
if (!visibility.showAlerts && !visibility.showOk && !visibility.useIndicator) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user