diff --git a/docs/tasks/TASK_PHASE_AGENT_PRESENCE_INDICATORS_MVP.md b/docs/tasks/TASK_PHASE_AGENT_PRESENCE_INDICATORS_MVP.md new file mode 100644 index 00000000..5aa25b64 --- /dev/null +++ b/docs/tasks/TASK_PHASE_AGENT_PRESENCE_INDICATORS_MVP.md @@ -0,0 +1,286 @@ +# TASK PHASE — AGENT PRESENCE INDICATORS (MVP) + +Version: 1.0 +Status: ACTIVE +Target: DAARION.space (Next.js frontend + city-service) + +## 1. Мета + +Реалізувати **Presence Indicators** для всіх агентів у МВП: +- Online/Offline статус з Matrix presence +- DAGI Router heartbeat індикатори +- Візуальні бейджі у всіх місцях де відображаються агенти + +Правило онтології: +> Агенти мають бути **"живими"** — їх статус має бути видимим завжди + +--- + +## 2. Область робіт + +### 2.1. Сторінки де потрібні Presence Indicators + +1. **Agent List** (`/agents`) — кожен агент у списку +2. **Agent Cabinet** (`/agents/:agentId`) — основний статус агента +3. **Node Dashboard** (`/nodes/:nodeId`) — Node Core Agents (Guardian/Steward) +4. **MicroDAO Dashboard** (`/microdao/:slug`) — Orchestrator + team agents +5. **City Dashboard** (`/city`) — civic agents (DAARWIZZ, DARIO, DARIA) + +### 2.2. Типи Presence + +#### Matrix Presence +- `online` — користувач активний (зелений) +- `unavailable` — користувач неактивний >5 хв (жовтий) +- `offline` — користувач офлайн (сірий) + +#### DAGI Router Presence +- `healthy` — DAGI router відповідає (зелений) +- `degraded` — проблеми з router (жовтий) +- `offline` — router недоступний (червоний) + +--- + +## 3. Backend Implementation + +### 3.1. Додати Presence API + +Додати до `services/city-service/routes_city.py`: + +```python +@api_router.get("/agents/presence") +async def get_agents_presence(): + """ + Отримати presence статус всіх активних агентів. + """ + try: + # Get agents from DB + agents = await repo_city.list_agents_summaries(limit=1000) + + # Get Matrix presence from matrix-presence-aggregator + matrix_presence = await get_matrix_presence_status() + + # Get DAGI router health + dagi_health = await get_dagi_router_health() + + # Combine data + presence_data = [] + for agent in agents: + matrix_status = matrix_presence.get(agent["id"], "offline") + dagi_status = dagi_health.get(agent["node_id"], {}).get("router_status", "unknown") + + presence_data.append({ + "agent_id": agent["id"], + "matrix_presence": matrix_status, + "dagi_router_presence": dagi_status, + "last_seen": matrix_presence.get(f"{agent['id']}_last_seen"), + "node_id": agent.get("node_id") + }) + + return {"presence": presence_data} + except Exception as e: + logger.error(f"Failed to get agents presence: {e}") + raise HTTPException(status_code=500, detail="Failed to get agents presence") +``` + +### 3.2. Інтегрувати з існуючими Presence системами + +Використати: +- `matrix-presence-aggregator` для Matrix presence +- `city-service/presence_gateway.py` для forwarding +- `usePresenceHeartbeat` hook для client-side heartbeats + +--- + +## 4. Frontend Implementation + +### 4.1. Presence Hook + +Створити `apps/web/src/hooks/useAgentPresence.ts`: + +```typescript +interface AgentPresence { + agent_id: string; + matrix_presence: 'online' | 'unavailable' | 'offline'; + dagi_router_presence: 'healthy' | 'degraded' | 'offline' | 'unknown'; + last_seen?: string; + node_id?: string; +} + +export function useAgentPresence(agentIds?: string[]) { + const [presenceData, setPresenceData] = useState>({}); + + // Fetch presence data + const fetchPresence = useCallback(async () => { + try { + const params = agentIds ? `?agent_ids=${agentIds.join(',')}` : ''; + const res = await fetch(`/api/v1/agents/presence${params}`); + const data = await res.json(); + setPresenceData(data.presence); + } catch (error) { + console.error('Failed to fetch agent presence:', error); + } + }, [agentIds]); + + // Auto-refresh every 30 seconds + useEffect(() => { + fetchPresence(); + const interval = setInterval(fetchPresence, 30000); + return () => clearInterval(interval); + }, [fetchPresence]); + + return presenceData; +} +``` + +### 4.2. Presence Badge Component + +Створити `apps/web/src/components/ui/AgentPresenceBadge.tsx`: + +```typescript +interface AgentPresenceBadgeProps { + agentId: string; + size?: 'sm' | 'md' | 'lg'; + showLabel?: boolean; + className?: string; +} + +export function AgentPresenceBadge({ + agentId, + size = 'sm', + showLabel = false, + className +}: AgentPresenceBadgeProps) { + const presenceData = useAgentPresence([agentId]); + const presence = presenceData[agentId]; + + if (!presence) return null; + + const getStatusInfo = () => { + const matrixStatus = presence.matrix_presence; + const dagiStatus = presence.dagi_router_presence; + + // Priority: Matrix status, then DAGI status + if (matrixStatus === 'online') { + return { color: 'bg-emerald-500', label: 'Online' }; + } else if (matrixStatus === 'unavailable') { + return { color: 'bg-amber-500', label: 'Away' }; + } else if (dagiStatus === 'healthy') { + return { color: 'bg-blue-500', label: 'Healthy' }; + } else if (dagiStatus === 'degraded') { + return { color: 'bg-orange-500', label: 'Degraded' }; + } else if (dagiStatus === 'offline') { + return { color: 'bg-red-500', label: 'Offline' }; + } else { + return { color: 'bg-gray-500', label: 'Unknown' }; + } + }; + + const statusInfo = getStatusInfo(); + const sizeClasses = { + sm: 'w-2 h-2', + md: 'w-3 h-3', + lg: 'w-4 h-4' + }; + + return ( +
+
+ {showLabel && ( + {statusInfo.label} + )} +
+ ); +} +``` + +### 4.3. Інтеграція в Agent Cards + +Додати Presence Badge до `apps/web/src/components/agent/AgentCard.tsx`: + +```typescript +// Inside AgentCard component + +``` + +--- + +## 5. Acceptance Criteria + +1. **Agent List** (`/agents`) + - Кожен агент має presence indicator у правому верхньому куті аватара + - Зеленый = online, Жовтий = away, Сірий = offline + - Індикатор оновлюється в реальному часі + +2. **Agent Cabinet** (`/agents/:agentId`) + - Великий presence badge у заголовку + - Показує обидва статуси: Matrix + DAGI Router + - Індикатор "Last seen: 5 min ago" + +3. **Node Dashboard** (`/nodes/:nodeId`) + - Guardian/Steward агенти мають presence indicators + - Показується DAGI router статус ноди + +4. **MicroDAO Dashboard** (`/microdao/:slug`) + - Orchestrator агент має presence indicator + - Team agents мають presence indicators + +5. **Real-time Updates** + - Presence оновлюється автоматично кожні 30 секунд + - Не блокує рендеринг якщо API недоступне + +--- + +## 6. Файли до створення + +### Backend +- `services/city-service/routes_presence.py` — presence API endpoints +- Інтеграція з `matrix-presence-aggregator` +- Інтеграція з DAGI router health checks + +### Frontend +- `apps/web/src/hooks/useAgentPresence.ts` — presence hook +- `apps/web/src/components/ui/AgentPresenceBadge.tsx` — presence badge component +- Інтеграція в усі agent-related компоненти + +### Конфігурація +- Додати presence API до Next.js rewrites +- Оновити presence gateway для forwarding agent presence + +--- + +## 7. Тестування + +```bash +# Перевірити API +curl https://daarion.space/api/v1/agents/presence + +# Перевірити UI +# Відкрити /agents - подивитися на presence indicators +# Відкрити /agents/daarwizz - подивитися на великий badge +# Відкрити /nodes/node-1-hetzner-gex44 - presence для Guardian +``` + +--- + +## 8. Подальше розширення (не в цьому MVP) + +- Agent typing indicators у кімнатах +- Agent "working on task" статус +- Presence history & analytics +- Push notifications для presence changes +- Agent availability scheduling + +--- + +**Target Date**: Today +**Priority**: High (core UX improvement) +**Dependencies**: Matrix presence aggregator, DAGI router health API