From 803cf8bfce376dd510a8d5b6e74cde3ed5646798 Mon Sep 17 00:00:00 2001 From: Agent Date: Fri, 3 Jul 2026 23:55:36 +0800 Subject: [PATCH] feat(discord): auto-rename thread title from generated session title MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add rename_dm_topic() to DiscordAdapter and wire it via title_callback in the Gateway's maybe_auto_title flow, mirroring the existing Telegram topic rename pattern. Tested on live Discord gateway with auto-title generation → callback → thread.rename chain confirmed working. --- gateway/run.py | 51 ++++++++++++++++++++++++++++ plugins/platforms/discord/adapter.py | 17 ++++++++++ 2 files changed, 68 insertions(+) diff --git a/gateway/run.py b/gateway/run.py index 646a4856928e..afa87519571e 100644 --- a/gateway/run.py +++ b/gateway/run.py @@ -13194,6 +13194,51 @@ def _log_rename_failure(fut) -> None: future.add_done_callback(_log_rename_failure) + def _schedule_discord_thread_title_rename( + self, + source: SessionSource, + title: str, + ) -> None: + """Schedule a Discord thread rename from the auto-title background thread.""" + if not title or source.platform != Platform.DISCORD or not source.thread_id: + return + try: + loop = asyncio.get_running_loop() + except RuntimeError: + loop = getattr(self, "_gateway_loop", None) + if loop is None or loop.is_closed(): + return + try: + copied_source = dataclasses.replace(source) + except Exception: + copied_source = source + adapter = self.adapters.get(Platform.DISCORD) if getattr(self, "adapters", None) else None + if adapter is None: + return + rename_topic = getattr(adapter, "rename_dm_topic", None) + if rename_topic is None: + return + future = safe_schedule_threadsafe( + rename_topic( + chat_id=str(copied_source.chat_id), + thread_id=str(copied_source.thread_id), + name=title, + ), + loop, + logger=logger, + log_message="Discord thread title rename failed to schedule", + ) + if future is None: + return + + def _log_rename_failure(fut) -> None: + try: + fut.result() + except Exception: + logger.debug("Discord thread title rename failed", exc_info=True) + + future.add_done_callback(_log_rename_failure) + _TELEGRAM_CAPABILITY_HINT_COOLDOWN_S = 300.0 def _should_send_telegram_capability_hint(self, source: SessionSource) -> bool: @@ -18362,6 +18407,12 @@ def _title_failure_cb(task: str, exc: BaseException) -> None: effective_session_id, title, ) + # Discord thread: rename on auto-title (same pattern as Telegram) + if source.platform == Platform.DISCORD and source.thread_id: + maybe_auto_title_kwargs["title_callback"] = lambda title: self._schedule_discord_thread_title_rename( + source, + title, + ) maybe_auto_title( getattr(self._session_db, "_db", self._session_db), effective_session_id, diff --git a/plugins/platforms/discord/adapter.py b/plugins/platforms/discord/adapter.py index bfe472450410..a26b3f3eddab 100644 --- a/plugins/platforms/discord/adapter.py +++ b/plugins/platforms/discord/adapter.py @@ -3720,6 +3720,23 @@ async def stop_typing(self, chat_id: str) -> None: except (asyncio.CancelledError, Exception): pass + async def rename_dm_topic( + self, chat_id: str, thread_id: str, name: str + ) -> None: + """Rename a Discord thread to the auto-generated session title.""" + if not chat_id or not thread_id or not name: + return + thread = self._client.get_channel(int(thread_id)) + if thread is None: + thread = await self._client.fetch_channel(int(thread_id)) + if thread is None: + return + await thread.edit(name=name[:100]) + logger.info( + "[%s] Renamed Discord thread %s → '%s'", + self.name, thread_id, name[:100], + ) + async def get_chat_info(self, chat_id: str) -> Dict[str, Any]: """Get information about a Discord channel.""" if not self._client: