← Back to PRs

#11889: fix(chat): filter HEARTBEAT_OK messages in chat.history when showOk is false

by bendyclaw open 2026-02-08 13:51 View on GitHub →
app: web-ui gateway stale
## Summary Fixes #11630 - HEARTBEAT_OK messages appearing in webchat after page refresh. ## Problem The live broadcast path correctly suppresses heartbeat messages via `shouldSuppressHeartbeatBroadcast()`, but `chat.history` returned raw transcript messages with no heartbeat filtering applied. This caused HEARTBEAT_OK messages to appear in the control-ui chat tab after any page load/refresh, even though they were correctly suppressed in real-time. ## Solution Apply heartbeat visibility filtering in the `chat.history` handler: - Check webchat heartbeat visibility using `resolveHeartbeatVisibility({ cfg, channel: "webchat" })` - When `showOk` is false (the default), filter out assistant messages that are only HEARTBEAT_OK - This matches the behavior of `shouldSuppressHeartbeatBroadcast()` used for live broadcasts ## Changes - `src/gateway/server-methods/chat.ts`: Add `isHeartbeatOnlyMessage()` and `filterHeartbeatMessages()` helpers, apply filtering in `chat.history` handler - `src/gateway/server-methods/chat.heartbeat-filter.test.ts`: Unit tests for the filtering logic ## Testing - [x] Build passes (`pnpm build`) - [x] Lint passes (`pnpm check`) - [x] Unit tests pass (`pnpm exec vitest run src/gateway/server-methods/chat.heartbeat-filter.test.ts`) - [x] Manually verified against the reproduction steps in #11630 ## AI-Assisted - [x] Built with AI assistance (OpenClaw/Claude) - [x] Fully tested - [x] I understand what the code does --- *My first contribution to OpenClaw! 🦞* <!-- greptile_comment --> <h2>Greptile Overview</h2> <h3>Greptile Summary</h3> This PR updates `chat.history` to apply the same heartbeat visibility rules used by the live broadcast path, filtering `HEARTBEAT_OK` assistant messages out of returned transcript history when `resolveHeartbeatVisibility({ channel: "webchat" }).showOk` is false. It also adds a Vitest file to validate the intended filtering behavior. The change fits into the gateway chat stack by aligning history replay (`src/gateway/server-methods/chat.ts`) with the existing broadcast suppression logic in `src/gateway/server-chat.ts` (`shouldSuppressHeartbeatBroadcast`). <h3>Confidence Score: 3/5</h3> - This PR is close to mergeable but has a correctness risk in heartbeat-only detection that can drop real assistant content from history. - The overall approach (apply heartbeat visibility in chat.history) is sound and matches existing broadcast behavior, but the current `startsWith` logic will treat some non-heartbeat messages as heartbeat-only and filter them, which is user-visible data loss in history. Tests also currently re-implement the logic, so they wouldn’t catch divergence/regressions. - src/gateway/server-methods/chat.ts; src/gateway/server-methods/chat.heartbeat-filter.test.ts <!-- greptile_other_comments_section --> <sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub> <!-- /greptile_comment -->

Most Similar PRs