from __future__ import annotations from abc import ABC, abstractmethod from typing import TYPE_CHECKING from yuxi.channels.models import SessionScope if TYPE_CHECKING: from yuxi.channels.models import ChannelMessage class SessionRouter(ABC): def __init__(self, channel_type: str, account_id: str = "default"): self.channel_type = channel_type self.account_id = account_id @abstractmethod def resolve_thread_key(self, message: ChannelMessage) -> str: """解析消息对应的线程键""" @abstractmethod def resolve_chat_id(self, message: ChannelMessage) -> str: """解析聊天ID""" @abstractmethod def resolve_session_scope(self, message: ChannelMessage) -> SessionScope: """解析会话范围级别""" @abstractmethod def normalize_target(self, target: str) -> str: """标准化目标地址""" def resolve_agent_route(self, message: ChannelMessage) -> str: thread_key = self.resolve_thread_key(message) scope = self.resolve_session_scope(message) return f"agent:main:{thread_key}:{scope.value}" def _build_key(self, scope: str, type_str: str, id_str: str) -> str: return f"{self.channel_type}:{self.account_id}:{scope}:{type_str}:{id_str}" class BaseSessionRouter(SessionRouter): def normalize_target(self, target: str) -> str: if target.startswith(f"{self.channel_type}:"): return target return f"{self.channel_type}:{target}" def resolve_thread_key(self, message: ChannelMessage) -> str: identity = message.identity chat_type = message.chat_type.value if hasattr(message.chat_type, "value") else str(message.chat_type) return self._build_key("chat", chat_type, identity.channel_chat_id) def resolve_chat_id(self, message: ChannelMessage) -> str: return message.identity.channel_chat_id def resolve_session_scope(self, message: ChannelMessage) -> SessionScope: from yuxi.channels.models import ChatType chat_type = message.chat_type if chat_type == ChatType.DIRECT: return SessionScope.DIRECT if chat_type == ChatType.THREAD: return SessionScope.THREAD return SessionScope.GROUP