/** * swarm-join.ts — Swarm coordination for dynamic agent groups * * Manages runtime join/leave swarms with configurable delivery strategies * (live streaming, quorum, batch). Unlike fixed GroupJoinManager, swarms * accept agents at runtime and deliver results via aggregation strategies. */ import type { AgentRecord } from "./types.js"; export type SwarmDeliveryCallback = (records: AgentRecord[], partial: boolean, swarmId: string, meta?: SwarmDeliveryMeta) => void; export interface SwarmDeliveryMeta { /** Delivery strategy used for this batch. */ strategy: SwarmStrategy; /** Number of agents that contributed. */ contributorCount: number; /** Number of agents still pending. */ pendingCount: number; /** Epoch/tick number for this delivery. */ epoch: number; /** Whether this was triggered by timeout (stragglers). */ timedOut: boolean; /** Quorum achieved? */ quorumMet: boolean; /** * Members that never joined because their spawn failed mid-fanout. * Absent when the swarm spawned complete. */ missingMembers?: number; } export type SwarmStrategy = "live" | "quorum" | "batch"; export type SwarmAgentStatus = "idle" | "running" | "completed" | "failed" | "timeout" | "left"; export interface SwarmAgentState { agentId: string; status: SwarmAgentStatus; joinedAt: number; completedAt?: number; record?: AgentRecord; } export interface SwarmConfig { /** Unique swarm identifier. */ swarmId: string; /** Human-readable name. */ name: string; /** Delivery strategy. Default: "live". */ strategy?: SwarmStrategy; /** Timeout after first completion (ms). Default: 30s. */ swarmTimeout?: number; /** Timeout for stragglers after partial delivery (ms). Default: 15s. */ stragglerTimeout?: number; /** Minimum agents required for quorum. Default: 1. */ quorumMin?: number; /** Percentage of agents required for quorum (0-1). Default: 0.5. */ quorumPercent?: number; /** Max deliveries per second (backpressure). Default: 10. */ maxDeliveryRate?: number; /** Auto-cleanup empty swarms. Default: true. */ autoCleanup?: boolean; /** * Members that will never join this swarm (mid-fanout spawn failure). * Surfaced in the delivery meta so the swarm finalizes with an explicit * partial status instead of unqualified success. */ missingMembers?: number; /** Callback when swarm state changes. */ onStateChange?: (swarmId: string, event: SwarmEvent) => void; } export type SwarmEvent = { type: "agent:joined"; agentId: string; timestamp: number; } | { type: "agent:left"; agentId: string; reason: "manual" | "timeout" | "failed" | "cleanup"; timestamp: number; } | { type: "agent:completed"; agentId: string; record: AgentRecord; timestamp: number; } | { type: "agent:failed"; agentId: string; error?: string; timestamp: number; } | { type: "delivery"; records: AgentRecord[]; partial: boolean; meta: SwarmDeliveryMeta; timestamp: number; } | { type: "quorum:met"; count: number; required: number; timestamp: number; } | { type: "timeout"; pendingAgents: string[]; timestamp: number; } | { type: "swarm:created"; timestamp: number; } | { type: "swarm:disposed"; timestamp: number; }; export declare class SwarmCoordinator { private swarms; private agentToSwarm; private deliverCb; private defaultSwarmTimeout; /** Global metrics aggregator. */ private metrics; constructor(deliverCb: SwarmDeliveryCallback, defaultSwarmTimeout?: number); /** * Create a new swarm with full configuration. * Returns the swarmId. */ createSwarm(name?: string): string; createSwarm(config: Omit & { swarmId?: string; }): string; /** * Dispose a swarm and clean up all resources. */ disposeSwarm(swarmId: string): boolean; /** * Add an agent to a swarm at runtime. Core primitive for dynamic collaboration. */ addAgentToSwarm(swarmId: string, agentId: string): boolean; /** * Remove an agent from its swarm. Supports graceful leave. */ removeAgentFromSwarm(agentId: string): boolean; /** * Called when a swarm agent completes its task. * * Strategies: * - "live": Deliver immediately (streaming collaboration) * - "quorum": Deliver when quorum reached * - "batch": Traditional batch, hold until all complete or timeout */ onAgentComplete(record: AgentRecord): "delivered" | "held" | "pass"; private onTimeout; private deliverBatch; private checkRateLimit; private cleanupRateLimit; private computeQuorumRequired; private emit; listSwarms(): Array<{ swarmId: string; name: string; agentCount: number; strategy: SwarmStrategy; }>; getSwarmMetrics(swarmId?: string): SwarmMetrics; dispose(): void; } export interface SwarmMetrics { totalDeliveries: number; totalRecordsDelivered: number; partialDeliveries: number; timedOutDeliveries: number; averageLatencyMs?: number; bySwarm: Record; } export declare function setActiveSwarmCoordinator(coordinator: SwarmCoordinator | null): void; export declare function getSwarmCoordinator(): SwarmCoordinator | null; /** * Backwards-compat convenience: create or join a swarm from the UI layer. */ export declare function uiCreateOrJoinSwarm(agentIds: string[], suggestedName?: string): string | null;