UNPKG

claude-flow-tbowman01

Version:

Enterprise-grade AI agent orchestration with ruv-swarm integration (Alpha Release)

360 lines 11.6 kB
/** * Conflict resolution mechanisms for multi-agent coordination */ /** * Priority-based resolution strategy */ export class PriorityResolutionStrategy { name = 'priority'; async resolve(conflict, context) { const priorities = conflict.agents.map((agentId) => ({ agentId, priority: context.agentPriorities.get(agentId) || 0, })); // Sort by priority (descending) priorities.sort((a, b) => b.priority - a.priority); const winner = priorities[0].agentId; const losers = priorities.slice(1).map((p) => p.agentId); return { type: 'priority', winner, losers, reason: `Agent ${winner} has highest priority (${priorities[0].priority})`, timestamp: new Date(), }; } } /** * First-come-first-served resolution strategy */ export class TimestampResolutionStrategy { name = 'timestamp'; async resolve(conflict, context) { const timestamps = conflict.agents.map((agentId) => ({ agentId, timestamp: context.requestTimestamps.get(agentId) || new Date(), })); // Sort by timestamp (ascending - earliest first) timestamps.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime()); const winner = timestamps[0].agentId; const losers = timestamps.slice(1).map((t) => t.agentId); return { type: 'timestamp', winner, losers, reason: `Agent ${winner} made the earliest request`, timestamp: new Date(), }; } } /** * Voting-based resolution strategy (for multi-agent consensus) */ export class VotingResolutionStrategy { name = 'vote'; async resolve(conflict, context) { const voteCounts = new Map(); // Count votes for (const [agentId, voters] of context.votes) { voteCounts.set(agentId, voters.length); } // Find winner let maxVotes = 0; let winner = ''; const losers = []; for (const [agentId, votes] of voteCounts) { if (votes > maxVotes) { if (winner) { losers.push(winner); } maxVotes = votes; winner = agentId; } else { losers.push(agentId); } } return { type: 'vote', winner, losers, reason: `Agent ${winner} received the most votes (${maxVotes})`, timestamp: new Date(), }; } } /** * Conflict resolution manager */ export class ConflictResolver { logger; eventBus; strategies = new Map(); conflicts = new Map(); resolutionHistory = []; constructor(logger, eventBus) { this.logger = logger; this.eventBus = eventBus; // Register default strategies this.registerStrategy(new PriorityResolutionStrategy()); this.registerStrategy(new TimestampResolutionStrategy()); this.registerStrategy(new VotingResolutionStrategy()); } /** * Register a conflict resolution strategy */ registerStrategy(strategy) { this.strategies.set(strategy.name, strategy); this.logger.info('Registered conflict resolution strategy', { name: strategy.name }); } /** * Report a resource conflict */ async reportResourceConflict(resourceId, agents) { const conflict = { id: `conflict-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, resourceId, agents, timestamp: new Date(), resolved: false, }; this.conflicts.set(conflict.id, conflict); this.logger.warn('Resource conflict reported', conflict); // Emit conflict event this.eventBus.emit('conflict:resource', conflict); return conflict; } /** * Report a task conflict */ async reportTaskConflict(taskId, agents, type) { const conflict = { id: `conflict-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`, taskId, agents, type, timestamp: new Date(), resolved: false, }; this.conflicts.set(conflict.id, conflict); this.logger.warn('Task conflict reported', conflict); // Emit conflict event this.eventBus.emit('conflict:task', conflict); return conflict; } /** * Resolve a conflict using a specific strategy */ async resolveConflict(conflictId, strategyName, context) { const conflict = this.conflicts.get(conflictId); if (!conflict) { throw new Error(`Conflict not found: ${conflictId}`); } if (conflict.resolved) { throw new Error(`Conflict already resolved: ${conflictId}`); } const strategy = this.strategies.get(strategyName); if (!strategy) { throw new Error(`Strategy not found: ${strategyName}`); } // Resolve the conflict const resolution = await strategy.resolve(conflict, context); // Update conflict conflict.resolved = true; conflict.resolution = resolution; // Store in history this.resolutionHistory.push(resolution); // Emit resolution event this.eventBus.emit('conflict:resolved', { conflict, resolution, }); this.logger.info('Conflict resolved', { conflictId, strategy: strategyName, resolution, }); return resolution; } /** * Auto-resolve conflicts based on configuration */ async autoResolve(conflictId, preferredStrategy = 'priority') { const conflict = this.conflicts.get(conflictId); if (!conflict) { throw new Error(`Conflict not found: ${conflictId}`); } // Build context based on conflict type let context = {}; if (preferredStrategy === 'priority') { // In a real implementation, fetch agent priorities from configuration context.agentPriorities = new Map(conflict.agents.map((id, index) => [id, conflict.agents.length - index])); } else if (preferredStrategy === 'timestamp') { // In a real implementation, fetch request timestamps context.requestTimestamps = new Map(conflict.agents.map((id, index) => [id, new Date(Date.now() - index * 1000)])); } return this.resolveConflict(conflictId, preferredStrategy, context); } /** * Get active conflicts */ getActiveConflicts() { return Array.from(this.conflicts.values()).filter((c) => !c.resolved); } /** * Get conflict history */ getConflictHistory(limit) { if (limit) { return this.resolutionHistory.slice(-limit); } return [...this.resolutionHistory]; } /** * Clear resolved conflicts older than a certain age */ cleanupOldConflicts(maxAgeMs) { const now = Date.now(); let removed = 0; for (const [id, conflict] of this.conflicts) { if (conflict.resolved && now - conflict.timestamp.getTime() > maxAgeMs) { this.conflicts.delete(id); removed++; } } // Also cleanup old history const cutoffTime = now - maxAgeMs; this.resolutionHistory = this.resolutionHistory.filter((r) => r.timestamp.getTime() > cutoffTime); return removed; } /** * Get conflict statistics */ getStats() { const stats = { totalConflicts: this.conflicts.size, activeConflicts: 0, resolvedConflicts: 0, resolutionsByStrategy: {}, conflictsByType: { resource: 0, task: 0, }, }; for (const conflict of this.conflicts.values()) { if (conflict.resolved) { stats.resolvedConflicts++; if (conflict.resolution) { const strategy = conflict.resolution.type; stats.resolutionsByStrategy[strategy] = (stats.resolutionsByStrategy[strategy] || 0) + 1; } } else { stats.activeConflicts++; } if ('resourceId' in conflict) { stats.conflictsByType.resource++; } else { stats.conflictsByType.task++; } } return stats; } } /** * Optimistic concurrency control for resource updates */ export class OptimisticLockManager { logger; versions = new Map(); locks = new Map(); constructor(logger) { this.logger = logger; } /** * Acquire an optimistic lock */ acquireLock(resourceId, agentId) { const currentVersion = this.versions.get(resourceId) || 0; this.locks.set(resourceId, { version: currentVersion, holder: agentId, timestamp: new Date(), }); this.logger.debug('Optimistic lock acquired', { resourceId, agentId, version: currentVersion, }); return currentVersion; } /** * Validate and update with optimistic lock */ validateAndUpdate(resourceId, agentId, expectedVersion) { const currentVersion = this.versions.get(resourceId) || 0; const lock = this.locks.get(resourceId); // Check if versions match if (currentVersion !== expectedVersion) { this.logger.warn('Optimistic lock conflict', { resourceId, agentId, expectedVersion, currentVersion, }); return false; } // Check if this agent holds the lock if (!lock || lock.holder !== agentId) { this.logger.warn('Agent does not hold lock', { resourceId, agentId, }); return false; } // Update version this.versions.set(resourceId, currentVersion + 1); this.locks.delete(resourceId); this.logger.debug('Optimistic update successful', { resourceId, agentId, newVersion: currentVersion + 1, }); return true; } /** * Release a lock without updating */ releaseLock(resourceId, agentId) { const lock = this.locks.get(resourceId); if (lock && lock.holder === agentId) { this.locks.delete(resourceId); this.logger.debug('Optimistic lock released', { resourceId, agentId, }); } } /** * Clean up stale locks */ cleanupStaleLocks(maxAgeMs) { const now = Date.now(); let removed = 0; for (const [resourceId, lock] of this.locks) { if (now - lock.timestamp.getTime() > maxAgeMs) { this.locks.delete(resourceId); removed++; this.logger.warn('Removed stale lock', { resourceId, holder: lock.holder, age: now - lock.timestamp.getTime(), }); } } return removed; } } //# sourceMappingURL=conflict-resolution.js.map