Merge PR #248: feat(gateway): include Discord channel topic in session context

Authored by Bartok9. Fixes #163.

Surfaces Discord channel topics in the agent's session context prompt,
allowing the agent to adapt its behavior based on the channel's purpose.
This commit is contained in:
teknium1 2026-03-02 00:51:20 -08:00
commit 3a840a130c
3 changed files with 21 additions and 1 deletions

View file

@ -736,9 +736,13 @@ class BasePlatformAdapter(ABC):
chat_type: str = "dm", chat_type: str = "dm",
user_id: Optional[str] = None, user_id: Optional[str] = None,
user_name: Optional[str] = None, user_name: Optional[str] = None,
thread_id: Optional[str] = None thread_id: Optional[str] = None,
chat_topic: Optional[str] = None,
) -> SessionSource: ) -> SessionSource:
"""Helper to build a SessionSource for this platform.""" """Helper to build a SessionSource for this platform."""
# Normalize empty topic to None
if chat_topic is not None and not chat_topic.strip():
chat_topic = None
return SessionSource( return SessionSource(
platform=self.platform, platform=self.platform,
chat_id=str(chat_id), chat_id=str(chat_id),
@ -747,6 +751,7 @@ class BasePlatformAdapter(ABC):
user_id=str(user_id) if user_id else None, user_id=str(user_id) if user_id else None,
user_name=user_name, user_name=user_name,
thread_id=str(thread_id) if thread_id else None, thread_id=str(thread_id) if thread_id else None,
chat_topic=chat_topic.strip() if chat_topic else None,
) )
@abstractmethod @abstractmethod

View file

@ -543,12 +543,16 @@ class DiscordAdapter(BasePlatformAdapter):
if hasattr(interaction.channel, "guild") and interaction.channel.guild: if hasattr(interaction.channel, "guild") and interaction.channel.guild:
chat_name = f"{interaction.channel.guild.name} / #{chat_name}" chat_name = f"{interaction.channel.guild.name} / #{chat_name}"
# Get channel topic (if available)
chat_topic = getattr(interaction.channel, "topic", None)
source = self.build_source( source = self.build_source(
chat_id=str(interaction.channel_id), chat_id=str(interaction.channel_id),
chat_name=chat_name, chat_name=chat_name,
chat_type=chat_type, chat_type=chat_type,
user_id=str(interaction.user.id), user_id=str(interaction.user.id),
user_name=interaction.user.display_name, user_name=interaction.user.display_name,
chat_topic=chat_topic,
) )
msg_type = MessageType.COMMAND if text.startswith("/") else MessageType.TEXT msg_type = MessageType.COMMAND if text.startswith("/") else MessageType.TEXT
@ -661,6 +665,9 @@ class DiscordAdapter(BasePlatformAdapter):
if isinstance(message.channel, discord.Thread): if isinstance(message.channel, discord.Thread):
thread_id = str(message.channel.id) thread_id = str(message.channel.id)
# Get channel topic (if available - TextChannels have topics, DMs/threads don't)
chat_topic = getattr(message.channel, "topic", None)
# Build source # Build source
source = self.build_source( source = self.build_source(
chat_id=str(message.channel.id), chat_id=str(message.channel.id),
@ -669,6 +676,7 @@ class DiscordAdapter(BasePlatformAdapter):
user_id=str(message.author.id), user_id=str(message.author.id),
user_name=message.author.display_name, user_name=message.author.display_name,
thread_id=thread_id, thread_id=thread_id,
chat_topic=chat_topic,
) )
# Build media URLs -- download image attachments to local cache so the # Build media URLs -- download image attachments to local cache so the

View file

@ -44,6 +44,7 @@ class SessionSource:
user_id: Optional[str] = None user_id: Optional[str] = None
user_name: Optional[str] = None user_name: Optional[str] = None
thread_id: Optional[str] = None # For forum topics, Discord threads, etc. thread_id: Optional[str] = None # For forum topics, Discord threads, etc.
chat_topic: Optional[str] = None # Channel topic/description (Discord, Slack)
@property @property
def description(self) -> str: def description(self) -> str:
@ -75,6 +76,7 @@ class SessionSource:
"user_id": self.user_id, "user_id": self.user_id,
"user_name": self.user_name, "user_name": self.user_name,
"thread_id": self.thread_id, "thread_id": self.thread_id,
"chat_topic": self.chat_topic,
} }
@classmethod @classmethod
@ -87,6 +89,7 @@ class SessionSource:
user_id=data.get("user_id"), user_id=data.get("user_id"),
user_name=data.get("user_name"), user_name=data.get("user_name"),
thread_id=data.get("thread_id"), thread_id=data.get("thread_id"),
chat_topic=data.get("chat_topic"),
) )
@classmethod @classmethod
@ -155,6 +158,10 @@ def build_session_context_prompt(context: SessionContext) -> str:
else: else:
lines.append(f"**Source:** {platform_name} ({context.source.description})") lines.append(f"**Source:** {platform_name} ({context.source.description})")
# Channel topic (if available - provides context about the channel's purpose)
if context.source.chat_topic:
lines.append(f"**Channel Topic:** {context.source.chat_topic}")
# User identity (especially useful for WhatsApp where multiple people DM) # User identity (especially useful for WhatsApp where multiple people DM)
if context.source.user_name: if context.source.user_name:
lines.append(f"**User:** {context.source.user_name}") lines.append(f"**User:** {context.source.user_name}")