#20860: feat(reactions): add configurable immediate reaction dispatch system
channel: bluebubbles
channel: discord
channel: signal
channel: slack
channel: telegram
agents
size: XL
trusted-contributor
Cluster:
Reaction Event Handling Enhancements
## Summary
Adds configurable immediate reaction delivery with debouncing across all channel providers (Discord, Telegram, Slack, Signal, BlueBubbles).
- **Per-channel config**: `reactionDelivery` ("deferred"|"immediate"), `reactionBundleWindowMs` (default: 2000ms), `reactionIncludeMessage` (bool)
- **Debounced bundling**: Multiple reactions on the same message within the bundle window are grouped into a single dispatch
- **Resilient fallback**: All providers wrap immediate dispatch in try/catch, falling back to deferred `enqueueSystemEvent` on failure (matching Signal's existing pattern)
- **Multi-agent safe**: Uses `resolveAgentIdFromSessionKey()` for correct session store resolution
- **Global singleton**: Debouncer is a process-wide singleton with mismatch detection for bundleWindowMs
### Key files
- `src/infra/reaction-dispatch/` — debouncer, dispatch, global singleton, context builder, types (NEW)
- `src/discord/monitor/listeners.ts` — immediate dispatch path
- `src/telegram/bot.ts` — immediate dispatch path
- `src/slack/monitor/events/reactions.ts` — immediate dispatch path with message fetch
- `src/signal/monitor/event-handler.ts` — immediate dispatch path (reference implementation)
- `extensions/bluebubbles/src/monitor-processing.ts` — immediate dispatch path
- Config schema additions in `zod-schema.core.ts`, `types.base.ts`, `schema.help.ts`, `schema.labels.ts`
## Test plan
- [ ] Verify typecheck passes (`pnpm tsgo`)
- [ ] Verify build succeeds (`pnpm build`)
- [ ] Test deferred mode (default): reactions enqueued via `enqueueSystemEvent` as before
- [ ] Test immediate mode: set `reactionDelivery: "immediate"` on a channel, verify reactions are debounced and dispatched
- [ ] Test fallback: simulate dispatch failure, verify graceful fallback to deferred path
- [ ] Test bundling: rapid reactions on same message within window are grouped
- [ ] Test multi-channel: different channels can have different `reactionDelivery` settings
---
_Re-opened from #18976 (auto-closed during fork maintenance)._
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Adds configurable immediate reaction delivery with debouncing across Discord, Telegram, Slack, Signal, and BlueBubbles. Reactions can now trigger dedicated agent turns (immediate mode) or queue for next message (deferred mode, default).
**Key changes:**
- New `src/infra/reaction-dispatch/` module with debouncer, dispatch logic, and global singleton
- Per-channel config: `reactionDelivery`, `reactionBundleWindowMs` (default 2000ms), `reactionIncludeMessage`
- All providers wrap immediate dispatch in try/catch with fallback to deferred `enqueueSystemEvent`
- Uses `resolveAgentIdFromSessionKey()` for multi-agent session store resolution
- Drains pending reactions before user message turns (in `runPreparedReply`)
**Minor improvement opportunity:**
- Discord listener duplicates `emojiLabel`, `actorLabel`, `guildSlug`, and `channelLabel` calculation that already exists in the `resolveReactionBase()` helper (lines 407-418)
<h3>Confidence Score: 4/5</h3>
- Safe to merge with thorough implementation and proper error handling
- Solid implementation with consistent error handling patterns, fallback mechanisms, and multi-agent safety. Minor code duplication in Discord listener doesn't affect correctness. All providers follow same resilient pattern with try/catch wrapping immediate dispatch.
- No files require special attention — the minor duplication in `src/discord/monitor/listeners.ts` is a style improvement, not a functional issue
<sub>Last reviewed commit: 90c8b9b</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#16716: feat(feishu): add reaction event support (created/deleted)
by schumilin · 2026-02-15
81.3%
#19816: feat(slack): add typingReaction config for DM typing indicator fall...
by dalefrieswthat · 2026-02-18
80.6%
#7980: feat(telegram): multi-stage reaction system for message pipeline vi...
by macmimi23 · 2026-02-03
79.9%
#19917: feat(discord): allow disabling intermediate status reactions
by Gitjay11 · 2026-02-18
79.8%
#21346: [AI-assisted] Telegram: add reaction state machine with fallback an...
by Archie818 · 2026-02-19
79.3%
#12894: feat(whatsapp): add reaction notifications support
by ekson73 · 2026-02-09
78.0%
#20399: feat(whatsapp): surface inbound reaction events to agent session
by andrewchen · 2026-02-18
77.9%
#20236: fix(telegram): make reaction handling soft-fail and message-id resi...
by PeterShanxin · 2026-02-18
77.3%
#13641: feat(whatsapp): surface incoming reaction events to agent
by asklee-klawd · 2026-02-10
76.1%
#17316: fix: ack reaction not removed when block streaming is enabled (Tele...
by czmathew · 2026-02-15
76.1%