#16716: feat(feishu): add reaction event support (created/deleted)
channel: feishu
size: M
Cluster:
Reaction Event Handling Enhancements
## Why this matters
In Feishu (and Lark), **emoji reactions are a core part of how people communicate** — they're used constantly to acknowledge messages, express agreement, or give quick feedback without interrupting the conversation flow. This is especially true in Feishu&Lark workplace culture where a 👍 or a +1 (meaning "I agree") carries real conversational weight.
Right now, **OpenClaw's Feishu plugin cannot receive reaction events at all**. When a user reacts to the bot's message, nothing happens — the bot is blind to it. This makes the bot feel unresponsive and disconnected from the natural rhythm of Feishu conversations.
The infrastructure is already 90% there:
- `reactions.ts` has full CRUD (`addReactionFeishu`, `removeReactionFeishu`, `listReactionsFeishu`)
- `typing.ts` uses the reaction API for typing indicators (proving the pipeline works)
- `channel.ts` declares `capabilities.reactions: true`
**The only missing piece is registering the inbound event handler in `monitor.ts`.** This PR closes that gap.
---
## What this does
- Registers `im.message.reaction.created_v1` and `im.message.reaction.deleted_v1` event handlers in the Feishu EventDispatcher
- Routes reaction events as synthetic inbound messages through `handleFeishuMessage`, giving the agent a dedicated turn to process each reaction and respond (e.g., react back)
- Filters out bot self-reactions (by `operator_type`), typing indicator emoji, and reaction-removed events
## Changes
**`extensions/feishu/src/monitor.ts`** (~130 lines added):
- `FeishuReactionEvent` type definition matching the Feishu API schema
- `handleReactionEvent()` — processes reaction events with proper filtering and routing
- Event handler registration in `registerEventHandlers()`
## Design decisions
### Synthetic messages over system events
We initially tried `enqueueSystemEvent()` (matching the Slack plugin pattern), but found that system events are passive — they only surface during the next agent turn and may be merged or delayed. For Feishu's interactive reaction culture, the agent needs a **dedicated turn** to process each reaction and respond in kind. Synthetic messages through `handleFeishuMessage` achieve this.
### DM routing for all reactions
Feishu's DM `chat_id` also uses the `oc_` prefix (unlike most platforms), making it impossible to distinguish DM vs group by prefix alone. To avoid group allowlist issues, all reactions are routed as p2p messages via the sender's `open_id`. This works correctly for single-agent setups. Group-specific session routing can be refined in a follow-up.
### Safety filters
- **Bot self-reactions** filtered by `operator_type === "app"` and `open_id` match
- **Typing indicator** (`Typing` emoji) excluded — used internally
- **Fire-and-forget**: reaction processing never blocks message handling
## Setup required
Users must subscribe to `im.message.reaction.created_v1` in their Feishu Open Platform app console (Events & Callbacks).
## Tested
Dogfooded on a live Feishu bot:
1. ✅ User reacts → bot receives event → agent processes and reacts back
2. ✅ Bot self-reactions correctly filtered (no loops)
3. ✅ Typing indicator reactions ignored
4. ✅ DM reactions route to correct session
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Adds support for Feishu reaction events (`im.message.reaction.created_v1` and `im.message.reaction.deleted_v1`) by registering handlers in the event dispatcher. Reactions are dispatched as synthetic DM messages through `handleFeishuMessage`, giving the agent a dedicated turn to process and respond to each reaction. The implementation includes proper filtering for bot self-reactions, typing indicator emoji, and reaction-removed events.
**Key changes:**
- Added `FeishuReactionEvent` type definition matching Feishu API schema
- Implemented `handleReactionEvent()` function with filtering logic and synthetic message creation
- Registered reaction event handlers in `registerEventHandlers()`
- Routes all reactions as p2p messages via sender's `open_id` to avoid group allowlist complexity
**Notes:**
- Requires users to subscribe to reaction events in Feishu Open Platform console
- Group reactions currently route to sender's session rather than group session (documented limitation)
- Implementation follows fire-and-forget pattern to avoid blocking message handling
<h3>Confidence Score: 4/5</h3>
- This PR is safe to merge with minimal risk - adds well-isolated new functionality with proper error handling
- The implementation is straightforward and follows existing patterns (similar to Slack's reaction handling via system events). The code has good defensive checks (bot self-reactions, typing indicator filtering, error handling). One logical issue exists with message ID collision risk when reactions happen within 1ms, and one style improvement opportunity for unused code cleanup. The synthetic message approach is well-documented and aligns with the stated goal of giving agents dedicated turns for reactions.
- No files require special attention
<sub>Last reviewed commit: 80d4b32</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
#20860: feat(reactions): add configurable immediate reaction dispatch system
by davidrudduck · 2026-02-19
81.3%
#19816: feat(slack): add typingReaction config for DM typing indicator fall...
by dalefrieswthat · 2026-02-18
78.3%
#20399: feat(whatsapp): surface inbound reaction events to agent session
by andrewchen · 2026-02-18
78.2%
#13641: feat(whatsapp): surface incoming reaction events to agent
by asklee-klawd · 2026-02-10
77.6%
#12894: feat(whatsapp): add reaction notifications support
by ekson73 · 2026-02-09
77.2%
#7980: feat(telegram): multi-stage reaction system for message pipeline vi...
by macmimi23 · 2026-02-03
77.1%
#22598: feat(feishu): support card action callback handler
by yingyixu · 2026-02-21
76.5%
#13211: feat(feishu): skip reply-to in DM conversations
by Vincentwei1021 · 2026-02-10
75.3%
#21346: [AI-assisted] Telegram: add reaction state machine with fallback an...
by Archie818 · 2026-02-19
74.8%
#19793: feat(feishu): reply-in-thread, parallel group sessions, and fire-an...
by yinsn · 2026-02-18
74.6%