Spaces:
Paused
Paused
| /** | |
| * Autonomous MCP Router | |
| * | |
| * Handles autonomous query routing with AI-powered source selection | |
| */ | |
| import { Router } from 'express'; | |
| import { getCognitiveMemory } from './memory/CognitiveMemory.js'; | |
| import { AutonomousAgent, startAutonomousLearning } from './autonomous/AutonomousAgent.js'; | |
| import { getSourceRegistry } from './SourceRegistry.js'; | |
| import { getDatabase } from '../database/index.js'; | |
| import { eventBus } from './EventBus.js'; | |
| import { hybridSearchEngine } from './cognitive/HybridSearchEngine.js'; | |
| import { emotionAwareDecisionEngine } from './cognitive/EmotionAwareDecisionEngine.js'; | |
| import { unifiedMemorySystem } from './cognitive/UnifiedMemorySystem.js'; | |
| import { unifiedGraphRAG } from './cognitive/UnifiedGraphRAG.js'; | |
| import { stateGraphRouter } from './cognitive/StateGraphRouter.js'; | |
| import { patternEvolutionEngine } from './cognitive/PatternEvolutionEngine.js'; | |
| import { agentTeam } from './cognitive/AgentTeam.js'; | |
| // WebSocket server for real-time events (will be injected) | |
| let wsServer: any = null; | |
| // Agent instance (declared before setWebSocketServer to avoid race condition) | |
| let agent: AutonomousAgent | null = null; | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // AUTONOMOUS RESPONSE SYSTEM - The Missing Link | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| interface AutonomousProposal { | |
| id: string; | |
| action: string; | |
| confidence: number; | |
| reasoning: string; | |
| suggestedParams: Record<string, any>; | |
| createdAt: Date; | |
| status: 'pending' | 'approved' | 'rejected' | 'executed'; | |
| } | |
| // Loop protection | |
| const recentResponses: Map<string, number> = new Map(); | |
| const RESPONSE_COOLDOWN_MS = 30000; // 30 seconds between same event types | |
| const MAX_DEPTH = 3; // Maximum nested autonomous actions | |
| let currentDepth = 0; | |
| // Store proposals for user approval | |
| const pendingProposals: Map<string, AutonomousProposal> = new Map(); | |
| /** | |
| * THE AUTONOMOUS LINK - Triggers autonomous response based on events | |
| * | |
| * Decision flow: | |
| * 1. Analyze incoming event | |
| * 2. Use AgentTeam/EmotionAware engine to decide action | |
| * 3. If confidence > 0.8 β Execute automatically | |
| * 4. If confidence < 0.8 β Create proposal for user | |
| */ | |
| async function triggerAutonomousResponse( | |
| event: any, | |
| agentInstance: AutonomousAgent | |
| ): Promise<void> { | |
| const eventType = event.type || 'unknown'; | |
| const eventKey = `${eventType}:${JSON.stringify(event.payload || {}).substring(0, 100)}`; | |
| // Loop protection: Check cooldown | |
| const lastResponse = recentResponses.get(eventKey); | |
| if (lastResponse && Date.now() - lastResponse < RESPONSE_COOLDOWN_MS) { | |
| console.log(`β³ Autonomous response on cooldown for: ${eventType}`); | |
| return; | |
| } | |
| // Loop protection: Check depth | |
| if (currentDepth >= MAX_DEPTH) { | |
| console.log(`π Max autonomous depth reached (${MAX_DEPTH}), stopping chain`); | |
| return; | |
| } | |
| currentDepth++; | |
| recentResponses.set(eventKey, Date.now()); | |
| try { | |
| console.log(`π€ Autonomous Response triggered for: ${eventType}`); | |
| // Step 1: Analyze event and determine action | |
| const decision = await analyzeEventAndDecide(event); | |
| // Step 2: Route based on confidence | |
| if (decision.confidence >= 0.8) { | |
| // High confidence - execute automatically | |
| console.log(`β Auto-executing (confidence: ${decision.confidence.toFixed(2)}): ${decision.action}`); | |
| await executeAutonomousAction(decision, agentInstance); | |
| eventBus.emit('agent.decision', { | |
| type: 'agent.decision', | |
| timestamp: new Date().toISOString(), | |
| source: 'autonomousRouter', | |
| payload: { | |
| event: eventType, | |
| decision: decision.action, | |
| confidence: decision.confidence, | |
| autoExecuted: true | |
| } | |
| }); | |
| } else { | |
| // Low confidence - create proposal for user | |
| console.log(`π Creating proposal (confidence: ${decision.confidence.toFixed(2)}): ${decision.action}`); | |
| const proposal = createProposal(decision); | |
| pendingProposals.set(proposal.id, proposal); | |
| eventBus.emit('agent.decision', { | |
| type: 'agent.decision', | |
| timestamp: new Date().toISOString(), | |
| source: 'autonomousRouter', | |
| payload: { | |
| event: eventType, | |
| decision: decision.action, | |
| confidence: decision.confidence, | |
| autoExecuted: false, | |
| proposalId: proposal.id | |
| } | |
| }); | |
| // Notify via WebSocket if available | |
| if (wsServer) { | |
| wsServer.broadcast?.({ | |
| type: 'autonomous:proposal', | |
| proposal | |
| }); | |
| } | |
| } | |
| } catch (error) { | |
| console.error('β Autonomous response error:', error); | |
| } finally { | |
| currentDepth--; | |
| } | |
| } | |
| /** | |
| * Analyze event and decide on action using cognitive systems | |
| */ | |
| async function analyzeEventAndDecide(event: any): Promise<{ | |
| action: string; | |
| confidence: number; | |
| reasoning: string; | |
| params: Record<string, any>; | |
| }> { | |
| const eventType = event.type || 'unknown'; | |
| const payload = event.payload || {}; | |
| // Use emotion-aware decision engine for analysis | |
| try { | |
| const emotionResult = await emotionAwareDecisionEngine.makeDecision( | |
| `analyze_event: ${eventType} ${JSON.stringify(payload)}`, | |
| { userId: 'system', orgId: 'autonomous' } | |
| ); | |
| if (emotionResult.action) { | |
| return { | |
| action: `${emotionResult.action.complexity}_action`, | |
| confidence: emotionResult.confidence || 0.5, | |
| reasoning: emotionResult.reasoning || 'Emotion-aware analysis', | |
| params: {} | |
| }; | |
| } | |
| } catch { | |
| // Fallback to rule-based decisions | |
| } | |
| // Rule-based fallback decisions | |
| return getDefaultDecision(eventType, payload); | |
| } | |
| /** | |
| * Default rule-based decisions for known event types | |
| */ | |
| function getDefaultDecision(eventType: string, payload: any): { | |
| action: string; | |
| confidence: number; | |
| reasoning: string; | |
| params: Record<string, any>; | |
| } { | |
| switch (eventType) { | |
| case 'system.alert': | |
| if (payload.severity === 'critical') { | |
| return { | |
| action: 'notify_and_escalate', | |
| confidence: 0.9, | |
| reasoning: 'Critical system alert requires immediate attention', | |
| params: { channel: 'all', priority: 'high' } | |
| }; | |
| } | |
| return { | |
| action: 'log_and_monitor', | |
| confidence: 0.85, | |
| reasoning: 'Non-critical alert, logging for monitoring', | |
| params: { logLevel: 'warn' } | |
| }; | |
| case 'security.alert': | |
| return { | |
| action: 'security_response', | |
| confidence: payload.severity === 'critical' ? 0.95 : 0.7, | |
| reasoning: 'Security event detected, initiating response protocol', | |
| params: { isolate: payload.severity === 'critical', investigate: true } | |
| }; | |
| case 'data:ingested': | |
| return { | |
| action: 'process_and_index', | |
| confidence: 0.9, | |
| reasoning: 'New data ingested, processing for knowledge graph', | |
| params: { source: payload.source, count: payload.count } | |
| }; | |
| case 'threat:detected': | |
| return { | |
| action: 'threat_analysis', | |
| confidence: 0.85, | |
| reasoning: 'Potential threat detected, running analysis', | |
| params: { threatType: payload.type, indicators: payload.indicators } | |
| }; | |
| default: | |
| return { | |
| action: 'observe_and_learn', | |
| confidence: 0.5, | |
| reasoning: 'Unknown event type, observing for pattern learning', | |
| params: { eventType, payload } | |
| }; | |
| } | |
| } | |
| /** | |
| * Execute autonomous action | |
| */ | |
| async function executeAutonomousAction( | |
| decision: { action: string; params: Record<string, any>; reasoning: string }, | |
| agentInstance: AutonomousAgent | |
| ): Promise<void> { | |
| const { action, params, reasoning } = decision; | |
| console.log(`π Executing: ${action} - ${reasoning}`); | |
| switch (action) { | |
| case 'notify_and_escalate': | |
| eventBus.emit('system.alert', { | |
| type: 'system.alert', | |
| timestamp: new Date().toISOString(), | |
| source: 'autonomous', | |
| payload: { message: reasoning, ...params } | |
| }); | |
| break; | |
| case 'log_and_monitor': | |
| console.log(`[AUTONOMOUS MONITOR] ${reasoning}`); | |
| break; | |
| case 'security_response': | |
| // Route to security agent in AgentTeam | |
| await agentTeam.routeMessage({ | |
| from: 'autonomous' as any, | |
| to: 'sentinel' as any, | |
| type: 'task', | |
| content: JSON.stringify({ action: 'investigate', ...params }), | |
| metadata: { reasoning }, | |
| timestamp: new Date() | |
| }); | |
| break; | |
| case 'process_and_index': | |
| // Trigger GraphRAG indexing | |
| await unifiedGraphRAG.query(`Index new data from ${params.source}`, { | |
| userId: 'system', | |
| orgId: 'autonomous' | |
| }); | |
| break; | |
| case 'threat_analysis': | |
| await agentTeam.coordinate({ | |
| type: 'threat_analysis', | |
| params | |
| } as any, { autoExecute: true }); | |
| break; | |
| case 'observe_and_learn': | |
| // Store pattern for learning - use working memory update | |
| await unifiedMemorySystem.updateWorkingMemory( | |
| { userId: 'system', orgId: 'autonomous' }, | |
| { event: `Observed: ${JSON.stringify(params)}`, action } | |
| ); | |
| break; | |
| default: | |
| console.log(`β οΈ Unknown action: ${action}`); | |
| } | |
| } | |
| /** | |
| * Create proposal for user approval | |
| */ | |
| function createProposal(decision: { | |
| action: string; | |
| confidence: number; | |
| reasoning: string; | |
| params: Record<string, any>; | |
| }): AutonomousProposal { | |
| return { | |
| id: `proposal_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`, | |
| action: decision.action, | |
| confidence: decision.confidence, | |
| reasoning: decision.reasoning, | |
| suggestedParams: decision.params, | |
| createdAt: new Date(), | |
| status: 'pending' | |
| }; | |
| } | |
| /** | |
| * Get pending proposals | |
| */ | |
| export function getPendingProposals(): AutonomousProposal[] { | |
| return Array.from(pendingProposals.values()).filter(p => p.status === 'pending'); | |
| } | |
| /** | |
| * Approve and execute a proposal | |
| */ | |
| export async function approveProposal(proposalId: string): Promise<boolean> { | |
| const proposal = pendingProposals.get(proposalId); | |
| if (!proposal || proposal.status !== 'pending') return false; | |
| proposal.status = 'approved'; | |
| if (agent) { | |
| await executeAutonomousAction({ | |
| action: proposal.action, | |
| params: proposal.suggestedParams, | |
| reasoning: proposal.reasoning | |
| }, agent); | |
| proposal.status = 'executed'; | |
| } | |
| return true; | |
| } | |
| /** | |
| * Reject a proposal | |
| */ | |
| export function rejectProposal(proposalId: string): boolean { | |
| const proposal = pendingProposals.get(proposalId); | |
| if (!proposal || proposal.status !== 'pending') return false; | |
| proposal.status = 'rejected'; | |
| return true; | |
| } | |
| export function setWebSocketServer(server: any): void { | |
| wsServer = server; | |
| // Update agent instance if it already exists | |
| if (agent) { | |
| agent.setWebSocketServer(server); | |
| } | |
| } | |
| export const autonomousRouter = Router(); | |
| // Re-export for convenience | |
| export { startAutonomousLearning }; | |
| /** | |
| * Initialize agent (called from main server) | |
| */ | |
| export function initAutonomousAgent(): AutonomousAgent { | |
| if (agent) return agent; | |
| const memory = getCognitiveMemory(); | |
| const registry = getSourceRegistry(); | |
| agent = new AutonomousAgent(memory, registry, wsServer); | |
| // Listen to system events - THE AUTONOMOUS LINK | |
| eventBus.onEvent('system.alert', async (event) => { | |
| if (agent) { | |
| await triggerAutonomousResponse(event, agent); | |
| } | |
| }); | |
| // Also listen to security alerts | |
| eventBus.onEvent('security.alert', async (event) => { | |
| if (agent) { | |
| await triggerAutonomousResponse(event, agent); | |
| } | |
| }); | |
| console.log('π€ Autonomous Agent initialized'); | |
| return agent; | |
| } | |
| /** | |
| * Autonomous query endpoint | |
| */ | |
| autonomousRouter.post('/query', async (req, res) => { | |
| if (!agent) { | |
| return res.status(503).json({ | |
| success: false, | |
| error: 'Autonomous agent not initialized' | |
| }); | |
| } | |
| try { | |
| const query = req.body; | |
| // Execute with autonomous routing | |
| const result = await agent.executeAndLearn(query, async (source) => { | |
| // Simple executor - calls source.query | |
| if ('query' in source && typeof source.query === 'function') { | |
| return await source.query(query.operation, query.params); | |
| } | |
| throw new Error(`Source ${source.name} does not support query operation`); | |
| }); | |
| res.json({ | |
| success: true, | |
| data: result.data, | |
| meta: { | |
| source: result.source, | |
| latency: result.latencyMs, | |
| cached: result.cached, | |
| timestamp: result.timestamp | |
| } | |
| }); | |
| } catch (error: any) { | |
| console.error('Autonomous query error:', error); | |
| res.status(500).json({ | |
| success: false, | |
| error: error.message | |
| }); | |
| } | |
| }); | |
| /** | |
| * Get agent statistics | |
| */ | |
| autonomousRouter.get('/stats', async (req, res) => { | |
| if (!agent) { | |
| return res.status(503).json({ error: 'Agent not initialized' }); | |
| } | |
| try { | |
| const stats = await agent.getStats(); | |
| res.json(stats); | |
| } catch (error: any) { | |
| res.status(500).json({ error: error.message }); | |
| } | |
| }); | |
| /** | |
| * Trigger predictive pre-fetch for a widget | |
| */ | |
| autonomousRouter.post('/prefetch/:widgetId', async (req, res) => { | |
| if (!agent) { | |
| return res.status(503).json({ error: 'Agent not initialized' }); | |
| } | |
| try { | |
| const { widgetId } = req.params; | |
| await agent.predictAndPrefetch(widgetId); | |
| res.json({ | |
| success: true, | |
| message: `Pre-fetch triggered for ${widgetId}` | |
| }); | |
| } catch (error: any) { | |
| res.status(500).json({ error: error.message }); | |
| } | |
| }); | |
| /** | |
| * List available sources | |
| */ | |
| autonomousRouter.get('/sources', async (req, res) => { | |
| try { | |
| const registry = getSourceRegistry(); | |
| const sources = registry.getAllSources(); | |
| const sourcesInfo = await Promise.all( | |
| sources.map(async (source) => { | |
| try { | |
| const health = await source.isHealthy(); | |
| return { | |
| name: source.name, | |
| type: source.type, | |
| capabilities: source.capabilities, | |
| healthy: health, | |
| estimatedLatency: source.estimatedLatency, | |
| costPerQuery: source.costPerQuery | |
| }; | |
| } catch { | |
| return { | |
| name: source.name, | |
| type: source.type, | |
| capabilities: source.capabilities, | |
| healthy: false, | |
| estimatedLatency: source.estimatedLatency, | |
| costPerQuery: source.costPerQuery | |
| }; | |
| } | |
| }) | |
| ); | |
| res.json({ sources: sourcesInfo }); | |
| } catch (error: any) { | |
| res.status(500).json({ error: error.message }); | |
| } | |
| }); | |
| /** | |
| * Get system health | |
| */ | |
| /** | |
| * Get decision history | |
| */ | |
| autonomousRouter.get('/decisions', async (req, res) => { | |
| try { | |
| const db = getDatabase(); | |
| const limit = parseInt(req.query.limit as string) || 50; | |
| const stmt = db.prepare(` | |
| SELECT * FROM mcp_decision_log | |
| ORDER BY timestamp DESC | |
| LIMIT ? | |
| `); | |
| // Use variadic parameters for consistency with sqlite3 API | |
| const decisions = stmt.all(limit); | |
| stmt.free(); | |
| res.json({ decisions }); | |
| } catch (error: any) { | |
| res.status(500).json({ error: error.message }); | |
| } | |
| }); | |
| /** | |
| * Get learned patterns | |
| */ | |
| autonomousRouter.get('/patterns', async (req, res) => { | |
| try { | |
| const memory = getCognitiveMemory(); | |
| const widgetId = req.query.widgetId as string; | |
| if (widgetId) { | |
| const patterns = await memory.getWidgetPatterns(widgetId); | |
| res.json({ patterns }); | |
| } else { | |
| // Get all patterns | |
| const db = getDatabase(); | |
| const stmt = db.prepare(` | |
| SELECT DISTINCT widget_id, query_type, source_used, | |
| AVG(latency_ms) as avg_latency, | |
| COUNT(*) as frequency | |
| FROM query_patterns | |
| GROUP BY widget_id, query_type, source_used | |
| ORDER BY frequency DESC | |
| LIMIT 100 | |
| `); | |
| const patterns = stmt.all(); | |
| stmt.free(); | |
| res.json({ patterns }); | |
| } | |
| } catch (error: any) { | |
| res.status(500).json({ error: error.message }); | |
| } | |
| }); | |
| /** | |
| * Trigger manual learning cycle | |
| */ | |
| autonomousRouter.post('/learn', async (req, res) => { | |
| if (!agent) { | |
| return res.status(503).json({ error: 'Agent not initialized' }); | |
| } | |
| try { | |
| await agent.learn(); | |
| res.json({ | |
| success: true, | |
| message: 'Learning cycle completed' | |
| }); | |
| } catch (error: any) { | |
| res.status(500).json({ error: error.message }); | |
| } | |
| }); | |
| /** | |
| * MCP Tool: Manage Project Memory | |
| * Allows autonomous agent to document its own actions | |
| */ | |
| autonomousRouter.post('/manage_project_memory', async (req, res) => { | |
| try { | |
| // Support both flat and nested param formats | |
| const action = req.body.action; | |
| const params = req.body.params || req.body; | |
| const { eventType, event_type, component_name, status, details, metadata, | |
| name, description, featureStatus, limit } = params; | |
| // Import projectMemory here to avoid circular dependency | |
| const { projectMemory } = await import('../services/project/ProjectMemory.js'); | |
| switch (action) { | |
| case 'log_event': | |
| const finalEventType = eventType || event_type; | |
| if (!finalEventType || !status) { | |
| return res.status(400).json({ error: 'event_type and status required' }); | |
| } | |
| // Merge component_name and description into details if provided | |
| const eventDetails = { | |
| ...(details || {}), | |
| ...(component_name && { component_name }), | |
| ...(description && { description }), | |
| ...(metadata && { metadata }) | |
| }; | |
| projectMemory.logLifecycleEvent({ | |
| eventType: finalEventType, | |
| status, | |
| details: eventDetails | |
| }); | |
| console.log(`β [ProjectMemory] Logged ${finalEventType} event: ${status}`); | |
| res.json({ success: true, message: 'Event logged', eventType: finalEventType }); | |
| break; | |
| case 'add_feature': | |
| const featureName = name || params.feature_name; | |
| const featureDesc = description; | |
| const featureStat = featureStatus || params.status; | |
| if (!featureName || !featureDesc || !featureStat) { | |
| return res.status(400).json({ | |
| error: 'feature_name, description, and status required', | |
| received: { name: featureName, description: featureDesc, status: featureStat } | |
| }); | |
| } | |
| projectMemory.addFeature({ | |
| name: featureName, | |
| description: featureDesc, | |
| status: featureStat | |
| }); | |
| console.log(`β [ProjectMemory] Added feature: ${featureName} (${featureStat})`); | |
| res.json({ success: true, message: 'Feature added', featureName }); | |
| break; | |
| case 'query_history': | |
| const queryLimit = limit || params.limit || 50; | |
| const events = projectMemory.getLifecycleEvents(queryLimit); | |
| res.json({ success: true, events, count: events.length }); | |
| break; | |
| case 'update_feature': | |
| if (!name || !featureStatus) { | |
| return res.status(400).json({ error: 'name and featureStatus required' }); | |
| } | |
| projectMemory.updateFeatureStatus(name, featureStatus); | |
| console.log(`β [ProjectMemory] Updated feature: ${name} β ${featureStatus}`); | |
| res.json({ success: true, message: 'Feature updated' }); | |
| break; | |
| default: | |
| res.status(400).json({ | |
| error: 'Invalid action', | |
| validActions: ['log_event', 'add_feature', 'query_history', 'update_feature'], | |
| received: { action, params } | |
| }); | |
| } | |
| } catch (error: any) { | |
| console.error('β [ProjectMemory] Error:', error); | |
| res.status(500).json({ error: error.message, stack: error.stack }); | |
| } | |
| }); | |
| /** | |
| * Hybrid search endpoint | |
| */ | |
| autonomousRouter.post('/search', async (req, res) => { | |
| try { | |
| const { query, limit, filters } = req.body; | |
| const userId = (req as any).user?.id || 'anonymous'; | |
| const orgId = (req as any).user?.orgId || 'default'; | |
| if (!query) { | |
| return res.status(400).json({ error: 'Query is required' }); | |
| } | |
| const results = await hybridSearchEngine.search(query, { | |
| userId, | |
| orgId, | |
| timestamp: new Date(), | |
| limit: limit || 20, | |
| filters: filters || {} | |
| }); | |
| res.json({ | |
| success: true, | |
| results, | |
| count: results.length | |
| }); | |
| } catch (error: any) { | |
| console.error('Hybrid search error:', error); | |
| res.status(500).json({ | |
| success: false, | |
| error: error.message | |
| }); | |
| } | |
| }); | |
| /** | |
| * Emotion-aware decision endpoint | |
| */ | |
| autonomousRouter.post('/decision', async (req, res) => { | |
| try { | |
| const query = req.body; | |
| const userId = (req as any).user?.id || 'anonymous'; | |
| const orgId = (req as any).user?.orgId || 'default'; | |
| const decision = await emotionAwareDecisionEngine.makeDecision(query, { | |
| userId, | |
| orgId | |
| }); | |
| res.json({ | |
| success: true, | |
| decision | |
| }); | |
| } catch (error: any) { | |
| console.error('Emotion-aware decision error:', error); | |
| res.status(500).json({ | |
| success: false, | |
| error: error.message | |
| }); | |
| } | |
| }); | |
| /** | |
| * GraphRAG endpoint - Multi-hop reasoning over knowledge graph | |
| */ | |
| autonomousRouter.post('/graphrag', async (req, res) => { | |
| try { | |
| const { query, maxHops, context } = req.body; | |
| const userId = (req as any).user?.id || context?.userId || 'anonymous'; | |
| const orgId = (req as any).user?.orgId || context?.orgId || 'default'; | |
| if (!query) { | |
| return res.status(400).json({ error: 'Query is required' }); | |
| } | |
| const result = await unifiedGraphRAG.query(query, { | |
| userId, | |
| orgId | |
| }); | |
| res.json({ | |
| success: true, | |
| result, | |
| query, | |
| maxHops: maxHops || 2 | |
| }); | |
| } catch (error: any) { | |
| console.error('GraphRAG error:', error); | |
| res.status(500).json({ | |
| success: false, | |
| error: error.message | |
| }); | |
| } | |
| }); | |
| /** | |
| * StateGraphRouter endpoint - LangGraph-style state routing | |
| */ | |
| autonomousRouter.post('/stategraph', async (req, res) => { | |
| try { | |
| const { taskId, input } = req.body; | |
| if (!taskId || !input) { | |
| return res.status(400).json({ error: 'taskId and input are required' }); | |
| } | |
| // Initialize state | |
| const state = stateGraphRouter.initState(taskId, input); | |
| // Route until completion | |
| let currentState = state; | |
| let iterations = 0; | |
| const maxIterations = 20; | |
| while (currentState.status === 'active' && iterations < maxIterations) { | |
| currentState = await stateGraphRouter.route(currentState); | |
| iterations++; | |
| } | |
| res.json({ | |
| success: true, | |
| state: currentState, | |
| iterations, | |
| checkpoints: stateGraphRouter.getCheckpoints(taskId) | |
| }); | |
| } catch (error: any) { | |
| console.error('StateGraphRouter error:', error); | |
| res.status(500).json({ | |
| success: false, | |
| error: error.message | |
| }); | |
| } | |
| }); | |
| /** | |
| * PatternEvolutionEngine endpoint - Strategy evolution | |
| */ | |
| autonomousRouter.post('/evolve', async (req, res) => { | |
| try { | |
| await patternEvolutionEngine.evolveStrategies(); | |
| const currentStrategy = patternEvolutionEngine.getCurrentStrategy(); | |
| const history = patternEvolutionEngine.getEvolutionHistory(); | |
| res.json({ | |
| success: true, | |
| currentStrategy, | |
| history: history.slice(0, 10), // Last 10 evolutions | |
| message: 'Evolution cycle completed' | |
| }); | |
| } catch (error: any) { | |
| console.error('PatternEvolution error:', error); | |
| res.status(500).json({ | |
| success: false, | |
| error: error.message | |
| }); | |
| } | |
| }); | |
| /** | |
| * Get current evolution strategy | |
| */ | |
| autonomousRouter.get('/evolution/strategy', async (req, res) => { | |
| try { | |
| const strategy = patternEvolutionEngine.getCurrentStrategy(); | |
| const history = patternEvolutionEngine.getEvolutionHistory(); | |
| res.json({ | |
| success: true, | |
| current: strategy, | |
| history: history.slice(0, 20) | |
| }); | |
| } catch (error: any) { | |
| res.status(500).json({ | |
| success: false, | |
| error: error.message | |
| }); | |
| } | |
| }); | |
| /** | |
| * AgentTeam endpoint - Route message to role-based agents | |
| */ | |
| autonomousRouter.post('/agentteam', async (req, res) => { | |
| try { | |
| const { from, to, type, content, metadata } = req.body; | |
| const userId = (req as any).user?.id || metadata?.userId || 'anonymous'; | |
| const orgId = (req as any).user?.orgId || metadata?.orgId || 'default'; | |
| if (!content) { | |
| return res.status(400).json({ error: 'content is required' }); | |
| } | |
| const message = { | |
| from: from || 'user', | |
| to: to || 'all', | |
| type: type || 'query', | |
| content, | |
| metadata: { ...metadata, userId, orgId }, | |
| timestamp: new Date() | |
| }; | |
| const result = await agentTeam.routeMessage(message); | |
| res.json({ | |
| success: true, | |
| result, | |
| message | |
| }); | |
| } catch (error: any) { | |
| console.error('AgentTeam error:', error); | |
| res.status(500).json({ | |
| success: false, | |
| error: error.message | |
| }); | |
| } | |
| }); | |
| /** | |
| * AgentTeam coordination endpoint - Complex multi-agent tasks | |
| */ | |
| autonomousRouter.post('/agentteam/coordinate', async (req, res) => { | |
| try { | |
| const { task, context } = req.body; | |
| if (!task) { | |
| return res.status(400).json({ error: 'task is required' }); | |
| } | |
| const result = await agentTeam.coordinate(task, context); | |
| res.json({ | |
| success: true, | |
| result | |
| }); | |
| } catch (error: any) { | |
| console.error('AgentTeam coordination error:', error); | |
| res.status(500).json({ | |
| success: false, | |
| error: error.message | |
| }); | |
| } | |
| }); | |
| /** | |
| * Get AgentTeam status | |
| */ | |
| autonomousRouter.get('/agentteam/status', async (req, res) => { | |
| try { | |
| const statuses = await agentTeam.getAllStatuses(); | |
| res.json({ | |
| success: true, | |
| agents: statuses, | |
| totalAgents: statuses.length, | |
| activeAgents: statuses.filter(s => s.active).length | |
| }); | |
| } catch (error: any) { | |
| res.status(500).json({ | |
| success: false, | |
| error: error.message | |
| }); | |
| } | |
| }); | |
| /** | |
| * Get PAL agent conversation history | |
| */ | |
| autonomousRouter.get('/agentteam/pal/history', async (req, res) => { | |
| try { | |
| const palAgent = agentTeam.getAgent('pal'); | |
| if (!palAgent) { | |
| return res.status(404).json({ error: 'PAL agent not found' }); | |
| } | |
| // Access conversation history if available | |
| const history = (palAgent as any).getConversationHistory?.() || []; | |
| res.json({ | |
| success: true, | |
| history, | |
| count: history.length | |
| }); | |
| } catch (error: any) { | |
| res.status(500).json({ | |
| success: false, | |
| error: error.message | |
| }); | |
| } | |
| }); | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| // PROPOSAL MANAGEMENT ENDPOINTS | |
| // βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| /** | |
| * Get pending autonomous proposals | |
| */ | |
| autonomousRouter.get('/proposals', async (req, res) => { | |
| try { | |
| const proposals = getPendingProposals(); | |
| res.json({ | |
| success: true, | |
| proposals, | |
| count: proposals.length | |
| }); | |
| } catch (error: any) { | |
| res.status(500).json({ success: false, error: error.message }); | |
| } | |
| }); | |
| /** | |
| * Approve a proposal | |
| */ | |
| autonomousRouter.post('/proposals/:id/approve', async (req, res) => { | |
| try { | |
| const success = await approveProposal(req.params.id); | |
| if (success) { | |
| res.json({ success: true, message: 'Proposal approved and executed' }); | |
| } else { | |
| res.status(404).json({ success: false, error: 'Proposal not found or already processed' }); | |
| } | |
| } catch (error: any) { | |
| res.status(500).json({ success: false, error: error.message }); | |
| } | |
| }); | |
| /** | |
| * Reject a proposal | |
| */ | |
| autonomousRouter.post('/proposals/:id/reject', async (req, res) => { | |
| try { | |
| const success = rejectProposal(req.params.id); | |
| if (success) { | |
| res.json({ success: true, message: 'Proposal rejected' }); | |
| } else { | |
| res.status(404).json({ success: false, error: 'Proposal not found or already processed' }); | |
| } | |
| } catch (error: any) { | |
| res.status(500).json({ success: false, error: error.message }); | |
| } | |
| }); | |
| /** | |
| * Get system health with cognitive analysis | |
| */ | |
| autonomousRouter.get('/health', async (req, res) => { | |
| try { | |
| const registry = getSourceRegistry(); | |
| const sources = registry.getAllSources(); | |
| const sourceHealth = await Promise.all( | |
| sources.map(async (source) => { | |
| try { | |
| const healthy = await source.isHealthy(); | |
| return { | |
| name: source.name, | |
| healthy, | |
| score: healthy ? 1.0 : 0.0 | |
| }; | |
| } catch { | |
| return { | |
| name: source.name, | |
| healthy: false, | |
| score: 0.0 | |
| }; | |
| } | |
| }) | |
| ); | |
| const healthyCount = sourceHealth.filter(s => s.healthy).length; | |
| const totalCount = sourceHealth.length; | |
| // Get cognitive system health | |
| const cognitiveHealth = await unifiedMemorySystem.analyzeSystemHealth(); | |
| res.json({ | |
| status: healthyCount > 0 ? 'healthy' : 'unhealthy', | |
| healthySourcesCount: healthyCount, | |
| totalSourcesCount: totalCount, | |
| sources: sourceHealth, | |
| cognitive: { | |
| globalHealth: cognitiveHealth.globalHealth, | |
| componentHealth: cognitiveHealth.componentHealth, | |
| wholePartRatio: cognitiveHealth.wholePartRatio, | |
| healthVariance: cognitiveHealth.healthVariance | |
| } | |
| }); | |
| } catch (error: any) { | |
| res.status(500).json({ | |
| status: 'error', | |
| error: error.message | |
| }); | |
| } | |
| }); | |