feat(telegram): pin incoming user message for duration of agent turn

When a user sends a message on Telegram, the incoming message is now
automatically pinned at the start of processing and unpinned when the
agent finishes its turn. This gives the user a visual indicator that
their message is being worked on, and keeps the conversation anchored.

Changes:
- telegram.py: Added pinChatMessage in on_processing_start and
  unpinChatMessage in on_processing_complete. Restructured both
  hooks so pin/unpin runs independently of the reactions feature
  (reactions are optional; pinning is always on).
- telegram.py: Pass message_id through SessionSource so it's
  available in the session context.
- session_context.py: Added HERMES_SESSION_MESSAGE_ID context var.
- run.py: Pass source.message_id through set_session_vars.

Pinning is silent (disable_notification=True) and failures are
logged at debug level without interrupting message processing.
Only the user's incoming message is pinned -- never the agent's
replies. Auto-resume events (which have no message_id) are
correctly skipped.
This commit is contained in:
Indigo Karasu 2026-05-15 16:05:23 -07:00 committed by Teknium
parent ce46e6bf08
commit a724c3b9cf

View file

@ -5416,16 +5416,25 @@ class TelegramAdapter(BasePlatformAdapter):
return False
async def on_processing_start(self, event: MessageEvent) -> None:
"""Add an in-progress reaction when message processing begins."""
if not self._reactions_enabled():
return
"""Add an in-progress reaction and pin the message when processing begins."""
chat_id = getattr(event.source, "chat_id", None)
message_id = getattr(event, "message_id", None)
if chat_id and message_id:
await self._set_reaction(chat_id, message_id, "\U0001f440")
if self._reactions_enabled():
await self._set_reaction(chat_id, message_id, "\U0001f440")
# Pin the incoming message for the duration of the turn
if self._bot:
try:
await self._bot.pin_chat_message(
chat_id=int(chat_id),
message_id=int(message_id),
disable_notification=True,
)
except Exception:
logger.debug("[Telegram] Failed to pin message %s in chat %s", message_id, chat_id)
async def on_processing_complete(self, event: MessageEvent, outcome: ProcessingOutcome) -> None:
"""Swap the in-progress reaction for a final success/failure reaction.
"""Swap the in-progress reaction for a final success/failure reaction and unpin.
Unlike Discord (additive reactions), Telegram's set_message_reaction
replaces all existing reactions in one call no remove step needed.
@ -5437,17 +5446,25 @@ class TelegramAdapter(BasePlatformAdapter):
another agent run to swap it to 👍/👎 which never happens if the
cancellation was the last activity in the chat.
"""
if not self._reactions_enabled():
return
chat_id = getattr(event.source, "chat_id", None)
message_id = getattr(event, "message_id", None)
if not (chat_id and message_id):
return
if outcome == ProcessingOutcome.CANCELLED:
await self._clear_reactions(chat_id, message_id)
else:
await self._set_reaction(
chat_id,
message_id,
"\U0001f44d" if outcome == ProcessingOutcome.SUCCESS else "\U0001f44e",
)
if self._reactions_enabled():
if outcome == ProcessingOutcome.CANCELLED:
await self._clear_reactions(chat_id, message_id)
else:
await self._set_reaction(
chat_id,
message_id,
"\U0001f44d" if outcome == ProcessingOutcome.SUCCESS else "\U0001f44e",
)
# Unpin the message when processing is complete
if self._bot:
try:
await self._bot.unpin_chat_message(
chat_id=int(chat_id),
message_id=int(message_id),
)
except Exception:
logger.debug("[Telegram] Failed to unpin message %s in chat %s", message_id, chat_id)