feat(telegram): inbound message reactions → agent actions - #54599
Open
thesubtleforces wants to merge 1 commit into
Open
feat(telegram): inbound message reactions → agent actions#54599thesubtleforces wants to merge 1 commit into
thesubtleforces wants to merge 1 commit into
Conversation
Collaborator
Related: this joins an open cluster of competing Telegram-inbound-reaction PRs — #24149 (ReactionEvent/ReactionHandler types), #13992 (env-toggled routing), #53814 (telegram:reaction hook event). This PR's distinct angle is a config-driven emoji→action map plus a |
Author
|
Approved |
1 similar comment
Author
|
Approved |
teknium1
reviewed
Jul 15, 2026
teknium1
left a comment
Contributor
There was a problem hiding this comment.
Thanks for the focused Telegram implementation. The inbound path is still absent from current main, but this version needs changes before it can safely enter the current adapter.
Problems
- Authorization bypass:
plugins/platforms/telegram/adapter.py:7210-7223calls a plugin handler, and:7272dispatches an agent event, without the current intake authorization prefilter. Current main documents that_is_user_authorized_from_message()prevents unauthorized prompt injection before event construction (plugins/platforms/telegram/adapter.py:908-916) and calls it in all normal inbound handlers (:7823,:7849,:7869,:8072). - The PR body’s
telegram.extra.reaction_actionsexample is not a usable config path: current docs state top-leveltelegram.extrakeys are silently dropped (website/docs/user-guide/messaging/telegram.md:468-481). - The body says config is checked before plugins, but
:7210-7223gives a plugin handler priority over a configured action for the same emoji; there is no collision test. register_reactionadds a new generic plugin surface (hermes_cli/plugins.py:581-613) without a consumer. The repository rubric rejects speculative extension points (AGENTS.md:98-101), and the prior member comment notes competing reaction-interface PRs.
Suggested changes
- Authorize the reaction actor before either plugin dispatch or agent dispatch, with regression tests for both paths.
- Document
platforms.telegram.extra.reaction_actionsand test precedence explicitly. - Align the plugin seam with the canonical interface selected for the reaction PR cluster.
Automated hermes-sweeper review.
This was referenced Aug 4, 2026
…oundary Rebuild of the reaction-actions feature on top of the normalized gateway_platform_event pipeline (NousResearch#64176 and follow-ups), replacing the original adapter-level MessageReactionHandler approach entirely: - adapter: expose added_emojis (new_reaction minus old_reaction) as an additive payload field — Telegram's new_reaction is the full current set, so consumers that act once per reaction need the delta, not the state; the catch-all's inertness gate now also admits reaction updates when platforms.telegram.extra.reaction_actions is configured, so the action layer works without a hook subscriber - gateway: after the SAME profile-scoped authorization decision that gates gateway_platform_event observers, a reaction whose newly-added emoji maps in platforms.<name>.extra.reaction_actions synthesizes an agent turn through _handle_message — the reacted-to message rides native reply context (reply_to_message_id/-text via rich_sent_store, reply_to_is_own_message); hook errors and action errors are isolated from each other and from the update loop - default-empty config keeps everything inert (no hook, no actions → event still drops before the auth check, preserving the original short-circuit) - docs: hooks.md payload row gains added_emojis; telegram.md gains the user-facing Reaction Actions section - tests: 14 new cases (added_emojis diff semantics, action dispatch, shared-auth gating, no-subscriber path, error isolation, fire-site gate) + 2 exact-payload assertions updated; full platform-event and telegram-auth suites green (59 passed) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
thesubtleforces
force-pushed
the
feat/telegram-reaction-actions
branch
from
August 15, 2026 23:22
1b47fc8 to
914435d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Config-driven reaction actions: a user long-presses a bot message, taps an emoji, and the gateway synthesizes an agent turn from a
platforms.<name>.extra.reaction_actionsemoji→instruction map. Default-empty config → fully inert and backward-compatible.Rebuilt on top of the normalized
gateway_platform_eventpipeline (#64176 and follow-ups) after it landed — the original adapter-levelMessageReactionHandlerapproach from earlier revisions of this PR is gone. The action layer now rides the existing normalize → post-auth boundary rather than adding a parallel reaction path:How it works
_normalize_reaction_eventgains an additive payload fieldadded_emojis— thenew_reaction−old_reactiondiff. Telegram'snew_reactionis the message's full current reaction set, so consumers that act once per reaction (unlike state-re-rendering observers) need the delta. Observers get this field too (hooks.md updated)._handle_gateway_platform_event), after the same profile-scoped_is_user_authorizeddecision that gates observers, a newly-added emoji with areaction_actionsmapping dispatches an agent turn through_handle_message— so session routing, history, and tool policy apply normally. The reacted-to message rides native reply context (reply_to_message_id/reply_to_textviarich_sent_store/reply_to_is_own_message=True).reaction_actionsis configured even with no hook subscriber (other update types keep the original skip). With no hook and no configured actions, events still drop before the auth check — the original short-circuit is preserved and pinned by the existing test.Config
Keys must come from Telegram's fixed reaction-emoji set. Documented in
website/docs/user-guide/messaging/telegram.md; thegateway_platform_eventpayload contract row in hooks.md gainsadded_emojis.Why this shape
The landed hook is deliberately observer-only (no bot handles, return ignored), so reaction→action can't be built as a plugin — but plenty of single-user deployments want "tap 👍 to complete the task" without writing a plugin at all. A config map at the gateway boundary reuses the pipeline's auth and normalization instead of duplicating either, and stays platform-agnostic (any platform that normalizes reaction events with
added_emojisgets actions for free).Tests
tests/gateway/test_gateway_platform_event_hook.pyextended with 14 cases (2 existing exact-payload assertions updated for the additive field); full platform-event + telegram-auth suites: 59 passed.added_emojisdiff semantics: excludes pre-existing, re-tap adds nothing, removal yields empty, malformedold_reactiontreated as empty🤖 Generated with Claude Code