Description
The heartbeat prompt (e.g. "Read HEARTBEAT.md if it exists...") is injected by the Gateway as a user-role message into the main session. In the Control UI (webchat), this prompt is displayed as if the user sent it, causing confusion.
Steps to Reproduce
- Open Control UI at http://127.0.0.1:18789/
- Wait for a heartbeat cycle (~30 min) or trigger one via gateway restart
- Observe the chat: a long message starting with
"Read HEARTBEAT.md..." appears as a user message
Expected Behavior
Heartbeat prompts should be hidden from the chat UI, similar to how HEARTBEAT_OK assistant replies are already filtered.
Root Cause Analysis
- Gateway correctly hides
HEARTBEAT_OK assistant responses via shouldHideHeartbeatChatOutput / normalizeHeartbeatChatFinalText
- However, the user-side heartbeat prompt is injected as a regular user message without any
isHeartbeat flag exposed to the frontend
- The Control UI
chat.history response does not include heartbeat metadata, so the frontend cannot distinguish heartbeat prompts from real user messages
- Frontend filters assistant replies containing
NO_REPLY / HEARTBEAT_OK (via eT / $w functions) but has no corresponding filter for the injected prompt
Suggested Fix
Either:
- Gateway-side: Mark heartbeat user messages with
isHeartbeat: true in chat.history response, and filter them in the frontend
- Or: Strip heartbeat prompts from
chat.history entirely before sending to the Control UI
Environment
- OpenClaw version: 2026.3.13+
- Platform: Control UI (browser-based webchat)
- Gateway: running on localhost
Related
Description
The heartbeat prompt (e.g.
"Read HEARTBEAT.md if it exists...") is injected by the Gateway as a user-role message into the main session. In the Control UI (webchat), this prompt is displayed as if the user sent it, causing confusion.Steps to Reproduce
"Read HEARTBEAT.md..."appears as a user messageExpected Behavior
Heartbeat prompts should be hidden from the chat UI, similar to how
HEARTBEAT_OKassistant replies are already filtered.Root Cause Analysis
HEARTBEAT_OKassistant responses viashouldHideHeartbeatChatOutput/normalizeHeartbeatChatFinalTextisHeartbeatflag exposed to the frontendchat.historyresponse does not include heartbeat metadata, so the frontend cannot distinguish heartbeat prompts from real user messagesNO_REPLY/HEARTBEAT_OK(viaeT/$wfunctions) but has no corresponding filter for the injected promptSuggested Fix
Either:
isHeartbeat: trueinchat.historyresponse, and filter them in the frontendchat.historyentirely before sending to the Control UIEnvironment
Related