Luxx/luxx/services/participant.py

129 lines
4.8 KiB
Python

"""Participant Service - unified service for users and agents in chat rooms."""
import logging
from typing import Dict, Any, Optional, AsyncGenerator
from luxx.agents.base import BaseAgent
from luxx.agents.registry import agent_registry
from luxx.models.participant import Participant
from luxx.services.room import chat_room_service
logger = logging.getLogger(__name__)
class ParticipantService:
"""Unified service for managing participants in chat rooms."""
def __init__(self):
self._active_agents: Dict[str, BaseAgent] = {}
self._active_users: Dict[int, Any] = {}
def _cm(self):
"""Lazy import connection manager."""
from luxx.services.room_ws import connection_manager
return connection_manager
# ==================== Agent ====================
def register_agent(self, agent: BaseAgent) -> Participant:
self._active_agents[agent.agent_id] = agent
agent_registry.register(agent)
return Participant.from_agent(
agent.agent_id, agent.name, agent.role, agent.avatar,
agent.auto_response, agent.mention_trigger, agent.priority
)
def unregister_agent(self, agent_id: str) -> bool:
if agent_id in self._active_agents:
del self._active_agents[agent_id]
agent_registry.unregister(agent_id)
return True
return False
def get_agent_participant(self, agent_id: str) -> Optional[Participant]:
agent = self._active_agents.get(agent_id) or chat_room_service.get_agent(agent_id)
if agent:
if agent_id not in self._active_agents:
self._active_agents[agent_id] = agent
return Participant.from_agent(
agent.agent_id, agent.name, agent.role, agent.avatar,
agent.auto_response, agent.mention_trigger, agent.priority
)
return None
# ==================== User ====================
def register_user(self, user) -> Participant:
self._active_users[user.id] = user
return Participant.from_user(user)
def get_user_participant(self, user_id: int) -> Optional[Participant]:
user = self._active_users.get(user_id)
if not user:
from luxx.core.database import SessionLocal
from luxx.models.user import User
db = SessionLocal()
try:
user = db.query(User).filter(User.id == user_id).first()
if user:
self._active_users[user_id] = user
finally:
db.close()
return Participant.from_user(user) if user else None
# ==================== Unified ====================
def get_participant(self, participant_id: str, ptype: str = "user") -> Optional[Participant]:
if ptype == "agent":
return self.get_agent_participant(participant_id)
try:
return self.get_user_participant(int(participant_id))
except (ValueError, TypeError):
return None
# ==================== Messages ====================
async def process_message(
self, room_id: str, content: str, sender_id: str,
sender_name: str, sender_type: str = "user", context: Dict = None
) -> AsyncGenerator[Dict[str, Any], None]:
cm = self._cm()
msg = chat_room_service.save_message(room_id, sender_type, sender_id, sender_name, content)
await cm.broadcast_to_room(room_id, {"event": "message", "data": msg})
room_agents = chat_room_service.get_room_agents(room_id)
if sender_type == "agent":
room_agents = [a for a in room_agents if a.agent_id != sender_id]
for agent in room_agents:
await cm.broadcast_to_room(room_id, {
"event": "typing",
"data": {"agent_id": agent.agent_id, "agent_name": agent.name, "is_typing": True}
})
ctx = (context or {})
ctx.update({"sender_type": sender_type, "sender_id": sender_id, "username": sender_name})
async for event in chat_room_service.process_message(room_id, content, sender_id, sender_name, ctx):
yield event
for agent in room_agents:
await cm.broadcast_to_room(room_id, {
"event": "typing",
"data": {"agent_id": agent.agent_id, "agent_name": agent.name, "is_typing": False}
})
async def send_message(
self, room_id: str, participant_id: str,
participant_type: str, participant_name: str, content: str
):
cm = self._cm()
msg = chat_room_service.save_message(
room_id, participant_type, participant_id, participant_name, content
)
await cm.broadcast_to_room(room_id, {"event": "message", "data": msg})
return msg
participant_service = ParticipantService()