@sparkleideas/swarm 3.0.0-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/MIGRATION.md +472 -0
  2. package/README.md +634 -0
  3. package/__tests__/consensus.test.ts +577 -0
  4. package/__tests__/coordinator.test.ts +501 -0
  5. package/__tests__/queen-coordinator.test.ts +1335 -0
  6. package/__tests__/topology.test.ts +621 -0
  7. package/package.json +32 -0
  8. package/src/agent-pool.ts +476 -0
  9. package/src/application/commands/create-task.command.ts +124 -0
  10. package/src/application/commands/spawn-agent.command.ts +122 -0
  11. package/src/application/index.ts +30 -0
  12. package/src/application/services/swarm-application-service.ts +200 -0
  13. package/src/attention-coordinator.ts +1000 -0
  14. package/src/consensus/byzantine.ts +431 -0
  15. package/src/consensus/gossip.ts +513 -0
  16. package/src/consensus/index.ts +267 -0
  17. package/src/consensus/raft.ts +443 -0
  18. package/src/coordination/agent-registry.ts +544 -0
  19. package/src/coordination/index.ts +23 -0
  20. package/src/coordination/swarm-hub.ts +776 -0
  21. package/src/coordination/task-orchestrator.ts +605 -0
  22. package/src/domain/entities/agent.d.ts +151 -0
  23. package/src/domain/entities/agent.d.ts.map +1 -0
  24. package/src/domain/entities/agent.js +280 -0
  25. package/src/domain/entities/agent.js.map +1 -0
  26. package/src/domain/entities/agent.ts +370 -0
  27. package/src/domain/entities/task.d.ts +133 -0
  28. package/src/domain/entities/task.d.ts.map +1 -0
  29. package/src/domain/entities/task.js +261 -0
  30. package/src/domain/entities/task.js.map +1 -0
  31. package/src/domain/entities/task.ts +319 -0
  32. package/src/domain/index.ts +41 -0
  33. package/src/domain/repositories/agent-repository.interface.d.ts +57 -0
  34. package/src/domain/repositories/agent-repository.interface.d.ts.map +1 -0
  35. package/src/domain/repositories/agent-repository.interface.js +9 -0
  36. package/src/domain/repositories/agent-repository.interface.js.map +1 -0
  37. package/src/domain/repositories/agent-repository.interface.ts +69 -0
  38. package/src/domain/repositories/task-repository.interface.d.ts +61 -0
  39. package/src/domain/repositories/task-repository.interface.d.ts.map +1 -0
  40. package/src/domain/repositories/task-repository.interface.js +9 -0
  41. package/src/domain/repositories/task-repository.interface.js.map +1 -0
  42. package/src/domain/repositories/task-repository.interface.ts +75 -0
  43. package/src/domain/services/coordination-service.ts +320 -0
  44. package/src/federation-hub.d.ts +284 -0
  45. package/src/federation-hub.d.ts.map +1 -0
  46. package/src/federation-hub.js +692 -0
  47. package/src/federation-hub.js.map +1 -0
  48. package/src/federation-hub.ts +979 -0
  49. package/src/index.ts +348 -0
  50. package/src/message-bus.ts +607 -0
  51. package/src/queen-coordinator.ts +2025 -0
  52. package/src/shared/events.ts +285 -0
  53. package/src/shared/types.ts +389 -0
  54. package/src/topology-manager.ts +656 -0
  55. package/src/types.ts +545 -0
  56. package/src/unified-coordinator.ts +1844 -0
  57. package/src/workers/index.ts +65 -0
  58. package/src/workers/worker-dispatch.d.ts +234 -0
  59. package/src/workers/worker-dispatch.d.ts.map +1 -0
  60. package/src/workers/worker-dispatch.js +842 -0
  61. package/src/workers/worker-dispatch.js.map +1 -0
  62. package/src/workers/worker-dispatch.ts +1076 -0
  63. package/tmp.json +0 -0
  64. package/tsconfig.json +9 -0
  65. package/vitest.config.ts +20 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-repository.interface.js","sourceRoot":"","sources":["agent-repository.interface.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Agent Repository Interface - Domain Layer
3
+ *
4
+ * Defines the contract for agent persistence.
5
+ *
6
+ * @module v3/swarm/domain/repositories
7
+ */
8
+
9
+ import { Agent, AgentStatus, AgentRole } from '../entities/agent.js';
10
+
11
+ /**
12
+ * Agent query options
13
+ */
14
+ export interface AgentQueryOptions {
15
+ status?: AgentStatus;
16
+ role?: AgentRole;
17
+ domain?: string;
18
+ parentId?: string;
19
+ capability?: string;
20
+ limit?: number;
21
+ offset?: number;
22
+ }
23
+
24
+ /**
25
+ * Agent statistics
26
+ */
27
+ export interface AgentStatistics {
28
+ total: number;
29
+ byStatus: Record<AgentStatus, number>;
30
+ byRole: Record<string, number>;
31
+ byDomain: Record<string, number>;
32
+ totalTasksCompleted: number;
33
+ averageUtilization: number;
34
+ }
35
+
36
+ /**
37
+ * Agent Repository Interface
38
+ */
39
+ export interface IAgentRepository {
40
+ // CRUD
41
+ save(agent: Agent): Promise<void>;
42
+ findById(id: string): Promise<Agent | null>;
43
+ findByName(name: string): Promise<Agent | null>;
44
+ delete(id: string): Promise<boolean>;
45
+ exists(id: string): Promise<boolean>;
46
+
47
+ // Bulk operations
48
+ saveMany(agents: Agent[]): Promise<void>;
49
+ findByIds(ids: string[]): Promise<Agent[]>;
50
+ deleteMany(ids: string[]): Promise<number>;
51
+
52
+ // Query operations
53
+ findAll(options?: AgentQueryOptions): Promise<Agent[]>;
54
+ findByStatus(status: AgentStatus): Promise<Agent[]>;
55
+ findByRole(role: AgentRole): Promise<Agent[]>;
56
+ findByDomain(domain: string): Promise<Agent[]>;
57
+ findByParent(parentId: string): Promise<Agent[]>;
58
+ findByCapability(capability: string): Promise<Agent[]>;
59
+ findAvailable(): Promise<Agent[]>;
60
+
61
+ // Statistics
62
+ getStatistics(): Promise<AgentStatistics>;
63
+ count(options?: AgentQueryOptions): Promise<number>;
64
+
65
+ // Lifecycle
66
+ initialize(): Promise<void>;
67
+ shutdown(): Promise<void>;
68
+ clear(): Promise<void>;
69
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Task Repository Interface - Domain Layer
3
+ *
4
+ * Defines the contract for task persistence.
5
+ *
6
+ * @module v3/swarm/domain/repositories
7
+ */
8
+ import { Task, TaskStatus, TaskPriority } from '../entities/task.js';
9
+ /**
10
+ * Task query options
11
+ */
12
+ export interface TaskQueryOptions {
13
+ status?: TaskStatus;
14
+ priority?: TaskPriority;
15
+ type?: string;
16
+ assignedAgentId?: string;
17
+ limit?: number;
18
+ offset?: number;
19
+ orderBy?: 'createdAt' | 'priority' | 'startedAt';
20
+ orderDirection?: 'asc' | 'desc';
21
+ }
22
+ /**
23
+ * Task statistics
24
+ */
25
+ export interface TaskStatistics {
26
+ total: number;
27
+ byStatus: Record<TaskStatus, number>;
28
+ byPriority: Record<TaskPriority, number>;
29
+ byType: Record<string, number>;
30
+ averageExecutionTime: number;
31
+ successRate: number;
32
+ retryRate: number;
33
+ }
34
+ /**
35
+ * Task Repository Interface
36
+ */
37
+ export interface ITaskRepository {
38
+ save(task: Task): Promise<void>;
39
+ findById(id: string): Promise<Task | null>;
40
+ delete(id: string): Promise<boolean>;
41
+ exists(id: string): Promise<boolean>;
42
+ saveMany(tasks: Task[]): Promise<void>;
43
+ findByIds(ids: string[]): Promise<Task[]>;
44
+ deleteMany(ids: string[]): Promise<number>;
45
+ findAll(options?: TaskQueryOptions): Promise<Task[]>;
46
+ findByStatus(status: TaskStatus): Promise<Task[]>;
47
+ findByPriority(priority: TaskPriority): Promise<Task[]>;
48
+ findByAgent(agentId: string): Promise<Task[]>;
49
+ findPending(): Promise<Task[]>;
50
+ findQueued(): Promise<Task[]>;
51
+ findRunning(): Promise<Task[]>;
52
+ findTimedOut(): Promise<Task[]>;
53
+ getNextTask(agentCapabilities?: string[]): Promise<Task | null>;
54
+ getTaskQueue(limit?: number): Promise<Task[]>;
55
+ getStatistics(): Promise<TaskStatistics>;
56
+ count(options?: TaskQueryOptions): Promise<number>;
57
+ initialize(): Promise<void>;
58
+ shutdown(): Promise<void>;
59
+ clear(): Promise<void>;
60
+ }
61
+ //# sourceMappingURL=task-repository.interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-repository.interface.d.ts","sourceRoot":"","sources":["task-repository.interface.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Task Repository Interface - Domain Layer
3
+ *
4
+ * Defines the contract for task persistence.
5
+ *
6
+ * @module v3/swarm/domain/repositories
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=task-repository.interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"task-repository.interface.js","sourceRoot":"","sources":["task-repository.interface.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Task Repository Interface - Domain Layer
3
+ *
4
+ * Defines the contract for task persistence.
5
+ *
6
+ * @module v3/swarm/domain/repositories
7
+ */
8
+
9
+ import { Task, TaskStatus, TaskPriority } from '../entities/task.js';
10
+
11
+ /**
12
+ * Task query options
13
+ */
14
+ export interface TaskQueryOptions {
15
+ status?: TaskStatus;
16
+ priority?: TaskPriority;
17
+ type?: string;
18
+ assignedAgentId?: string;
19
+ limit?: number;
20
+ offset?: number;
21
+ orderBy?: 'createdAt' | 'priority' | 'startedAt';
22
+ orderDirection?: 'asc' | 'desc';
23
+ }
24
+
25
+ /**
26
+ * Task statistics
27
+ */
28
+ export interface TaskStatistics {
29
+ total: number;
30
+ byStatus: Record<TaskStatus, number>;
31
+ byPriority: Record<TaskPriority, number>;
32
+ byType: Record<string, number>;
33
+ averageExecutionTime: number;
34
+ successRate: number;
35
+ retryRate: number;
36
+ }
37
+
38
+ /**
39
+ * Task Repository Interface
40
+ */
41
+ export interface ITaskRepository {
42
+ // CRUD
43
+ save(task: Task): Promise<void>;
44
+ findById(id: string): Promise<Task | null>;
45
+ delete(id: string): Promise<boolean>;
46
+ exists(id: string): Promise<boolean>;
47
+
48
+ // Bulk operations
49
+ saveMany(tasks: Task[]): Promise<void>;
50
+ findByIds(ids: string[]): Promise<Task[]>;
51
+ deleteMany(ids: string[]): Promise<number>;
52
+
53
+ // Query operations
54
+ findAll(options?: TaskQueryOptions): Promise<Task[]>;
55
+ findByStatus(status: TaskStatus): Promise<Task[]>;
56
+ findByPriority(priority: TaskPriority): Promise<Task[]>;
57
+ findByAgent(agentId: string): Promise<Task[]>;
58
+ findPending(): Promise<Task[]>;
59
+ findQueued(): Promise<Task[]>;
60
+ findRunning(): Promise<Task[]>;
61
+ findTimedOut(): Promise<Task[]>;
62
+
63
+ // Queue operations
64
+ getNextTask(agentCapabilities?: string[]): Promise<Task | null>;
65
+ getTaskQueue(limit?: number): Promise<Task[]>;
66
+
67
+ // Statistics
68
+ getStatistics(): Promise<TaskStatistics>;
69
+ count(options?: TaskQueryOptions): Promise<number>;
70
+
71
+ // Lifecycle
72
+ initialize(): Promise<void>;
73
+ shutdown(): Promise<void>;
74
+ clear(): Promise<void>;
75
+ }
@@ -0,0 +1,320 @@
1
+ /**
2
+ * Coordination Domain Service - Domain Layer
3
+ *
4
+ * Contains coordination logic that spans multiple entities.
5
+ * Handles task assignment, load balancing, and swarm orchestration.
6
+ *
7
+ * @module v3/swarm/domain/services
8
+ */
9
+
10
+ import { Agent, AgentRole } from '../entities/agent.js';
11
+ import { Task, TaskPriority } from '../entities/task.js';
12
+ import { IAgentRepository } from '../repositories/agent-repository.interface.js';
13
+ import { ITaskRepository } from '../repositories/task-repository.interface.js';
14
+
15
+ /**
16
+ * Load balancing strategy
17
+ */
18
+ export type LoadBalancingStrategy = 'round-robin' | 'least-loaded' | 'capability-match' | 'random';
19
+
20
+ /**
21
+ * Task assignment result
22
+ */
23
+ export interface TaskAssignmentResult {
24
+ success: boolean;
25
+ taskId: string;
26
+ agentId?: string;
27
+ reason?: string;
28
+ }
29
+
30
+ /**
31
+ * Swarm health status
32
+ */
33
+ export interface SwarmHealth {
34
+ healthy: boolean;
35
+ totalAgents: number;
36
+ activeAgents: number;
37
+ errorAgents: number;
38
+ pendingTasks: number;
39
+ runningTasks: number;
40
+ queueDepth: number;
41
+ averageUtilization: number;
42
+ issues: string[];
43
+ }
44
+
45
+ /**
46
+ * Coordination Domain Service
47
+ *
48
+ * Provides domain-level coordination operations.
49
+ */
50
+ export class CoordinationService {
51
+ constructor(
52
+ private readonly agentRepository: IAgentRepository,
53
+ private readonly taskRepository: ITaskRepository
54
+ ) {}
55
+
56
+ /**
57
+ * Assign a task to the best available agent
58
+ */
59
+ async assignTask(
60
+ taskId: string,
61
+ strategy: LoadBalancingStrategy = 'capability-match'
62
+ ): Promise<TaskAssignmentResult> {
63
+ const task = await this.taskRepository.findById(taskId);
64
+ if (!task) {
65
+ return { success: false, taskId, reason: 'Task not found' };
66
+ }
67
+
68
+ // Check dependencies
69
+ const completedTasks = await this.taskRepository.findByStatus('completed');
70
+ const completedIds = new Set(completedTasks.map((t) => t.id));
71
+
72
+ if (!task.areDependenciesSatisfied(completedIds)) {
73
+ return { success: false, taskId, reason: 'Dependencies not satisfied' };
74
+ }
75
+
76
+ // Find best agent
77
+ const agent = await this.findBestAgent(task, strategy);
78
+ if (!agent) {
79
+ return { success: false, taskId, reason: 'No available agents' };
80
+ }
81
+
82
+ // Assign task
83
+ task.assign(agent.id);
84
+ agent.assignTask(taskId);
85
+
86
+ await this.taskRepository.save(task);
87
+ await this.agentRepository.save(agent);
88
+
89
+ return { success: true, taskId, agentId: agent.id };
90
+ }
91
+
92
+ /**
93
+ * Find the best agent for a task based on strategy
94
+ */
95
+ private async findBestAgent(
96
+ task: Task,
97
+ strategy: LoadBalancingStrategy
98
+ ): Promise<Agent | null> {
99
+ const availableAgents = await this.agentRepository.findAvailable();
100
+
101
+ if (availableAgents.length === 0) return null;
102
+
103
+ switch (strategy) {
104
+ case 'round-robin':
105
+ return this.roundRobinSelection(availableAgents);
106
+
107
+ case 'least-loaded':
108
+ return this.leastLoadedSelection(availableAgents);
109
+
110
+ case 'capability-match':
111
+ return this.capabilityMatchSelection(availableAgents, task);
112
+
113
+ case 'random':
114
+ return availableAgents[Math.floor(Math.random() * availableAgents.length)];
115
+
116
+ default:
117
+ return availableAgents[0];
118
+ }
119
+ }
120
+
121
+ private roundRobinSelection(agents: Agent[]): Agent {
122
+ // Sort by last active time and pick least recently used
123
+ return [...agents].sort(
124
+ (a, b) => a.lastActiveAt.getTime() - b.lastActiveAt.getTime()
125
+ )[0];
126
+ }
127
+
128
+ private leastLoadedSelection(agents: Agent[]): Agent {
129
+ return [...agents].sort((a, b) => a.getUtilization() - b.getUtilization())[0];
130
+ }
131
+
132
+ private capabilityMatchSelection(agents: Agent[], task: Task): Agent | null {
133
+ // Extract required capabilities from task type and metadata
134
+ const requiredCapabilities = this.extractRequiredCapabilities(task);
135
+
136
+ // Score agents by capability match
137
+ const scored = agents.map((agent) => {
138
+ let score = 0;
139
+ for (const cap of requiredCapabilities) {
140
+ if (agent.hasCapability(cap)) score++;
141
+ }
142
+ // Factor in utilization (prefer less loaded)
143
+ score -= agent.getUtilization() * 0.5;
144
+ return { agent, score };
145
+ });
146
+
147
+ scored.sort((a, b) => b.score - a.score);
148
+
149
+ // Return best match if any capabilities matched
150
+ if (scored.length > 0 && scored[0].score > 0) {
151
+ return scored[0].agent;
152
+ }
153
+
154
+ // Fallback to least loaded
155
+ return this.leastLoadedSelection(agents);
156
+ }
157
+
158
+ private extractRequiredCapabilities(task: Task): string[] {
159
+ const capabilities: string[] = [task.type];
160
+
161
+ // Map task types to required capabilities
162
+ const capabilityMap: Record<string, string[]> = {
163
+ implementation: ['coding', 'testing'],
164
+ review: ['review', 'analysis'],
165
+ testing: ['testing', 'qa'],
166
+ documentation: ['documentation', 'writing'],
167
+ security: ['security', 'audit'],
168
+ performance: ['performance', 'optimization'],
169
+ };
170
+
171
+ if (capabilityMap[task.type]) {
172
+ capabilities.push(...capabilityMap[task.type]);
173
+ }
174
+
175
+ return capabilities;
176
+ }
177
+
178
+ /**
179
+ * Process completed tasks and release agents
180
+ */
181
+ async processTaskCompletion(taskId: string, output?: unknown): Promise<void> {
182
+ const task = await this.taskRepository.findById(taskId);
183
+ if (!task || !task.assignedAgentId) return;
184
+
185
+ const agent = await this.agentRepository.findById(task.assignedAgentId);
186
+
187
+ task.complete(output);
188
+ await this.taskRepository.save(task);
189
+
190
+ if (agent) {
191
+ agent.completeTask(taskId);
192
+ await this.agentRepository.save(agent);
193
+ }
194
+
195
+ // Check for dependent tasks that can now be queued
196
+ await this.queueDependentTasks(taskId);
197
+ }
198
+
199
+ /**
200
+ * Queue tasks whose dependencies are now satisfied
201
+ */
202
+ private async queueDependentTasks(completedTaskId: string): Promise<void> {
203
+ const pendingTasks = await this.taskRepository.findPending();
204
+ const completedTasks = await this.taskRepository.findByStatus('completed');
205
+ const completedIds = new Set(completedTasks.map((t) => t.id));
206
+
207
+ for (const task of pendingTasks) {
208
+ if (
209
+ task.dependencies.includes(completedTaskId) &&
210
+ task.areDependenciesSatisfied(completedIds)
211
+ ) {
212
+ task.queue();
213
+ await this.taskRepository.save(task);
214
+ }
215
+ }
216
+ }
217
+
218
+ /**
219
+ * Handle task failure with retry logic
220
+ */
221
+ async processTaskFailure(taskId: string, error: string): Promise<boolean> {
222
+ const task = await this.taskRepository.findById(taskId);
223
+ if (!task) return false;
224
+
225
+ const agentId = task.assignedAgentId;
226
+
227
+ task.fail(error);
228
+ await this.taskRepository.save(task);
229
+
230
+ if (agentId) {
231
+ const agent = await this.agentRepository.findById(agentId);
232
+ if (agent) {
233
+ agent.completeTask(taskId);
234
+ await this.agentRepository.save(agent);
235
+ }
236
+ }
237
+
238
+ // Return true if task was requeued for retry
239
+ return task.status === 'queued';
240
+ }
241
+
242
+ /**
243
+ * Get overall swarm health
244
+ */
245
+ async getSwarmHealth(): Promise<SwarmHealth> {
246
+ const agentStats = await this.agentRepository.getStatistics();
247
+ const taskStats = await this.taskRepository.getStatistics();
248
+ const queuedTasks = await this.taskRepository.findQueued();
249
+
250
+ const issues: string[] = [];
251
+
252
+ // Check for issues
253
+ if (agentStats.byStatus.error > 0) {
254
+ issues.push(`${agentStats.byStatus.error} agents in error state`);
255
+ }
256
+ if (queuedTasks.length > agentStats.byStatus.active * 10) {
257
+ issues.push('Task queue backlog detected');
258
+ }
259
+ if (agentStats.averageUtilization > 0.9) {
260
+ issues.push('High agent utilization');
261
+ }
262
+
263
+ const timedOutTasks = await this.taskRepository.findTimedOut();
264
+ if (timedOutTasks.length > 0) {
265
+ issues.push(`${timedOutTasks.length} timed out tasks`);
266
+ }
267
+
268
+ return {
269
+ healthy: issues.length === 0,
270
+ totalAgents: agentStats.total,
271
+ activeAgents: agentStats.byStatus.active + agentStats.byStatus.busy,
272
+ errorAgents: agentStats.byStatus.error,
273
+ pendingTasks: taskStats.byStatus.pending,
274
+ runningTasks: taskStats.byStatus.running,
275
+ queueDepth: queuedTasks.length,
276
+ averageUtilization: agentStats.averageUtilization,
277
+ issues,
278
+ };
279
+ }
280
+
281
+ /**
282
+ * Scale agents based on workload
283
+ */
284
+ async calculateScalingRecommendation(): Promise<{
285
+ action: 'scale-up' | 'scale-down' | 'none';
286
+ count: number;
287
+ reason: string;
288
+ }> {
289
+ const health = await this.getSwarmHealth();
290
+ const queuedTasks = await this.taskRepository.findQueued();
291
+
292
+ // Scale up if queue is deep and agents are highly utilized
293
+ if (queuedTasks.length > 10 && health.averageUtilization > 0.8) {
294
+ const additionalAgents = Math.ceil(queuedTasks.length / 5);
295
+ return {
296
+ action: 'scale-up',
297
+ count: additionalAgents,
298
+ reason: 'High queue depth with high agent utilization',
299
+ };
300
+ }
301
+
302
+ // Scale down if queue is empty and many agents are idle
303
+ if (queuedTasks.length === 0 && health.averageUtilization < 0.2) {
304
+ const excessAgents = Math.floor(health.totalAgents * 0.3);
305
+ if (excessAgents > 0) {
306
+ return {
307
+ action: 'scale-down',
308
+ count: excessAgents,
309
+ reason: 'Low utilization with empty queue',
310
+ };
311
+ }
312
+ }
313
+
314
+ return {
315
+ action: 'none',
316
+ count: 0,
317
+ reason: 'Current scaling is appropriate',
318
+ };
319
+ }
320
+ }