From 9405cdc8dd0347fee65b554e3aba0d2eab7a7b7f Mon Sep 17 00:00:00 2001 From: annguyenNous Date: Fri, 29 May 2026 15:05:33 +0700 Subject: [PATCH] fix(ntfy): prevent echo loop by tagging outgoing messages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When publish_topic equals the subscribe topic, the agent's own replies are echoed back by ntfy as incoming messages, creating an infinite reply spiral. Fix: tag outgoing messages with X-Tags: hermes-agent header, and skip incoming messages that carry this tag. This is zero-config — works automatically regardless of topic configuration. Fixes NousResearch/hermes-agent#34447 --- plugins/platforms/ntfy/adapter.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/plugins/platforms/ntfy/adapter.py b/plugins/platforms/ntfy/adapter.py index b9280ab9e..e53d987bc 100644 --- a/plugins/platforms/ntfy/adapter.py +++ b/plugins/platforms/ntfy/adapter.py @@ -81,6 +81,7 @@ DEDUP_WINDOW_SECONDS = 300 DEDUP_MAX_SIZE = 1000 RECONNECT_BACKOFF = [2, 5, 10, 30, 60] STREAM_TIMEOUT_SECONDS = 90 # ntfy keepalive default is 55s; give margin +_ECHO_TAG = "hermes-agent" # tag added to outgoing messages for echo-loop prevention def _build_auth_header(token: str) -> Dict[str, str]: @@ -311,6 +312,12 @@ class NtfyAdapter(BasePlatformAdapter): logger.debug("[%s] Duplicate message %s, skipping", self.name, msg_id) return + # Echo-loop prevention: skip messages tagged by this adapter. + tags = event.get("tags") or [] + if _ECHO_TAG in tags: + logger.debug("[%s] Skipping own message (echo tag)", self.name) + return + text = (event.get("message") or "").strip() if not text: logger.debug("[%s] Empty message body, skipping", self.name) @@ -387,7 +394,11 @@ class NtfyAdapter(BasePlatformAdapter): url = f"{self._server}/{publish_topic}" markdown_enabled = (self.config.extra or {}).get("markdown", False) - headers = {**self._auth_headers(), "Content-Type": "text/plain; charset=utf-8"} + headers = { + **self._auth_headers(), + "Content-Type": "text/plain; charset=utf-8", + "X-Tags": _ECHO_TAG, + } if markdown_enabled: headers["X-Markdown"] = "true"