refactor(agent-office): extend useAgentManager with lotto agent and refresh triggers

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-27 08:38:04 +09:00
parent 6bd6cbd635
commit 22a37cf6d9

View File

@@ -1,81 +1,84 @@
// 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({});
const [pendingTasks, setPendingTasks] = useState([]);
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 [notifications, setNotifications] = useState({});
const [refreshTrigger, setRefreshTrigger] = useState(0); // 탭 데이터 리프레시용
const wsRef = useRef(null);
const reconnectTimer = useRef(null);
const reconnectRef = useRef(null);
const connect = useCallback(() => {
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = `${protocol}//${window.location.host}/api/agent-office/ws`;
const ws = new WebSocket(wsUrl);
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);
if (reconnectTimer.current) clearTimeout(reconnectTimer.current);
};
ws.onopen = () => setConnected(true);
ws.onclose = () => {
setConnected(false);
reconnectTimer.current = setTimeout(connect, 3000);
};
ws.onerror = () => { ws.close(); };
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
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 };
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, taskId: msg.task_id },
[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':
setAgents(prev => ({
...prev,
[msg.agent]: { ...prev[msg.agent], lastResult: msg.result },
}));
setPendingTasks(prev => prev.filter(id => id !== msg.task_id));
break;
case 'command_result':
setAgents(prev => ({
...prev,
[msg.agent]: { ...prev[msg.agent], lastCommand: msg.result },
}));
setRefreshTrigger(n => n + 1);
break;
case 'notification':
setNotifications(prev => ({
...prev,
[msg.agent]: (prev[msg.agent] || 0) + 1,
[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 (reconnectTimer.current) clearTimeout(reconnectTimer.current);
if (reconnectRef.current) clearTimeout(reconnectRef.current);
};
}, [connect]);
@@ -92,12 +95,17 @@ export function useAgentManager() {
}, []);
const clearNotifications = useCallback((agentId) => {
setNotifications(prev => {
const next = { ...prev };
delete next[agentId];
return next;
});
setNotifications(prev => ({ ...prev, [agentId]: 0 }));
}, []);
return { agents, pendingTasks, connected, notifications, sendCommand, sendApproval, clearNotifications };
return {
agents,
pendingTasks,
notifications,
connected,
refreshTrigger,
sendCommand,
sendApproval,
clearNotifications
};
}