#20236: fix(telegram): make reaction handling soft-fail and message-id resilient
channel: telegram
agents
size: M
Cluster:
Reaction Event Handling Enhancements
## Summary
This PR hardens Telegram reaction handling to fail softly and improves message-id compatibility/fallback routing.
## Problem
Hard errors in reaction paths can trigger provider re-generation loops and duplicate content. Also, real-world payloads may use message_id and reaction targets may be omitted.
## Changes
- Accept snake_case message_id aliases in reaction input parsing.
- Return structured soft failures (ok:false) for reaction failure cases:
- disabled via reaction policy/gates
- missing token
- invalid emoji
- transport/API failures
- Fallback reaction target to current inbound message context when messageId is omitted.
- Thread currentMessageId through tool context/dispatch.
- Align Telegram reaction e2e expectations with soft-fail behavior.
## Risk
Medium-low. User-facing behavior change is intentional and scoped to Telegram reaction/dispatch flow.
## Validation
- Updated Telegram e2e tests and related parsing tests.
- Behavior goals:
- no hard throw/re-generation loop for reaction failures
- stable reaction targeting from inbound context fallback.
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
This PR converts Telegram reaction failures from hard throws to structured soft-fail responses (`{ok: false, reason: "..."}`) and threads `currentMessageId` through the tool context chain to enable fallback reaction targeting when `messageId` is omitted. It also adds snake_case alias support for tool input parameters (e.g., `message_id` → `messageId`).
- **Soft-fail for reactions**: All reaction error paths in `handleTelegramAction` now return `jsonResult({ok: false, ...})` instead of throwing. This prevents Gemini Flash from re-generating duplicate content when reactions fail. Reason codes include `disabled`, `missing_token`, `REACTION_INVALID`, and `error`.
- **`currentMessageId` propagation**: The inbound message ID (`MessageSidFull ?? MessageSid`) is now threaded through `ChannelThreadingToolContext` → `MessageToolOptions` → `RunEmbeddedPiAgentParams` → tool execution, enabling the Telegram react action to fall back to the current inbound message when no explicit `messageId` is provided.
- **snake_case param fallback**: `readParamRaw` in `common.ts` now checks for snake_case equivalents of camelCase keys (e.g., `chatId` → `chat_id`), which handles real-world payloads that may use snake_case naming.
- **Telegram threading fix**: The Telegram dock's `buildToolContext` no longer uses `ReplyToId` as a thread/topic ID fallback — `ReplyToId` is a message ID and was causing invalid `message_thread_id` in DMs.
- **Plugin-sdk compatibility**: `safeParseTelegramReplyToMessageId` in the Telegram extension guards against `parseTelegramReplyToMessageId` not being available from the plugin-sdk export.
- **Test updates**: e2e tests updated to expect soft-fail results instead of thrown errors; new tests for snake_case param aliases and `message_id` acceptance.
- **Unrelated**: Shell-env tests now skip correctly on Windows.
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge with low risk — changes are well-scoped to Telegram reaction handling with appropriate test coverage.
- The changes are well-structured and internally consistent. Soft-fail pattern is correctly applied across all reaction error paths. The currentMessageId threading touches many files but follows established patterns (similar to currentThreadTs). Tests are updated to match the new behavior. The only area of minor concern is the explicit message_id field in the reaction schema (redundant with the snake_case readParamRaw fallback), but this is not a correctness issue.
- `src/channels/dock.ts` deserves attention — the change to stop using `ReplyToId` as a threading fallback for Telegram is a behavioral change that could affect reply threading in certain Telegram configurations.
<sub>Last reviewed commit: 5995554</sub>
<!-- greptile_other_comments_section -->
<sub>(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#21346: [AI-assisted] Telegram: add reaction state machine with fallback an...
by Archie818 · 2026-02-19
84.0%
#12978: fix(telegram): use real message_id for inline button callback react...
by omair445 · 2026-02-10
82.1%
#19213: Telegram: preserve DM topic thread in direct replies
by Kemalau · 2026-02-17
81.8%
#16548: fix(telegram): enhance chat_id validation and diagnostics
by tanujbhaud · 2026-02-14
80.9%
#12936: fix(telegram): omit message_thread_id for private DM chats
by omair445 · 2026-02-09
80.9%
#7980: feat(telegram): multi-stage reaction system for message pipeline vi...
by macmimi23 · 2026-02-03
80.8%
#22331: Fix Telegram reaction emoji normalization
by AIflow-Labs · 2026-02-21
80.6%
#18893: fix(message): use currentMessageId for react fallback and suppress ...
by teededung · 2026-02-17
80.0%
#17316: fix: ack reaction not removed when block streaming is enabled (Tele...
by czmathew · 2026-02-15
79.6%
#18408: fix(message): support react current alias and suppress leaked react...
by sggolakiya · 2026-02-16
79.4%