- matrix-gateway: POST /internal/matrix/presence/online endpoint - usePresenceHeartbeat hook with activity tracking - Auto away after 5 min inactivity - Offline on page close/visibility change - Integrated in MatrixChatRoom component
149 lines
4.9 KiB
Python
149 lines
4.9 KiB
Python
"""
|
||
Agent Router — Маршрутизація запитів до агентів через NATS
|
||
"""
|
||
|
||
import json
|
||
from typing import Dict, Any, Optional
|
||
from datetime import datetime
|
||
from nats.aio.client import Client as NATS
|
||
from nats_helpers.publisher import NATSPublisher
|
||
|
||
class AgentRouter:
|
||
"""
|
||
Маршрутизує запити до агентів через NATS
|
||
|
||
Flow:
|
||
1. Отримати запит від користувача
|
||
2. Визначити агента
|
||
3. Опублікувати agents.invoke
|
||
4. Очікувати agents.reply або agents.error (опційно)
|
||
"""
|
||
|
||
def __init__(self, nc: NATS):
|
||
self.nc = nc
|
||
self.publisher = NATSPublisher(nc)
|
||
|
||
async def route_to_agent(
|
||
self,
|
||
agent_id: str,
|
||
channel_id: str,
|
||
message_text: str,
|
||
user_id: Optional[str] = None,
|
||
context: Optional[Dict[str, Any]] = None,
|
||
wait_for_reply: bool = False,
|
||
timeout_seconds: int = 30
|
||
) -> Optional[Dict[str, Any]]:
|
||
"""
|
||
Маршрутизувати запит до агента
|
||
|
||
Args:
|
||
agent_id: ID агента (e.g., "agent:sofia")
|
||
channel_id: ID каналу
|
||
message_text: Текст повідомлення
|
||
user_id: ID користувача (опційно)
|
||
context: Додатковий контекст (опційно)
|
||
wait_for_reply: Чи очікувати відповідь агента
|
||
timeout_seconds: Таймаут очікування відповіді
|
||
|
||
Returns:
|
||
Dict з відповіддю агента (якщо wait_for_reply=True)
|
||
"""
|
||
# Публікуємо запит
|
||
await self.publisher.publish_agent_invoke(
|
||
agent_id=agent_id,
|
||
channel_id=channel_id,
|
||
message_text=message_text,
|
||
user_id=user_id,
|
||
context=context
|
||
)
|
||
|
||
print(f"🔀 Routed to {agent_id}: {message_text[:50]}...")
|
||
|
||
# Якщо не очікуємо відповідь — повертаємо None
|
||
if not wait_for_reply:
|
||
return None
|
||
|
||
# TODO: Імплементувати Request-Reply pattern з NATS
|
||
# Наразі просто повертаємо None
|
||
# Для повної реалізації потрібно:
|
||
# 1. Створити унікальний inbox subject
|
||
# 2. Підписатися на inbox
|
||
# 3. Вказати reply-to в запиті
|
||
# 4. Очікувати відповідь з timeout
|
||
|
||
return None
|
||
|
||
async def broadcast_to_agents(
|
||
self,
|
||
agent_ids: list[str],
|
||
channel_id: str,
|
||
message_text: str,
|
||
user_id: Optional[str] = None
|
||
) -> None:
|
||
"""
|
||
Надіслати запит до кількох агентів одночасно
|
||
|
||
Args:
|
||
agent_ids: Список ID агентів
|
||
channel_id: ID каналу
|
||
message_text: Текст повідомлення
|
||
user_id: ID користувача
|
||
"""
|
||
for agent_id in agent_ids:
|
||
await self.route_to_agent(
|
||
agent_id=agent_id,
|
||
channel_id=channel_id,
|
||
message_text=message_text,
|
||
user_id=user_id,
|
||
wait_for_reply=False
|
||
)
|
||
|
||
print(f"📣 Broadcasted to {len(agent_ids)} agents")
|
||
|
||
async def route_command(
|
||
self,
|
||
command: str,
|
||
args: Optional[str],
|
||
channel_id: str,
|
||
user_id: str
|
||
) -> Dict[str, Any]:
|
||
"""
|
||
Маршрутизувати команду
|
||
|
||
Args:
|
||
command: Назва команди (без "/" або "!")
|
||
args: Аргументи команди
|
||
channel_id: ID каналу
|
||
user_id: ID користувача
|
||
|
||
Returns:
|
||
Dict з результатом виконання команди
|
||
"""
|
||
# TODO: Імплементувати обробку команд
|
||
# Наразі просто повертаємо mock відповідь
|
||
|
||
if command == "help":
|
||
return {
|
||
"success": True,
|
||
"message": "Available commands: /help, /status, /list, /agent"
|
||
}
|
||
|
||
elif command == "status":
|
||
return {
|
||
"success": True,
|
||
"message": f"System status: OK\nAgent: {args or 'all'}"
|
||
}
|
||
|
||
elif command == "list":
|
||
return {
|
||
"success": True,
|
||
"message": "Available agents: sofia, yaromir, greenfood"
|
||
}
|
||
|
||
else:
|
||
return {
|
||
"success": False,
|
||
"message": f"Unknown command: /{command}"
|
||
}
|
||
|