#14977: fix(telegram): remove ack reaction after block-streamed replies
channel: telegram
size: S
Cluster:
Telegram Message Handling Fixes
Closes #7753
## Summary
When block streaming is enabled (the default), all reply content is delivered via `sendBlockReply` (kind `"block"`). The final `replyResult` is null and `queuedFinal` is `false`. The `hasFinalResponse` check at the end of `dispatchTelegramMessage` was:
```typescript
const hasFinalResponse = queuedFinal || sentFallback;
```
This evaluated to `false` after block-streamed delivery, causing an early return that skipped `removeAckReactionAfterReply`. The ack reaction (e.g., 👀) remained on the message permanently.
**Fix:** Include `deliveryState.delivered` in the check:
```typescript
const hasFinalResponse = queuedFinal || sentFallback || deliveryState.delivered;
```
`deliveryState.delivered` is already set to `true` whenever the `deliver` callback succeeds, including for block-streamed replies.
## Test plan
- [x] Added test: ack reaction removed after block-streamed delivery with no final reply
- [x] Added test: ack reaction not removed when nothing was delivered
- [x] Existing draft streaming test passes
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR fixes a Telegram ack-reaction cleanup bug when block streaming is used: replies can be fully delivered via `deliver()` callbacks (kind `"block"`) without ever queueing a final reply, which previously caused an early return that skipped `removeAckReactionAfterReply`. The dispatch logic now treats any successful delivery (`deliveryState.delivered`) as a “final response” for cleanup purposes.
It also adds two unit tests covering ack reaction removal after block-streamed delivery, and ensuring no removal occurs when nothing was delivered, while refactoring common test setup into helper builders.
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge with low functional risk; the core logic change is small and targeted.
- The production change is a narrow boolean condition update that aligns with how delivery is tracked (`deliveryState.delivered` is already set on any successful deliver callback). The added tests cover the reported regression path. Main remaining concern is test-type looseness (helpers return untyped context objects), which can reduce test signal over time but doesn’t affect runtime behavior.
- src/telegram/bot-message-dispatch.test.ts (tighten typing in test helpers for reliability)
<sub>Last reviewed commit: 49dbcd7</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#17316: fix: ack reaction not removed when block streaming is enabled (Tele...
by czmathew · 2026-02-15
88.4%
#17953: fix(telegram): prevent silent message loss and duplicate messages i...
by zuyan9 · 2026-02-16
85.4%
#19673: fix(telegram): avoid starting streaming replies with only 1-2 words
by emanuelst · 2026-02-18
82.6%
#19479: fix(telegram): skip redundant final edit in partial streaming mode
by v8hid · 2026-02-17
80.5%
#12936: fix(telegram): omit message_thread_id for private DM chats
by omair445 · 2026-02-09
80.2%
#18072: fix(Telegram): usage footer not sent to Telegram when blockStreamin...
by yinghaosang · 2026-02-16
80.1%
#23728: fix(telegram): clear done reaction when removeAckAfterReply is true
by kevinWangSheng · 2026-02-22
79.6%
#5764: fix(telegram): enable streaming in private chats without topics
by garnetlyx · 2026-01-31
78.7%
#20236: fix(telegram): make reaction handling soft-fail and message-id resi...
by PeterShanxin · 2026-02-18
78.4%
#18460: fix(telegram): send fallback when streamMode partial drops all mess...
by BinHPdev · 2026-02-16
78.4%