#17316: fix: ack reaction not removed when block streaming is enabled (Telegram & Discord)
channel: discord
channel: telegram
stale
size: XS
Cluster:
Telegram Message Handling Fixes
## Summary
- **Problem:** When block streaming is enabled, the ack reaction emoji (e.g. ๐) is never removed from the original message after the bot replies. This affects Telegram and Discord.
- **Why it matters:** Users configure `removeAckAfterReply: true` expecting the ack reaction to disappear after the bot responds. With block streaming on, it stays forever.
- **What changed:** Added delivery state checks to the early-return guards in Telegram and Discord handlers, matching the pattern already used in the Slack handler.
- **What did NOT change:** Slack handler (already correct), Signal handler (does not use ack reaction removal), core `removeAckReactionAfterReply` function.
## Change Type (select all)
- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Docs
- [ ] Security hardening
- [ ] Chore/infra
## Scope (select all touched areas)
- [ ] Gateway / orchestration
- [ ] Skills / tool execution
- [ ] Auth / tokens
- [ ] Memory / storage
- [x] Integrations
- [ ] API / contracts
- [ ] UI / DX
- [ ] CI/CD / infra
## Linked Issue/PR
- No existing issue
## User-visible / Behavior Changes
- Ack reaction emoji is now correctly removed after reply delivery when block streaming is enabled on Telegram and Discord.
## Security Impact (required)
- New permissions/capabilities? `No`
- Secrets/tokens handling changed? `No`
- New/changed network calls? `No`
- Command/tool execution surface changed? `No`
- Data access scope changed? `No`
## Repro + Verification
### Environment
- OS: Ubuntu 24.04 LTS (VM on Proxmox)
- Runtime/container: Node.js v22, OpenClaw 2026.2.14
- Model/provider: Anthropic Claude Opus 4.6
- Integration/channel: Telegram
- Relevant config:
```json
{
"messages": { "ackReaction": "๐", "ackReactionScope": "all", "removeAckAfterReply": true },
"agents": { "defaults": { "blockStreamingDefault": "on" } }
}
```
### Steps
1. Enable block streaming (`blockStreamingDefault: "on"`) and ack reaction with `removeAckAfterReply: true`
2. Send a message to the bot on Telegram
3. Bot adds ๐ reaction, then replies in streamed blocks
4. Observe: ๐ reaction stays on the message
### Expected
- ๐ reaction is removed after reply delivery completes
### Actual
- ๐ reaction remains on the message permanently
## Evidence
- [x] Verified manually on Telegram: with block streaming OFF, ๐ is removed โ
; with block streaming ON (before fix), ๐ stays โ; with block streaming ON (after fix), ๐ is removed โ
## Human Verification (required)
- Verified scenarios: Telegram DM with block streaming on/off, ack reaction added and removed correctly after patching compiled dist/ files
- Edge cases checked: Confirmed Slack handler already uses the correct pattern (`anyReplyDelivered` includes `counts.block`), Signal does not call `removeAckReactionAfterReply` so no change needed
- What you did **not** verify: Discord (no Discord bot configured), building from source (only tested patched dist/)
## Compatibility / Migration
- Backward compatible? `Yes`
- Config/env changes? `No`
- Migration needed? `No`
## Failure Recovery (if this breaks)
- How to disable/revert this change quickly: Revert the two one-line changes
- Files/config to restore: `src/telegram/bot-message-dispatch.ts`, `src/discord/monitor/message-handler.process.ts`
- Known bad symptoms: If the guard becomes too permissive, `removeAckReactionAfterReply` might fire when no reply was delivered (but this is safe โ the function checks `ackReactionPromise` resolution)
## Risks and Mitigations
- Risk: The broadened guard could run post-reply cleanup (history clearing, ack removal) even when only block replies were sent but no final reply โ though this matches the Slack behavior which has been working.
- Mitigation: The `removeAckReactionAfterReply` function already safely chains off the ack promise and only removes if the ack was actually sent.
## AI Disclosure ๐ค
This fix was identified and developed with AI assistance (Claude Code + OpenClaw agent). The root cause was traced by analyzing the compiled dist/ files and comparing Telegram/Discord handlers against the already-correct Slack handler. The fix was manually verified on a live Telegram bot.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Fixes a bug where the ack reaction emoji (e.g. ๐) was not removed after reply delivery when block streaming was enabled on Telegram and Discord. The root cause was that the early-return guards in both handlers only checked for final/queued replies but not for block streaming deliveries, causing the post-reply cleanup (including ack reaction removal) to be skipped.
- **Telegram** (`bot-message-dispatch.ts`): Added `deliveryState.delivered` to the `hasFinalResponse` check. This flag is already set to `true` in the `deliver` callback for all reply kinds (including block), making it the correct signal for the Telegram handler's architecture.
- **Discord** (`message-handler.process.ts`): Broadened the guard from `!queuedFinal` to `!(queuedFinal || (counts.block ?? 0) > 0 || (counts.final ?? 0) > 0)`, exactly matching the pattern already used in the Slack handler.
- Both fixes are minimal, targeted, and consistent with existing patterns in the codebase. The `removeAckReactionAfterReply` function itself is safe to call even when no ack was sent, as it checks the `ackReactionPromise` resolution before attempting removal.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge โ minimal, well-scoped bug fix that aligns Telegram and Discord handlers with the already-correct Slack pattern.
- Both changes are one-line fixes that broaden early-return guards to account for block streaming deliveries. The Discord fix exactly mirrors the existing Slack handler logic. The Telegram fix uses the handler's own delivery tracking flag which is already set correctly for all reply kinds. The underlying `removeAckReactionAfterReply` function has its own safety checks (verifying ack was actually sent before attempting removal). No new code paths, no behavioral changes beyond the intended fix.
- No files require special attention.
<sub>Last reviewed commit: d9668f0</sub>
<!-- 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
#14977: fix(telegram): remove ack reaction after block-streamed replies
by Diaspar4u ยท 2026-02-12
88.4%
#17953: fix(telegram): prevent silent message loss and duplicate messages i...
by zuyan9 ยท 2026-02-16
85.3%
#19673: fix(telegram): avoid starting streaming replies with only 1-2 words
by emanuelst ยท 2026-02-18
82.2%
#21346: [AI-assisted] Telegram: add reaction state machine with fallback an...
by Archie818 ยท 2026-02-19
80.7%
#23728: fix(telegram): clear done reaction when removeAckAfterReply is true
by kevinWangSheng ยท 2026-02-22
80.5%
#19213: Telegram: preserve DM topic thread in direct replies
by Kemalau ยท 2026-02-17
80.4%
#20623: fix(slack): duplicate replies and missing streaming recipient params
by rahulsub-be ยท 2026-02-19
80.1%
#19399: telegram: fix MEDIA false positives and partial final drop
by HOYALIM ยท 2026-02-17
79.6%
#20236: fix(telegram): make reaction handling soft-fail and message-id resi...
by PeterShanxin ยท 2026-02-18
79.6%
#19235: fix(telegram): tool error warnings no longer overwrite streamed rep...
by gatewaybuddy ยท 2026-02-17
79.5%