From 1f7a81e5eebafad5e21c5760a92880c3155bcefe Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 23 Feb 2026 10:15:12 +0000 Subject: [PATCH] feat(slack): isolate session context per thread Each Slack thread now gets its own conversation session instead of sharing one session per channel. DM sessions are unchanged. Added as a generic feature to also support if Feishu threads support is added in the future. --- nanobot/bus/events.py | 3 ++- nanobot/channels/base.py | 4 +++- nanobot/channels/slack.py | 6 +++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/nanobot/bus/events.py b/nanobot/bus/events.py index a149e20..a48660d 100644 --- a/nanobot/bus/events.py +++ b/nanobot/bus/events.py @@ -16,11 +16,12 @@ class InboundMessage: timestamp: datetime = field(default_factory=datetime.now) media: list[str] = field(default_factory=list) # Media URLs metadata: dict[str, Any] = field(default_factory=dict) # Channel-specific data + session_key_override: str | None = None # Optional override for thread-scoped sessions @property def session_key(self) -> str: """Unique key for session identification.""" - return f"{self.channel}:{self.chat_id}" + return self.session_key_override or f"{self.channel}:{self.chat_id}" @dataclass diff --git a/nanobot/channels/base.py b/nanobot/channels/base.py index 3a5a785..2201686 100644 --- a/nanobot/channels/base.py +++ b/nanobot/channels/base.py @@ -111,13 +111,15 @@ class BaseChannel(ABC): ) return + meta = metadata or {} msg = InboundMessage( channel=self.name, sender_id=str(sender_id), chat_id=str(chat_id), content=content, media=media or [], - metadata=metadata or {} + metadata=meta, + session_key_override=meta.get("session_key"), ) await self.bus.publish_inbound(msg) diff --git a/nanobot/channels/slack.py b/nanobot/channels/slack.py index b0f9bbb..2e91f7b 100644 --- a/nanobot/channels/slack.py +++ b/nanobot/channels/slack.py @@ -179,6 +179,9 @@ class SlackChannel(BaseChannel): except Exception as e: logger.debug("Slack reactions_add failed: {}", e) + # Thread-scoped session key for channel/group messages + session_key = f"slack:{chat_id}:{thread_ts}" if thread_ts and channel_type != "im" else None + try: await self._handle_message( sender_id=sender_id, @@ -189,7 +192,8 @@ class SlackChannel(BaseChannel): "event": event, "thread_ts": thread_ts, "channel_type": channel_type, - } + }, + "session_key": session_key, }, ) except Exception: