"""Session routing for Synology Chat conversations. Routes incoming messages to agent sessions based on chat type (direct/group), user identity, and account for multi-account isolation. DM sessions are keyed by userId to prevent cross-user session confusion in shared DM channels. Group sessions are keyed by chat_id since group context is shared among all members in the same group. Identity links allow mapping between different representations of the same user (e.g. webhook user_id ↔ DSM API user_id). """ from __future__ import annotations from yuxi.channels.models import ChannelMessage, ChatType DEFAULT_ACCOUNT_ID = "default" def resolve_session_route( msg: ChannelMessage, default_agent_id: str = "default", account_id: str = DEFAULT_ACCOUNT_ID, ) -> str: user_id = msg.identity.channel_user_id chat_id = msg.identity.channel_chat_id chat_type = msg.chat_type if chat_type == ChatType.DIRECT: return f"agent:{default_agent_id}:synologychat:{account_id}:direct:{user_id}" else: return f"agent:{default_agent_id}:synologychat:{account_id}:group:{chat_id}" def build_identity_link( user_id: str, account_id: str = DEFAULT_ACCOUNT_ID, username: str = "", chat_id: str = "", ) -> dict: return { "channel": "synologychat", "account_id": account_id, "user_id": user_id, "username": username, "chat_id": chat_id, } def resolve_identity_links( msg: ChannelMessage, account_id: str = DEFAULT_ACCOUNT_ID, ) -> list[dict]: links = [ build_identity_link( user_id=msg.identity.channel_user_id, account_id=account_id, username=msg.metadata.get("dsm_user_name", "") if msg.metadata else "", chat_id=msg.identity.channel_chat_id, ) ] forwarded_from = msg.metadata.get("forwarded_from") if msg.metadata else None if forwarded_from: links.append( build_identity_link( user_id=str(forwarded_from), account_id=account_id, chat_id=msg.identity.channel_chat_id, ) ) return links