feat: complete Phase 1 MVP - add agent executor and WebSocket real-time updates
Agent Executor Service: - BaseAgent class with LLM integration via LiteLLM proxy - AgentExecutor service that processes pending executions every 5 seconds - Action execution: create_subtask, update_status, send_notification, add_comment - Approval workflow: CxO level agents require user approval before execution - Telegram notifications for approvals and completions - Error handling and execution status tracking WebSocket Real-Time Updates: - WebSocket endpoint at /ws/opc for real-time task updates - ConnectionManager for broadcasting to all connected clients - Frontend WebSocket client with auto-reconnect - Live updates for task create/update/move/delete actions - Agent execution status broadcasts Integration: - Agent executor starts on dashboard startup - Task router broadcasts WebSocket updates on all mutations - Frontend OPC page subscribes to WebSocket and updates UI in real-time - Agents (PM, CTO, COO) can now execute tasks autonomously Phase 1 MVP Complete: ✅ PostgreSQL database with full schema ✅ Task CRUD API with automatic time tracking ✅ Kanban board with drag-and-drop ✅ Agent executor service with LLM integration ✅ WebSocket real-time updates ✅ 3 core agents ready to execute Next: Agent panel UI, email notifications, PDF invoicing
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* OPC WebSocket Client - Real-time updates
|
||||
*/
|
||||
|
||||
let ws = null;
|
||||
let reconnectTimer = null;
|
||||
let listeners = new Set();
|
||||
|
||||
export function connect() {
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
return;
|
||||
}
|
||||
|
||||
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
||||
const wsUrl = `${protocol}//${window.location.host}/ws/opc`;
|
||||
|
||||
ws = new WebSocket(wsUrl);
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log("OPC WebSocket connected");
|
||||
if (reconnectTimer) {
|
||||
clearTimeout(reconnectTimer);
|
||||
reconnectTimer = null;
|
||||
}
|
||||
|
||||
// Send ping every 30 seconds to keep connection alive
|
||||
const pingInterval = setInterval(() => {
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
ws.send("ping");
|
||||
} else {
|
||||
clearInterval(pingInterval);
|
||||
}
|
||||
}, 30000);
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
try {
|
||||
const message = JSON.parse(event.data);
|
||||
notifyListeners(message);
|
||||
} catch (e) {
|
||||
console.error("Failed to parse WebSocket message:", e);
|
||||
}
|
||||
};
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error("WebSocket error:", error);
|
||||
};
|
||||
|
||||
ws.onclose = () => {
|
||||
console.log("OPC WebSocket disconnected");
|
||||
ws = null;
|
||||
|
||||
// Reconnect after 5 seconds
|
||||
reconnectTimer = setTimeout(() => {
|
||||
console.log("Reconnecting WebSocket...");
|
||||
connect();
|
||||
}, 5000);
|
||||
};
|
||||
}
|
||||
|
||||
export function disconnect() {
|
||||
if (ws) {
|
||||
ws.close();
|
||||
ws = null;
|
||||
}
|
||||
if (reconnectTimer) {
|
||||
clearTimeout(reconnectTimer);
|
||||
reconnectTimer = null;
|
||||
}
|
||||
}
|
||||
|
||||
export function subscribe(callback) {
|
||||
listeners.add(callback);
|
||||
return () => listeners.delete(callback);
|
||||
}
|
||||
|
||||
function notifyListeners(message) {
|
||||
listeners.forEach((callback) => {
|
||||
try {
|
||||
callback(message);
|
||||
} catch (e) {
|
||||
console.error("Listener error:", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user