Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'

This commit is contained in:
ruv
2026-02-28 14:39:40 -05:00
7854 changed files with 3522914 additions and 0 deletions

View File

@@ -0,0 +1,110 @@
/**
* ByzantineConsensus - Byzantine Fault Tolerant Consensus
*
* Implements PBFT-style consensus for distributed decision making.
* Tolerates f faulty nodes where f < n/3.
*/
import { EventEmitter } from 'events';
export type ConsensusPhase = 'pre-prepare' | 'prepare' | 'commit' | 'decided' | 'failed';
export interface ConsensusConfig {
replicas: number;
timeout: number;
retries: number;
requireSignatures: boolean;
}
export interface Proposal<T = unknown> {
id: string;
value: T;
proposerId: string;
timestamp: Date;
}
export interface Vote {
proposalId: string;
voterId: string;
phase: ConsensusPhase;
accept: boolean;
signature?: string;
}
export interface ConsensusResult<T = unknown> {
proposalId: string;
value: T;
phase: ConsensusPhase;
votes: Vote[];
decided: boolean;
timestamp: Date;
}
export interface ReplicaInfo {
id: string;
isLeader: boolean;
lastActivity: Date;
status: 'active' | 'suspected' | 'faulty';
}
export declare class ByzantineConsensus<T = unknown> extends EventEmitter {
private readonly config;
private readonly replicaId;
private replicas;
private proposals;
private votes;
private decided;
private leaderId;
private viewNumber;
constructor(config?: Partial<ConsensusConfig>);
/**
* Get maximum tolerable faulty nodes
*/
get maxFaulty(): number;
/**
* Get quorum size required for consensus
*/
get quorumSize(): number;
/**
* Initialize replicas
*/
initializeReplicas(replicaIds: string[]): void;
/**
* Propose a value for consensus
*/
propose(value: T, proposerId?: string): Promise<ConsensusResult<T>>;
/**
* Vote on a proposal (called by replicas)
*/
vote(proposalId: string, voterId: string, phase: ConsensusPhase, accept: boolean): void;
/**
* Get consensus result for a proposal
*/
getResult(proposalId: string): ConsensusResult<T> | undefined;
/**
* Get all decided proposals
*/
getDecided(): ConsensusResult<T>[];
/**
* Get replica status
*/
getReplicaStatus(): ReplicaInfo[];
/**
* Mark a replica as faulty
*/
markFaulty(replicaId: string): void;
/**
* Get consensus statistics
*/
getStats(): {
totalReplicas: number;
activeReplicas: number;
faultyReplicas: number;
maxFaulty: number;
quorumSize: number;
totalProposals: number;
decidedProposals: number;
viewNumber: number;
leaderId: string | null;
};
private prePrepare;
private prepare;
private commit;
private waitForPhase;
private viewChange;
}
export declare function createByzantineConsensus<T = unknown>(config?: Partial<ConsensusConfig>): ByzantineConsensus<T>;
export default ByzantineConsensus;
//# sourceMappingURL=ByzantineConsensus.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"ByzantineConsensus.d.ts","sourceRoot":"","sources":["ByzantineConsensus.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,270 @@
"use strict";
/**
* ByzantineConsensus - Byzantine Fault Tolerant Consensus
*
* Implements PBFT-style consensus for distributed decision making.
* Tolerates f faulty nodes where f < n/3.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ByzantineConsensus = void 0;
exports.createByzantineConsensus = createByzantineConsensus;
const uuid_1 = require("uuid");
const events_1 = require("events");
// ============================================================================
// ByzantineConsensus Implementation
// ============================================================================
class ByzantineConsensus extends events_1.EventEmitter {
constructor(config = {}) {
super();
this.replicas = new Map();
this.proposals = new Map();
this.votes = new Map();
this.decided = new Map();
this.leaderId = null;
this.viewNumber = 0;
this.config = {
replicas: config.replicas ?? 5,
timeout: config.timeout ?? 30000,
retries: config.retries ?? 3,
requireSignatures: config.requireSignatures ?? false,
};
this.replicaId = (0, uuid_1.v4)();
// Validate Byzantine tolerance requirement
const maxFaulty = Math.floor((this.config.replicas - 1) / 3);
if (maxFaulty < 1 && this.config.replicas > 1) {
console.warn('ByzantineConsensus: Minimum 4 replicas recommended for fault tolerance');
}
}
/**
* Get maximum tolerable faulty nodes
*/
get maxFaulty() {
return Math.floor((this.config.replicas - 1) / 3);
}
/**
* Get quorum size required for consensus
*/
get quorumSize() {
return Math.ceil((2 * this.config.replicas) / 3);
}
/**
* Initialize replicas
*/
initializeReplicas(replicaIds) {
this.replicas.clear();
for (let i = 0; i < replicaIds.length; i++) {
this.replicas.set(replicaIds[i], {
id: replicaIds[i],
isLeader: i === 0,
lastActivity: new Date(),
status: 'active',
});
if (i === 0) {
this.leaderId = replicaIds[i];
}
}
}
/**
* Propose a value for consensus
*/
async propose(value, proposerId) {
const proposal = {
id: (0, uuid_1.v4)(),
value,
proposerId: proposerId ?? this.replicaId,
timestamp: new Date(),
};
this.proposals.set(proposal.id, proposal);
this.votes.set(proposal.id, []);
this.emit('proposal:created', proposal);
try {
// Phase 1: Pre-prepare
await this.prePrepare(proposal);
// Phase 2: Prepare
await this.prepare(proposal);
// Phase 3: Commit
const result = await this.commit(proposal);
return result;
}
catch (error) {
const failedResult = {
proposalId: proposal.id,
value,
phase: 'failed',
votes: this.votes.get(proposal.id) ?? [],
decided: false,
timestamp: new Date(),
};
this.emit('consensus:failed', { proposal, error });
return failedResult;
}
}
/**
* Vote on a proposal (called by replicas)
*/
vote(proposalId, voterId, phase, accept) {
const vote = {
proposalId,
voterId,
phase,
accept,
};
let proposalVotes = this.votes.get(proposalId);
if (!proposalVotes) {
proposalVotes = [];
this.votes.set(proposalId, proposalVotes);
}
proposalVotes.push(vote);
// Update replica activity
const replica = this.replicas.get(voterId);
if (replica) {
replica.lastActivity = new Date();
}
this.emit('vote:received', vote);
}
/**
* Get consensus result for a proposal
*/
getResult(proposalId) {
return this.decided.get(proposalId);
}
/**
* Get all decided proposals
*/
getDecided() {
return Array.from(this.decided.values());
}
/**
* Get replica status
*/
getReplicaStatus() {
return Array.from(this.replicas.values());
}
/**
* Mark a replica as faulty
*/
markFaulty(replicaId) {
const replica = this.replicas.get(replicaId);
if (replica) {
replica.status = 'faulty';
this.emit('replica:faulty', replica);
// If leader is faulty, trigger view change
if (replica.isLeader) {
this.viewChange();
}
}
}
/**
* Get consensus statistics
*/
getStats() {
let activeReplicas = 0;
let faultyReplicas = 0;
for (const replica of this.replicas.values()) {
if (replica.status === 'active')
activeReplicas++;
if (replica.status === 'faulty')
faultyReplicas++;
}
return {
totalReplicas: this.replicas.size,
activeReplicas,
faultyReplicas,
maxFaulty: this.maxFaulty,
quorumSize: this.quorumSize,
totalProposals: this.proposals.size,
decidedProposals: this.decided.size,
viewNumber: this.viewNumber,
leaderId: this.leaderId,
};
}
// ==========================================================================
// Private Methods - PBFT Phases
// ==========================================================================
async prePrepare(proposal) {
this.emit('phase:pre-prepare', proposal);
// Leader broadcasts pre-prepare
// In a real implementation, this would be sent to all replicas
// Here we simulate immediate local acceptance
// Wait for pre-prepare acceptance (simulated)
await this.waitForPhase(proposal.id, 'pre-prepare', 1);
}
async prepare(proposal) {
this.emit('phase:prepare', proposal);
// Broadcast prepare message to all replicas
// Replicas validate and send prepare messages
// Simulate self-vote
this.vote(proposal.id, this.replicaId, 'prepare', true);
// Wait for quorum of prepare messages
await this.waitForPhase(proposal.id, 'prepare', this.quorumSize);
}
async commit(proposal) {
this.emit('phase:commit', proposal);
// Broadcast commit message
// Simulate self-vote
this.vote(proposal.id, this.replicaId, 'commit', true);
// Wait for quorum of commit messages
await this.waitForPhase(proposal.id, 'commit', this.quorumSize);
// Decision reached
const result = {
proposalId: proposal.id,
value: proposal.value,
phase: 'decided',
votes: this.votes.get(proposal.id) ?? [],
decided: true,
timestamp: new Date(),
};
this.decided.set(proposal.id, result);
this.emit('consensus:decided', result);
return result;
}
async waitForPhase(proposalId, phase, required) {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error(`Timeout waiting for ${phase} phase`));
}, this.config.timeout);
const checkVotes = () => {
const votes = this.votes.get(proposalId) ?? [];
const phaseVotes = votes.filter(v => v.phase === phase && v.accept);
if (phaseVotes.length >= required) {
clearTimeout(timeout);
resolve();
return;
}
// Check again
setTimeout(checkVotes, 100);
};
checkVotes();
});
}
viewChange() {
this.viewNumber++;
// Select new leader (round-robin)
const replicaIds = Array.from(this.replicas.keys());
const activeReplicas = replicaIds.filter(id => {
const replica = this.replicas.get(id);
return replica && replica.status === 'active';
});
if (activeReplicas.length === 0) {
this.emit('consensus:no-quorum');
return;
}
const newLeaderIndex = this.viewNumber % activeReplicas.length;
const newLeaderId = activeReplicas[newLeaderIndex];
// Update leader status
for (const [id, replica] of this.replicas) {
replica.isLeader = id === newLeaderId;
}
this.leaderId = newLeaderId;
this.emit('view:changed', { viewNumber: this.viewNumber, leaderId: newLeaderId });
}
}
exports.ByzantineConsensus = ByzantineConsensus;
// ============================================================================
// Factory Function
// ============================================================================
function createByzantineConsensus(config) {
return new ByzantineConsensus(config);
}
exports.default = ByzantineConsensus;
//# sourceMappingURL=ByzantineConsensus.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,385 @@
/**
* ByzantineConsensus - Byzantine Fault Tolerant Consensus
*
* Implements PBFT-style consensus for distributed decision making.
* Tolerates f faulty nodes where f < n/3.
*/
import { v4 as uuidv4 } from 'uuid';
import { EventEmitter } from 'events';
// ============================================================================
// Types
// ============================================================================
export type ConsensusPhase = 'pre-prepare' | 'prepare' | 'commit' | 'decided' | 'failed';
export interface ConsensusConfig {
replicas: number; // Total number of replicas
timeout: number; // Timeout for each phase (ms)
retries: number; // Number of retries before failing
requireSignatures: boolean;
}
export interface Proposal<T = unknown> {
id: string;
value: T;
proposerId: string;
timestamp: Date;
}
export interface Vote {
proposalId: string;
voterId: string;
phase: ConsensusPhase;
accept: boolean;
signature?: string;
}
export interface ConsensusResult<T = unknown> {
proposalId: string;
value: T;
phase: ConsensusPhase;
votes: Vote[];
decided: boolean;
timestamp: Date;
}
export interface ReplicaInfo {
id: string;
isLeader: boolean;
lastActivity: Date;
status: 'active' | 'suspected' | 'faulty';
}
// ============================================================================
// ByzantineConsensus Implementation
// ============================================================================
export class ByzantineConsensus<T = unknown> extends EventEmitter {
private readonly config: ConsensusConfig;
private readonly replicaId: string;
private replicas: Map<string, ReplicaInfo> = new Map();
private proposals: Map<string, Proposal<T>> = new Map();
private votes: Map<string, Vote[]> = new Map();
private decided: Map<string, ConsensusResult<T>> = new Map();
private leaderId: string | null = null;
private viewNumber: number = 0;
constructor(config: Partial<ConsensusConfig> = {}) {
super();
this.config = {
replicas: config.replicas ?? 5,
timeout: config.timeout ?? 30000,
retries: config.retries ?? 3,
requireSignatures: config.requireSignatures ?? false,
};
this.replicaId = uuidv4();
// Validate Byzantine tolerance requirement
const maxFaulty = Math.floor((this.config.replicas - 1) / 3);
if (maxFaulty < 1 && this.config.replicas > 1) {
console.warn('ByzantineConsensus: Minimum 4 replicas recommended for fault tolerance');
}
}
/**
* Get maximum tolerable faulty nodes
*/
get maxFaulty(): number {
return Math.floor((this.config.replicas - 1) / 3);
}
/**
* Get quorum size required for consensus
*/
get quorumSize(): number {
return Math.ceil((2 * this.config.replicas) / 3);
}
/**
* Initialize replicas
*/
initializeReplicas(replicaIds: string[]): void {
this.replicas.clear();
for (let i = 0; i < replicaIds.length; i++) {
this.replicas.set(replicaIds[i], {
id: replicaIds[i],
isLeader: i === 0,
lastActivity: new Date(),
status: 'active',
});
if (i === 0) {
this.leaderId = replicaIds[i];
}
}
}
/**
* Propose a value for consensus
*/
async propose(value: T, proposerId?: string): Promise<ConsensusResult<T>> {
const proposal: Proposal<T> = {
id: uuidv4(),
value,
proposerId: proposerId ?? this.replicaId,
timestamp: new Date(),
};
this.proposals.set(proposal.id, proposal);
this.votes.set(proposal.id, []);
this.emit('proposal:created', proposal);
try {
// Phase 1: Pre-prepare
await this.prePrepare(proposal);
// Phase 2: Prepare
await this.prepare(proposal);
// Phase 3: Commit
const result = await this.commit(proposal);
return result;
} catch (error) {
const failedResult: ConsensusResult<T> = {
proposalId: proposal.id,
value,
phase: 'failed',
votes: this.votes.get(proposal.id) ?? [],
decided: false,
timestamp: new Date(),
};
this.emit('consensus:failed', { proposal, error });
return failedResult;
}
}
/**
* Vote on a proposal (called by replicas)
*/
vote(proposalId: string, voterId: string, phase: ConsensusPhase, accept: boolean): void {
const vote: Vote = {
proposalId,
voterId,
phase,
accept,
};
let proposalVotes = this.votes.get(proposalId);
if (!proposalVotes) {
proposalVotes = [];
this.votes.set(proposalId, proposalVotes);
}
proposalVotes.push(vote);
// Update replica activity
const replica = this.replicas.get(voterId);
if (replica) {
replica.lastActivity = new Date();
}
this.emit('vote:received', vote);
}
/**
* Get consensus result for a proposal
*/
getResult(proposalId: string): ConsensusResult<T> | undefined {
return this.decided.get(proposalId);
}
/**
* Get all decided proposals
*/
getDecided(): ConsensusResult<T>[] {
return Array.from(this.decided.values());
}
/**
* Get replica status
*/
getReplicaStatus(): ReplicaInfo[] {
return Array.from(this.replicas.values());
}
/**
* Mark a replica as faulty
*/
markFaulty(replicaId: string): void {
const replica = this.replicas.get(replicaId);
if (replica) {
replica.status = 'faulty';
this.emit('replica:faulty', replica);
// If leader is faulty, trigger view change
if (replica.isLeader) {
this.viewChange();
}
}
}
/**
* Get consensus statistics
*/
getStats(): {
totalReplicas: number;
activeReplicas: number;
faultyReplicas: number;
maxFaulty: number;
quorumSize: number;
totalProposals: number;
decidedProposals: number;
viewNumber: number;
leaderId: string | null;
} {
let activeReplicas = 0;
let faultyReplicas = 0;
for (const replica of this.replicas.values()) {
if (replica.status === 'active') activeReplicas++;
if (replica.status === 'faulty') faultyReplicas++;
}
return {
totalReplicas: this.replicas.size,
activeReplicas,
faultyReplicas,
maxFaulty: this.maxFaulty,
quorumSize: this.quorumSize,
totalProposals: this.proposals.size,
decidedProposals: this.decided.size,
viewNumber: this.viewNumber,
leaderId: this.leaderId,
};
}
// ==========================================================================
// Private Methods - PBFT Phases
// ==========================================================================
private async prePrepare(proposal: Proposal<T>): Promise<void> {
this.emit('phase:pre-prepare', proposal);
// Leader broadcasts pre-prepare
// In a real implementation, this would be sent to all replicas
// Here we simulate immediate local acceptance
// Wait for pre-prepare acceptance (simulated)
await this.waitForPhase(proposal.id, 'pre-prepare', 1);
}
private async prepare(proposal: Proposal<T>): Promise<void> {
this.emit('phase:prepare', proposal);
// Broadcast prepare message to all replicas
// Replicas validate and send prepare messages
// Simulate self-vote
this.vote(proposal.id, this.replicaId, 'prepare', true);
// Wait for quorum of prepare messages
await this.waitForPhase(proposal.id, 'prepare', this.quorumSize);
}
private async commit(proposal: Proposal<T>): Promise<ConsensusResult<T>> {
this.emit('phase:commit', proposal);
// Broadcast commit message
// Simulate self-vote
this.vote(proposal.id, this.replicaId, 'commit', true);
// Wait for quorum of commit messages
await this.waitForPhase(proposal.id, 'commit', this.quorumSize);
// Decision reached
const result: ConsensusResult<T> = {
proposalId: proposal.id,
value: proposal.value,
phase: 'decided',
votes: this.votes.get(proposal.id) ?? [],
decided: true,
timestamp: new Date(),
};
this.decided.set(proposal.id, result);
this.emit('consensus:decided', result);
return result;
}
private async waitForPhase(
proposalId: string,
phase: ConsensusPhase,
required: number
): Promise<void> {
return new Promise((resolve, reject) => {
const timeout = setTimeout(() => {
reject(new Error(`Timeout waiting for ${phase} phase`));
}, this.config.timeout);
const checkVotes = () => {
const votes = this.votes.get(proposalId) ?? [];
const phaseVotes = votes.filter(v => v.phase === phase && v.accept);
if (phaseVotes.length >= required) {
clearTimeout(timeout);
resolve();
return;
}
// Check again
setTimeout(checkVotes, 100);
};
checkVotes();
});
}
private viewChange(): void {
this.viewNumber++;
// Select new leader (round-robin)
const replicaIds = Array.from(this.replicas.keys());
const activeReplicas = replicaIds.filter(id => {
const replica = this.replicas.get(id);
return replica && replica.status === 'active';
});
if (activeReplicas.length === 0) {
this.emit('consensus:no-quorum');
return;
}
const newLeaderIndex = this.viewNumber % activeReplicas.length;
const newLeaderId = activeReplicas[newLeaderIndex];
// Update leader status
for (const [id, replica] of this.replicas) {
replica.isLeader = id === newLeaderId;
}
this.leaderId = newLeaderId;
this.emit('view:changed', { viewNumber: this.viewNumber, leaderId: newLeaderId });
}
}
// ============================================================================
// Factory Function
// ============================================================================
export function createByzantineConsensus<T = unknown>(
config?: Partial<ConsensusConfig>
): ByzantineConsensus<T> {
return new ByzantineConsensus<T>(config);
}
export default ByzantineConsensus;

View File

@@ -0,0 +1,141 @@
/**
* SwarmCoordinator - Multi-Agent Swarm Orchestration
*
* Provides distributed task coordination using agentic-flow patterns.
* Supports multiple topologies and consensus protocols.
*/
import { EventEmitter } from 'events';
export type SwarmTopology = 'hierarchical' | 'mesh' | 'hierarchical-mesh' | 'adaptive';
export type ConsensusProtocol = 'byzantine' | 'raft' | 'gossip' | 'crdt';
export type WorkerType = 'ultralearn' | 'optimize' | 'consolidate' | 'predict' | 'audit' | 'map' | 'preload' | 'deepdive' | 'document' | 'refactor' | 'benchmark' | 'testgaps';
export type WorkerPriority = 'low' | 'normal' | 'high' | 'critical';
export interface SwarmConfig {
topology: SwarmTopology;
maxAgents: number;
strategy: 'specialized' | 'balanced' | 'adaptive';
consensus: ConsensusProtocol;
heartbeatInterval?: number;
taskTimeout?: number;
}
export interface WorkerConfig {
type: WorkerType;
priority: WorkerPriority;
concurrency: number;
timeout: number;
retries: number;
backoff: 'exponential' | 'linear';
}
export interface SwarmTask {
id: string;
worker: WorkerType;
type: string;
content: unknown;
priority: WorkerPriority;
status: 'pending' | 'running' | 'completed' | 'failed';
assignedAgent?: string;
result?: unknown;
error?: string;
createdAt: Date;
startedAt?: Date;
completedAt?: Date;
}
export interface SwarmAgent {
id: string;
type: WorkerType;
status: 'idle' | 'busy' | 'offline';
currentTask?: string;
completedTasks: number;
failedTasks: number;
lastHeartbeat: Date;
}
export interface DispatchOptions {
worker: WorkerType;
task: {
type: string;
content: unknown;
};
priority?: WorkerPriority;
timeout?: number;
}
export declare const WORKER_DEFAULTS: Record<WorkerType, WorkerConfig>;
export declare class SwarmCoordinator extends EventEmitter {
private readonly config;
private agents;
private tasks;
private taskQueue;
private heartbeatTimer?;
private started;
constructor(config?: Partial<SwarmConfig>);
/**
* Start the swarm coordinator
*/
start(): Promise<void>;
/**
* Stop the swarm coordinator
*/
stop(): Promise<void>;
/**
* Spawn a new worker agent
*/
spawnAgent(type: WorkerType): Promise<SwarmAgent>;
/**
* Remove an agent
*/
removeAgent(agentId: string): Promise<boolean>;
/**
* Dispatch a task to the swarm
*/
dispatch(options: DispatchOptions): Promise<SwarmTask>;
/**
* Wait for a task to complete
*/
waitForTask(taskId: string, timeout?: number): Promise<SwarmTask>;
/**
* Complete a task (called by worker)
*/
completeTask(taskId: string, result?: unknown, error?: string): void;
/**
* Get swarm status
*/
getStatus(): {
topology: SwarmTopology;
consensus: ConsensusProtocol;
agentCount: number;
maxAgents: number;
idleAgents: number;
busyAgents: number;
pendingTasks: number;
runningTasks: number;
completedTasks: number;
failedTasks: number;
};
/**
* Get all agents
*/
getAgents(): SwarmAgent[];
/**
* Get agent by ID
*/
getAgent(agentId: string): SwarmAgent | undefined;
/**
* Get all tasks
*/
getTasks(): SwarmTask[];
/**
* Get task by ID
*/
getTask(taskId: string): SwarmTask | undefined;
/**
* Update agent heartbeat
*/
heartbeat(agentId: string): void;
private enqueueTask;
private dequeueTask;
private processQueue;
private findTaskForAgent;
private assignTask;
private checkHeartbeats;
}
export declare function createSwarmCoordinator(config?: Partial<SwarmConfig>): SwarmCoordinator;
export default SwarmCoordinator;
//# sourceMappingURL=SwarmCoordinator.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"SwarmCoordinator.d.ts","sourceRoot":"","sources":["SwarmCoordinator.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,384 @@
"use strict";
/**
* SwarmCoordinator - Multi-Agent Swarm Orchestration
*
* Provides distributed task coordination using agentic-flow patterns.
* Supports multiple topologies and consensus protocols.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.SwarmCoordinator = exports.WORKER_DEFAULTS = void 0;
exports.createSwarmCoordinator = createSwarmCoordinator;
const uuid_1 = require("uuid");
const events_1 = require("events");
// ============================================================================
// Default Worker Configurations
// ============================================================================
exports.WORKER_DEFAULTS = {
ultralearn: { type: 'ultralearn', priority: 'normal', concurrency: 2, timeout: 60000, retries: 3, backoff: 'exponential' },
optimize: { type: 'optimize', priority: 'high', concurrency: 4, timeout: 30000, retries: 2, backoff: 'exponential' },
consolidate: { type: 'consolidate', priority: 'low', concurrency: 1, timeout: 120000, retries: 1, backoff: 'linear' },
predict: { type: 'predict', priority: 'normal', concurrency: 2, timeout: 15000, retries: 2, backoff: 'exponential' },
audit: { type: 'audit', priority: 'critical', concurrency: 1, timeout: 45000, retries: 3, backoff: 'exponential' },
map: { type: 'map', priority: 'normal', concurrency: 2, timeout: 60000, retries: 2, backoff: 'linear' },
preload: { type: 'preload', priority: 'low', concurrency: 4, timeout: 10000, retries: 1, backoff: 'linear' },
deepdive: { type: 'deepdive', priority: 'normal', concurrency: 2, timeout: 90000, retries: 2, backoff: 'exponential' },
document: { type: 'document', priority: 'normal', concurrency: 2, timeout: 30000, retries: 2, backoff: 'linear' },
refactor: { type: 'refactor', priority: 'normal', concurrency: 2, timeout: 60000, retries: 2, backoff: 'exponential' },
benchmark: { type: 'benchmark', priority: 'normal', concurrency: 1, timeout: 120000, retries: 1, backoff: 'linear' },
testgaps: { type: 'testgaps', priority: 'normal', concurrency: 2, timeout: 45000, retries: 2, backoff: 'linear' },
};
// ============================================================================
// SwarmCoordinator Implementation
// ============================================================================
class SwarmCoordinator extends events_1.EventEmitter {
constructor(config = {}) {
super();
this.agents = new Map();
this.tasks = new Map();
this.taskQueue = new Map();
this.started = false;
this.config = {
topology: config.topology ?? 'hierarchical',
maxAgents: config.maxAgents ?? 8,
strategy: config.strategy ?? 'specialized',
consensus: config.consensus ?? 'raft',
heartbeatInterval: config.heartbeatInterval ?? 5000,
taskTimeout: config.taskTimeout ?? 60000,
};
// Initialize priority queues
this.taskQueue.set('critical', []);
this.taskQueue.set('high', []);
this.taskQueue.set('normal', []);
this.taskQueue.set('low', []);
}
/**
* Start the swarm coordinator
*/
async start() {
if (this.started)
return;
// Start heartbeat monitoring
this.heartbeatTimer = setInterval(() => this.checkHeartbeats(), this.config.heartbeatInterval);
this.started = true;
this.emit('started');
}
/**
* Stop the swarm coordinator
*/
async stop() {
if (!this.started)
return;
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = undefined;
}
// Mark all agents as offline
for (const agent of this.agents.values()) {
agent.status = 'offline';
}
this.started = false;
this.emit('stopped');
}
/**
* Spawn a new worker agent
*/
async spawnAgent(type) {
if (this.agents.size >= this.config.maxAgents) {
throw new Error(`Max agents (${this.config.maxAgents}) reached`);
}
const agent = {
id: (0, uuid_1.v4)(),
type,
status: 'idle',
completedTasks: 0,
failedTasks: 0,
lastHeartbeat: new Date(),
};
this.agents.set(agent.id, agent);
this.emit('agent:spawned', agent);
// Try to assign pending tasks
await this.processQueue();
return agent;
}
/**
* Remove an agent
*/
async removeAgent(agentId) {
const agent = this.agents.get(agentId);
if (!agent)
return false;
// If agent has a current task, re-queue it
if (agent.currentTask) {
const task = this.tasks.get(agent.currentTask);
if (task && task.status === 'running') {
task.status = 'pending';
task.assignedAgent = undefined;
this.enqueueTask(task);
}
}
this.agents.delete(agentId);
this.emit('agent:removed', agent);
return true;
}
/**
* Dispatch a task to the swarm
*/
async dispatch(options) {
const workerConfig = exports.WORKER_DEFAULTS[options.worker];
const priority = options.priority ?? workerConfig.priority;
const task = {
id: (0, uuid_1.v4)(),
worker: options.worker,
type: options.task.type,
content: options.task.content,
priority,
status: 'pending',
createdAt: new Date(),
};
this.tasks.set(task.id, task);
this.enqueueTask(task);
this.emit('task:created', task);
// Try to assign immediately
await this.processQueue();
return task;
}
/**
* Wait for a task to complete
*/
async waitForTask(taskId, timeout) {
const effectiveTimeout = timeout ?? this.config.taskTimeout;
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
reject(new Error(`Task ${taskId} timed out`));
}, effectiveTimeout);
const checkTask = () => {
const task = this.tasks.get(taskId);
if (!task) {
clearTimeout(timer);
reject(new Error(`Task ${taskId} not found`));
return;
}
if (task.status === 'completed' || task.status === 'failed') {
clearTimeout(timer);
resolve(task);
return;
}
// Check again soon
setTimeout(checkTask, 100);
};
checkTask();
});
}
/**
* Complete a task (called by worker)
*/
completeTask(taskId, result, error) {
const task = this.tasks.get(taskId);
if (!task)
return;
task.completedAt = new Date();
if (error) {
task.status = 'failed';
task.error = error;
}
else {
task.status = 'completed';
task.result = result;
}
// Update agent stats
if (task.assignedAgent) {
const agent = this.agents.get(task.assignedAgent);
if (agent) {
agent.status = 'idle';
agent.currentTask = undefined;
if (error) {
agent.failedTasks++;
}
else {
agent.completedTasks++;
}
}
}
this.emit(error ? 'task:failed' : 'task:completed', task);
// Process queue for next task
this.processQueue();
}
/**
* Get swarm status
*/
getStatus() {
let idleAgents = 0;
let busyAgents = 0;
let pendingTasks = 0;
let runningTasks = 0;
let completedTasks = 0;
let failedTasks = 0;
for (const agent of this.agents.values()) {
if (agent.status === 'idle')
idleAgents++;
if (agent.status === 'busy')
busyAgents++;
}
for (const task of this.tasks.values()) {
switch (task.status) {
case 'pending':
pendingTasks++;
break;
case 'running':
runningTasks++;
break;
case 'completed':
completedTasks++;
break;
case 'failed':
failedTasks++;
break;
}
}
return {
topology: this.config.topology,
consensus: this.config.consensus,
agentCount: this.agents.size,
maxAgents: this.config.maxAgents,
idleAgents,
busyAgents,
pendingTasks,
runningTasks,
completedTasks,
failedTasks,
};
}
/**
* Get all agents
*/
getAgents() {
return Array.from(this.agents.values());
}
/**
* Get agent by ID
*/
getAgent(agentId) {
return this.agents.get(agentId);
}
/**
* Get all tasks
*/
getTasks() {
return Array.from(this.tasks.values());
}
/**
* Get task by ID
*/
getTask(taskId) {
return this.tasks.get(taskId);
}
/**
* Update agent heartbeat
*/
heartbeat(agentId) {
const agent = this.agents.get(agentId);
if (agent) {
agent.lastHeartbeat = new Date();
}
}
// ==========================================================================
// Private Methods
// ==========================================================================
enqueueTask(task) {
const queue = this.taskQueue.get(task.priority);
if (queue) {
queue.push(task);
}
}
dequeueTask() {
// Priority order: critical > high > normal > low
const priorities = ['critical', 'high', 'normal', 'low'];
for (const priority of priorities) {
const queue = this.taskQueue.get(priority);
if (queue && queue.length > 0) {
return queue.shift();
}
}
return undefined;
}
async processQueue() {
// Find idle agents matching pending tasks
for (const agent of this.agents.values()) {
if (agent.status !== 'idle')
continue;
// Find a matching task
const task = this.findTaskForAgent(agent);
if (!task)
continue;
// Assign task
await this.assignTask(task, agent);
}
}
findTaskForAgent(agent) {
const priorities = ['critical', 'high', 'normal', 'low'];
for (const priority of priorities) {
const queue = this.taskQueue.get(priority);
if (!queue)
continue;
// Find task matching agent type (for specialized strategy)
// or any task (for balanced strategy)
const taskIndex = queue.findIndex(task => {
if (this.config.strategy === 'specialized') {
return task.worker === agent.type;
}
return true;
});
if (taskIndex >= 0) {
return queue.splice(taskIndex, 1)[0];
}
}
return undefined;
}
async assignTask(task, agent) {
task.status = 'running';
task.assignedAgent = agent.id;
task.startedAt = new Date();
agent.status = 'busy';
agent.currentTask = task.id;
this.emit('task:assigned', { task, agent });
// Set timeout for task
const workerConfig = exports.WORKER_DEFAULTS[task.worker];
setTimeout(() => {
const currentTask = this.tasks.get(task.id);
if (currentTask && currentTask.status === 'running') {
this.completeTask(task.id, undefined, 'Task timed out');
}
}, workerConfig.timeout);
}
checkHeartbeats() {
const now = Date.now();
const threshold = this.config.heartbeatInterval * 3; // 3 missed heartbeats
for (const agent of this.agents.values()) {
if (agent.status === 'offline')
continue;
const lastHeartbeat = agent.lastHeartbeat.getTime();
if (now - lastHeartbeat > threshold) {
agent.status = 'offline';
this.emit('agent:offline', agent);
// Re-queue any running task
if (agent.currentTask) {
const task = this.tasks.get(agent.currentTask);
if (task && task.status === 'running') {
task.status = 'pending';
task.assignedAgent = undefined;
this.enqueueTask(task);
}
}
}
}
}
}
exports.SwarmCoordinator = SwarmCoordinator;
// ============================================================================
// Factory Function
// ============================================================================
function createSwarmCoordinator(config) {
return new SwarmCoordinator(config);
}
exports.default = SwarmCoordinator;
//# sourceMappingURL=SwarmCoordinator.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,534 @@
/**
* SwarmCoordinator - Multi-Agent Swarm Orchestration
*
* Provides distributed task coordination using agentic-flow patterns.
* Supports multiple topologies and consensus protocols.
*/
import { v4 as uuidv4 } from 'uuid';
import { EventEmitter } from 'events';
// ============================================================================
// Types
// ============================================================================
export type SwarmTopology =
| 'hierarchical' // Queen-worker (anti-drift)
| 'mesh' // Peer-to-peer network
| 'hierarchical-mesh' // Hybrid for scalability
| 'adaptive'; // Dynamic switching
export type ConsensusProtocol =
| 'byzantine' // BFT (f < n/3 faulty)
| 'raft' // Leader-based (f < n/2)
| 'gossip' // Eventually consistent
| 'crdt'; // Conflict-free replication
export type WorkerType =
| 'ultralearn' // Deep knowledge acquisition
| 'optimize' // Performance optimization
| 'consolidate' // Memory consolidation (EWC++)
| 'predict' // Predictive preloading
| 'audit' // Security analysis
| 'map' // Codebase mapping
| 'preload' // Resource preloading
| 'deepdive' // Deep code analysis
| 'document' // Auto-documentation
| 'refactor' // Refactoring suggestions
| 'benchmark' // Performance benchmarking
| 'testgaps'; // Test coverage analysis
export type WorkerPriority = 'low' | 'normal' | 'high' | 'critical';
export interface SwarmConfig {
topology: SwarmTopology;
maxAgents: number;
strategy: 'specialized' | 'balanced' | 'adaptive';
consensus: ConsensusProtocol;
heartbeatInterval?: number;
taskTimeout?: number;
}
export interface WorkerConfig {
type: WorkerType;
priority: WorkerPriority;
concurrency: number;
timeout: number;
retries: number;
backoff: 'exponential' | 'linear';
}
export interface SwarmTask {
id: string;
worker: WorkerType;
type: string;
content: unknown;
priority: WorkerPriority;
status: 'pending' | 'running' | 'completed' | 'failed';
assignedAgent?: string;
result?: unknown;
error?: string;
createdAt: Date;
startedAt?: Date;
completedAt?: Date;
}
export interface SwarmAgent {
id: string;
type: WorkerType;
status: 'idle' | 'busy' | 'offline';
currentTask?: string;
completedTasks: number;
failedTasks: number;
lastHeartbeat: Date;
}
export interface DispatchOptions {
worker: WorkerType;
task: {
type: string;
content: unknown;
};
priority?: WorkerPriority;
timeout?: number;
}
// ============================================================================
// Default Worker Configurations
// ============================================================================
export const WORKER_DEFAULTS: Record<WorkerType, WorkerConfig> = {
ultralearn: { type: 'ultralearn', priority: 'normal', concurrency: 2, timeout: 60000, retries: 3, backoff: 'exponential' },
optimize: { type: 'optimize', priority: 'high', concurrency: 4, timeout: 30000, retries: 2, backoff: 'exponential' },
consolidate: { type: 'consolidate', priority: 'low', concurrency: 1, timeout: 120000, retries: 1, backoff: 'linear' },
predict: { type: 'predict', priority: 'normal', concurrency: 2, timeout: 15000, retries: 2, backoff: 'exponential' },
audit: { type: 'audit', priority: 'critical', concurrency: 1, timeout: 45000, retries: 3, backoff: 'exponential' },
map: { type: 'map', priority: 'normal', concurrency: 2, timeout: 60000, retries: 2, backoff: 'linear' },
preload: { type: 'preload', priority: 'low', concurrency: 4, timeout: 10000, retries: 1, backoff: 'linear' },
deepdive: { type: 'deepdive', priority: 'normal', concurrency: 2, timeout: 90000, retries: 2, backoff: 'exponential' },
document: { type: 'document', priority: 'normal', concurrency: 2, timeout: 30000, retries: 2, backoff: 'linear' },
refactor: { type: 'refactor', priority: 'normal', concurrency: 2, timeout: 60000, retries: 2, backoff: 'exponential' },
benchmark: { type: 'benchmark', priority: 'normal', concurrency: 1, timeout: 120000, retries: 1, backoff: 'linear' },
testgaps: { type: 'testgaps', priority: 'normal', concurrency: 2, timeout: 45000, retries: 2, backoff: 'linear' },
};
// ============================================================================
// SwarmCoordinator Implementation
// ============================================================================
export class SwarmCoordinator extends EventEmitter {
private readonly config: SwarmConfig;
private agents: Map<string, SwarmAgent> = new Map();
private tasks: Map<string, SwarmTask> = new Map();
private taskQueue: Map<WorkerPriority, SwarmTask[]> = new Map();
private heartbeatTimer?: ReturnType<typeof setInterval>;
private started: boolean = false;
constructor(config: Partial<SwarmConfig> = {}) {
super();
this.config = {
topology: config.topology ?? 'hierarchical',
maxAgents: config.maxAgents ?? 8,
strategy: config.strategy ?? 'specialized',
consensus: config.consensus ?? 'raft',
heartbeatInterval: config.heartbeatInterval ?? 5000,
taskTimeout: config.taskTimeout ?? 60000,
};
// Initialize priority queues
this.taskQueue.set('critical', []);
this.taskQueue.set('high', []);
this.taskQueue.set('normal', []);
this.taskQueue.set('low', []);
}
/**
* Start the swarm coordinator
*/
async start(): Promise<void> {
if (this.started) return;
// Start heartbeat monitoring
this.heartbeatTimer = setInterval(
() => this.checkHeartbeats(),
this.config.heartbeatInterval
);
this.started = true;
this.emit('started');
}
/**
* Stop the swarm coordinator
*/
async stop(): Promise<void> {
if (!this.started) return;
if (this.heartbeatTimer) {
clearInterval(this.heartbeatTimer);
this.heartbeatTimer = undefined;
}
// Mark all agents as offline
for (const agent of this.agents.values()) {
agent.status = 'offline';
}
this.started = false;
this.emit('stopped');
}
/**
* Spawn a new worker agent
*/
async spawnAgent(type: WorkerType): Promise<SwarmAgent> {
if (this.agents.size >= this.config.maxAgents) {
throw new Error(`Max agents (${this.config.maxAgents}) reached`);
}
const agent: SwarmAgent = {
id: uuidv4(),
type,
status: 'idle',
completedTasks: 0,
failedTasks: 0,
lastHeartbeat: new Date(),
};
this.agents.set(agent.id, agent);
this.emit('agent:spawned', agent);
// Try to assign pending tasks
await this.processQueue();
return agent;
}
/**
* Remove an agent
*/
async removeAgent(agentId: string): Promise<boolean> {
const agent = this.agents.get(agentId);
if (!agent) return false;
// If agent has a current task, re-queue it
if (agent.currentTask) {
const task = this.tasks.get(agent.currentTask);
if (task && task.status === 'running') {
task.status = 'pending';
task.assignedAgent = undefined;
this.enqueueTask(task);
}
}
this.agents.delete(agentId);
this.emit('agent:removed', agent);
return true;
}
/**
* Dispatch a task to the swarm
*/
async dispatch(options: DispatchOptions): Promise<SwarmTask> {
const workerConfig = WORKER_DEFAULTS[options.worker];
const priority = options.priority ?? workerConfig.priority;
const task: SwarmTask = {
id: uuidv4(),
worker: options.worker,
type: options.task.type,
content: options.task.content,
priority,
status: 'pending',
createdAt: new Date(),
};
this.tasks.set(task.id, task);
this.enqueueTask(task);
this.emit('task:created', task);
// Try to assign immediately
await this.processQueue();
return task;
}
/**
* Wait for a task to complete
*/
async waitForTask(taskId: string, timeout?: number): Promise<SwarmTask> {
const effectiveTimeout = timeout ?? this.config.taskTimeout;
return new Promise((resolve, reject) => {
const timer = setTimeout(() => {
reject(new Error(`Task ${taskId} timed out`));
}, effectiveTimeout);
const checkTask = () => {
const task = this.tasks.get(taskId);
if (!task) {
clearTimeout(timer);
reject(new Error(`Task ${taskId} not found`));
return;
}
if (task.status === 'completed' || task.status === 'failed') {
clearTimeout(timer);
resolve(task);
return;
}
// Check again soon
setTimeout(checkTask, 100);
};
checkTask();
});
}
/**
* Complete a task (called by worker)
*/
completeTask(taskId: string, result?: unknown, error?: string): void {
const task = this.tasks.get(taskId);
if (!task) return;
task.completedAt = new Date();
if (error) {
task.status = 'failed';
task.error = error;
} else {
task.status = 'completed';
task.result = result;
}
// Update agent stats
if (task.assignedAgent) {
const agent = this.agents.get(task.assignedAgent);
if (agent) {
agent.status = 'idle';
agent.currentTask = undefined;
if (error) {
agent.failedTasks++;
} else {
agent.completedTasks++;
}
}
}
this.emit(error ? 'task:failed' : 'task:completed', task);
// Process queue for next task
this.processQueue();
}
/**
* Get swarm status
*/
getStatus(): {
topology: SwarmTopology;
consensus: ConsensusProtocol;
agentCount: number;
maxAgents: number;
idleAgents: number;
busyAgents: number;
pendingTasks: number;
runningTasks: number;
completedTasks: number;
failedTasks: number;
} {
let idleAgents = 0;
let busyAgents = 0;
let pendingTasks = 0;
let runningTasks = 0;
let completedTasks = 0;
let failedTasks = 0;
for (const agent of this.agents.values()) {
if (agent.status === 'idle') idleAgents++;
if (agent.status === 'busy') busyAgents++;
}
for (const task of this.tasks.values()) {
switch (task.status) {
case 'pending': pendingTasks++; break;
case 'running': runningTasks++; break;
case 'completed': completedTasks++; break;
case 'failed': failedTasks++; break;
}
}
return {
topology: this.config.topology,
consensus: this.config.consensus,
agentCount: this.agents.size,
maxAgents: this.config.maxAgents,
idleAgents,
busyAgents,
pendingTasks,
runningTasks,
completedTasks,
failedTasks,
};
}
/**
* Get all agents
*/
getAgents(): SwarmAgent[] {
return Array.from(this.agents.values());
}
/**
* Get agent by ID
*/
getAgent(agentId: string): SwarmAgent | undefined {
return this.agents.get(agentId);
}
/**
* Get all tasks
*/
getTasks(): SwarmTask[] {
return Array.from(this.tasks.values());
}
/**
* Get task by ID
*/
getTask(taskId: string): SwarmTask | undefined {
return this.tasks.get(taskId);
}
/**
* Update agent heartbeat
*/
heartbeat(agentId: string): void {
const agent = this.agents.get(agentId);
if (agent) {
agent.lastHeartbeat = new Date();
}
}
// ==========================================================================
// Private Methods
// ==========================================================================
private enqueueTask(task: SwarmTask): void {
const queue = this.taskQueue.get(task.priority);
if (queue) {
queue.push(task);
}
}
private dequeueTask(): SwarmTask | undefined {
// Priority order: critical > high > normal > low
const priorities: WorkerPriority[] = ['critical', 'high', 'normal', 'low'];
for (const priority of priorities) {
const queue = this.taskQueue.get(priority);
if (queue && queue.length > 0) {
return queue.shift();
}
}
return undefined;
}
private async processQueue(): Promise<void> {
// Find idle agents matching pending tasks
for (const agent of this.agents.values()) {
if (agent.status !== 'idle') continue;
// Find a matching task
const task = this.findTaskForAgent(agent);
if (!task) continue;
// Assign task
await this.assignTask(task, agent);
}
}
private findTaskForAgent(agent: SwarmAgent): SwarmTask | undefined {
const priorities: WorkerPriority[] = ['critical', 'high', 'normal', 'low'];
for (const priority of priorities) {
const queue = this.taskQueue.get(priority);
if (!queue) continue;
// Find task matching agent type (for specialized strategy)
// or any task (for balanced strategy)
const taskIndex = queue.findIndex(task => {
if (this.config.strategy === 'specialized') {
return task.worker === agent.type;
}
return true;
});
if (taskIndex >= 0) {
return queue.splice(taskIndex, 1)[0];
}
}
return undefined;
}
private async assignTask(task: SwarmTask, agent: SwarmAgent): Promise<void> {
task.status = 'running';
task.assignedAgent = agent.id;
task.startedAt = new Date();
agent.status = 'busy';
agent.currentTask = task.id;
this.emit('task:assigned', { task, agent });
// Set timeout for task
const workerConfig = WORKER_DEFAULTS[task.worker];
setTimeout(() => {
const currentTask = this.tasks.get(task.id);
if (currentTask && currentTask.status === 'running') {
this.completeTask(task.id, undefined, 'Task timed out');
}
}, workerConfig.timeout);
}
private checkHeartbeats(): void {
const now = Date.now();
const threshold = this.config.heartbeatInterval! * 3; // 3 missed heartbeats
for (const agent of this.agents.values()) {
if (agent.status === 'offline') continue;
const lastHeartbeat = agent.lastHeartbeat.getTime();
if (now - lastHeartbeat > threshold) {
agent.status = 'offline';
this.emit('agent:offline', agent);
// Re-queue any running task
if (agent.currentTask) {
const task = this.tasks.get(agent.currentTask);
if (task && task.status === 'running') {
task.status = 'pending';
task.assignedAgent = undefined;
this.enqueueTask(task);
}
}
}
}
}
}
// ============================================================================
// Factory Function
// ============================================================================
export function createSwarmCoordinator(config?: Partial<SwarmConfig>): SwarmCoordinator {
return new SwarmCoordinator(config);
}
export default SwarmCoordinator;

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,eAAe,EACf,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,UAAU,EACf,KAAK,eAAe,GACrB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,kBAAkB,EAClB,wBAAwB,EACxB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,QAAQ,EACb,KAAK,IAAI,EACT,KAAK,eAAe,EACpB,KAAK,WAAW,GACjB,MAAM,yBAAyB,CAAC"}

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAEH,6DAa+B;AAZ7B,uHAAA,gBAAgB,OAAA;AAChB,6HAAA,sBAAsB,OAAA;AACtB,sHAAA,eAAe,OAAA;AAYjB,iEASiC;AAR/B,2HAAA,kBAAkB,OAAA;AAClB,iIAAA,wBAAwB,OAAA"}

View File

@@ -0,0 +1,31 @@
/**
* Swarm module exports
*
* Multi-agent swarm coordination with agentic-flow patterns.
*/
export {
SwarmCoordinator,
createSwarmCoordinator,
WORKER_DEFAULTS,
type SwarmTopology,
type ConsensusProtocol,
type WorkerType,
type WorkerPriority,
type SwarmConfig,
type WorkerConfig,
type SwarmTask,
type SwarmAgent,
type DispatchOptions,
} from './SwarmCoordinator.js';
export {
ByzantineConsensus,
createByzantineConsensus,
type ConsensusPhase,
type ConsensusConfig,
type Proposal,
type Vote,
type ConsensusResult,
type ReplicaInfo,
} from './ByzantineConsensus.js';