Files
microdao-daarion/services/agents-service/agent_router.py
Apple 3de3c8cb36 feat: Add presence heartbeat for Matrix online status
- 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
2025-11-27 00:19:40 -08:00

149 lines
4.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
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}"
}