| |
| |
| |
| |
|
|
| 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', () => { |
| |
| const api = useApi() |
| const ws = useWebSocket() |
| |
| |
| |
| |
| |
| const agents = ref<SaapAgent[]>([]) |
| const selectedAgent = ref<SaapAgent | null>(null) |
| const systemStatus = ref<SystemStatus | null>(null) |
| const chatHistory = ref<ChatMessage[]>([]) |
| const activeOperations = ref<AgentOperation[]>([]) |
| const notifications = ref<NotificationMessage[]>([]) |
| |
| |
| const loading = reactive({ |
| agents: false, |
| systemStatus: false, |
| operations: false |
| }) |
| |
| |
| const connectionStatus = reactive({ |
| api: false, |
| websocket: false, |
| lastCheck: null as string | null |
| }) |
| |
| |
| |
| |
| |
| 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<string, SaapAgent[]> = {} |
| 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 |
| ) |
| }) |
| |
| |
| |
| |
| |
| const fetchAgents = async (): Promise<boolean> => { |
| 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<boolean> => { |
| const agent = agents.value.find(a => a.id === agentId) |
| if (agent) { |
| selectedAgent.value = agent |
| return true |
| } |
| |
| |
| 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 |
| |
| |
| if (selectedAgent.value?.id === updatedAgent.id) { |
| selectedAgent.value = updatedAgent |
| } |
| } |
| } |
| |
| |
| |
| |
| |
| const startAgent = async (agentId: string): Promise<boolean> => { |
| try { |
| addOperation(agentId, 'starting') |
| |
| const result = await api.startAgent(agentId) |
| |
| if (result?.success) { |
| |
| 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...`, |
| }) |
| |
| |
| 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<boolean> => { |
| try { |
| addOperation(agentId, 'stopping') |
| |
| const result = await api.stopAgent(agentId) |
| |
| if (result?.success) { |
| |
| 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') |
| } |
| } |
| |
| |
| |
| |
| |
| const chatWithAgent = async (agentId: string, message: string): Promise<ChatMessage | null> => { |
| try { |
| addOperation(agentId, 'chatting') |
| |
| const result = await api.chatWithAgent(agentId, message) |
| |
| if (result) { |
| |
| chatHistory.value.push(result) |
| |
| |
| 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 |
| } |
| |
| |
| |
| |
| |
| const fetchSystemStatus = async (): Promise<boolean> => { |
| 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<void> => { |
| |
| connectionStatus.api = await api.testConnection() |
| |
| |
| 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'}`, |
| }) |
| } |
| |
| |
| |
| |
| |
| 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) |
| } |
| } |
| |
| |
| |
| |
| |
| const showNotification = (notification: Omit<NotificationMessage, 'id' | 'timestamp'>) => { |
| 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) |
| |
| |
| 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 = [] |
| } |
| |
| |
| |
| |
| |
| const initializeWebSocket = () => { |
| |
| ws.subscribeToAgentUpdates((agentData: any) => { |
| console.log('🤖 Agent update received:', agentData) |
| |
| if (agentData.agent) { |
| updateAgentInStore(agentData.agent) |
| } |
| }) |
| |
| |
| ws.subscribeToMessageUpdates((messageData: any) => { |
| console.log('💬 Message update received:', messageData) |
| |
| if (messageData.agent_id) { |
| |
| const exists = chatHistory.value.some( |
| msg => msg.timestamp === messageData.timestamp && |
| msg.agent_id === messageData.agent_id |
| ) |
| |
| if (!exists) { |
| chatHistory.value.push(messageData) |
| } |
| } |
| }) |
| |
| |
| ws.subscribeToSystemUpdates((statusData: any) => { |
| console.log('🔧 System update received:', statusData) |
| |
| if (statusData.agents) { |
| systemStatus.value = statusData |
| } |
| }) |
| |
| |
| ws.connect().then(connected => { |
| connectionStatus.websocket = connected |
| if (connected) { |
| ws.startHeartbeat() |
| } |
| }) |
| } |
| |
| |
| |
| |
| |
| const initialize = async (): Promise<void> => { |
| console.log('🚀 Initializing SAAP Agent Store...') |
| |
| |
| initializeWebSocket() |
| |
| |
| await fetchSystemStatus() |
| await fetchAgents() |
| |
| console.log('✅ SAAP Agent Store initialized') |
| } |
| |
| |
| |
| |
| |
| const cleanup = () => { |
| ws.disconnect() |
| ws.stopHeartbeat() |
| agents.value = [] |
| selectedAgent.value = null |
| chatHistory.value = [] |
| activeOperations.value = [] |
| notifications.value = [] |
| } |
| |
| return { |
| |
| agents, |
| selectedAgent, |
| systemStatus, |
| chatHistory, |
| activeOperations, |
| notifications, |
| loading, |
| connectionStatus, |
| |
| |
| activeAgents, |
| inactiveAgents, |
| agentsByType, |
| totalMessages, |
| averageResponseTime, |
| isOperationActive, |
| |
| |
| fetchAgents, |
| selectAgent, |
| updateAgentInStore, |
| |
| |
| startAgent, |
| stopAgent, |
| |
| |
| chatWithAgent, |
| getChatHistory, |
| |
| |
| fetchSystemStatus, |
| testConnections, |
| |
| |
| showNotification, |
| removeNotification, |
| clearNotifications, |
| |
| |
| initialize, |
| cleanup, |
| } |
| }) |
|
|
| |
| export type { AgentOperation, NotificationMessage } |