// src/pages/agent-office/hooks/useAgentManager.js import { useState, useEffect, useRef, useCallback } from 'react'; const WS_RECONNECT_DELAY = 3000; export function useAgentManager() { const [agents, setAgents] = useState({}); // { agentId: { state, detail, task_id } } const [pendingTasks, setPendingTasks] = useState([]); // [{id, agent_id, task_type, input_data}] const [notifications, setNotifications] = useState({}); // { agentId: count } const [connected, setConnected] = useState(false); const [refreshTrigger, setRefreshTrigger] = useState(0); // 탭 데이터 리프레시용 const wsRef = useRef(null); const reconnectRef = useRef(null); const connect = useCallback(() => { const protocol = window.location.protocol === 'https:' ? 'wss' : 'ws'; const ws = new WebSocket(`${protocol}://${window.location.host}/api/agent-office/ws`); wsRef.current = ws; ws.onopen = () => setConnected(true); ws.onmessage = (e) => { const msg = JSON.parse(e.data); switch (msg.type) { case 'init': { // 에이전트 초기 상태 세팅 const agentMap = {}; for (const a of msg.agents) { agentMap[a.agent_id] = { state: a.state, detail: a.detail || '', task_id: a.task_id }; } setAgents(agentMap); setPendingTasks(msg.pending || []); break; } case 'agent_state': setAgents(prev => ({ ...prev, [msg.agent]: { state: msg.state, detail: msg.detail || '', task_id: msg.task_id } })); // idle 전환 시 데이터 리프레시 if (msg.state === 'idle') { setRefreshTrigger(n => n + 1); } break; case 'task_complete': setRefreshTrigger(n => n + 1); break; case 'notification': setNotifications(prev => ({ ...prev, [msg.agent]: (prev[msg.agent] || 0) + 1 })); break; case 'command_result': // 사이드 패널에서 처리 break; default: break; } }; ws.onclose = () => { setConnected(false); reconnectRef.current = setTimeout(connect, WS_RECONNECT_DELAY); }; ws.onerror = () => ws.close(); }, []); useEffect(() => { connect(); return () => { if (wsRef.current) wsRef.current.close(); if (reconnectRef.current) clearTimeout(reconnectRef.current); }; }, [connect]); const sendCommand = useCallback((agent, action, params = {}) => { if (wsRef.current?.readyState === WebSocket.OPEN) { wsRef.current.send(JSON.stringify({ type: 'command', agent, action, params })); } }, []); const sendApproval = useCallback((agent, taskId, approved) => { if (wsRef.current?.readyState === WebSocket.OPEN) { wsRef.current.send(JSON.stringify({ type: 'approval', agent, task_id: taskId, approved })); } }, []); const clearNotifications = useCallback((agentId) => { setNotifications(prev => ({ ...prev, [agentId]: 0 })); }, []); return { agents, pendingTasks, notifications, connected, refreshTrigger, sendCommand, sendApproval, clearNotifications }; }