ForcePilot/backend/package/yuxi/channel/application/service/session_resolver.py

98 lines
3.6 KiB
Python
Raw Normal View History

from __future__ import annotations
import logging
from yuxi.channel.domain.model.binding.channel_binding import ChannelBinding
from yuxi.channel.domain.model.session.channel_session import ChannelSession
from yuxi.channel.domain.repository.binding_repository import BindingRepositoryPort
from yuxi.channel.domain.repository.session_repository import SessionRepositoryPort
logger = logging.getLogger(__name__)
class SessionResolver:
def __init__(
self,
session_repo: SessionRepositoryPort,
binding_repo: BindingRepositoryPort,
*,
default_agent_config_id: int = 1,
session_key_strategy: str = "auto",
) -> None:
self._session_repo = session_repo
self._binding_repo = binding_repo
self._default_agent_config_id = default_agent_config_id
self._session_key_strategy = session_key_strategy
async def resolve(self, payload: dict) -> ChannelSession | None:
channel_type = payload["channel_type"]
sender_id = payload.get("sender_id", "")
metadata = payload.get("metadata", {})
agent_config_id = payload.get("agent_config_id")
if not agent_config_id:
agent_config_id = await self._resolve_agent_config(channel_type, metadata)
binding = await self._binding_repo.find_binding(
channel_type=channel_type,
account_id=metadata.get("account_id", ""),
group_id=metadata.get("group_id", ""),
)
session_key = self._resolve_session_key(payload, channel_type, sender_id, binding)
try:
session = await self._session_repo.get_or_create(
channel_type=channel_type,
account_id=session_key,
agent_config_id=agent_config_id,
)
return session
except Exception:
logger.exception(
"session creation failed: %s [%s]",
payload.get("message_id", ""),
payload.get("trace_id", ""),
)
return None
async def _resolve_agent_config(self, channel_type: str, metadata: dict) -> int:
binding = await self._binding_repo.find_binding(
channel_type=channel_type,
account_id=metadata.get("account_id", ""),
group_id=metadata.get("group_id", ""),
)
return binding.agent_config_id if binding else self._default_agent_config_id
def _resolve_session_key(
self, payload: dict, channel_type: str, sender_id: str, binding: ChannelBinding | None
) -> str:
metadata = payload.get("metadata", {})
if binding:
strategy = binding.resolve_session_key_strategy()
else:
strategy = metadata.get("session_key_strategy", self._session_key_strategy)
if strategy == "main":
return sender_id
elif strategy == "channel_group":
group_id = metadata.get("group_id", "")
if group_id:
return f"{sender_id}:{channel_type}:{group_id}"
return sender_id
elif strategy == "custom":
prefix = metadata.get("session_key_prefix", "")
custom_key = metadata.get("session_key", "")
if custom_key and prefix:
return f"{prefix}:{custom_key}"
elif custom_key:
return custom_key
return sender_id
else:
is_group = metadata.get("is_group", False)
if is_group:
group_id = metadata.get("group_id", "")
return f"{sender_id}:{channel_type}:{group_id}" if group_id else sender_id
return sender_id