fix: prevent HEARTBEAT_OK discard from swallowing steered user responses#30449
fix: prevent HEARTBEAT_OK discard from swallowing steered user responses#30449Jo2234 wants to merge 1 commit into
Conversation
When queue mode is set to 'steer', a user message that arrives during an active heartbeat run is injected into that run. The agent may respond with 'HEARTBEAT_OK' followed by a real answer to the user's question. Previously, stripHeartbeatToken() stripped the HEARTBEAT_OK token and then checked if the remaining text was <= maxAckChars (default 300). Since many user responses are under 300 characters, the entire response was treated as a brief heartbeat ack and suppressed — the user never received their answer. This commit adds a heuristic check: after stripping HEARTBEAT_OK, if the remaining text contains multi-sentence structure (sentence-ending punctuation followed by more content), it is recognized as a substantive response rather than a brief ack, and delivery proceeds normally. The heuristic preserves backward compatibility: - Pure HEARTBEAT_OK → still suppressed - HEARTBEAT_OK with emoji/short junk → still suppressed - HEARTBEAT_OK with single-fragment ack → still suppressed - HEARTBEAT_OK followed by multi-sentence response → NOW DELIVERED Added 3 test cases covering: - Multi-sentence steered response after HEARTBEAT_OK (preserved) - Single-fragment ack after HEARTBEAT_OK (still suppressed) - Question/answer pattern response (preserved) Fixes openclaw#30197
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9263b43c2f
ℹ️ 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".
| const hasMultipleSentences = /[.!?]\s+\S/.test(rest); | ||
| const hasSubstantiveContent = rest.length > 0 && hasMultipleSentences; |
There was a problem hiding this comment.
Exclude token-leading punctuation from substantive check
The new hasMultipleSentences heuristic treats punctuation left behind by start-token stripping as evidence of a multi-sentence answer, so heartbeat acks like HEARTBEAT_OK. Nothing to report are now delivered instead of suppressed. In stripTokenAtEdges(), stripping a leading token keeps the ./! that follows the token, and this line then matches /[.!?]\s+\S/, setting shouldSkip to false for short non-actionable heartbeat text. This will cause regular heartbeat chatter to leak to users whenever the model formats acknowledgements as HEARTBEAT_OK. plus a short sentence.
Useful? React with 👍 / 👎.
Greptile SummaryFixes bug where user messages sent during active heartbeat runs get silently swallowed in Changes:
Behavior:
Confidence Score: 4/5
Last reviewed commit: 9263b43 |
| // patterns, treat it as a real response and do NOT skip. | ||
| const hasMultipleSentences = /[.!?]\s+\S/.test(rest); | ||
| const hasSubstantiveContent = rest.length > 0 && hasMultipleSentences; |
There was a problem hiding this comment.
comment mentions "or starts with common response patterns" but only multi-sentence detection is implemented - single-sentence responses like "The answer is 42." would still be suppressed
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/auto-reply/heartbeat.ts
Line: 174-176
Comment:
comment mentions "or starts with common response patterns" but only multi-sentence detection is implemented - single-sentence responses like "The answer is 42." would still be suppressed
How can I resolve this? If you propose a fix, please make it concise.…user responses When 'steer' mode injects a user message into a heartbeat run, the agent produces a combined response like 'HEARTBEAT_OK Sure! Here is the answer.' The previous logic stripped HEARTBEAT_OK and then checked if the remaining text was ≤ maxAckChars (300). Since many user responses are under 300 chars, the entire response was treated as a brief heartbeat ack and suppressed. This fix adds a heuristic: after stripping HEARTBEAT_OK, if the remaining text contains multi-sentence structure (sentence-ending punctuation [.!?] followed by more content), it is recognized as a substantive response and NOT suppressed. Fixes openclaw#30449
|
This pull request has been automatically marked as stale due to inactivity. |
|
Closing due to inactivity. |
Summary
Fix a bug where user messages sent during an active heartbeat run get silently swallowed when
queue.modeis set tosteer.Problem
When
steermode injects a user message into a heartbeat run, the agent produces a combined response like:The current
stripHeartbeatToken()logic stripsHEARTBEAT_OKand then checks if the remaining text is ≤maxAckChars(default: 300). Since many user responses are under 300 characters, the entire response is treated as a brief heartbeat ack and suppressed — the user never receives their answer.Before (broken)
After (fixed)
Root Cause
In
stripHeartbeatToken()(src/auto-reply/heartbeat.ts), themaxAckCharscheck does not distinguish between:"Nothing to report"(single fragment, no sentence structure)"Sure! Here is the answer. Let me know if you need more."(multi-sentence, addresses user)Fix
Added a heuristic in the
maxAckCharscheck: after strippingHEARTBEAT_OK, if the remaining text contains multi-sentence structure (sentence-ending punctuation[.!?]followed by more content), it is recognized as a substantive response and NOT suppressed.Backward Compatibility
HEARTBEAT_OKHEARTBEAT_OK 🦞HEARTBEAT_OK Nothing to reportHEARTBEAT_OK Sure! Here is the answer.HEARTBEAT_OK The server is fine. Deploy at 3:42.Files Changed
src/auto-reply/heartbeat.tsstripHeartbeatToken()src/auto-reply/heartbeat.test.tsTest Cases Added
Fixes #30197