/** * SAAP Agent Store - Pinia State Management * Centralized state management for SAAP agents and system */ import { defineStore } from 'pinia' import { ref, reactive, computed } from 'vue' import { useApi, type SaapAgent, type ChatMessage, type SystemStatus } from '@/composables/useApi' import { useWebSocket } from '@/composables/useWebSocket' interface AgentOperation { agentId: string operation: 'starting' | 'stopping' | 'chatting' timestamp: string } interface NotificationMessage { id: string type: 'success' | 'error' | 'info' | 'warning' title: string message: string timestamp: string duration?: number } export const useAgentStore = defineStore('agents', () => { // API and WebSocket composables const api = useApi() const ws = useWebSocket() // ===================================================== // STATE // ===================================================== const agents = ref([]) const selectedAgent = ref(null) const systemStatus = ref(null) const chatHistory = ref([]) const activeOperations = ref([]) const notifications = ref([]) // Loading states const loading = reactive({ agents: false, systemStatus: false, operations: false }) // Connection status const connectionStatus = reactive({ api: false, websocket: false, lastCheck: null as string | null }) // ===================================================== // COMPUTED // ===================================================== const activeAgents = computed(() => agents.value.filter(agent => agent.status === 'active') ) const inactiveAgents = computed(() => agents.value.filter(agent => agent.status === 'inactive') ) const agentsByType = computed(() => { const grouped: Record = {} agents.value.forEach(agent => { if (!grouped[agent.type]) { grouped[agent.type] = [] } grouped[agent.type].push(agent) }) return grouped }) const totalMessages = computed(() => agents.value.reduce((total, agent) => total + (agent.metrics?.messages_processed || 0), 0 ) ) const averageResponseTime = computed(() => { const responseTimes = agents.value .map(agent => agent.metrics?.average_response_time) .filter((time): time is number => time !== undefined && time > 0) if (responseTimes.length === 0) return 0 return responseTimes.reduce((sum, time) => sum + time, 0) / responseTimes.length }) const isOperationActive = computed(() => (agentId: string, operation: string) => { return activeOperations.value.some( op => op.agentId === agentId && op.operation === operation ) }) // ===================================================== // AGENT MANAGEMENT ACTIONS // ===================================================== const fetchAgents = async (): Promise => { try { loading.agents = true const result = await api.getAgents() if (result) { agents.value = result showNotification({ type: 'success', title: 'Agents Loaded', message: `Loaded ${result.length} agents successfully`, }) return true } return false } catch (error) { showNotification({ type: 'error', title: 'Load Failed', message: 'Failed to load agents from server', }) return false } finally { loading.agents = false } } const selectAgent = async (agentId: string): Promise => { const agent = agents.value.find(a => a.id === agentId) if (agent) { selectedAgent.value = agent return true } // Try to fetch from API if not found locally const result = await api.getAgent(agentId) if (result) { selectedAgent.value = result return true } return false } const updateAgentInStore = (updatedAgent: SaapAgent) => { const index = agents.value.findIndex(a => a.id === updatedAgent.id) if (index !== -1) { agents.value[index] = updatedAgent // Update selected agent if it's the same if (selectedAgent.value?.id === updatedAgent.id) { selectedAgent.value = updatedAgent } } } // ===================================================== // AGENT LIFECYCLE ACTIONS // ===================================================== const startAgent = async (agentId: string): Promise => { try { addOperation(agentId, 'starting') const result = await api.startAgent(agentId) if (result?.success) { // Update agent status immediately const agent = agents.value.find(a => a.id === agentId) if (agent) { agent.status = 'starting' } showNotification({ type: 'success', title: 'Agent Starting', message: `${result.agent?.name || agentId} is starting...`, }) // Refresh agents after a short delay to get updated status setTimeout(() => { fetchAgents() }, 2000) return true } return false } catch (error) { showNotification({ type: 'error', title: 'Start Failed', message: `Failed to start agent ${agentId}`, }) return false } finally { removeOperation(agentId, 'starting') } } const stopAgent = async (agentId: string): Promise => { try { addOperation(agentId, 'stopping') const result = await api.stopAgent(agentId) if (result?.success) { // Update agent status immediately const agent = agents.value.find(a => a.id === agentId) if (agent) { agent.status = 'inactive' } showNotification({ type: 'info', title: 'Agent Stopped', message: `Agent ${agentId} stopped successfully`, }) return true } return false } catch (error) { showNotification({ type: 'error', title: 'Stop Failed', message: `Failed to stop agent ${agentId}`, }) return false } finally { removeOperation(agentId, 'stopping') } } // ===================================================== // AGENT COMMUNICATION ACTIONS // ===================================================== const chatWithAgent = async (agentId: string, message: string): Promise => { try { addOperation(agentId, 'chatting') const result = await api.chatWithAgent(agentId, message) if (result) { // Add to chat history chatHistory.value.push(result) // Update agent metrics const agent = agents.value.find(a => a.id === agentId) if (agent && agent.metrics) { agent.metrics.messages_processed = (agent.metrics.messages_processed || 0) + 1 if (result.response_time) { agent.metrics.average_response_time = result.response_time } } showNotification({ type: 'success', title: 'Message Sent', message: `Received response from ${result.agent_name || agentId}`, duration: 3000 }) return result } return null } catch (error) { showNotification({ type: 'error', title: 'Chat Failed', message: `Failed to chat with agent ${agentId}`, }) return null } finally { removeOperation(agentId, 'chatting') } } const getChatHistory = (agentId?: string): ChatMessage[] => { if (agentId) { return chatHistory.value.filter(msg => msg.agent_id === agentId) } return chatHistory.value } // ===================================================== // SYSTEM STATUS ACTIONS // ===================================================== const fetchSystemStatus = async (): Promise => { try { loading.systemStatus = true const result = await api.getSystemStatus() if (result) { systemStatus.value = result connectionStatus.api = true connectionStatus.lastCheck = new Date().toISOString() return true } connectionStatus.api = false return false } catch (error) { connectionStatus.api = false return false } finally { loading.systemStatus = false } } const testConnections = async (): Promise => { // Test API connection connectionStatus.api = await api.testConnection() // Test WebSocket connection if (!ws.connectionStatus.connected) { connectionStatus.websocket = await ws.connect() } else { connectionStatus.websocket = true } connectionStatus.lastCheck = new Date().toISOString() showNotification({ type: connectionStatus.api && connectionStatus.websocket ? 'success' : 'warning', title: 'Connection Test', message: `API: ${connectionStatus.api ? 'Connected' : 'Failed'}, WebSocket: ${connectionStatus.websocket ? 'Connected' : 'Failed'}`, }) } // ===================================================== // OPERATIONS TRACKING // ===================================================== const addOperation = (agentId: string, operation: AgentOperation['operation']) => { activeOperations.value.push({ agentId, operation, timestamp: new Date().toISOString() }) } const removeOperation = (agentId: string, operation: AgentOperation['operation']) => { const index = activeOperations.value.findIndex( op => op.agentId === agentId && op.operation === operation ) if (index !== -1) { activeOperations.value.splice(index, 1) } } // ===================================================== // NOTIFICATIONS // ===================================================== const showNotification = (notification: Omit) => { const id = Date.now().toString() + Math.random().toString(36).substr(2, 9) const fullNotification: NotificationMessage = { ...notification, id, timestamp: new Date().toISOString(), duration: notification.duration || 5000 } notifications.value.push(fullNotification) // Auto-remove notification after duration if (fullNotification.duration && fullNotification.duration > 0) { setTimeout(() => { removeNotification(id) }, fullNotification.duration) } } const removeNotification = (id: string) => { const index = notifications.value.findIndex(n => n.id === id) if (index !== -1) { notifications.value.splice(index, 1) } } const clearNotifications = () => { notifications.value = [] } // ===================================================== // WEBSOCKET INTEGRATION // ===================================================== const initializeWebSocket = () => { // Subscribe to agent updates ws.subscribeToAgentUpdates((agentData: any) => { console.log('🤖 Agent update received:', agentData) if (agentData.agent) { updateAgentInStore(agentData.agent) } }) // Subscribe to message updates ws.subscribeToMessageUpdates((messageData: any) => { console.log('💬 Message update received:', messageData) if (messageData.agent_id) { // Add to chat history if not already present const exists = chatHistory.value.some( msg => msg.timestamp === messageData.timestamp && msg.agent_id === messageData.agent_id ) if (!exists) { chatHistory.value.push(messageData) } } }) // Subscribe to system updates ws.subscribeToSystemUpdates((statusData: any) => { console.log('🔧 System update received:', statusData) if (statusData.agents) { systemStatus.value = statusData } }) // Connect WebSocket ws.connect().then(connected => { connectionStatus.websocket = connected if (connected) { ws.startHeartbeat() } }) } // ===================================================== // INITIALIZATION // ===================================================== const initialize = async (): Promise => { console.log('🚀 Initializing SAAP Agent Store...') // Initialize WebSocket initializeWebSocket() // Fetch initial data await fetchSystemStatus() await fetchAgents() console.log('✅ SAAP Agent Store initialized') } // ===================================================== // CLEANUP // ===================================================== const cleanup = () => { ws.disconnect() ws.stopHeartbeat() agents.value = [] selectedAgent.value = null chatHistory.value = [] activeOperations.value = [] notifications.value = [] } return { // State agents, selectedAgent, systemStatus, chatHistory, activeOperations, notifications, loading, connectionStatus, // Computed activeAgents, inactiveAgents, agentsByType, totalMessages, averageResponseTime, isOperationActive, // Agent Management fetchAgents, selectAgent, updateAgentInStore, // Agent Lifecycle startAgent, stopAgent, // Communication chatWithAgent, getChatHistory, // System fetchSystemStatus, testConnections, // Notifications showNotification, removeNotification, clearNotifications, // Lifecycle initialize, cleanup, } }) // Export types export type { AgentOperation, NotificationMessage }