@gotza02/seq-thinking 1.1.5 → 1.1.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.
- package/README.md +4 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp-server.js +1 -1
- package/package.json +9 -3
- package/agents_test.log +0 -15
- package/data/agents/1770106504306-dljh9ef.json +0 -68
- package/data/agents/1770106504310-4oarrst.json +0 -58
- package/data/agents/1770106540588-pvitt55.json +0 -68
- package/data/agents/1770106540595-z2ya871.json +0 -58
- package/data/agents/1770106710890-0e2naq1.json +0 -68
- package/data/agents/1770106710893-r076yxx.json +0 -58
- package/data/agents/1770109212161-4ybd0i7.json +0 -68
- package/data/agents/1770109212166-gkhya8h.json +0 -58
- package/data/agents/1770117726716-lrnm415.json +0 -68
- package/data/agents/1770117726719-w6hsf3v.json +0 -58
- package/data/sessions/1770100622009-5afiuyv.json +0 -499
- package/data/sessions/1770106504312-75zk750.json +0 -107
- package/data/sessions/1770106540597-z8e8soo.json +0 -150
- package/data/sessions/1770106710894-0kxgy5x.json +0 -150
- package/data/sessions/1770109212169-zpddeb9.json +0 -150
- package/data/sessions/1770117726720-frcwj99.json +0 -150
- package/real_world_test.log +0 -200
- package/real_world_test_dynamic.log +0 -184
- package/real_world_test_real.log +0 -184
- package/src/__tests__/agents.test.ts +0 -858
- package/src/__tests__/mcp-server.test.ts +0 -380
- package/src/__tests__/sequential-thinking.test.ts +0 -687
- package/src/__tests__/swarm-coordinator.test.ts +0 -903
- package/src/__tests__/types.test.ts +0 -839
- package/src/__tests__/utils.test.ts +0 -322
- package/src/agents/base-agent.ts +0 -288
- package/src/agents/critic-agent.ts +0 -582
- package/src/agents/index.ts +0 -11
- package/src/agents/meta-reasoning-agent.ts +0 -314
- package/src/agents/reasoner-agent.ts +0 -312
- package/src/agents/synthesizer-agent.ts +0 -641
- package/src/index.ts +0 -118
- package/src/mcp-server.ts +0 -391
- package/src/real_world_test.ts +0 -89
- package/src/sequential-thinking.ts +0 -614
- package/src/swarm-coordinator.ts +0 -772
- package/src/types/index.ts +0 -915
- package/src/utils/index.ts +0 -1004
- package/src/utils/llm-adapter.ts +0 -110
- package/src/utils/logger.ts +0 -56
- package/src/utils/persistence.ts +0 -109
- package/test_output.log +0 -0
- package/tsconfig.json +0 -21
package/src/swarm-coordinator.ts
DELETED
|
@@ -1,772 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Swarm Coordinator
|
|
3
|
-
* Handles agent registration, task queueing, message brokering, consensus, and conflict resolution.
|
|
4
|
-
*/
|
|
5
|
-
import {
|
|
6
|
-
MessageType,
|
|
7
|
-
ConsensusAlgorithm,
|
|
8
|
-
ConflictResolutionStrategy,
|
|
9
|
-
AgentConfig,
|
|
10
|
-
AgentCapability,
|
|
11
|
-
Task,
|
|
12
|
-
TaskResult,
|
|
13
|
-
SwarmMessage,
|
|
14
|
-
ConsensusVote,
|
|
15
|
-
ConsensusResult,
|
|
16
|
-
Conflict,
|
|
17
|
-
ConflictResolution,
|
|
18
|
-
ConflictPosition,
|
|
19
|
-
TaskStatus,
|
|
20
|
-
AgentStatus,
|
|
21
|
-
ConflictStatus
|
|
22
|
-
} from './types/index.js';
|
|
23
|
-
import { BaseAgent } from './agents/base-agent.js';
|
|
24
|
-
|
|
25
|
-
import { PersistenceManager } from './utils/persistence.js';
|
|
26
|
-
import { Logger } from './utils/logger.js';
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Registry to track all agents in the swarm
|
|
30
|
-
*/
|
|
31
|
-
export class AgentRegistry {
|
|
32
|
-
private agents = new Map<string, {
|
|
33
|
-
config: AgentConfig;
|
|
34
|
-
status: AgentStatus;
|
|
35
|
-
currentTasks: string[];
|
|
36
|
-
performanceHistory: { taskId: string; quality: number; timeMs: number; timestamp: Date }[];
|
|
37
|
-
instance?: BaseAgent;
|
|
38
|
-
}>();
|
|
39
|
-
|
|
40
|
-
private agentsByType = new Map<string, Set<string>>();
|
|
41
|
-
private agentsByCapability = new Map<string, Set<string>>();
|
|
42
|
-
private persistence: PersistenceManager | null = null;
|
|
43
|
-
|
|
44
|
-
constructor(persistenceDir?: string) {
|
|
45
|
-
if (persistenceDir) {
|
|
46
|
-
this.persistence = new PersistenceManager(persistenceDir);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
async initialize() {
|
|
51
|
-
if (this.persistence) {
|
|
52
|
-
await this.persistence.initialize(['agents']);
|
|
53
|
-
await this.loadAgents();
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
private async loadAgents() {
|
|
58
|
-
if (!this.persistence) return;
|
|
59
|
-
const ids = await this.persistence.list('agents');
|
|
60
|
-
for (const id of ids) {
|
|
61
|
-
const savedData = await this.persistence.load<any>('agents', id);
|
|
62
|
-
if (savedData) {
|
|
63
|
-
// We only persist the config and metadata, instances must be re-registered
|
|
64
|
-
const agent = {
|
|
65
|
-
config: savedData.config,
|
|
66
|
-
status: AgentStatus.OFFLINE, // Loaded agents start offline until instances are registered
|
|
67
|
-
currentTasks: [],
|
|
68
|
-
performanceHistory: savedData.performanceHistory || [],
|
|
69
|
-
};
|
|
70
|
-
this.agents.set(id, agent);
|
|
71
|
-
this.indexAgent(agent.config);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
private indexAgent(config: AgentConfig) {
|
|
77
|
-
if (!this.agentsByType.has(config.type)) {
|
|
78
|
-
this.agentsByType.set(config.type, new Set());
|
|
79
|
-
}
|
|
80
|
-
this.agentsByType.get(config.type)!.add(config.id);
|
|
81
|
-
|
|
82
|
-
for (const capability of config.capabilities) {
|
|
83
|
-
if (!this.agentsByCapability.has(capability.name)) {
|
|
84
|
-
this.agentsByCapability.set(capability.name, new Set());
|
|
85
|
-
}
|
|
86
|
-
this.agentsByCapability.get(capability.name)!.add(config.id);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
async registerAgent(config: AgentConfig, instance?: BaseAgent) {
|
|
91
|
-
const agent = {
|
|
92
|
-
config,
|
|
93
|
-
status: AgentStatus.IDLE, // Default to IDLE for registered agents
|
|
94
|
-
currentTasks: [],
|
|
95
|
-
performanceHistory: [],
|
|
96
|
-
instance
|
|
97
|
-
};
|
|
98
|
-
this.agents.set(config.id, agent);
|
|
99
|
-
this.indexAgent(config);
|
|
100
|
-
|
|
101
|
-
if (this.persistence) {
|
|
102
|
-
await this.persistence.save('agents', config.id, {
|
|
103
|
-
config,
|
|
104
|
-
performanceHistory: agent.performanceHistory
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return agent;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
async unregisterAgent(agentId: string) {
|
|
112
|
-
const agent = this.agents.get(agentId);
|
|
113
|
-
if (!agent) return false;
|
|
114
|
-
|
|
115
|
-
this.agents.delete(agentId);
|
|
116
|
-
this.agentsByType.get(agent.config.type)?.delete(agentId);
|
|
117
|
-
|
|
118
|
-
for (const capability of agent.config.capabilities) {
|
|
119
|
-
this.agentsByCapability.get(capability.name)?.delete(agentId);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (this.persistence) {
|
|
123
|
-
await this.persistence.delete('agents', agentId);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
return true;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
getAgent(agentId: string) {
|
|
130
|
-
return this.agents.get(agentId);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
getAgentsByType(type: string) {
|
|
134
|
-
const ids = this.agentsByType.get(type);
|
|
135
|
-
if (!ids) return [];
|
|
136
|
-
return Array.from(ids)
|
|
137
|
-
.map(id => this.agents.get(id))
|
|
138
|
-
.filter((a): a is any => a !== undefined);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
getAgentsByCapability(capability: string) {
|
|
142
|
-
const ids = this.agentsByCapability.get(capability);
|
|
143
|
-
if (!ids) return [];
|
|
144
|
-
return Array.from(ids)
|
|
145
|
-
.map(id => this.agents.get(id))
|
|
146
|
-
.filter((a): a is any => a !== undefined);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
getAllAgents() {
|
|
150
|
-
return Array.from(this.agents.values());
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
getAvailableAgents() {
|
|
154
|
-
return this.getAllAgents().filter(a => a.status === AgentStatus.IDLE);
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
updateAgentStatus(agentId: string, status: AgentStatus) {
|
|
158
|
-
const agent = this.agents.get(agentId);
|
|
159
|
-
if (agent) agent.status = status;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
recordPerformance(agentId: string, taskId: string, quality: number, timeMs: number) {
|
|
163
|
-
const agent = this.agents.get(agentId);
|
|
164
|
-
if (agent) {
|
|
165
|
-
agent.performanceHistory.push({ taskId, quality, timeMs, timestamp: new Date() });
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Broker for swarm communication
|
|
172
|
-
*/
|
|
173
|
-
export class MessageBroker {
|
|
174
|
-
private messages = new Map<string, SwarmMessage>();
|
|
175
|
-
private subscriptions = new Map<string, Set<(message: SwarmMessage) => void>>();
|
|
176
|
-
|
|
177
|
-
sendMessage(message: Partial<SwarmMessage> & { type: MessageType; senderId: string; payload: any }): SwarmMessage {
|
|
178
|
-
const fullMessage: SwarmMessage = {
|
|
179
|
-
id: `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
|
|
180
|
-
timestamp: new Date(),
|
|
181
|
-
type: message.type,
|
|
182
|
-
senderId: message.senderId,
|
|
183
|
-
recipientId: message.recipientId || null,
|
|
184
|
-
payload: message.payload,
|
|
185
|
-
context: message.context || {},
|
|
186
|
-
metadata: message.metadata || { priority: 1, ttl: 60000, retryCount: 0 }
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
this.messages.set(fullMessage.id, fullMessage);
|
|
190
|
-
|
|
191
|
-
if (fullMessage.recipientId) {
|
|
192
|
-
this.deliverToRecipient(fullMessage);
|
|
193
|
-
} else {
|
|
194
|
-
this.broadcast(fullMessage);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
return fullMessage;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
public broadcast(message: SwarmMessage) {
|
|
201
|
-
const subscribers = this.subscriptions.get('broadcast');
|
|
202
|
-
if (subscribers) {
|
|
203
|
-
subscribers.forEach(callback => {
|
|
204
|
-
try { callback(message); } catch (e) { /* ignore */ }
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
public deliverToRecipient(message: SwarmMessage) {
|
|
210
|
-
if (!message.recipientId) return;
|
|
211
|
-
const subscribers = this.subscriptions.get(message.recipientId);
|
|
212
|
-
if (subscribers) {
|
|
213
|
-
subscribers.forEach(callback => {
|
|
214
|
-
try { callback(message); } catch (e) { /* ignore */ }
|
|
215
|
-
});
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
subscribe(agentId: string, callback: (message: SwarmMessage) => void) {
|
|
220
|
-
if (!this.subscriptions.has(agentId)) {
|
|
221
|
-
this.subscriptions.set(agentId, new Set());
|
|
222
|
-
}
|
|
223
|
-
this.subscriptions.get(agentId)!.add(callback);
|
|
224
|
-
return () => { this.subscriptions.get(agentId)?.delete(callback); };
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Manager for task lifecycle
|
|
230
|
-
*/
|
|
231
|
-
export class TaskQueueManager {
|
|
232
|
-
private tasks = new Map<string, Task>();
|
|
233
|
-
private pendingQueue: string[] = [];
|
|
234
|
-
|
|
235
|
-
createTask(type: string, description: string, input: any, requirements: any, context: any = { dependencies: [] }) {
|
|
236
|
-
const task: Task = {
|
|
237
|
-
id: `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
|
|
238
|
-
type,
|
|
239
|
-
description,
|
|
240
|
-
input,
|
|
241
|
-
context,
|
|
242
|
-
requirements,
|
|
243
|
-
assignedAgentId: null,
|
|
244
|
-
status: TaskStatus.PENDING,
|
|
245
|
-
result: null,
|
|
246
|
-
metadata: { createdAt: new Date() }
|
|
247
|
-
};
|
|
248
|
-
this.tasks.set(task.id, task);
|
|
249
|
-
this.pendingQueue.push(task.id);
|
|
250
|
-
return task;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
assignTask(taskId: string, agentId: string) {
|
|
254
|
-
const task = this.tasks.get(taskId);
|
|
255
|
-
if (!task || task.status !== TaskStatus.PENDING) return null;
|
|
256
|
-
|
|
257
|
-
task.assignedAgentId = agentId;
|
|
258
|
-
task.status = TaskStatus.ASSIGNED;
|
|
259
|
-
task.metadata.assignedAt = new Date();
|
|
260
|
-
|
|
261
|
-
const index = this.pendingQueue.indexOf(taskId);
|
|
262
|
-
if (index > -1) this.pendingQueue.splice(index, 1);
|
|
263
|
-
|
|
264
|
-
return task;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
startTask(taskId: string) {
|
|
268
|
-
const task = this.tasks.get(taskId);
|
|
269
|
-
if (!task || task.status !== TaskStatus.ASSIGNED) return null;
|
|
270
|
-
|
|
271
|
-
task.status = TaskStatus.IN_PROGRESS;
|
|
272
|
-
task.metadata.startedAt = new Date();
|
|
273
|
-
return task;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
completeTask(taskId: string, result: TaskResult) {
|
|
277
|
-
const task = this.tasks.get(taskId);
|
|
278
|
-
if (!task) return;
|
|
279
|
-
|
|
280
|
-
task.status = TaskStatus.COMPLETED;
|
|
281
|
-
task.result = result;
|
|
282
|
-
task.metadata.completedAt = new Date();
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
failTask(taskId: string, error: string) {
|
|
286
|
-
const task = this.tasks.get(taskId);
|
|
287
|
-
if (!task) return;
|
|
288
|
-
|
|
289
|
-
task.status = TaskStatus.FAILED;
|
|
290
|
-
task.result = {
|
|
291
|
-
taskId,
|
|
292
|
-
agentId: task.assignedAgentId || 'unknown',
|
|
293
|
-
success: false,
|
|
294
|
-
output: null,
|
|
295
|
-
confidence: 0,
|
|
296
|
-
processingTimeMs: 0,
|
|
297
|
-
metadata: { tokensUsed: 0, reasoningSteps: 0, intermediateResults: [], error }
|
|
298
|
-
};
|
|
299
|
-
task.metadata.completedAt = new Date();
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
getTask(taskId: string) {
|
|
303
|
-
return this.tasks.get(taskId);
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
getTasksByStatus(status: TaskStatus) {
|
|
307
|
-
return Array.from(this.tasks.values()).filter(t => t.status === status);
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
getPendingTasks() {
|
|
311
|
-
return this.getTasksByStatus(TaskStatus.PENDING);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
getInProgressTasks() {
|
|
315
|
-
return this.getTasksByStatus(TaskStatus.IN_PROGRESS);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
getCompletedTasks() {
|
|
319
|
-
return this.getTasksByStatus(TaskStatus.COMPLETED);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Strategy for assigning tasks to agents
|
|
325
|
-
*/
|
|
326
|
-
export class TaskAssigner {
|
|
327
|
-
private lastAssignmentIndex = new Map<string, number>();
|
|
328
|
-
|
|
329
|
-
constructor(private registry: AgentRegistry) {}
|
|
330
|
-
|
|
331
|
-
assignTask(task: Task, strategy: string = 'adaptive', excludeAgentIds: string[] = []) {
|
|
332
|
-
const availableAgents = this.registry.getAvailableAgents()
|
|
333
|
-
.filter(a => !excludeAgentIds.includes(a.config.id))
|
|
334
|
-
.filter(a => this.hasRequiredCapabilities(a, task.requirements?.requiredCapabilities || task.requiredCapabilities || []));
|
|
335
|
-
|
|
336
|
-
if (availableAgents.length === 0) return null;
|
|
337
|
-
|
|
338
|
-
switch (strategy) {
|
|
339
|
-
case 'round_robin':
|
|
340
|
-
return this.roundRobin(availableAgents, task.type);
|
|
341
|
-
case 'capability_based':
|
|
342
|
-
return this.capabilityBased(availableAgents, task);
|
|
343
|
-
case 'load_balanced':
|
|
344
|
-
return this.loadBalanced(availableAgents);
|
|
345
|
-
default:
|
|
346
|
-
// Default to best capable
|
|
347
|
-
return this.capabilityBased(availableAgents, task);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
private hasRequiredCapabilities(agent: any, required: string[]) {
|
|
352
|
-
const agentCaps = agent.config.capabilities.map((c: any) => c.name);
|
|
353
|
-
return required.every(cap => agentCaps.includes(cap));
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
private roundRobin(agents: any[], taskType: string) {
|
|
357
|
-
const lastIndex = this.lastAssignmentIndex.get(taskType) ?? -1;
|
|
358
|
-
const nextIndex = (lastIndex + 1) % agents.length;
|
|
359
|
-
this.lastAssignmentIndex.set(taskType, nextIndex);
|
|
360
|
-
return agents[nextIndex];
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
private capabilityBased(agents: any[], task: Task) {
|
|
364
|
-
return agents.reduce((best, current) => {
|
|
365
|
-
const bestScore = this.calculateCapabilityScore(best, task);
|
|
366
|
-
const currentScore = this.calculateCapabilityScore(current, task);
|
|
367
|
-
return currentScore > bestScore ? current : best;
|
|
368
|
-
});
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
private calculateCapabilityScore(agent: any, task: Task) {
|
|
372
|
-
const requiredCaps = task.requirements?.requiredCapabilities || task.requiredCapabilities || [];
|
|
373
|
-
if (requiredCaps.length === 0) return 1.0;
|
|
374
|
-
|
|
375
|
-
const agentCaps = agent.config.capabilities;
|
|
376
|
-
let score = 0;
|
|
377
|
-
for (const reqCap of requiredCaps) {
|
|
378
|
-
const cap = agentCaps.find((c: any) => c.name === reqCap);
|
|
379
|
-
if (cap) score += cap.confidence;
|
|
380
|
-
}
|
|
381
|
-
return score / requiredCaps.length;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
private loadBalanced(agents: any[]) {
|
|
385
|
-
return agents.reduce((best, current) =>
|
|
386
|
-
current.currentTasks.length < best.currentTasks.length ? current : best
|
|
387
|
-
);
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
/**
|
|
392
|
-
* Engine for reaching consensus among agents
|
|
393
|
-
*/
|
|
394
|
-
export class ConsensusEngine {
|
|
395
|
-
async reachConsensus(
|
|
396
|
-
proposalId: string,
|
|
397
|
-
algorithm: ConsensusAlgorithm,
|
|
398
|
-
votes: ConsensusVote[],
|
|
399
|
-
minAgreementRatio: number = 0.67,
|
|
400
|
-
maxRounds: number = 1
|
|
401
|
-
): Promise<ConsensusResult> {
|
|
402
|
-
const counts = new Map<any, number>();
|
|
403
|
-
for (const vote of votes) {
|
|
404
|
-
counts.set(vote.vote, (counts.get(vote.vote) || 0) + vote.confidence);
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
let winner: any = null;
|
|
408
|
-
let maxCount = 0;
|
|
409
|
-
for (const [option, count] of counts) {
|
|
410
|
-
if (count > maxCount) {
|
|
411
|
-
maxCount = count;
|
|
412
|
-
winner = option;
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
const totalWeight = Array.from(counts.values()).reduce((a, b) => a + b, 0);
|
|
417
|
-
const agreementRatio = totalWeight > 0 ? maxCount / totalWeight : 0;
|
|
418
|
-
|
|
419
|
-
return {
|
|
420
|
-
proposalId,
|
|
421
|
-
algorithm,
|
|
422
|
-
winningOption: winner,
|
|
423
|
-
confidence: votes.length > 0 ? votes.reduce((s, v) => s + v.confidence, 0) / votes.length : 0,
|
|
424
|
-
votes,
|
|
425
|
-
agreementRatio,
|
|
426
|
-
dissentingOpinions: votes.filter(v => v.vote !== winner).map(v => ({
|
|
427
|
-
agentId: v.agentId,
|
|
428
|
-
opinion: v.vote,
|
|
429
|
-
reasoning: v.reasoning
|
|
430
|
-
})),
|
|
431
|
-
metadata: {
|
|
432
|
-
rounds: maxRounds,
|
|
433
|
-
totalVotingTimeMs: 0,
|
|
434
|
-
convergenceRate: agreementRatio
|
|
435
|
-
}
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
/**
|
|
441
|
-
* Resolver for conflicts between agents
|
|
442
|
-
*/
|
|
443
|
-
export class ConflictResolver {
|
|
444
|
-
private conflicts = new Map<string, Conflict>();
|
|
445
|
-
|
|
446
|
-
identifyConflict(type: string, description: string, positions: ConflictPosition[]) {
|
|
447
|
-
const conflict: Conflict = {
|
|
448
|
-
id: `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
|
|
449
|
-
type,
|
|
450
|
-
description,
|
|
451
|
-
involvedAgents: positions.map(p => p.agentId),
|
|
452
|
-
conflictingPositions: positions,
|
|
453
|
-
status: ConflictStatus.DETECTED,
|
|
454
|
-
resolution: null,
|
|
455
|
-
metadata: { createdAt: new Date() }
|
|
456
|
-
};
|
|
457
|
-
this.conflicts.set(conflict.id, conflict);
|
|
458
|
-
return conflict;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
resolveConflict(conflictId: string, strategy: ConflictResolutionStrategy, resolverAgentId: string) {
|
|
462
|
-
const conflict = this.conflicts.get(conflictId);
|
|
463
|
-
if (!conflict) throw new Error(`Conflict not found: ${conflictId}`);
|
|
464
|
-
|
|
465
|
-
conflict.status = ConflictStatus.RESOLVING;
|
|
466
|
-
|
|
467
|
-
let resolution: ConflictResolution;
|
|
468
|
-
switch (strategy) {
|
|
469
|
-
case ConflictResolutionStrategy.ARBITRATION:
|
|
470
|
-
const highest = conflict.conflictingPositions.reduce((max, p) => p.confidence > max.confidence ? p : max);
|
|
471
|
-
resolution = {
|
|
472
|
-
strategy: ConflictResolutionStrategy.ARBITRATION,
|
|
473
|
-
result: highest.position,
|
|
474
|
-
confidence: highest.confidence,
|
|
475
|
-
reasoning: highest.reasoning || 'Highest confidence position'
|
|
476
|
-
};
|
|
477
|
-
break;
|
|
478
|
-
case ConflictResolutionStrategy.VOTING:
|
|
479
|
-
const votes = new Map<any, number>();
|
|
480
|
-
for (const pos of conflict.conflictingPositions) {
|
|
481
|
-
votes.set(pos.position, (votes.get(pos.position) || 0) + pos.confidence);
|
|
482
|
-
}
|
|
483
|
-
let winner: any = null;
|
|
484
|
-
let maxVotes = 0;
|
|
485
|
-
for (const [pos, count] of votes) {
|
|
486
|
-
if (count > maxVotes) {
|
|
487
|
-
maxVotes = count;
|
|
488
|
-
winner = pos;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
resolution = {
|
|
492
|
-
strategy: ConflictResolutionStrategy.VOTING,
|
|
493
|
-
result: winner,
|
|
494
|
-
confidence: conflict.conflictingPositions.length > 0 ? maxVotes / conflict.conflictingPositions.length : 0,
|
|
495
|
-
reasoning: 'Majority vote'
|
|
496
|
-
};
|
|
497
|
-
break;
|
|
498
|
-
default:
|
|
499
|
-
resolution = {
|
|
500
|
-
strategy: strategy,
|
|
501
|
-
result: conflict.conflictingPositions[0]?.position,
|
|
502
|
-
confidence: 0.5,
|
|
503
|
-
reasoning: `Resolved via ${strategy}`
|
|
504
|
-
};
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
conflict.resolution = resolution;
|
|
508
|
-
conflict.status = ConflictStatus.RESOLVED;
|
|
509
|
-
conflict.metadata.resolvedAt = new Date();
|
|
510
|
-
conflict.metadata.resolutionStrategy = strategy;
|
|
511
|
-
conflict.metadata.resolverAgentId = resolverAgentId;
|
|
512
|
-
|
|
513
|
-
return { conflict, resolution };
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
getConflict(conflictId: string) {
|
|
517
|
-
return this.conflicts.get(conflictId);
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
getAllConflicts() {
|
|
521
|
-
return Array.from(this.conflicts.values());
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
/**
|
|
526
|
-
* Orchestrates all swarm activities
|
|
527
|
-
*/
|
|
528
|
-
export class SwarmCoordinator {
|
|
529
|
-
public registry: AgentRegistry;
|
|
530
|
-
public messageBroker = new MessageBroker();
|
|
531
|
-
public taskQueue = new TaskQueueManager();
|
|
532
|
-
public taskAssigner: TaskAssigner;
|
|
533
|
-
public consensusEngine = new ConsensusEngine();
|
|
534
|
-
public conflictResolver = new ConflictResolver();
|
|
535
|
-
|
|
536
|
-
constructor(persistenceDir?: string) {
|
|
537
|
-
this.registry = new AgentRegistry(persistenceDir);
|
|
538
|
-
this.taskAssigner = new TaskAssigner(this.registry);
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
async initialize() {
|
|
542
|
-
await this.registry.initialize();
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
async registerAgent(agentOrConfig: BaseAgent | AgentConfig) {
|
|
546
|
-
if (agentOrConfig instanceof BaseAgent || typeof (agentOrConfig as any).execute === 'function') {
|
|
547
|
-
const agent = agentOrConfig as BaseAgent;
|
|
548
|
-
return await this.registry.registerAgent(agent.config, agent);
|
|
549
|
-
}
|
|
550
|
-
return await this.registry.registerAgent(agentOrConfig as AgentConfig);
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
getAllAgents() {
|
|
554
|
-
return this.registry.getAllAgents();
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
async unregisterAgent(agentId: string) {
|
|
558
|
-
return await this.registry.unregisterAgent(agentId);
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
submitTask(type: string, description: string, input: any, requirements: any, strategy: string = 'adaptive') {
|
|
562
|
-
const task = this.taskQueue.createTask(type, description, input, requirements);
|
|
563
|
-
const agent = this.taskAssigner.assignTask(task, strategy);
|
|
564
|
-
|
|
565
|
-
if (agent) {
|
|
566
|
-
this.taskQueue.assignTask(task.id, agent.config.id);
|
|
567
|
-
this.registry.updateAgentStatus(agent.config.id, AgentStatus.BUSY);
|
|
568
|
-
}
|
|
569
|
-
return { task, assignedAgent: agent };
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
async executeTask(taskId: string, maxRetries: number = 3) {
|
|
573
|
-
let globalRetries = 0;
|
|
574
|
-
let lastError: any = null;
|
|
575
|
-
const maxGlobalRetries = maxRetries * 2; // Allow attempts across multiple agents
|
|
576
|
-
const failedAgents = new Set<string>();
|
|
577
|
-
|
|
578
|
-
while (globalRetries < maxGlobalRetries) {
|
|
579
|
-
const task = this.taskQueue.getTask(taskId);
|
|
580
|
-
if (!task) throw new Error(`Task not found: ${taskId}`);
|
|
581
|
-
|
|
582
|
-
// Auto-reassignment logic if not assigned
|
|
583
|
-
if (!task.assignedAgentId) {
|
|
584
|
-
const agent = this.taskAssigner.assignTask(task, 'adaptive', Array.from(failedAgents));
|
|
585
|
-
if (agent) {
|
|
586
|
-
this.taskQueue.assignTask(task.id, agent.config.id);
|
|
587
|
-
this.registry.updateAgentStatus(agent.config.id, AgentStatus.BUSY);
|
|
588
|
-
Logger.info(`Reassigned task ${taskId} to agent ${agent.config.id}`);
|
|
589
|
-
} else {
|
|
590
|
-
// No more agents available
|
|
591
|
-
Logger.warn(`No suitable agent found for task ${taskId} (Agents tried: ${Array.from(failedAgents).join(', ')})`);
|
|
592
|
-
break;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
// Check assignment validity
|
|
597
|
-
if (!task.assignedAgentId) {
|
|
598
|
-
break; // Should be handled above, but safety check
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
const agentState = this.registry.getAgent(task.assignedAgentId);
|
|
602
|
-
if (!agentState || !agentState.instance) {
|
|
603
|
-
// Agent gone? Treat as failure
|
|
604
|
-
failedAgents.add(task.assignedAgentId);
|
|
605
|
-
task.assignedAgentId = null;
|
|
606
|
-
globalRetries++;
|
|
607
|
-
continue;
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
this.taskQueue.startTask(taskId);
|
|
611
|
-
|
|
612
|
-
try {
|
|
613
|
-
const result = await agentState.instance.execute(task);
|
|
614
|
-
this.taskQueue.completeTask(taskId, result);
|
|
615
|
-
this.registry.updateAgentStatus(task.assignedAgentId, AgentStatus.IDLE);
|
|
616
|
-
this.registry.recordPerformance(task.assignedAgentId, taskId, result.confidence, result.processingTimeMs);
|
|
617
|
-
return result;
|
|
618
|
-
} catch (error) {
|
|
619
|
-
lastError = error;
|
|
620
|
-
globalRetries++;
|
|
621
|
-
Logger.warn(`Task ${taskId} failed with agent ${task.assignedAgentId} (attempt ${globalRetries}/${maxGlobalRetries})`, { error });
|
|
622
|
-
|
|
623
|
-
// Mark agent as failed for this task and unassign
|
|
624
|
-
if (task.assignedAgentId) {
|
|
625
|
-
failedAgents.add(task.assignedAgentId);
|
|
626
|
-
this.registry.updateAgentStatus(task.assignedAgentId, AgentStatus.IDLE);
|
|
627
|
-
task.assignedAgentId = null; // Unassign to trigger reassignment
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
task.status = TaskStatus.PENDING; // Reset status for next attempt
|
|
631
|
-
|
|
632
|
-
// Wait a bit before next loop
|
|
633
|
-
await new Promise(resolve => setTimeout(resolve, 500 * globalRetries));
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
const processingTime = 0;
|
|
638
|
-
this.taskQueue.failTask(taskId, String(lastError));
|
|
639
|
-
// Final cleanup if task is still assigned
|
|
640
|
-
const task = this.taskQueue.getTask(taskId);
|
|
641
|
-
if (task?.assignedAgentId) {
|
|
642
|
-
this.registry.updateAgentStatus(task.assignedAgentId, AgentStatus.IDLE);
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
const result: TaskResult = {
|
|
646
|
-
taskId,
|
|
647
|
-
agentId: task?.assignedAgentId || 'unknown',
|
|
648
|
-
success: false,
|
|
649
|
-
output: null,
|
|
650
|
-
confidence: 0,
|
|
651
|
-
processingTimeMs: processingTime,
|
|
652
|
-
metadata: { tokensUsed: 0, reasoningSteps: 0, intermediateResults: [], error: String(lastError) }
|
|
653
|
-
};
|
|
654
|
-
return result;
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
async reachConsensus(
|
|
658
|
-
proposal: any,
|
|
659
|
-
options: any[],
|
|
660
|
-
algorithm: ConsensusAlgorithm = ConsensusAlgorithm.WEIGHTED_VOTE,
|
|
661
|
-
participatingAgents?: string[],
|
|
662
|
-
minAgreementRatio: number = 0.67,
|
|
663
|
-
maxRounds: number = 3,
|
|
664
|
-
context: any = {}
|
|
665
|
-
): Promise<ConsensusResult> {
|
|
666
|
-
const agentIds = participatingAgents || this.registry.getAllAgents().map(a => a.config.id);
|
|
667
|
-
const proposalId = `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
|
|
668
|
-
|
|
669
|
-
const votes: ConsensusVote[] = [];
|
|
670
|
-
const startTime = Date.now();
|
|
671
|
-
|
|
672
|
-
const votePromises = agentIds.map(async (agentId) => {
|
|
673
|
-
const agentState = this.registry.getAgent(agentId);
|
|
674
|
-
if (!agentState || !agentState.instance) return null;
|
|
675
|
-
|
|
676
|
-
// Enhanced context for consensus voting
|
|
677
|
-
const task = this.taskQueue.createTask(
|
|
678
|
-
'consensus_vote',
|
|
679
|
-
`Vote on proposal: ${typeof proposal === 'string' ? proposal : JSON.stringify(proposal)}`,
|
|
680
|
-
{
|
|
681
|
-
proposal,
|
|
682
|
-
options,
|
|
683
|
-
proposalId,
|
|
684
|
-
algorithm,
|
|
685
|
-
context: {
|
|
686
|
-
...context,
|
|
687
|
-
swarmStats: this.getSwarmStats(),
|
|
688
|
-
previousVotes: votes.map(v => ({ agentId: v.agentId, vote: v.vote }))
|
|
689
|
-
}
|
|
690
|
-
},
|
|
691
|
-
{ requiredCapabilities: ['consensus_vote'], minConfidence: 0, maxTimeMs: 10000 }
|
|
692
|
-
);
|
|
693
|
-
|
|
694
|
-
this.taskQueue.assignTask(task.id, agentId);
|
|
695
|
-
this.registry.updateAgentStatus(agentId, AgentStatus.BUSY);
|
|
696
|
-
|
|
697
|
-
try {
|
|
698
|
-
const result = await agentState.instance.execute(task);
|
|
699
|
-
this.taskQueue.completeTask(task.id, result);
|
|
700
|
-
this.registry.updateAgentStatus(agentId, AgentStatus.IDLE);
|
|
701
|
-
|
|
702
|
-
if (result.success && result.output) {
|
|
703
|
-
const output = result.output as any;
|
|
704
|
-
return {
|
|
705
|
-
agentId,
|
|
706
|
-
proposalId,
|
|
707
|
-
vote: output.vote ?? options[0],
|
|
708
|
-
confidence: result.confidence,
|
|
709
|
-
reasoning: output.reasoning || 'No reasoning provided',
|
|
710
|
-
timestamp: new Date()
|
|
711
|
-
} as ConsensusVote;
|
|
712
|
-
}
|
|
713
|
-
} catch (error) {
|
|
714
|
-
this.taskQueue.failTask(task.id, String(error));
|
|
715
|
-
this.registry.updateAgentStatus(agentId, AgentStatus.IDLE);
|
|
716
|
-
}
|
|
717
|
-
return null;
|
|
718
|
-
});
|
|
719
|
-
|
|
720
|
-
const results = await Promise.all(votePromises);
|
|
721
|
-
for (const res of results) {
|
|
722
|
-
if (res) votes.push(res);
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
const consensus = await this.consensusEngine.reachConsensus(proposalId, algorithm, votes, minAgreementRatio, 1);
|
|
726
|
-
consensus.metadata.totalVotingTimeMs = Date.now() - startTime;
|
|
727
|
-
|
|
728
|
-
return consensus;
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
identifyConflict(type: string, description: string, positions: ConflictPosition[]) {
|
|
732
|
-
return this.conflictResolver.identifyConflict(type, description, positions);
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
resolveConflict(conflictId: string, strategy: ConflictResolutionStrategy, resolverAgentId?: string) {
|
|
736
|
-
return this.conflictResolver.resolveConflict(conflictId, strategy, resolverAgentId || 'coordinator');
|
|
737
|
-
}
|
|
738
|
-
|
|
739
|
-
broadcastMessage(senderId: string, payload: any) {
|
|
740
|
-
return this.messageBroker.sendMessage({
|
|
741
|
-
type: MessageType.BROADCAST,
|
|
742
|
-
senderId,
|
|
743
|
-
recipientId: null,
|
|
744
|
-
payload,
|
|
745
|
-
context: {},
|
|
746
|
-
metadata: { priority: 1, ttl: 60000, retryCount: 0 }
|
|
747
|
-
});
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
sendDirectMessage(senderId: string, recipientId: string, payload: any) {
|
|
751
|
-
return this.messageBroker.sendMessage({
|
|
752
|
-
type: MessageType.DIRECT,
|
|
753
|
-
senderId,
|
|
754
|
-
recipientId,
|
|
755
|
-
payload,
|
|
756
|
-
context: {},
|
|
757
|
-
metadata: { priority: 1, ttl: 60000, retryCount: 0 }
|
|
758
|
-
});
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
getSwarmStats() {
|
|
762
|
-
return {
|
|
763
|
-
totalAgents: this.registry.getAllAgents().length,
|
|
764
|
-
availableAgents: this.registry.getAvailableAgents().length,
|
|
765
|
-
busyAgents: this.registry.getAllAgents().filter(a => a.status === AgentStatus.BUSY).length,
|
|
766
|
-
pendingTasks: this.taskQueue.getPendingTasks().length,
|
|
767
|
-
inProgressTasks: this.taskQueue.getInProgressTasks().length,
|
|
768
|
-
completedTasks: this.taskQueue.getCompletedTasks().length,
|
|
769
|
-
activeConflicts: this.conflictResolver.getAllConflicts().filter(c => c.status !== ConflictStatus.RESOLVED).length
|
|
770
|
-
};
|
|
771
|
-
}
|
|
772
|
-
}
|