Skip to content

Comments

fix: don't filter cron payloads containing 'heartbeat'#2219

Merged
thewilloftheshadow merged 1 commit intoopenclaw:mainfrom
dwfinkelstein:main
Jan 26, 2026
Merged

fix: don't filter cron payloads containing 'heartbeat'#2219
thewilloftheshadow merged 1 commit intoopenclaw:mainfrom
dwfinkelstein:main

Conversation

@dwfinkelstein
Copy link

Problem

The compactSystemEvent filter in session-updates.ts was filtering out any system event containing the word "heartbeat". This was intended to suppress the standard heartbeat prompt from being echoed, but it inadvertently blocked cron job payloads that mentioned "heartbeat" in their text.

Impact: Cron jobs with payload text like "📧 EMAIL SCANNER HEARTBEAT" would silently fail - the cron would report "ok" but the message never reached the agent because it was filtered out.

Solution

Changed the filter to be more specific:

  • Filter the actual heartbeat prompt (starts with 'Read HEARTBEAT.md')
  • Filter heartbeat poll/wake noise messages
  • Allow cron payloads that happen to mention 'heartbeat'

Testing

Tested locally with a cron job that has "heartbeat" in its payload - it now properly delivers the message to the agent.


Found while debugging why hourly heartbeat cron jobs were reporting success but never posting messages.

Copilot AI review requested due to automatic review settings January 26, 2026 13:07
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Refines system-event compaction so events containing the word “heartbeat” are no longer broadly filtered (preventing cron payloads from being dropped), and adds Android support for specifying a manual gateway password used when connecting to manual endpoints.

Changes:

  • Narrow compactSystemEvent filtering to match the actual heartbeat prompt / noise strings instead of any occurrence of “heartbeat”.
  • Add an Android “Manual Gateway Password” preference (encrypted) and UI input for it.
  • Use the manual password (when set) for connections to manual gateway endpoints.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/auto-reply/reply/session-updates.ts Makes heartbeat filtering more specific to avoid dropping cron/system events that merely mention “heartbeat”.
apps/android/app/src/main/java/com/clawdbot/android/ui/SettingsSheet.kt Adds a password input field for manual gateway configuration.
apps/android/app/src/main/java/com/clawdbot/android/SecurePrefs.kt Persists a manual gateway password in encrypted prefs and exposes it as a StateFlow.
apps/android/app/src/main/java/com/clawdbot/android/NodeRuntime.kt Plumbs manual password into runtime and uses it when connecting to `manual
apps/android/app/src/main/java/com/clawdbot/android/MainViewModel.kt Exposes manual password state and setter to the Compose UI layer.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 571 to 576
// For manual endpoints, use the manual password if set; otherwise fall back to stored password.
val password = if (endpoint.stableId.startsWith("manual|")) {
manualPassword.value.takeIf { it.isNotEmpty() } ?: prefs.loadGatewayPassword()
} else {
prefs.loadGatewayPassword()
}
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

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

connect() now uses manualPassword for endpoints with stableId starting with "manual|", but refreshGatewayConnection() still always uses prefs.loadGatewayPassword(). If the app is connected to a manual endpoint that requires a different password, a refresh/reconnect path can switch back to the stored password and fail. Consider centralizing password selection (manual vs stored) and using it consistently in both connect() and refreshGatewayConnection().

Copilot uses AI. Check for mistakes.
Comment on lines 408 to 416
OutlinedTextField(
value = manualPassword,
onValueChange = viewModel::setManualPassword,
label = { Text("Password") },
modifier = Modifier.fillMaxWidth(),
enabled = manualEnabled,
visualTransformation = PasswordVisualTransformation(),
singleLine = true,
)
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

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

The PR title/description focuses on fixing heartbeat-related filtering in session-updates.ts, but this change set also adds a new manual gateway password preference + UI field and connection behavior on Android. If this Android work is intentional, please update the PR description to reflect it; otherwise consider splitting it into a separate PR to keep scope focused.

Copilot uses AI. Check for mistakes.
Comment on lines +24 to +28
// Filter out the actual heartbeat prompt, but not cron jobs that mention "heartbeat"
// The heartbeat prompt starts with "Read HEARTBEAT.md" - cron payloads won't match this
if (lower.startsWith("read heartbeat.md")) return null;
// Also filter heartbeat poll/wake noise
if (lower.includes("heartbeat poll") || lower.includes("heartbeat wake")) return null;
Copy link

Copilot AI Jan 26, 2026

Choose a reason for hiding this comment

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

Add/adjust unit tests for the updated system-event filtering behavior. There are existing tests for prependSystemEvents, but none asserting that (1) the heartbeat prompt line is filtered and (2) system events containing the word "heartbeat" in arbitrary payload text (e.g. cron payloads) are not filtered. Covering both cases will prevent regressions back to over-broad filtering.

Copilot uses AI. Check for mistakes.