# NousResearch/hermes-agent · Telegram notification mode to suppress intermediate pushes

## Open now

- Nothing open on GitHub.

These members all concern adding a notification mode to the Telegram gateway integration that suppresses intermediate push notifications. The work appears across a feature request and at least two related implementation attempts.

## TL;DR

- 3 member(s): 0 open issue(s), 1 closed issue(s), 0 open PR(s), 1 merged PR(s), 1 PR(s) closed without merging.
- A fix was merged to main in PR #22793. Verify it addresses your case.
- **Recommended:** read PR #22793 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `resolved` · deciding PR(s): `pr-22793`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_SPANNING`): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
- Pairwise link density `0.67`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Closed / duplicate issues

- #22771: Telegram: add notification mode to suppress intermediate push notifications

## Prior & competing PRs

- **#22793: feat(gateway): add Telegram notification mode (salvage #22772)**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `gateway/platforms/base.py`, `gateway/platforms/telegram.py`, `gateway/run.py`, `scripts/release.py`, `tests/gateway/test_base_topic_sessions.py`
  - fix hunks:
  - `gateway/platforms/base.py`

    ```diff
    @@ -2950,6 +2950,18 @@ async def _stop_typing_task() -> None:
                     if text_content:
                         logger.info("[%s] Sending response (%d chars) to %s", self.name, len(text_content), event.source.chat_id)
                         _reply_anchor = _reply_anchor_for_event(event)
    +                    # Mark final response messages for notification delivery.
    +                    # Platform adapters that support per-message notification
    +                    # control (e.g. Telegram's disable_notification) use this
    +                    # flag to override silent-mode and ensure the final
    +                    # response triggers a push notification.
    +                    # Clone to avoid mutating the metadata shared with the
    +                    # typing-indicator task (which must remain unmarked).
    +                    if _thread_metadata is not None:
    +                        _thread_metadata = dict(_thread_metadata)
    +                        _thread_metadata["notify"] = True
    +                    else:
    +                        _thread_metadata = {"notify": True}
                         result = await self._send_with_retry(
                             chat_id=event.source.chat_id,
                             content=text_content,
    ```
  - `gateway/platforms/telegram.py`

    ```diff
    @@ -319,6 +319,30 @@ def __init__(self, config: PlatformConfig):
             # Slash-confirm button state: confirm_id → session_key (for /reload-mcp
             # and any other slash-confirm prompts; see GatewayRunner._request_slash_confirm).
             self._slash_confirm_state: Dict[str, str] = {}
    +        # Notification mode for message sends.
    +        # "important" — only final responses, approvals, and slash confirmations
    +        #               trigger notifications; tool progress, streaming, status
    +        #               messages are delivered silently via disable_notification.
    +        #               This is the default — Telegram users found per-tool-call
    +        #               push notifications too noisy.
    +        # "all"       — every message triggers a push notification (legacy
    +        #               behavior; opt-in via display.platforms.telegram.notifications).
    +        self._notifications_mode: str = "important"
    +
    +    def _notification_kwargs(
    +        self, metadata: Optional[Dict[str, Any]]
    +    ) -> Dict[str, Any]:
    +        """Return disable_notification kwargs when the adapter is in silent mode.
    +
    +        In "important" mode, all message sends are silently delivered
    +        (disable_notification=True) unless the caller explicitly requests a
    +        notification by setting ``metadata["notify"] = True``.
    +        """
    +        if getattr(self, "_notifications_mode", "important") != "important":
    +            return {}
    +        if (metadata or {}).get("notify"):
    +            return {}
    +        return {"disable_notification": True}
     
         def _is_callback_user_authorized(
             self,
    ```

    ```diff
    @@ -1414,6 +1438,7 @@ async def send(
                                     reply_to_message_id=reply_to_id,
                                     **thread_kwargs,
                                     **self._link_preview_kwargs(),
    +                                **self._notification_kwargs(metadata),
                                 )
                             except Exception as md_error:
                                 # Markdown parsing failed, try plain text
    ```

    ```diff
    @@ -1427,6 +1452,7 @@ async def send(
                                         reply_to_message_id=reply_to_id,
                                         **thread_kwargs,
                                         **self._link_preview_kwargs(),
    +                                    **self._notification_kwargs(metadata),
                                     )
                                 else:
                                     raise
    ```

    ```diff
    @@ -2374,6 +2400,7 @@ async def send_voice(
                                 "caption": caption[:1024] if caption else None,
                                 "reply_to_message_id": reply_to_id,
                                 **voice_thread_kwargs,
    +                            **self._notification_kwargs(metadata),
                             },
                             metadata,
                             reply_to_id,
    ```

    ```diff
    @@ -2398,6 +2425,7 @@ async def send_voice(
                                 "caption": caption[:1024] if caption else None,
                                 "reply_to_message_id": reply_to_id,
                                 **audio_thread_kwargs,
    +                            **self._notification_kwargs(metadata),
                             },
                             metadata,
                             reply_to_id,
    ```

    ```diff
    @@ -2534,6 +2562,7 @@ def _reset_opened_files() -> None:
                             "media": media,
                             "reply_to_message_id": reply_to_id,
                             **thread_kwargs,
    +                        **self._notification_kwargs(metadata),
                         },
                         metadata,
                         reply_to_id,
    ```

    ```diff
    @@ -2591,6 +2620,7 @@ async def send_image_file(
                             "caption": caption[:1024] if caption else None,
                             "reply_to_message_id": reply_to_id,
                             **thread_kwargs,
    +                        **self._notification_kwargs(metadata),
                         },
                         metadata,
                         reply_to_id,
    ```

    ```diff
    @@ -2686,6 +2716,7 @@ async def send_document(
                             "caption": caption[:1024] if caption else None,
                             "reply_to_message_id": reply_to_id,
                             **thread_kwargs,
    +                        **self._notification_kwargs(metadata),
                         },
                         metadata,
                         reply_to_id,
    ```

    ```diff
    @@ -2731,6 +2762,7 @@ async def send_video(
                             "caption": caption[:1024] if caption else None,
                             "reply_to_message_id": reply_to_id,
                             **thread_kwargs,
    +                        **self._notification_kwargs(metadata),
                         },
                         metadata,
                         reply_to_id,
    ```

    ```diff
    @@ -2781,6 +2813,7 @@ async def send_image(
                         "caption": caption[:1024] if caption else None,
                         "reply_to_message_id": reply_to_id,
                         **photo_thread_kwargs,
    +                    **self._notification_kwargs(metadata),
                     },
                     metadata,
                     reply_to_id,
    ```

    ```diff
    @@ -2816,6 +2849,7 @@ async def send_image(
                             "caption": caption[:1024] if caption else None,
                             "reply_to_message_id": reply_to_id,
                             **upload_thread_kwargs,
    +                        **self._notification_kwargs(metadata),
                         },
                         metadata,
                         reply_to_id,
    ```

    ```diff
    @@ -2861,6 +2895,7 @@ async def send_animation(
                         "caption": caption[:1024] if caption else None,
                         "reply_to_message_id": reply_to_id,
                         **animation_thread_kwargs,
    +                    **self._notification_kwargs(metadata),
                     },
                     metadata,
                     reply_to_id,
    ```
  - `gateway/run.py`

    ```diff
    @@ -4649,7 +4649,29 @@ def _create_adapter(
                 if not check_telegram_requirements():
                     logger.warning("Telegram: python-telegram-bot not installed")
                     return None
    -            return TelegramAdapter(config)
    +            adapter = TelegramAdapter(config)
    +            # Apply Telegram notification mode from config.  Controls whether
    +            # intermediate messages (tool progress, streaming, status) trigger
    +            # push notifications.  Supports ENV override for quick testing.
    +            _notify_mode = os.getenv("HERMES_TELEGRAM_NOTIFICATIONS", "")
    +            if not _notify_mode:
    +                try:
    +                    _gw_cfg = _load_gateway_config()
    +                    _raw = cfg_get(_gw_cfg, "display", "platforms", "telegram", "notifications")
    +                    if _raw not in (None, ""):
    +                        _notify_mode = str(_raw).strip().lower()
    +                except Exception:
    +                    pass
    +            _notify_mode = _notify_mode or "important"
    +            if _notify_mode not in ("all", "important"):
    +                logger.warning(
    +                    "Unknown telegram notifications mode '%s', "
    +                    "defaulting to 'important' (valid: all, important)",
    +                    _notify_mode,
    +                )
    +                _notify_mode = "important"
    +            adapter._notifications_mode = _notify_mode
    +            return adapter
             
             elif platform == Platform.DISCORD:
                 from gateway.platforms.discord import DiscordAdapter, check_discord_requirements
    ```
  - `scripts/release.py`

    ```diff
    @@ -65,6 +65,7 @@
         "[redacted:email]": "subtract0",
         "[redacted:email]": "qWaitCrypto",
         "[redacted:email]": "Qwinty",
    +    "[redacted:email]": "CalmProton",
         "[redacted:email]": "wesleysimplicio",
         "[redacted:email]": "SiliconID",
         "[redacted:email]": "xieNniu",
    ```
  - `tests/gateway/test_base_topic_sessions.py`

    ```diff
    @@ -130,8 +130,8 @@ async def hold_typing(_chat_id, interval=2.0, metadata=None):
                 {
                     "chat_id": "-1001",
                     "content": "ack",
    -                "reply_to": "1",
    -                "metadata": {"thread_id": "17585"},
    +                "reply_to": None,
    +                "metadata": {"thread_id": "17585", "notify": True},
                 }
             ]
             assert typing_calls == [
    ```
- **#22772: feat(gateway): add Telegram notification mode to suppress intermediate push notifications**. closed without merge
  - maintainer direction: category `merged_via`; implication `superseded`; refs `#22793`

## Fix status

- Merged to main in PR #22793 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-05-09`.
