diff --git a/nanobot/channels/dingtalk.py b/nanobot/channels/dingtalk.py index 72199fdf9..4be3ccb97 100644 --- a/nanobot/channels/dingtalk.py +++ b/nanobot/channels/dingtalk.py @@ -160,6 +160,7 @@ class DingTalkConfig(Base): allow_from: list[str] = Field(default_factory=list) allow_remote_media_redirects: bool = False remote_media_redirect_allowed_hosts: list[str] = Field(default_factory=list) + group_user_isolation: bool = False # If True, each user in group chat gets their own session class DingTalkChannel(BaseChannel): @@ -693,6 +694,9 @@ class DingTalkChannel(BaseChannel): self.logger.info("inbound: {} from {}", content, sender_name) is_group = conversation_type == "2" and conversation_id chat_id = f"group:{conversation_id}" if is_group else sender_id + session_key = None + if is_group and self.config.group_user_isolation: + session_key = f"{self.name}:group:{conversation_id}:{sender_id}" await self._handle_message( sender_id=sender_id, chat_id=chat_id, @@ -702,6 +706,7 @@ class DingTalkChannel(BaseChannel): "platform": "dingtalk", "conversation_type": conversation_type, }, + session_key=session_key, ) except Exception: self.logger.exception("Error publishing message") diff --git a/tests/channels/test_dingtalk_channel.py b/tests/channels/test_dingtalk_channel.py index f14c81302..d36759431 100644 --- a/tests/channels/test_dingtalk_channel.py +++ b/tests/channels/test_dingtalk_channel.py @@ -98,6 +98,55 @@ async def test_group_message_keeps_sender_id_and_routes_chat_id() -> None: assert msg.metadata["conversation_type"] == "2" +@pytest.mark.asyncio +async def test_group_user_isolation_false_uses_shared_session() -> None: + """By default group messages share the same session_key.""" + config = DingTalkConfig( + client_id="app", client_secret="secret", allow_from=["*"], group_user_isolation=False + ) + bus = MessageBus() + channel = DingTalkChannel(config, bus) + + for user_id in ("user1", "user2"): + await channel._on_message( + "hello", + sender_id=user_id, + sender_name=user_id, + conversation_type="2", + conversation_id="conv123", + ) + + msg1 = await bus.consume_inbound() + msg2 = await bus.consume_inbound() + assert msg1.session_key == msg2.session_key == "dingtalk:group:conv123" + assert msg1.chat_id == msg2.chat_id == "group:conv123" + + +@pytest.mark.asyncio +async def test_group_user_isolation_true_separates_sessions() -> None: + """When group_user_isolation is True, each user gets their own session_key.""" + config = DingTalkConfig( + client_id="app", client_secret="secret", allow_from=["*"], group_user_isolation=True + ) + bus = MessageBus() + channel = DingTalkChannel(config, bus) + + for user_id in ("user1", "user2"): + await channel._on_message( + "hello", + sender_id=user_id, + sender_name=user_id, + conversation_type="2", + conversation_id="conv123", + ) + + msg1 = await bus.consume_inbound() + msg2 = await bus.consume_inbound() + assert msg1.session_key == "dingtalk:group:conv123:user1" + assert msg2.session_key == "dingtalk:group:conv123:user2" + assert msg1.chat_id == msg2.chat_id == "group:conv123" + + @pytest.mark.asyncio async def test_group_send_uses_group_messages_api() -> None: config = DingTalkConfig(client_id="app", client_secret="secret", allow_from=["*"])