Skip to content

feat(telegram): handle incoming user reactions as feedback signals - #23731

Open
zetxek wants to merge 1 commit into
NousResearch:mainfrom
zetxek:feat/telegram-incoming-reaction-feedback
Open

feat(telegram): handle incoming user reactions as feedback signals#23731
zetxek wants to merge 1 commit into
NousResearch:mainfrom
zetxek:feat/telegram-incoming-reaction-feedback

Conversation

@zetxek

@zetxek zetxek commented May 11, 2026

Copy link
Copy Markdown

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:

  1. Captures the MessageReactionUpdated event (already received via Update.ALL_TYPES — no polling change needed)
  2. Interprets the emoji as a feedback signal
  3. Logs structured feedback to ~/.hermes/feedback.jsonl
  4. For significant reactions, appends human-readable notes to ~/.hermes/memory/feedback-log.md for the agent to learn from

Emoji → Feedback mapping

Emoji Type Action
👍 positive Logged to feedback.jsonl
👎 negative Logged + note written to memory/feedback-log.md
❤️ save Logged + saved to memory/feedback-log.md
🔥 strong_positive Logged + saved to memory/feedback-log.md

Unknown emojis are silently ignored.

Files changed

  • gateway/platforms/telegram.py — adds _handle_reaction() method and registers MessageReactionHandler inside _start_polling
  • tests/gateway/test_telegram_incoming_reactions.py — 17 new tests covering all feedback types, edge cases (missing fields, unknown emojis, empty reactions), and file I/O

Tests

All 30 tests pass (17 new + 13 existing reaction tests):

30 passed in 5.09s

Backwards compatibility

  • MessageReactionHandler import is wrapped in try/except ImportError — gracefully skips on older PTB versions with a debug log
  • No changes to existing outbound reaction behaviour

Copilot AI review requested due to automatic review settings May 11, 2026 10:47

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment on lines +4614 to +4621
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"
Comment on lines +4614 to +4618
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")

Comment on lines +4616 to +4618
with open(feedback_file, "a") as f:
f.write(json.dumps(entry) + "\n")

Comment on lines +4620 to +4624
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")
Comment on lines +4567 to +4572
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

Comment on lines +4605 to +4608
entry = {
"timestamp": datetime.datetime.utcnow().isoformat(),
"emoji": emoji,
"feedback_type": feedback_type,
assert entry["emoji"] == "\U00002764"


@pytest.mark.asyncio
Comment on lines +140 to +151

@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()
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/gateway Gateway runner, session dispatch, delivery platform/telegram Telegram bot adapter labels May 11, 2026
@konsisumer

Copy link
Copy Markdown
Contributor

Closing — deferring to #13992 by @giwaov which addresses the same. Reopen if that PR stalls.

@teknium1

Copy link
Copy Markdown
Contributor

Thanks for the reaction-feedback contribution. The underlying gap remains: current Telegram startup has no inbound reaction handler (plugins/platforms/telegram/adapter.py:3173-3190), while its existing reaction code is outbound-only (plugins/platforms/telegram/adapter.py:8468-8545).

Problems

  • The PR modifies gateway/platforms/telegram.py, but Telegram was migrated to plugins/platforms/telegram/adapter.py by 5600105478ffde29d7566b45421b100eaa29c4ef; the old module no longer exists on current main.
  • The proposed Path.home() / ".hermes" persistence bypasses the profile-aware get_hermes_home() contract (hermes_constants.py:55-77).
  • The handler does not establish that a reaction targets a bot-authored message. The existing Feishu implementation explicitly verifies the target sender before routing (plugins/platforms/feishu/adapter.py:2901-2915).
  • No current code reads feedback.jsonl or feedback-log.md, so writing these files alone does not make feedback available to later agent sessions.

Suggested changes

  • Rework this against the bundled Telegram plugin and its current startup path.
  • Define an opt-in config-backed behavior, verify bot-message ownership and routing context, and feed the signal into a supported event or memory path.
  • Use get_hermes_home() and add current-path tests for profile isolation and non-bot targets.

Automated hermes-sweeper review.

@teknium1 teknium1 added sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 13, 2026
@filipkis

Copy link
Copy Markdown

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 ~/.hermes/telegram_reactions.jsonl (adds/removes, with chat_id, message_id, emoji, timestamp) and the hydration scripts poll that file to detect 👍 on their sent message IDs. Works great locally — happy to contribute if helpful.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have platform/telegram Telegram bot adapter sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-platform-windows Sweeper risk: may break or behave differently on native Windows type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants