feat(telegram): handle incoming user reactions as feedback signals - #23731
feat(telegram): handle incoming user reactions as feedback signals#23731zetxek wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds support in the Telegram gateway adapter for interpreting incoming emoji reactions on bot messages as user feedback signals, persisting them to disk for later analysis/learning.
Changes:
- Registers a Telegram
MessageReactionHandler(when available) to receive reaction updates. - Implements
TelegramAdapter._handle_reaction()to map supported emojis to feedback types and append entries to a JSONL log plus an additional Markdown log for stronger signals. - Adds a new pytest suite covering reaction handling and file output behavior.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 8 comments.
| File | Description |
|---|---|
gateway/platforms/telegram.py |
Adds handler registration and a new _handle_reaction() method to log reaction feedback to disk. |
tests/gateway/test_telegram_incoming_reactions.py |
Introduces tests for reaction-to-feedback mapping, ignored cases, multi-reaction updates, and file writes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| feedback_file = pathlib.Path.home() / ".hermes" / "feedback.jsonl" | ||
| feedback_file.parent.mkdir(parents=True, exist_ok=True) | ||
| with open(feedback_file, "a") as f: | ||
| f.write(json.dumps(entry) + "\n") | ||
|
|
||
| # For negative feedback or saves, write to memory log | ||
| if feedback_type in ("negative", "save", "strong_positive"): | ||
| memory_dir = pathlib.Path.home() / ".hermes" / "memory" |
| feedback_file = pathlib.Path.home() / ".hermes" / "feedback.jsonl" | ||
| feedback_file.parent.mkdir(parents=True, exist_ok=True) | ||
| with open(feedback_file, "a") as f: | ||
| f.write(json.dumps(entry) + "\n") | ||
|
|
| with open(feedback_file, "a") as f: | ||
| f.write(json.dumps(entry) + "\n") | ||
|
|
| if feedback_type in ("negative", "save", "strong_positive"): | ||
| memory_dir = pathlib.Path.home() / ".hermes" / "memory" | ||
| memory_dir.mkdir(parents=True, exist_ok=True) | ||
| log_file = memory_dir / "feedback-log.md" | ||
| ts = datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M") |
| Supported reactions and their meanings: | ||
| 👍 (\U0001f44d) → positive feedback | ||
| 👎 (\U0001f44e) → negative feedback — also logged to memory/feedback-log.md | ||
| ❤️ (\U00002764) → save/bookmark this response — also logged to memory | ||
| 🔥 (\U0001f525) → strong positive — also logged to memory | ||
|
|
| entry = { | ||
| "timestamp": datetime.datetime.utcnow().isoformat(), | ||
| "emoji": emoji, | ||
| "feedback_type": feedback_type, |
| assert entry["emoji"] == "\U00002764" | ||
|
|
||
|
|
||
| @pytest.mark.asyncio |
|
|
||
| @pytest.mark.asyncio | ||
| async def test_thumbs_down_writes_to_memory_log(tmp_path, monkeypatch): | ||
| """👎 reaction should write a note to memory/feedback-log.md.""" | ||
| monkeypatch.setattr(pathlib.Path, "home", lambda: tmp_path) | ||
| adapter = _make_adapter() | ||
| update = _make_reaction_update("\U0001f44e", message_id=77, chat_id=555) | ||
|
|
||
| await adapter._handle_reaction(update, MagicMock()) | ||
|
|
||
| log_file = tmp_path / ".hermes" / "memory" / "feedback-log.md" | ||
| assert log_file.exists() |
|
Thanks for the reaction-feedback contribution. The underlying gap remains: current Telegram startup has no inbound reaction handler ( Problems
Suggested changes
Automated hermes-sweeper review. |
|
Use case that triggered finding this issue: hydration reminders sent by a cron job, acknowledged by the user reacting with 👍. The reaction is the natural Telegram UX — no new habit to form. Would love to see this land! Note: I have implemented a local patch that stores incoming reactions to |
Summary
Adds support for receiving emoji reactions from users on Telegram as feedback signals, enabling self-learning over time.
How it works
When a user reacts to one of the bot's messages with a supported emoji, the bot:
MessageReactionUpdatedevent (already received viaUpdate.ALL_TYPES— no polling change needed)~/.hermes/feedback.jsonl~/.hermes/memory/feedback-log.mdfor the agent to learn fromEmoji → Feedback mapping
positivenegativesavestrong_positiveUnknown emojis are silently ignored.
Files changed
gateway/platforms/telegram.py— adds_handle_reaction()method and registersMessageReactionHandlerinside_start_pollingtests/gateway/test_telegram_incoming_reactions.py— 17 new tests covering all feedback types, edge cases (missing fields, unknown emojis, empty reactions), and file I/OTests
All 30 tests pass (17 new + 13 existing reaction tests):
Backwards compatibility
MessageReactionHandlerimport is wrapped intry/except ImportError— gracefully skips on older PTB versions with a debug log