From bb1e4d94bf7150179800063cc875399b1a780998 Mon Sep 17 00:00:00 2001 From: Devorun <130918800+devorun@users.noreply.github.com> Date: Tue, 31 Mar 2026 14:57:28 +0300 Subject: [PATCH] fix(mattermost): resolve thread follow-ups and tool output leaks (#4221) --- gateway/platforms/mattermost.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/gateway/platforms/mattermost.py b/gateway/platforms/mattermost.py index c134bb35da56..5ed36732820b 100644 --- a/gateway/platforms/mattermost.py +++ b/gateway/platforms/mattermost.py @@ -101,6 +101,8 @@ def __init__(self, config: PlatformConfig): self._SEEN_MAX = 2000 self._SEEN_TTL = 300 # 5 minutes + self._known_threads: set[str] = set() + # ------------------------------------------------------------------ # HTTP helpers # ------------------------------------------------------------------ @@ -265,6 +267,10 @@ async def send( formatted = self.format_message(content) chunks = self.truncate_message(formatted, MAX_POST_LENGTH) + thread_root = reply_to + if not thread_root and metadata: + thread_root = metadata.get("thread_id") + last_id = None for chunk in chunks: payload: Dict[str, Any] = { @@ -272,8 +278,10 @@ async def send( "message": chunk, } # Thread support: reply_to is the root post ID. - if reply_to and self._reply_mode == "thread": - payload["root_id"] = reply_to + if thread_root and self._reply_mode == "thread": + payload["root_id"] = thread_root + if hasattr(self, "_known_threads"): + self._known_threads.add(thread_root) data = await self._api_post("posts", payload) if not data or "id" not in data: @@ -625,13 +633,19 @@ async def _handle_ws_event(self, event: Dict[str, Any]) -> None: for pattern in mention_patterns ) - if require_mention and not is_free_channel and not has_mention: + thread_id = post.get("root_id") or None + bot_involved = thread_id and hasattr(self, "_known_threads") and thread_id in self._known_threads + + if require_mention and not is_free_channel and not has_mention and not bot_involved: logger.debug( "Mattermost: skipping non-DM message without @mention (channel=%s)", channel_id, ) return + if thread_id and hasattr(self, "_known_threads"): + self._known_threads.add(thread_id) + # Strip @mention from the message text so the agent sees clean input. if has_mention: for pattern in mention_patterns: