Skip to content

fix(cron): pass heartbeat target=last for main-session cron jobs (#28508)#28583

Merged
Takhoffman merged 2 commits intoopenclaw:mainfrom
widingmarcus-cyber:fix/cron-main-heartbeat-delivery-regression
Feb 28, 2026
Merged

fix(cron): pass heartbeat target=last for main-session cron jobs (#28508)#28583
Takhoffman merged 2 commits intoopenclaw:mainfrom
widingmarcus-cyber:fix/cron-main-heartbeat-delivery-regression

Conversation

@widingmarcus-cyber
Copy link
Contributor

Problem

Scheduled cron jobs with sessionTarget: "main" and wakeMode: "now" stopped delivering responses to messaging channels (Telegram, WhatsApp, etc.) after v2026.2.26.

Who is affected: All users with sessionTarget: "main" cron jobs that expect delivery to their messaging channel.

Root Cause

Commit e2362d35 ("fix(heartbeat): default target none and internalize relay prompts", Feb 25) intentionally changed the default heartbeat target from "last" to "none" to prevent unsolicited heartbeat messages. However, when cron jobs with sessionTarget: "main" fire with wakeMode: "now", they trigger runHeartbeatOnce() to execute the agent turn. Without an explicit heartbeat target override, the new "none" default causes the heartbeat runner to silently discard the response instead of delivering it to the last active channel.

Specific files:

  • src/infra/outbound/targets.ts:210resolveHeartbeatDeliveryTarget() defaults to "none" and returns early without any delivery target
  • src/cron/service/timer.ts:655runHeartbeatOnce() called without heartbeat config override

Fix

Three surgical changes:

  1. src/cron/service/timer.ts: Pass heartbeat: { target: "last" } to runHeartbeatOnce() when executing sessionTarget: "main" cron jobs with wakeMode: "now". This ensures cron-triggered heartbeats deliver to the last active channel.

  2. src/cron/service/state.ts: Extend CronServiceDeps.runHeartbeatOnce type to accept an optional heartbeat config parameter.

  3. src/gateway/server-cron.ts: Wire the heartbeat config override through the gateway cron service builder, merging it with the existing agent heartbeat config.

This preserves the intentional "none" default for regular periodic heartbeats while restoring delivery for cron-triggered ones.

Testing

New test file: src/cron/service.main-job-passes-heartbeat-target-last.test.ts

  • ✅ Verifies runHeartbeatOnce receives heartbeat.target = "last" for wakeMode: "now" main jobs
  • ✅ Verifies wakeMode: "next-heartbeat" jobs use requestHeartbeatNow (not runHeartbeatOnce)
  • ✅ All 271 existing cron tests pass
  • ✅ All 56 heartbeat runner tests pass
  • ✅ All 3 gateway server cron tests pass

@greptile-apps

Fixes #28508

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6680124eec

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +188 to +190
const baseHeartbeat = runtimeConfig.agents?.defaults?.heartbeat;
const heartbeatOverride = opts?.heartbeat
? { ...baseHeartbeat, ...opts.heartbeat }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Merge cron heartbeat override with resolved agent heartbeat

When opts.heartbeat is present, this path builds the override from runtimeConfig.agents?.defaults?.heartbeat only, so any per-agent heartbeat overrides are dropped for cron wakeMode: "now" runs. Because runHeartbeatOnce uses opts.heartbeat directly (and does not call its internal resolveHeartbeatConfig merge in that case), non-default agents can lose settings like every, prompt, model, accountId, or custom targeting during cron-triggered heartbeats. This regresses multi-agent configurations where cron jobs are scoped to an agent with heartbeat overrides.

Useful? React with 👍 / 👎.

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 27, 2026

Greptile Summary

Restores delivery for cron-triggered heartbeats after recent default change from "last" to "none". The fix surgically addresses the regression by passing heartbeat: { target: "last" } when executing sessionTarget: "main" cron jobs with wakeMode: "now", ensuring responses reach the last active messaging channel.

Key changes:

  • src/cron/service/timer.ts:663 - Passes explicit target: "last" override to runHeartbeatOnce()
  • src/gateway/server-cron.ts:185-210 - Merges cron-supplied override with agent-specific heartbeat config, preserving agent settings (accountId, to, etc.) while applying the cron's delivery target
  • src/cron/service/state.ts:59 - Extends type to accept optional heartbeat config parameter
  • New test file validates both wakeMode: "now" (uses runHeartbeatOnce) and wakeMode: "next-heartbeat" (uses requestHeartbeatNow) paths

The implementation correctly preserves the new "none" default for regular periodic heartbeats while restoring delivery for cron-triggered ones.

Confidence Score: 5/5

  • Safe to merge - surgical fix with comprehensive test coverage
  • Well-isolated change that addresses a specific regression. The fix is properly scoped to only affect cron-triggered heartbeats with sessionTarget: "main" and wakeMode: "now". Gateway merging logic correctly preserves agent-specific config while applying the override. New test file validates both execution paths. All existing tests pass (271 cron, 56 heartbeat, 3 gateway).
  • No files require special attention

Last reviewed commit: d45aa29

@widingmarcus-cyber widingmarcus-cyber force-pushed the fix/cron-main-heartbeat-delivery-regression branch from 6680124 to d45aa29 Compare February 27, 2026 13:17
@widingmarcus-cyber
Copy link
Contributor Author

@greptile-apps please re-review — fixed heartbeat config merge to resolve agent-specific config (agents.list[].heartbeat) before falling back to defaults, addressing the edge case noted in previous review.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d45aa29b5c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +189 to +193
const agentEntry =
Array.isArray(runtimeConfig.agents?.list) &&
runtimeConfig.agents.list.find(
(entry) =>
entry && typeof entry.id === "string" && normalizeAgentId(entry.id) === agentId,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Resolve default agent before heartbeat override merge

For wakeMode: "now" main jobs that omit agentId (the normal default-agent path), resolveCronWakeTarget can return agentId as undefined, so this lookup never matches an agents.list entry. When opts.heartbeat is set, heartbeatOverride is then built from agents.defaults.heartbeat only and passed into runHeartbeatOnce, which bypasses the runner’s own resolveHeartbeatConfig merge and drops default-agent agents.list[].heartbeat overrides such as model, prompt, accountId, or every. Fresh evidence is that executeJobCore still forwards optional job.agentId directly for these cron runs, so this undefined-agent case is reachable.

Useful? React with 👍 / 👎.

When a cron job with sessionTarget=main and wakeMode=now fires, it
triggers a heartbeat via runHeartbeatOnce. Since e2362d3 changed the
default heartbeat target from "last" to "none", these cron-triggered
heartbeats silently discard their responses instead of delivering them
to the last active channel (e.g. Telegram).

Fix: pass heartbeat: { target: "last" } from the cron timer to
runHeartbeatOnce for main-session jobs, and wire the override through
the gateway cron service builder. This restores delivery for
sessionTarget=main cron jobs without reverting the intentional default
change for regular heartbeats.

Regression introduced in: e2362d3 (2026-02-25)

Fixes openclaw#28508
@Takhoffman Takhoffman force-pushed the fix/cron-main-heartbeat-delivery-regression branch from d45aa29 to bbf4d10 Compare February 28, 2026 17:13
@Takhoffman Takhoffman merged commit 8ae1987 into openclaw:main Feb 28, 2026
8 checks passed
Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 74d8034c4c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +199 to +200
const heartbeatOverride = opts?.heartbeat
? { ...baseHeartbeat, ...opts.heartbeat }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Resolve default agent before merging heartbeat override

For sessionTarget: "main" + wakeMode: "now" jobs that omit agentId (the normal default-agent path), resolveCronWakeTarget leaves agentId undefined, so baseHeartbeat includes only agents.defaults.heartbeat and misses agents.list[defaultAgent].heartbeat; then this heartbeatOverride is passed to runHeartbeatOnce, which bypasses its internal resolveHeartbeatConfig merge and drops default-agent overrides like model, prompt, and accountId. Fresh evidence is that this commit now always sends heartbeat: { target: "last" } from executeJobCore, so the override path is exercised on every such cron run.

Useful? React with 👍 / 👎.

mrosmarin added a commit to mrosmarin/openclaw that referenced this pull request Feb 28, 2026
* main: (31 commits)
  fix(browser): resolve correct targetId in navigate response after renderer swap (openclaw#25326)
  fix: sed escaping and UID mismatch in Podman Quadlet setup (openclaw#26414)
  fix(cron): pass heartbeat target=last for main-session cron jobs (openclaw#28508) (openclaw#28583)
  fix(cron): disable messaging tool when delivery.mode is none (openclaw#21808) (openclaw#21896)
  fix: clear delivery routing state when creating isolated cron sessions (openclaw#27778)
  fix(cron): avoid marking queued announce paths as delivered (openclaw#29716)
  fix(cron): enable completion direct send for text-only announce delivery (openclaw#29151)
  fix(cron): force main-target system events onto main session (openclaw#28898)
  fix(cron): condition requireExplicitMessageTarget on resolved delivery (openclaw#28017)
  feat(cron): add --account flag for multi-account delivery routing (openclaw#26284)
  fix: schedule nextWakeAtMs for isolated sessionTarget cron jobs (openclaw#19541)
  fix: sandbox browser docker no-sandbox rollout (openclaw#29879) (thanks @Lukavyi)
  GitHub: add regression bug issue template and routing (openclaw#29864) thanks @Takhoffman
  feat(feishu): add chat info/member tool (openclaw#14674)
  feat(feishu): add markdown tables, positional insert, color_text, and table ops (openclaw#29411)
  feat(feishu): add parent/root inbound context for quote support (openclaw#18529)
  fix: land android onboarding and voice reliability updates (openclaw#29796)
  fix(android-voice): rotate playback token per assistant reply
  fix(android-voice): retry talk config after transient failures
  fix(android-voice): cancel in-flight speech when speaker muted
  ...
newtontech pushed a commit to newtontech/openclaw-fork that referenced this pull request Feb 28, 2026
…nclaw#28508) (openclaw#28583)

* fix(cron): pass heartbeat target=last for main-session cron jobs

When a cron job with sessionTarget=main and wakeMode=now fires, it
triggers a heartbeat via runHeartbeatOnce. Since e2362d3 changed the
default heartbeat target from "last" to "none", these cron-triggered
heartbeats silently discard their responses instead of delivering them
to the last active channel (e.g. Telegram).

Fix: pass heartbeat: { target: "last" } from the cron timer to
runHeartbeatOnce for main-session jobs, and wire the override through
the gateway cron service builder. This restores delivery for
sessionTarget=main cron jobs without reverting the intentional default
change for regular heartbeats.

Regression introduced in: e2362d3 (2026-02-25)

Fixes openclaw#28508

* Cron: align server-cron wake routing expectations for main-target jobs

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
nsd97 pushed a commit to nsd97/openclaw that referenced this pull request Feb 28, 2026
…nclaw#28508) (openclaw#28583)

* fix(cron): pass heartbeat target=last for main-session cron jobs

When a cron job with sessionTarget=main and wakeMode=now fires, it
triggers a heartbeat via runHeartbeatOnce. Since e2362d3 changed the
default heartbeat target from "last" to "none", these cron-triggered
heartbeats silently discard their responses instead of delivering them
to the last active channel (e.g. Telegram).

Fix: pass heartbeat: { target: "last" } from the cron timer to
runHeartbeatOnce for main-session jobs, and wire the override through
the gateway cron service builder. This restores delivery for
sessionTarget=main cron jobs without reverting the intentional default
change for regular heartbeats.

Regression introduced in: e2362d3 (2026-02-25)

Fixes openclaw#28508

* Cron: align server-cron wake routing expectations for main-target jobs

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
wanjizheng pushed a commit to wanjizheng/openclaw that referenced this pull request Mar 1, 2026
…nclaw#28508) (openclaw#28583)

* fix(cron): pass heartbeat target=last for main-session cron jobs

When a cron job with sessionTarget=main and wakeMode=now fires, it
triggers a heartbeat via runHeartbeatOnce. Since e2362d3 changed the
default heartbeat target from "last" to "none", these cron-triggered
heartbeats silently discard their responses instead of delivering them
to the last active channel (e.g. Telegram).

Fix: pass heartbeat: { target: "last" } from the cron timer to
runHeartbeatOnce for main-session jobs, and wire the override through
the gateway cron service builder. This restores delivery for
sessionTarget=main cron jobs without reverting the intentional default
change for regular heartbeats.

Regression introduced in: e2362d3 (2026-02-25)

Fixes openclaw#28508

* Cron: align server-cron wake routing expectations for main-target jobs

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
wanjizheng pushed a commit to wanjizheng/openclaw that referenced this pull request Mar 1, 2026
…nclaw#28508) (openclaw#28583)

* fix(cron): pass heartbeat target=last for main-session cron jobs

When a cron job with sessionTarget=main and wakeMode=now fires, it
triggers a heartbeat via runHeartbeatOnce. Since e2362d3 changed the
default heartbeat target from "last" to "none", these cron-triggered
heartbeats silently discard their responses instead of delivering them
to the last active channel (e.g. Telegram).

Fix: pass heartbeat: { target: "last" } from the cron timer to
runHeartbeatOnce for main-session jobs, and wire the override through
the gateway cron service builder. This restores delivery for
sessionTarget=main cron jobs without reverting the intentional default
change for regular heartbeats.

Regression introduced in: e2362d3 (2026-02-25)

Fixes openclaw#28508

* Cron: align server-cron wake routing expectations for main-target jobs

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
ansh pushed a commit to vibecode/openclaw that referenced this pull request Mar 2, 2026
…nclaw#28508) (openclaw#28583)

* fix(cron): pass heartbeat target=last for main-session cron jobs

When a cron job with sessionTarget=main and wakeMode=now fires, it
triggers a heartbeat via runHeartbeatOnce. Since e2362d3 changed the
default heartbeat target from "last" to "none", these cron-triggered
heartbeats silently discard their responses instead of delivering them
to the last active channel (e.g. Telegram).

Fix: pass heartbeat: { target: "last" } from the cron timer to
runHeartbeatOnce for main-session jobs, and wire the override through
the gateway cron service builder. This restores delivery for
sessionTarget=main cron jobs without reverting the intentional default
change for regular heartbeats.

Regression introduced in: e2362d3 (2026-02-25)

Fixes openclaw#28508

* Cron: align server-cron wake routing expectations for main-target jobs

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
steipete pushed a commit to Sid-Qin/openclaw that referenced this pull request Mar 2, 2026
…nclaw#28508) (openclaw#28583)

* fix(cron): pass heartbeat target=last for main-session cron jobs

When a cron job with sessionTarget=main and wakeMode=now fires, it
triggers a heartbeat via runHeartbeatOnce. Since e2362d3 changed the
default heartbeat target from "last" to "none", these cron-triggered
heartbeats silently discard their responses instead of delivering them
to the last active channel (e.g. Telegram).

Fix: pass heartbeat: { target: "last" } from the cron timer to
runHeartbeatOnce for main-session jobs, and wire the override through
the gateway cron service builder. This restores delivery for
sessionTarget=main cron jobs without reverting the intentional default
change for regular heartbeats.

Regression introduced in: e2362d3 (2026-02-25)

Fixes openclaw#28508

* Cron: align server-cron wake routing expectations for main-target jobs

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
safzanpirani pushed a commit to safzanpirani/clawdbot that referenced this pull request Mar 2, 2026
…nclaw#28508) (openclaw#28583)

* fix(cron): pass heartbeat target=last for main-session cron jobs

When a cron job with sessionTarget=main and wakeMode=now fires, it
triggers a heartbeat via runHeartbeatOnce. Since e2362d3 changed the
default heartbeat target from "last" to "none", these cron-triggered
heartbeats silently discard their responses instead of delivering them
to the last active channel (e.g. Telegram).

Fix: pass heartbeat: { target: "last" } from the cron timer to
runHeartbeatOnce for main-session jobs, and wire the override through
the gateway cron service builder. This restores delivery for
sessionTarget=main cron jobs without reverting the intentional default
change for regular heartbeats.

Regression introduced in: e2362d3 (2026-02-25)

Fixes openclaw#28508

* Cron: align server-cron wake routing expectations for main-target jobs

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
steipete pushed a commit to Sid-Qin/openclaw that referenced this pull request Mar 2, 2026
…nclaw#28508) (openclaw#28583)

* fix(cron): pass heartbeat target=last for main-session cron jobs

When a cron job with sessionTarget=main and wakeMode=now fires, it
triggers a heartbeat via runHeartbeatOnce. Since e2362d3 changed the
default heartbeat target from "last" to "none", these cron-triggered
heartbeats silently discard their responses instead of delivering them
to the last active channel (e.g. Telegram).

Fix: pass heartbeat: { target: "last" } from the cron timer to
runHeartbeatOnce for main-session jobs, and wire the override through
the gateway cron service builder. This restores delivery for
sessionTarget=main cron jobs without reverting the intentional default
change for regular heartbeats.

Regression introduced in: e2362d3 (2026-02-25)

Fixes openclaw#28508

* Cron: align server-cron wake routing expectations for main-target jobs

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
robertchang-ga pushed a commit to robertchang-ga/openclaw that referenced this pull request Mar 2, 2026
…nclaw#28508) (openclaw#28583)

* fix(cron): pass heartbeat target=last for main-session cron jobs

When a cron job with sessionTarget=main and wakeMode=now fires, it
triggers a heartbeat via runHeartbeatOnce. Since e2362d3 changed the
default heartbeat target from "last" to "none", these cron-triggered
heartbeats silently discard their responses instead of delivering them
to the last active channel (e.g. Telegram).

Fix: pass heartbeat: { target: "last" } from the cron timer to
runHeartbeatOnce for main-session jobs, and wire the override through
the gateway cron service builder. This restores delivery for
sessionTarget=main cron jobs without reverting the intentional default
change for regular heartbeats.

Regression introduced in: e2362d3 (2026-02-25)

Fixes openclaw#28508

* Cron: align server-cron wake routing expectations for main-target jobs

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
execute008 pushed a commit to execute008/openclaw that referenced this pull request Mar 2, 2026
…nclaw#28508) (openclaw#28583)

* fix(cron): pass heartbeat target=last for main-session cron jobs

When a cron job with sessionTarget=main and wakeMode=now fires, it
triggers a heartbeat via runHeartbeatOnce. Since e2362d3 changed the
default heartbeat target from "last" to "none", these cron-triggered
heartbeats silently discard their responses instead of delivering them
to the last active channel (e.g. Telegram).

Fix: pass heartbeat: { target: "last" } from the cron timer to
runHeartbeatOnce for main-session jobs, and wire the override through
the gateway cron service builder. This restores delivery for
sessionTarget=main cron jobs without reverting the intentional default
change for regular heartbeats.

Regression introduced in: e2362d3 (2026-02-25)

Fixes openclaw#28508

* Cron: align server-cron wake routing expectations for main-target jobs

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
dorgonman pushed a commit to kanohorizonia/openclaw that referenced this pull request Mar 3, 2026
…nclaw#28508) (openclaw#28583)

* fix(cron): pass heartbeat target=last for main-session cron jobs

When a cron job with sessionTarget=main and wakeMode=now fires, it
triggers a heartbeat via runHeartbeatOnce. Since e2362d3 changed the
default heartbeat target from "last" to "none", these cron-triggered
heartbeats silently discard their responses instead of delivering them
to the last active channel (e.g. Telegram).

Fix: pass heartbeat: { target: "last" } from the cron timer to
runHeartbeatOnce for main-session jobs, and wire the override through
the gateway cron service builder. This restores delivery for
sessionTarget=main cron jobs without reverting the intentional default
change for regular heartbeats.

Regression introduced in: e2362d3 (2026-02-25)

Fixes openclaw#28508

* Cron: align server-cron wake routing expectations for main-target jobs

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
sachinkundu pushed a commit to sachinkundu/openclaw that referenced this pull request Mar 6, 2026
…nclaw#28508) (openclaw#28583)

* fix(cron): pass heartbeat target=last for main-session cron jobs

When a cron job with sessionTarget=main and wakeMode=now fires, it
triggers a heartbeat via runHeartbeatOnce. Since e2362d3 changed the
default heartbeat target from "last" to "none", these cron-triggered
heartbeats silently discard their responses instead of delivering them
to the last active channel (e.g. Telegram).

Fix: pass heartbeat: { target: "last" } from the cron timer to
runHeartbeatOnce for main-session jobs, and wire the override through
the gateway cron service builder. This restores delivery for
sessionTarget=main cron jobs without reverting the intentional default
change for regular heartbeats.

Regression introduced in: e2362d3 (2026-02-25)

Fixes openclaw#28508

* Cron: align server-cron wake routing expectations for main-target jobs

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
zooqueen pushed a commit to hanzoai/bot that referenced this pull request Mar 6, 2026
…nclaw#28508) (openclaw#28583)

* fix(cron): pass heartbeat target=last for main-session cron jobs

When a cron job with sessionTarget=main and wakeMode=now fires, it
triggers a heartbeat via runHeartbeatOnce. Since e2362d3 changed the
default heartbeat target from "last" to "none", these cron-triggered
heartbeats silently discard their responses instead of delivering them
to the last active channel (e.g. Telegram).

Fix: pass heartbeat: { target: "last" } from the cron timer to
runHeartbeatOnce for main-session jobs, and wire the override through
the gateway cron service builder. This restores delivery for
sessionTarget=main cron jobs without reverting the intentional default
change for regular heartbeats.

Regression introduced in: e2362d3 (2026-02-25)

Fixes openclaw#28508

* Cron: align server-cron wake routing expectations for main-target jobs

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
Mateljan1 pushed a commit to Mateljan1/openclaw that referenced this pull request Mar 7, 2026
…nclaw#28508) (openclaw#28583)

* fix(cron): pass heartbeat target=last for main-session cron jobs

When a cron job with sessionTarget=main and wakeMode=now fires, it
triggers a heartbeat via runHeartbeatOnce. Since e2362d3 changed the
default heartbeat target from "last" to "none", these cron-triggered
heartbeats silently discard their responses instead of delivering them
to the last active channel (e.g. Telegram).

Fix: pass heartbeat: { target: "last" } from the cron timer to
runHeartbeatOnce for main-session jobs, and wire the override through
the gateway cron service builder. This restores delivery for
sessionTarget=main cron jobs without reverting the intentional default
change for regular heartbeats.

Regression introduced in: e2362d3 (2026-02-25)

Fixes openclaw#28508

* Cron: align server-cron wake routing expectations for main-target jobs

---------

Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gateway Gateway runtime size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Scheduled cron jobs not delivering messages to Telegram (regression)

2 participants