From b59ed9c6bc564e1158875dc795141405c4ed927d Mon Sep 17 00:00:00 2001 From: 1RB <86501179+1RB@users.noreply.github.com> Date: Wed, 13 May 2026 23:08:47 -0700 Subject: [PATCH] fix(discord): handle forwarded messages via message_snapshots MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Discord introduced message_snapshots for forwarded messages — text and attachments live inside snap.content / snap.attachments rather than on the parent message. _handle_message wasn't reading them, so forwards showed up empty. Defensively extracts snapshot text (when raw_content is empty) and appends snapshot attachments to the working all_attachments list used for type detection and media routing. hasattr/getattr guards keep this safe on older discord.py installs without the field. Salvage of #25462 by @1RB (manually re-applied — original branch was stale against current main). --- gateway/platforms/discord.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/gateway/platforms/discord.py b/gateway/platforms/discord.py index b1b5012776b..bcca80c5b5f 100644 --- a/gateway/platforms/discord.py +++ b/gateway/platforms/discord.py @@ -4186,6 +4186,17 @@ class DiscordAdapter(BasePlatformAdapter): raw_content = message.content.strip() normalized_content = raw_content mention_prefix = False + + snapshot_attachments = [] + if hasattr(message, "message_snapshots") and message.message_snapshots: + snapshot_text_parts = [] + for snap in message.message_snapshots: + if getattr(snap, "content", None): + snapshot_text_parts.append(snap.content.strip()) + snapshot_attachments.extend(getattr(snap, "attachments", []) or []) + if snapshot_text_parts and not raw_content: + raw_content = "\n".join(snapshot_text_parts) + normalized_content = raw_content if self._client.user and self._client.user in message.mentions: mention_prefix = True normalized_content = normalized_content.replace(f"<@{self._client.user.id}>", "").strip() @@ -4261,13 +4272,15 @@ class DiscordAdapter(BasePlatformAdapter): auto_threaded_channel = thread self._threads.mark(thread_id) + all_attachments = list(message.attachments) + snapshot_attachments + # Determine message type msg_type = MessageType.TEXT if normalized_content.startswith("/"): msg_type = MessageType.COMMAND - elif message.attachments: + elif all_attachments: # Check attachment types - for att in message.attachments: + for att in all_attachments: if att.content_type: if att.content_type.startswith("image/"): msg_type = MessageType.PHOTO @@ -4326,7 +4339,7 @@ class DiscordAdapter(BasePlatformAdapter): media_urls = [] media_types = [] pending_text_injection: Optional[str] = None - for att in message.attachments: + for att in all_attachments: content_type = att.content_type or "unknown" if content_type.startswith("image/"): try: