/** * Hook для DAGI Agent Audit та Router Agents * Отримує дані про стан агентів в контексті DAGI Router */ import useSWR from 'swr'; // Types export interface DAGIAuditSummary { node_id: string; timestamp: string; router_total: number; db_total: number; active_count: number; phantom_count: number; stale_count: number; triggered_by?: string; } export interface DAGIActiveAgent { router_id: string; router_name: string; db_id: string; db_name: string; db_external_id?: string; kind?: string; status: string; } export interface DAGIPhantomAgent { router_id: string; router_name: string; description?: string; reason: string; } export interface DAGIStaleAgent { db_id: string; db_name: string; db_external_id?: string; kind?: string; reason: string; } export interface DAGIAuditFull { summary: DAGIAuditSummary; active_agents: DAGIActiveAgent[]; phantom_agents: DAGIPhantomAgent[]; stale_agents: DAGIStaleAgent[]; report_data?: unknown; } export interface DAGIAuditHistory { node_id: string; history: DAGIAuditSummary[]; } // Router Agents Types (for Table) export interface DAGIRouterAgent { id: string; name: string; role?: string; status: 'active' | 'phantom' | 'stale' | 'error'; node_id?: string; models: string[]; gpu?: string; cpu?: string; last_seen_at?: string; has_cabinet: boolean; cabinet_slug?: string; description?: string; has_prompts?: boolean; // Чи є системні промти в БД } export interface DAGIRouterAgentsSummary { active: number; phantom: number; stale: number; router_total: number; system_total: number; } export interface DAGIRouterAgentsResponse { node_id: string; last_audit_at?: string; summary: DAGIRouterAgentsSummary; agents: DAGIRouterAgent[]; } // Node Metrics Types export interface NodeMetrics { node_id: string; node_name?: string; hostname?: string; status?: string; environment?: string; cpu_model?: string; cpu_cores: number; cpu_usage: number; gpu_model?: string; gpu_memory_total: number; gpu_memory_used: number; ram_total: number; ram_used: number; disk_total: number; disk_used: number; agent_count_router: number; agent_count_system: number; last_heartbeat?: string; } // API URL const CITY_SERVICE_URL = process.env.NEXT_PUBLIC_CITY_SERVICE_URL || ''; // Fetcher const fetcher = async (url: string) => { const res = await fetch(url); if (!res.ok) { if (res.status === 404) return null; throw new Error(`Failed to fetch: ${res.status}`); } return res.json(); }; /** * Отримати останній DAGI audit summary */ export function useDAGIAuditSummary(nodeId: string | undefined) { const { data, error, isLoading, mutate } = useSWR( nodeId ? `${CITY_SERVICE_URL}/city/internal/node/${nodeId}/dagi-audit` : null, fetcher, { refreshInterval: 60000, // Оновлювати кожну хвилину revalidateOnFocus: false } ); return { summary: data, isLoading, error, refresh: mutate }; } /** * Отримати повний DAGI audit з деталями */ export function useDAGIAuditFull(nodeId: string | undefined) { const { data, error, isLoading, mutate } = useSWR( nodeId ? `${CITY_SERVICE_URL}/city/internal/node/${nodeId}/dagi-audit/full` : null, fetcher, { refreshInterval: 60000, revalidateOnFocus: false } ); return { audit: data, isLoading, error, refresh: mutate }; } /** * Отримати агентів DAGI Router для таблиці */ export function useDAGIRouterAgents(nodeId: string | undefined) { const { data, error, isLoading, mutate } = useSWR( nodeId ? `${CITY_SERVICE_URL}/city/internal/node/${nodeId}/dagi-router/agents` : null, fetcher, { refreshInterval: 30000, // Оновлювати кожні 30 сек revalidateOnFocus: true } ); return { data, agents: data?.agents || [], summary: data?.summary || { active: 0, phantom: 0, stale: 0, router_total: 0, system_total: 0 }, lastAuditAt: data?.last_audit_at, isLoading, error, refresh: mutate }; } /** * Отримати історію DAGI audits */ export function useDAGIAuditHistory(nodeId: string | undefined, limit: number = 10) { const { data, error, isLoading } = useSWR( nodeId ? `${CITY_SERVICE_URL}/city/internal/node/${nodeId}/dagi-audit/history?limit=${limit}` : null, fetcher ); return { history: data?.history || [], isLoading, error }; } /** * Отримати метрики ноди */ export function useNodeMetrics(nodeId: string | undefined) { const { data, error, isLoading, mutate } = useSWR( nodeId ? `${CITY_SERVICE_URL}/city/internal/node/${nodeId}/metrics/current` : null, fetcher, { refreshInterval: 30000, revalidateOnFocus: true } ); return { metrics: data, isLoading, error, refresh: mutate }; } /** * Запустити DAGI audit */ export async function runDAGIAudit(nodeId: string): Promise<{ status: string; report_id: string; summary: { router_total: number; db_total: number; active_count: number; phantom_count: number; stale_count: number; }; message: string; }> { const res = await fetch( `${CITY_SERVICE_URL}/city/internal/node/${nodeId}/dagi-audit/run`, { method: 'POST', headers: { 'Content-Type': 'application/json' } } ); if (!res.ok) { const err = await res.json().catch(() => ({ detail: 'Unknown error' })); throw new Error(err.detail || 'Failed to run audit'); } return res.json(); } /** * Синхронізувати phantom агентів (створити в БД) */ export async function syncPhantomAgents( nodeId: string, agentIds: string[] ): Promise<{ status: string; created_count: number; created_agents: Array<{ id: string; name: string; external_id: string }>; }> { const res = await fetch( `${CITY_SERVICE_URL}/city/internal/node/${nodeId}/dagi-router/phantom/sync`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ agent_ids: agentIds }) } ); if (!res.ok) { const err = await res.json().catch(() => ({ detail: 'Unknown error' })); throw new Error(err.detail || 'Failed to sync phantom agents'); } return res.json(); } /** * Позначити агентів як stale */ export async function markStaleAgents( nodeId: string, agentIds: string[] ): Promise<{ status: string; marked_count: number; }> { const res = await fetch( `${CITY_SERVICE_URL}/city/internal/node/${nodeId}/dagi-router/stale/mark`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ agent_ids: agentIds }) } ); if (!res.ok) { const err = await res.json().catch(() => ({ detail: 'Unknown error' })); throw new Error(err.detail || 'Failed to mark stale agents'); } return res.json(); } // ============================================================================= // Node Agents API // ============================================================================= export interface NodeAgent { id: string; name: string; slug?: string; kind?: string; role?: string; status: string; dagi_status?: string; last_seen_at?: string; is_guardian: boolean; is_steward: boolean; } export interface NodeAgentsResponse { node_id: string; total: number; guardian?: NodeAgent; steward?: NodeAgent; agents: NodeAgent[]; } /** * Отримати агентів ноди (Guardian, Steward, runtime agents) */ export function useNodeAgents(nodeId: string | undefined) { const { data, error, isLoading, mutate } = useSWR( nodeId ? `${CITY_SERVICE_URL}/city/internal/node/${nodeId}/agents` : null, fetcher, { refreshInterval: 60000, revalidateOnFocus: false } ); return { data, guardian: data?.guardian, steward: data?.steward, agents: data?.agents || [], total: data?.total || 0, isLoading, error, refresh: mutate }; }