fix(cron): suppress HEARTBEAT_OK summary from leaking into main session#32093
fix(cron): suppress HEARTBEAT_OK summary from leaking into main session#32093steipete merged 2 commits intoopenclaw:mainfrom
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 46d43cc1b8
ℹ️ 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".
| res.status === "error" && res.errorKind === "delivery-target" && deliveryPlan.requested; | ||
| if ( | ||
| summaryText && | ||
| isCronSystemEvent(summaryText) && |
There was a problem hiding this comment.
Narrow heartbeat suppression to token-only summaries
isCronSystemEvent(summaryText) is a broader classifier than the bug requires: it returns false for any text containing "heartbeat poll", "heartbeat wake", "exec finished", or starting with HEARTBEAT_OK plus punctuation (see isCronSystemEvent in src/infra/heartbeat-events-filter.ts). In this fallback path (deliveryPlan.requested && !res.delivered && res.deliveryAttempted !== true), that means legitimate isolated-job summaries can now be dropped instead of enqueued to the main session, e.g. a real summary like "Heartbeat wake checklist completed" when direct delivery is skipped. The gate here should only suppress heartbeat-ack-only outputs, not all strings matching the broader system-event filter.
Useful? React with 👍 / 👎.
Greptile SummaryThis PR fixes a bug where The fix adds a filter check using the existing Key changes:
The implementation is consistent with how Confidence Score: 5/5
Last reviewed commit: 46d43cc |
…on (openclaw#32013) When an isolated cron agent returns HEARTBEAT_OK (nothing to announce), the direct delivery is correctly skipped, but the fallback path in timer.ts still enqueues the summary as a system event to the main session. Filter out heartbeat-only summaries using isCronSystemEvent before enqueuing, so internal ack tokens never reach user conversations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
46d43cc to
9a74498
Compare
|
Landed via temp rebase onto main.
Thanks @scoootscooob! |
|
Correction: merge commit SHA
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9a74498567
ℹ️ About Codex in GitHub
Your team has set up Codex to 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 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| res.status === "error" && res.errorKind === "delivery-target" && deliveryPlan.requested; | ||
| if ( | ||
| summaryText && | ||
| isCronSystemEvent(summaryText) && |
There was a problem hiding this comment.
Use heartbeat-only classifier for fallback suppression
The new fallback gate uses isCronSystemEvent(summaryText), but isolated-delivery skipping uses isHeartbeatOnlyResponse(...) (src/cron/isolated-agent/helpers.ts:93), and these classifiers are not equivalent: heartbeat-only outputs like <b>HEARTBEAT_OK</b> are treated as heartbeat-only (delivery skipped) while isCronSystemEvent still returns true, so this branch will enqueue that ack text to the main session. In other words, the leak still occurs for formatted HEARTBEAT_OK variants; the fallback suppression should use the same heartbeat-token stripping logic as the delivery-skip path.
Useful? React with 👍 / 👎.
Closes #32013
Summary
HEARTBEAT_OK(nothing to announce), direct delivery is correctly skipped viaskipHeartbeatDeliverytimer.tsstill enqueues the summary as a system event to the main session becausedelivered=falseanddeliveryAttempted=falseisCronSystemEvent(summaryText)which filters out heartbeat ack tokens and exec-completion noiseisCronSystemEventutility fromheartbeat-events-filter.ts— no new abstractionsChanges
src/cron/service/timer.ts: importisCronSystemEvent, add filter check beforeenqueueSystemEventcallsrc/cron/service.heartbeat-ok-summary-suppressed.test.ts: 2 tests — HEARTBEAT_OK suppressed, real summaries still forwardedWhat did NOT change
Test plan
npx tsgotype check passes🤖 Generated with Claude Code