From 694b029fa980c68b0e179597de404f54a556cae7 Mon Sep 17 00:00:00 2001 From: radling005 Date: Thu, 29 Jan 2026 17:57:24 -0600 Subject: [PATCH] fix: bypass empty-heartbeat-file check for cron jobs Cron jobs with wakeMode: 'now' were being skipped when HEARTBEAT.md was empty, even though they had pending system events to process. This adds cron jobs to the bypass list alongside exec events, since both have the same need: they've already enqueued system events and need the agent to wake up and process them. Fixes #4224 --- src/infra/heartbeat-runner.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/infra/heartbeat-runner.ts b/src/infra/heartbeat-runner.ts index 8e0c9a4ee..d4ddc75b0 100644 --- a/src/infra/heartbeat-runner.ts +++ b/src/infra/heartbeat-runner.ts @@ -459,13 +459,14 @@ export async function runHeartbeatOnce(opts: { // Skip heartbeat if HEARTBEAT.md exists but has no actionable content. // This saves API calls/costs when the file is effectively empty (only comments/headers). - // EXCEPTION: Don't skip for exec events - they have pending system events to process. + // EXCEPTION: Don't skip for exec events or cron jobs - they have pending system events to process. const isExecEventReason = opts.reason === "exec-event"; + const isCronReason = opts.reason?.startsWith("cron:"); const workspaceDir = resolveAgentWorkspaceDir(cfg, agentId); const heartbeatFilePath = path.join(workspaceDir, DEFAULT_HEARTBEAT_FILENAME); try { const heartbeatFileContent = await fs.readFile(heartbeatFilePath, "utf-8"); - if (isHeartbeatContentEffectivelyEmpty(heartbeatFileContent) && !isExecEventReason) { + if (isHeartbeatContentEffectivelyEmpty(heartbeatFileContent) && !isExecEventReason && !isCronReason) { emitHeartbeatEvent({ status: "skipped", reason: "empty-heartbeat-file",