"use strict"; /** * Regional Agent - Per-region agent implementation for distributed processing * * Handles: * - Region-specific initialization * - Local query processing * - Cross-region communication * - State synchronization * - Metrics reporting */ Object.defineProperty(exports, "__esModule", { value: true }); exports.RegionalAgent = void 0; const events_1 = require("events"); const child_process_1 = require("child_process"); const util_1 = require("util"); const execAsync = (0, util_1.promisify)(child_process_1.exec); class RegionalAgent extends events_1.EventEmitter { constructor(config) { super(); this.config = config; this.activeStreams = 0; this.totalQueries = 0; this.totalLatency = 0; this.localIndex = new Map(); this.syncQueue = []; this.rateLimiter = new RateLimiter({ maxRequests: config.maxConcurrentStreams, windowMs: 1000, }); this.initialize(); } /** * Initialize regional agent */ async initialize() { console.log(`[RegionalAgent:${this.config.region}] Initializing agent ${this.config.agentId}...`); if (this.config.enableClaudeFlowHooks) { try { // Pre-task hook for agent initialization await execAsync(`npx claude-flow@alpha hooks pre-task --description "Initialize regional agent ${this.config.agentId} in ${this.config.region}"`); // Restore session if available await execAsync(`npx claude-flow@alpha hooks session-restore --session-id "agent-${this.config.agentId}"`); console.log(`[RegionalAgent:${this.config.region}] Claude-flow hooks initialized`); } catch (error) { console.warn(`[RegionalAgent:${this.config.region}] Claude-flow hooks not available:`, error); } } // Load local index from storage await this.loadLocalIndex(); // Start metrics reporting this.startMetricsReporting(); // Start sync process this.startSyncProcess(); // Register with coordinator await this.registerWithCoordinator(); this.emit('agent:initialized', { agentId: this.config.agentId, region: this.config.region, }); console.log(`[RegionalAgent:${this.config.region}] Agent ${this.config.agentId} initialized successfully`); } /** * Load local index from persistent storage */ async loadLocalIndex() { try { // Placeholder for actual storage loading // In production, this would load from disk/database console.log(`[RegionalAgent:${this.config.region}] Loading local index from ${this.config.localStoragePath}`); // Simulate loading this.localIndex.clear(); console.log(`[RegionalAgent:${this.config.region}] Local index loaded: ${this.localIndex.size} vectors`); } catch (error) { console.error(`[RegionalAgent:${this.config.region}] Error loading local index:`, error); throw error; } } /** * Register with coordinator */ async registerWithCoordinator() { try { console.log(`[RegionalAgent:${this.config.region}] Registering with coordinator at ${this.config.coordinatorEndpoint}`); // In production, this would be an HTTP/gRPC call // For now, emit event this.emit('coordinator:register', { agentId: this.config.agentId, region: this.config.region, endpoint: `https://${this.config.region}.ruvector.io/agent/${this.config.agentId}`, capabilities: this.config.capabilities, capacity: this.config.maxConcurrentStreams, registeredAt: Date.now(), }); console.log(`[RegionalAgent:${this.config.region}] Successfully registered with coordinator`); } catch (error) { console.error(`[RegionalAgent:${this.config.region}] Failed to register with coordinator:`, error); throw error; } } /** * Process query request locally */ async processQuery(request) { const startTime = Date.now(); // Check rate limit if (!this.rateLimiter.tryAcquire()) { throw new Error('Rate limit exceeded'); } this.activeStreams++; this.totalQueries++; try { console.log(`[RegionalAgent:${this.config.region}] Processing query ${request.id}`); // Validate query this.validateQuery(request); // Execute vector search const matches = await this.searchVectors(request); const latency = Date.now() - startTime; this.totalLatency += latency; const result = { id: request.id, matches, latency, region: this.config.region, }; this.emit('query:completed', { queryId: request.id, latency, matchCount: matches.length, }); if (this.config.enableClaudeFlowHooks) { try { // Notify about query completion await execAsync(`npx claude-flow@alpha hooks notify --message "Query ${request.id} completed in ${latency}ms with ${matches.length} matches"`); } catch (error) { // Non-critical error } } return result; } catch (error) { console.error(`[RegionalAgent:${this.config.region}] Error processing query ${request.id}:`, error); this.emit('query:failed', { queryId: request.id, error: error instanceof Error ? error.message : 'Unknown error', }); throw error; } finally { this.activeStreams--; this.rateLimiter.release(); } } /** * Validate query request */ validateQuery(request) { if (!request.vector || request.vector.length !== this.config.vectorDimensions) { throw new Error(`Invalid vector dimensions: expected ${this.config.vectorDimensions}, got ${request.vector?.length || 0}`); } if (request.topK <= 0 || request.topK > 1000) { throw new Error(`Invalid topK value: ${request.topK} (must be between 1 and 1000)`); } } /** * Search vectors in local index */ async searchVectors(request) { // Placeholder for actual vector search // In production, this would use FAISS, Annoy, or similar library const matches = []; // Simulate vector search for (const [id, vector] of this.localIndex.entries()) { const score = this.calculateSimilarity(request.vector, vector); // Apply filters if present if (request.filters && !this.matchesFilters(vector.metadata, request.filters)) { continue; } matches.push({ id, score, metadata: vector.metadata || {}, }); } // Sort by score and return top-k matches.sort((a, b) => b.score - a.score); return matches.slice(0, request.topK); } /** * Calculate cosine similarity between vectors */ calculateSimilarity(v1, v2) { let dotProduct = 0; let norm1 = 0; let norm2 = 0; for (let i = 0; i < v1.length; i++) { dotProduct += v1[i] * v2[i]; norm1 += v1[i] * v1[i]; norm2 += v2[i] * v2[i]; } return dotProduct / (Math.sqrt(norm1) * Math.sqrt(norm2)); } /** * Check if metadata matches filters */ matchesFilters(metadata, filters) { for (const [key, value] of Object.entries(filters)) { if (metadata[key] !== value) { return false; } } return true; } /** * Add/update vectors in local index */ async indexVectors(vectors) { console.log(`[RegionalAgent:${this.config.region}] Indexing ${vectors.length} vectors`); for (const { id, vector, metadata } of vectors) { this.localIndex.set(id, { vector, metadata }); } // Queue for cross-region sync this.syncQueue.push({ type: 'index', data: vectors, timestamp: Date.now(), sourceRegion: this.config.region, }); this.emit('vectors:indexed', { count: vectors.length }); if (this.config.enableClaudeFlowHooks) { try { await execAsync(`npx claude-flow@alpha hooks post-edit --file "local-index" --memory-key "swarm/${this.config.agentId}/index-update"`); } catch (error) { // Non-critical } } } /** * Delete vectors from local index */ async deleteVectors(ids) { console.log(`[RegionalAgent:${this.config.region}] Deleting ${ids.length} vectors`); for (const id of ids) { this.localIndex.delete(id); } // Queue for cross-region sync this.syncQueue.push({ type: 'delete', data: ids, timestamp: Date.now(), sourceRegion: this.config.region, }); this.emit('vectors:deleted', { count: ids.length }); } /** * Handle sync payload from other regions */ async handleSyncPayload(payload) { // Don't process our own sync messages if (payload.sourceRegion === this.config.region) { return; } console.log(`[RegionalAgent:${this.config.region}] Received sync payload from ${payload.sourceRegion}: ${payload.type}`); try { switch (payload.type) { case 'index': await this.indexVectors(payload.data); break; case 'update': await this.indexVectors(payload.data); break; case 'delete': await this.deleteVectors(payload.data); break; } this.emit('sync:applied', { type: payload.type, sourceRegion: payload.sourceRegion, }); } catch (error) { console.error(`[RegionalAgent:${this.config.region}] Error applying sync payload:`, error); this.emit('sync:failed', { type: payload.type, sourceRegion: payload.sourceRegion, error: error instanceof Error ? error.message : 'Unknown error', }); } } /** * Start metrics reporting loop */ startMetricsReporting() { this.metricsTimer = setInterval(() => { this.reportMetrics(); }, this.config.metricsReportInterval); } /** * Report metrics to coordinator */ reportMetrics() { const metrics = { agentId: this.config.agentId, region: this.config.region, cpuUsage: this.getCpuUsage(), memoryUsage: this.getMemoryUsage(), activeStreams: this.activeStreams, queryLatency: this.totalQueries > 0 ? this.totalLatency / this.totalQueries : 0, timestamp: Date.now(), healthy: this.isHealthy(), }; this.emit('metrics:report', metrics); // Reset counters (sliding window) if (this.totalQueries > 1000) { this.totalQueries = 0; this.totalLatency = 0; } } /** * Get CPU usage (placeholder) */ getCpuUsage() { // In production, this would read from /proc/stat or similar return Math.random() * 100; } /** * Get memory usage (placeholder) */ getMemoryUsage() { // In production, this would read from process.memoryUsage() const usage = process.memoryUsage(); return (usage.heapUsed / usage.heapTotal) * 100; } /** * Check if agent is healthy */ isHealthy() { return (this.activeStreams < this.config.maxConcurrentStreams && this.getMemoryUsage() < 90 && this.getCpuUsage() < 90); } /** * Start sync process loop */ startSyncProcess() { this.syncTimer = setInterval(() => { this.processSyncQueue(); }, this.config.syncInterval); } /** * Process sync queue (send to other regions) */ async processSyncQueue() { if (this.syncQueue.length === 0) return; const batch = this.syncQueue.splice(0, 100); // Process in batches console.log(`[RegionalAgent:${this.config.region}] Processing sync batch: ${batch.length} items`); for (const payload of batch) { this.emit('sync:broadcast', payload); } } /** * Get agent status */ getStatus() { return { agentId: this.config.agentId, region: this.config.region, healthy: this.isHealthy(), activeStreams: this.activeStreams, indexSize: this.localIndex.size, syncQueueSize: this.syncQueue.length, avgQueryLatency: this.totalQueries > 0 ? this.totalLatency / this.totalQueries : 0, }; } /** * Shutdown agent gracefully */ async shutdown() { console.log(`[RegionalAgent:${this.config.region}] Shutting down agent ${this.config.agentId}...`); // Stop timers if (this.metricsTimer) { clearInterval(this.metricsTimer); } if (this.syncTimer) { clearInterval(this.syncTimer); } // Process remaining sync queue await this.processSyncQueue(); // Save local index await this.saveLocalIndex(); if (this.config.enableClaudeFlowHooks) { try { await execAsync(`npx claude-flow@alpha hooks post-task --task-id "agent-${this.config.agentId}-shutdown"`); await execAsync(`npx claude-flow@alpha hooks session-end --export-metrics true`); } catch (error) { console.warn(`[RegionalAgent:${this.config.region}] Error executing shutdown hooks:`, error); } } this.emit('agent:shutdown', { agentId: this.config.agentId, region: this.config.region, }); } /** * Save local index to persistent storage */ async saveLocalIndex() { try { console.log(`[RegionalAgent:${this.config.region}] Saving local index to ${this.config.localStoragePath}`); // Placeholder for actual storage saving // In production, this would write to disk/database console.log(`[RegionalAgent:${this.config.region}] Local index saved: ${this.localIndex.size} vectors`); } catch (error) { console.error(`[RegionalAgent:${this.config.region}] Error saving local index:`, error); throw error; } } } exports.RegionalAgent = RegionalAgent; /** * Rate limiter for query processing */ class RateLimiter { constructor(config) { this.config = config; this.requests = 0; this.windowStart = Date.now(); } tryAcquire() { const now = Date.now(); // Reset window if expired if (now - this.windowStart >= this.config.windowMs) { this.requests = 0; this.windowStart = now; } if (this.requests < this.config.maxRequests) { this.requests++; return true; } return false; } release() { if (this.requests > 0) { this.requests--; } } } //# sourceMappingURL=regional-agent.js.map