Files
wifi-densepose/vendor/ruvector/npm/packages/agentic-integration/swarm-manager.js

453 lines
16 KiB
JavaScript

"use strict";
/**
* Swarm Manager - Dynamic agent swarm management
*
* Handles:
* - Dynamic agent spawning based on load
* - Agent lifecycle management
* - Topology management (mesh coordination)
* - Memory/state sharing via claude-flow hooks
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.SwarmManager = void 0;
const events_1 = require("events");
const child_process_1 = require("child_process");
const util_1 = require("util");
const regional_agent_1 = require("./regional-agent");
const execAsync = (0, util_1.promisify)(child_process_1.exec);
class SwarmManager extends events_1.EventEmitter {
constructor(config, coordinator) {
super();
this.config = config;
this.coordinator = coordinator;
this.agents = new Map();
this.agentConfigs = new Map();
this.lastScaleUp = new Map();
this.lastScaleDown = new Map();
this.swarmMemory = new Map();
this.agentCounter = 0;
this.initialize();
}
/**
* Initialize swarm manager
*/
async initialize() {
console.log('[SwarmManager] Initializing swarm manager...');
console.log(`[SwarmManager] Topology: ${this.config.topology}`);
console.log(`[SwarmManager] Regions: ${this.config.regions.join(', ')}`);
if (this.config.enableClaudeFlowHooks) {
try {
// Initialize swarm coordination via claude-flow
await execAsync(`npx claude-flow@alpha hooks pre-task --description "Initialize swarm manager with ${this.config.topology} topology"`);
// Initialize swarm topology
const topologyCmd = JSON.stringify({
topology: this.config.topology,
maxAgents: this.config.maxAgentsPerRegion * this.config.regions.length,
}).replace(/"/g, '\\"');
console.log('[SwarmManager] Initializing claude-flow swarm coordination...');
// Store swarm configuration in memory
await this.storeInMemory('swarm/config', this.config);
console.log('[SwarmManager] Claude-flow hooks initialized');
}
catch (error) {
console.warn('[SwarmManager] Claude-flow hooks not available:', error);
}
}
// Spawn initial agents for each region
await this.spawnInitialAgents();
// Start health monitoring
if (this.config.healthCheckInterval > 0) {
this.startHealthMonitoring();
}
// Start auto-scaling
if (this.config.enableAutoScaling) {
this.startAutoScaling();
}
this.emit('swarm:initialized', {
topology: this.config.topology,
regions: this.config.regions,
initialAgents: this.agents.size,
});
console.log(`[SwarmManager] Swarm initialized with ${this.agents.size} agents`);
}
/**
* Spawn initial agents for each region
*/
async spawnInitialAgents() {
console.log('[SwarmManager] Spawning initial agents...');
const spawnPromises = [];
for (const region of this.config.regions) {
for (let i = 0; i < this.config.minAgentsPerRegion; i++) {
spawnPromises.push(this.spawnAgent(region));
}
}
await Promise.all(spawnPromises);
console.log(`[SwarmManager] Spawned ${this.agents.size} initial agents`);
}
/**
* Spawn a new agent in specific region
*/
async spawnAgent(region, capacity = 1000) {
const agentId = `agent-${region}-${this.agentCounter++}`;
console.log(`[SwarmManager] Spawning agent ${agentId} in ${region}`);
const agentConfig = {
agentId,
region,
coordinatorEndpoint: 'coordinator.ruvector.io',
localStoragePath: `/var/lib/ruvector/${region}/${agentId}`,
maxConcurrentStreams: 1000,
metricsReportInterval: 30000, // 30 seconds
syncInterval: 5000, // 5 seconds
enableClaudeFlowHooks: this.config.enableClaudeFlowHooks,
vectorDimensions: 768, // Default dimension
capabilities: ['query', 'index', 'sync'],
};
// Create agent instance
const agent = new regional_agent_1.RegionalAgent(agentConfig);
// Set up event handlers
this.setupAgentEventHandlers(agent, agentConfig);
// Store agent
this.agents.set(agentId, agent);
this.agentConfigs.set(agentId, agentConfig);
// Register with coordinator
const registration = {
agentId,
region,
endpoint: `https://${region}.ruvector.io/agent/${agentId}`,
capabilities: agentConfig.capabilities,
capacity,
registeredAt: Date.now(),
};
await this.coordinator.registerAgent(registration);
if (this.config.enableClaudeFlowHooks) {
try {
// Notify about agent spawn
await execAsync(`npx claude-flow@alpha hooks notify --message "Spawned agent ${agentId} in ${region}"`);
// Store agent info in swarm memory
await this.storeInMemory(`swarm/agents/${agentId}`, {
config: agentConfig,
registration,
spawnedAt: Date.now(),
});
}
catch (error) {
// Non-critical
}
}
this.emit('agent:spawned', { agentId, region });
return agentId;
}
/**
* Set up event handlers for agent
*/
setupAgentEventHandlers(agent, config) {
// Forward agent events to swarm manager
agent.on('metrics:report', (metrics) => {
this.coordinator.updateAgentMetrics(metrics);
});
agent.on('query:completed', (data) => {
this.emit('query:completed', { ...data, agentId: config.agentId });
});
agent.on('query:failed', (data) => {
this.emit('query:failed', { ...data, agentId: config.agentId });
});
agent.on('sync:broadcast', (payload) => {
this.handleSyncBroadcast(payload, config.region);
});
agent.on('agent:shutdown', () => {
this.handleAgentShutdown(config.agentId);
});
}
/**
* Handle sync broadcast from agent
*/
async handleSyncBroadcast(payload, sourceRegion) {
// Broadcast to all agents in other regions
for (const [agentId, agent] of this.agents.entries()) {
const agentConfig = this.agentConfigs.get(agentId);
if (agentConfig && agentConfig.region !== sourceRegion) {
try {
await agent.handleSyncPayload(payload);
}
catch (error) {
console.error(`[SwarmManager] Error syncing to agent ${agentId}:`, error);
}
}
}
}
/**
* Despawn an agent
*/
async despawnAgent(agentId) {
console.log(`[SwarmManager] Despawning agent ${agentId}`);
const agent = this.agents.get(agentId);
if (!agent) {
throw new Error(`Agent ${agentId} not found`);
}
// Unregister from coordinator
await this.coordinator.unregisterAgent(agentId);
// Shutdown agent
await agent.shutdown();
// Remove from tracking
this.agents.delete(agentId);
this.agentConfigs.delete(agentId);
if (this.config.enableClaudeFlowHooks) {
try {
await execAsync(`npx claude-flow@alpha hooks notify --message "Despawned agent ${agentId}"`);
// Remove from swarm memory
await this.removeFromMemory(`swarm/agents/${agentId}`);
}
catch (error) {
// Non-critical
}
}
this.emit('agent:despawned', { agentId });
}
/**
* Handle agent shutdown
*/
handleAgentShutdown(agentId) {
console.log(`[SwarmManager] Agent ${agentId} has shut down`);
this.agents.delete(agentId);
this.agentConfigs.delete(agentId);
this.emit('agent:shutdown', { agentId });
}
/**
* Start health monitoring
*/
startHealthMonitoring() {
this.healthCheckTimer = setInterval(() => {
this.performHealthChecks();
}, this.config.healthCheckInterval);
}
/**
* Perform health checks on all agents
*/
async performHealthChecks() {
const unhealthyAgents = [];
for (const [agentId, agent] of this.agents.entries()) {
const status = agent.getStatus();
if (!status.healthy) {
unhealthyAgents.push(agentId);
console.warn(`[SwarmManager] Agent ${agentId} is unhealthy`);
}
}
if (unhealthyAgents.length > 0) {
this.emit('health:check', {
unhealthyAgents,
totalAgents: this.agents.size,
});
}
// Could implement auto-recovery here
// for (const agentId of unhealthyAgents) {
// await this.recoverAgent(agentId);
// }
}
/**
* Start auto-scaling
*/
startAutoScaling() {
this.autoScaleTimer = setInterval(() => {
this.evaluateScaling();
}, 10000); // Evaluate every 10 seconds
}
/**
* Evaluate if scaling is needed
*/
async evaluateScaling() {
const metrics = this.calculateSwarmMetrics();
for (const [region, regionMetrics] of Object.entries(metrics.regionMetrics)) {
const avgLoad = (regionMetrics.avgCpuUsage + regionMetrics.avgMemoryUsage) / 2;
// Check scale-up condition
if (avgLoad > this.config.scaleUpThreshold &&
regionMetrics.agentCount < this.config.maxAgentsPerRegion &&
this.canScaleUp(region)) {
console.log(`[SwarmManager] Scaling up in region ${region} (load: ${avgLoad.toFixed(1)}%)`);
await this.scaleUp(region);
}
// Check scale-down condition
if (avgLoad < this.config.scaleDownThreshold &&
regionMetrics.agentCount > this.config.minAgentsPerRegion &&
this.canScaleDown(region)) {
console.log(`[SwarmManager] Scaling down in region ${region} (load: ${avgLoad.toFixed(1)}%)`);
await this.scaleDown(region);
}
}
}
/**
* Check if can scale up (respects cooldown)
*/
canScaleUp(region) {
const lastScaleUp = this.lastScaleUp.get(region) || 0;
return Date.now() - lastScaleUp > this.config.scaleUpCooldown;
}
/**
* Check if can scale down (respects cooldown)
*/
canScaleDown(region) {
const lastScaleDown = this.lastScaleDown.get(region) || 0;
return Date.now() - lastScaleDown > this.config.scaleDownCooldown;
}
/**
* Scale up agents in region
*/
async scaleUp(region) {
try {
await this.spawnAgent(region);
this.lastScaleUp.set(region, Date.now());
this.emit('swarm:scale-up', { region, totalAgents: this.agents.size });
}
catch (error) {
console.error(`[SwarmManager] Error scaling up in ${region}:`, error);
}
}
/**
* Scale down agents in region
*/
async scaleDown(region) {
// Find agent with lowest load in region
const regionAgents = Array.from(this.agents.entries())
.filter(([_, agent]) => {
const config = this.agentConfigs.get(agent.getStatus().agentId);
return config?.region === region;
})
.map(([agentId, agent]) => ({
agentId,
status: agent.getStatus(),
}))
.sort((a, b) => a.status.activeStreams - b.status.activeStreams);
if (regionAgents.length > 0) {
const agentToDespawn = regionAgents[0];
try {
await this.despawnAgent(agentToDespawn.agentId);
this.lastScaleDown.set(region, Date.now());
this.emit('swarm:scale-down', { region, totalAgents: this.agents.size });
}
catch (error) {
console.error(`[SwarmManager] Error scaling down in ${region}:`, error);
}
}
}
/**
* Calculate swarm metrics
*/
calculateSwarmMetrics() {
const regionMetrics = {};
let totalLoad = 0;
let activeAgents = 0;
// Initialize region metrics
for (const region of this.config.regions) {
regionMetrics[region] = {
region,
agentCount: 0,
activeAgents: 0,
avgCpuUsage: 0,
avgMemoryUsage: 0,
totalStreams: 0,
avgQueryLatency: 0,
};
}
// Aggregate metrics
for (const [agentId, agent] of this.agents.entries()) {
const status = agent.getStatus();
const config = this.agentConfigs.get(agentId);
if (!config)
continue;
const regionMetric = regionMetrics[config.region];
regionMetric.agentCount++;
if (status.healthy) {
activeAgents++;
regionMetric.activeAgents++;
}
regionMetric.totalStreams += status.activeStreams;
regionMetric.avgQueryLatency += status.avgQueryLatency;
// Note: In production, we would get actual CPU/memory metrics
totalLoad += status.activeStreams;
}
// Calculate averages
for (const region of this.config.regions) {
const metric = regionMetrics[region];
if (metric.agentCount > 0) {
metric.avgQueryLatency /= metric.agentCount;
// Placeholder for actual CPU/memory aggregation
metric.avgCpuUsage = Math.random() * 100;
metric.avgMemoryUsage = Math.random() * 100;
}
}
return {
totalAgents: this.agents.size,
activeAgents,
totalLoad,
averageLoad: this.agents.size > 0 ? totalLoad / this.agents.size : 0,
regionMetrics,
timestamp: Date.now(),
};
}
/**
* Store data in swarm memory via claude-flow hooks
*/
async storeInMemory(key, value) {
this.swarmMemory.set(key, value);
if (this.config.enableClaudeFlowHooks) {
try {
const serialized = JSON.stringify(value).replace(/"/g, '\\"');
await execAsync(`npx claude-flow@alpha hooks post-edit --file "swarm-memory" --memory-key "${key}"`);
}
catch (error) {
console.warn(`[SwarmManager] Error storing in memory: ${key}`, error);
}
}
}
/**
* Retrieve data from swarm memory
*/
async retrieveFromMemory(key) {
return this.swarmMemory.get(key);
}
/**
* Remove data from swarm memory
*/
async removeFromMemory(key) {
this.swarmMemory.delete(key);
}
/**
* Get swarm status
*/
getStatus() {
return {
topology: this.config.topology,
regions: this.config.regions,
totalAgents: this.agents.size,
metrics: this.calculateSwarmMetrics(),
};
}
/**
* Shutdown swarm gracefully
*/
async shutdown() {
console.log('[SwarmManager] Shutting down swarm...');
// Stop timers
if (this.healthCheckTimer) {
clearInterval(this.healthCheckTimer);
}
if (this.autoScaleTimer) {
clearInterval(this.autoScaleTimer);
}
// Shutdown all agents
const shutdownPromises = Array.from(this.agents.keys()).map(agentId => this.despawnAgent(agentId));
await Promise.all(shutdownPromises);
if (this.config.enableClaudeFlowHooks) {
try {
await execAsync(`npx claude-flow@alpha hooks post-task --task-id "swarm-shutdown"`);
await execAsync(`npx claude-flow@alpha hooks session-end --export-metrics true`);
}
catch (error) {
console.warn('[SwarmManager] Error executing shutdown hooks:', error);
}
}
this.emit('swarm:shutdown');
console.log('[SwarmManager] Swarm shutdown complete');
}
}
exports.SwarmManager = SwarmManager;
//# sourceMappingURL=swarm-manager.js.map