@juspay/neurolink 9.83.0 → 9.84.0
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/CHANGELOG.md +12 -0
- package/dist/agent/agent.d.ts +104 -0
- package/dist/agent/agent.js +401 -0
- package/dist/agent/agentNetwork.d.ts +87 -0
- package/dist/agent/agentNetwork.js +458 -0
- package/dist/agent/communication/index.d.ts +9 -0
- package/dist/agent/communication/index.js +9 -0
- package/dist/agent/communication/message-bus.d.ts +113 -0
- package/dist/agent/communication/message-bus.js +406 -0
- package/dist/agent/coordination/coordinator.d.ts +83 -0
- package/dist/agent/coordination/coordinator.js +598 -0
- package/dist/agent/coordination/index.d.ts +10 -0
- package/dist/agent/coordination/index.js +10 -0
- package/dist/agent/coordination/task-distributor.d.ts +113 -0
- package/dist/agent/coordination/task-distributor.js +585 -0
- package/dist/agent/index.d.ts +38 -0
- package/dist/agent/index.js +44 -0
- package/dist/agent/orchestration/index.d.ts +10 -0
- package/dist/agent/orchestration/index.js +10 -0
- package/dist/agent/orchestration/orchestrator.d.ts +114 -0
- package/dist/agent/orchestration/orchestrator.js +476 -0
- package/dist/agent/orchestration/topology.d.ts +164 -0
- package/dist/agent/orchestration/topology.js +520 -0
- package/dist/agent/prompts/routingPrompts.d.ts +63 -0
- package/dist/agent/prompts/routingPrompts.js +201 -0
- package/dist/browser/neurolink.min.js +377 -358
- package/dist/cli/commands/agent.d.ts +37 -0
- package/dist/cli/commands/agent.js +718 -0
- package/dist/cli/factories/commandFactory.d.ts +8 -0
- package/dist/cli/factories/commandFactory.js +116 -0
- package/dist/cli/loop/optionsSchema.d.ts +1 -1
- package/dist/cli/parser.js +4 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +19 -0
- package/dist/lib/agent/agent.d.ts +104 -0
- package/dist/lib/agent/agent.js +402 -0
- package/dist/lib/agent/agentNetwork.d.ts +87 -0
- package/dist/lib/agent/agentNetwork.js +459 -0
- package/dist/lib/agent/communication/index.d.ts +9 -0
- package/dist/lib/agent/communication/index.js +10 -0
- package/dist/lib/agent/communication/message-bus.d.ts +113 -0
- package/dist/lib/agent/communication/message-bus.js +407 -0
- package/dist/lib/agent/coordination/coordinator.d.ts +83 -0
- package/dist/lib/agent/coordination/coordinator.js +599 -0
- package/dist/lib/agent/coordination/index.d.ts +10 -0
- package/dist/lib/agent/coordination/index.js +11 -0
- package/dist/lib/agent/coordination/task-distributor.d.ts +113 -0
- package/dist/lib/agent/coordination/task-distributor.js +586 -0
- package/dist/lib/agent/index.d.ts +38 -0
- package/dist/lib/agent/index.js +45 -0
- package/dist/lib/agent/orchestration/index.d.ts +10 -0
- package/dist/lib/agent/orchestration/index.js +11 -0
- package/dist/lib/agent/orchestration/orchestrator.d.ts +114 -0
- package/dist/lib/agent/orchestration/orchestrator.js +477 -0
- package/dist/lib/agent/orchestration/topology.d.ts +164 -0
- package/dist/lib/agent/orchestration/topology.js +521 -0
- package/dist/lib/agent/prompts/routingPrompts.d.ts +63 -0
- package/dist/lib/agent/prompts/routingPrompts.js +202 -0
- package/dist/lib/index.d.ts +6 -0
- package/dist/lib/index.js +19 -0
- package/dist/lib/neurolink.d.ts +129 -0
- package/dist/lib/neurolink.js +276 -0
- package/dist/lib/processors/config/{fileTypes.js → fileExtensions.js} +1 -1
- package/dist/lib/processors/config/index.d.ts +2 -2
- package/dist/lib/processors/config/index.js +2 -2
- package/dist/lib/processors/config/{mimeTypes.js → mimeConstants.js} +1 -1
- package/dist/lib/processors/index.js +8 -0
- package/dist/lib/providers/googleAiStudio.js +3 -3
- package/dist/lib/providers/googleNativeGemini3.d.ts +18 -0
- package/dist/lib/providers/googleNativeGemini3.js +47 -1
- package/dist/lib/providers/googleVertex.js +5 -5
- package/dist/lib/types/agentNetwork.d.ts +1184 -0
- package/dist/lib/types/agentNetwork.js +8 -0
- package/dist/lib/types/cli.d.ts +66 -0
- package/dist/lib/types/generate.d.ts +53 -0
- package/dist/lib/types/index.d.ts +2 -0
- package/dist/lib/types/index.js +3 -0
- package/dist/lib/types/ioProcessor.d.ts +119 -0
- package/dist/lib/types/ioProcessor.js +10 -0
- package/dist/lib/types/stream.d.ts +36 -0
- package/dist/lib/utils/piiDetector.d.ts +24 -0
- package/dist/lib/utils/piiDetector.js +221 -0
- package/dist/lib/utils/responseValidator.d.ts +21 -0
- package/dist/lib/utils/responseValidator.js +354 -0
- package/dist/lib/utils/tripwireEvaluator.d.ts +73 -0
- package/dist/lib/utils/tripwireEvaluator.js +285 -0
- package/dist/neurolink.d.ts +129 -0
- package/dist/neurolink.js +276 -0
- package/dist/processors/config/index.d.ts +2 -2
- package/dist/processors/config/index.js +2 -2
- package/dist/processors/index.js +8 -0
- package/dist/providers/googleAiStudio.js +3 -3
- package/dist/providers/googleNativeGemini3.d.ts +18 -0
- package/dist/providers/googleNativeGemini3.js +47 -1
- package/dist/providers/googleVertex.js +5 -5
- package/dist/types/agentNetwork.d.ts +1184 -0
- package/dist/types/agentNetwork.js +7 -0
- package/dist/types/cli.d.ts +66 -0
- package/dist/types/generate.d.ts +53 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.js +3 -0
- package/dist/types/ioProcessor.d.ts +119 -0
- package/dist/types/ioProcessor.js +9 -0
- package/dist/types/stream.d.ts +36 -0
- package/dist/utils/piiDetector.d.ts +24 -0
- package/dist/utils/piiDetector.js +220 -0
- package/dist/utils/responseValidator.d.ts +21 -0
- package/dist/utils/responseValidator.js +353 -0
- package/dist/utils/tripwireEvaluator.d.ts +73 -0
- package/dist/utils/tripwireEvaluator.js +284 -0
- package/package.json +1 -1
- /package/dist/lib/processors/config/{fileTypes.d.ts → fileExtensions.d.ts} +0 -0
- /package/dist/lib/processors/config/{mimeTypes.d.ts → mimeConstants.d.ts} +0 -0
- /package/dist/processors/config/{fileTypes.d.ts → fileExtensions.d.ts} +0 -0
- /package/dist/processors/config/{fileTypes.js → fileExtensions.js} +0 -0
- /package/dist/processors/config/{mimeTypes.d.ts → mimeConstants.d.ts} +0 -0
- /package/dist/processors/config/{mimeTypes.js → mimeConstants.js} +0 -0
|
@@ -0,0 +1,598 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Coordinator - Manages coordination between agents in a network
|
|
3
|
+
*
|
|
4
|
+
* The Coordinator is responsible for:
|
|
5
|
+
* - Managing agent lifecycle and state
|
|
6
|
+
* - Coordinating task execution across multiple agents
|
|
7
|
+
* - Handling agent dependencies and execution order
|
|
8
|
+
* - Managing shared context and state between agents
|
|
9
|
+
*/
|
|
10
|
+
import { EventEmitter } from "events";
|
|
11
|
+
import { randomUUID } from "crypto";
|
|
12
|
+
import { withTimeout } from "../../utils/async/withTimeout.js";
|
|
13
|
+
import { logger } from "../../utils/logger.js";
|
|
14
|
+
/**
|
|
15
|
+
* Agent Coordinator - Orchestrates multi-agent execution
|
|
16
|
+
*/
|
|
17
|
+
export class AgentCoordinator {
|
|
18
|
+
agents = new Map();
|
|
19
|
+
config;
|
|
20
|
+
emitter;
|
|
21
|
+
activeExecutions = new Map();
|
|
22
|
+
executionHistory = [];
|
|
23
|
+
roundRobinCursor = 0;
|
|
24
|
+
constructor(config) {
|
|
25
|
+
this.config = {
|
|
26
|
+
strategy: "sequential",
|
|
27
|
+
maxConcurrency: 3,
|
|
28
|
+
agentTimeout: 60000,
|
|
29
|
+
continueOnFailure: false,
|
|
30
|
+
...config,
|
|
31
|
+
};
|
|
32
|
+
this.emitter = new EventEmitter();
|
|
33
|
+
logger.debug("[AgentCoordinator] Created with config", {
|
|
34
|
+
strategy: this.config.strategy,
|
|
35
|
+
maxConcurrency: this.config.maxConcurrency,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Register an agent with the coordinator
|
|
40
|
+
*/
|
|
41
|
+
registerAgent(agent) {
|
|
42
|
+
this.agents.set(agent.id, agent);
|
|
43
|
+
logger.debug(`[AgentCoordinator] Registered agent: ${agent.name}`);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Unregister an agent
|
|
47
|
+
*/
|
|
48
|
+
unregisterAgent(agentId) {
|
|
49
|
+
this.agents.delete(agentId);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Get all registered agents
|
|
53
|
+
*/
|
|
54
|
+
getAgents() {
|
|
55
|
+
return Array.from(this.agents.values());
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Get agent status
|
|
59
|
+
*/
|
|
60
|
+
getAgentStatus(agentId) {
|
|
61
|
+
const agent = this.agents.get(agentId);
|
|
62
|
+
return agent?.getStatus();
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Execute a coordinated task across agents
|
|
66
|
+
*/
|
|
67
|
+
async coordinate(task, options) {
|
|
68
|
+
const startTime = Date.now();
|
|
69
|
+
const executionId = randomUUID();
|
|
70
|
+
const config = { ...this.config, ...options };
|
|
71
|
+
const context = {
|
|
72
|
+
currentStep: 0,
|
|
73
|
+
previousResults: new Map(),
|
|
74
|
+
sharedState: new Map(),
|
|
75
|
+
metadata: {
|
|
76
|
+
startTime,
|
|
77
|
+
strategy: config.strategy,
|
|
78
|
+
executionId,
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
this.emitter.emit("coordination:start", { executionId, task });
|
|
82
|
+
try {
|
|
83
|
+
let result;
|
|
84
|
+
switch (config.strategy) {
|
|
85
|
+
case "sequential":
|
|
86
|
+
result = await this.executeSequential(task, context, config);
|
|
87
|
+
break;
|
|
88
|
+
case "parallel":
|
|
89
|
+
result = await this.executeParallel(task, context, config);
|
|
90
|
+
break;
|
|
91
|
+
case "pipeline":
|
|
92
|
+
result = await this.executePipeline(task, context, config);
|
|
93
|
+
break;
|
|
94
|
+
case "roundRobin":
|
|
95
|
+
result = await this.executeRoundRobin(task, context, config);
|
|
96
|
+
break;
|
|
97
|
+
case "leastBusy":
|
|
98
|
+
result = await this.executeLeastBusy(task, context, config);
|
|
99
|
+
break;
|
|
100
|
+
case "custom":
|
|
101
|
+
if (!config.customCoordinator) {
|
|
102
|
+
throw new Error("Custom coordinator function required for custom strategy");
|
|
103
|
+
}
|
|
104
|
+
result = await config.customCoordinator(this.getAgents(), task, context);
|
|
105
|
+
break;
|
|
106
|
+
default:
|
|
107
|
+
throw new Error(`Unknown coordination strategy: ${config.strategy}`);
|
|
108
|
+
}
|
|
109
|
+
this.emitter.emit("coordination:complete", { executionId, result });
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
const errorResult = {
|
|
114
|
+
success: false,
|
|
115
|
+
agentResults: context.previousResults,
|
|
116
|
+
steps: this.executionHistory,
|
|
117
|
+
errors: [
|
|
118
|
+
{
|
|
119
|
+
agentId: "coordinator",
|
|
120
|
+
error: error instanceof Error ? error.message : String(error),
|
|
121
|
+
},
|
|
122
|
+
],
|
|
123
|
+
duration: Date.now() - startTime,
|
|
124
|
+
metadata: {
|
|
125
|
+
executionId,
|
|
126
|
+
strategy: config.strategy,
|
|
127
|
+
agentsExecuted: context.previousResults.size,
|
|
128
|
+
agentsFailed: 1,
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
this.emitter.emit("coordination:error", { executionId, error });
|
|
132
|
+
return errorResult;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Execute agents sequentially
|
|
137
|
+
*/
|
|
138
|
+
async executeSequential(task, context, config) {
|
|
139
|
+
const agents = this.getAgents();
|
|
140
|
+
if (agents.length === 0) {
|
|
141
|
+
return {
|
|
142
|
+
success: false,
|
|
143
|
+
agentResults: context.previousResults,
|
|
144
|
+
steps: [],
|
|
145
|
+
finalOutput: "",
|
|
146
|
+
errors: [{ agentId: "coordinator", error: "No agents registered" }],
|
|
147
|
+
duration: Date.now() - context.metadata.startTime,
|
|
148
|
+
metadata: {
|
|
149
|
+
executionId: context.metadata.executionId,
|
|
150
|
+
strategy: config.strategy ?? "sequential",
|
|
151
|
+
agentsExecuted: 0,
|
|
152
|
+
agentsFailed: 0,
|
|
153
|
+
},
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
const errors = [];
|
|
157
|
+
const steps = [];
|
|
158
|
+
let currentInput = task;
|
|
159
|
+
let finalOutput = "";
|
|
160
|
+
for (let i = 0; i < agents.length; i++) {
|
|
161
|
+
const agent = agents[i];
|
|
162
|
+
context.currentStep = i;
|
|
163
|
+
const stepStart = Date.now();
|
|
164
|
+
try {
|
|
165
|
+
const result = await this.executeAgentWithTimeout(agent, currentInput, context);
|
|
166
|
+
context.previousResults.set(agent.id, result);
|
|
167
|
+
steps.push({
|
|
168
|
+
index: i,
|
|
169
|
+
primitive: { type: "agent", id: agent.id, name: agent.name },
|
|
170
|
+
input: currentInput,
|
|
171
|
+
output: result.content,
|
|
172
|
+
duration: Date.now() - stepStart,
|
|
173
|
+
usage: result.usage,
|
|
174
|
+
timestamp: stepStart,
|
|
175
|
+
});
|
|
176
|
+
if (result.status === "success") {
|
|
177
|
+
currentInput = result.content;
|
|
178
|
+
finalOutput = result.content;
|
|
179
|
+
}
|
|
180
|
+
else if (result.error) {
|
|
181
|
+
errors.push({ agentId: agent.id, error: result.error });
|
|
182
|
+
if (!config.continueOnFailure) {
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
189
|
+
errors.push({ agentId: agent.id, error: errorMsg });
|
|
190
|
+
steps.push({
|
|
191
|
+
index: i,
|
|
192
|
+
primitive: { type: "agent", id: agent.id, name: agent.name },
|
|
193
|
+
input: currentInput,
|
|
194
|
+
error: errorMsg,
|
|
195
|
+
duration: Date.now() - stepStart,
|
|
196
|
+
timestamp: stepStart,
|
|
197
|
+
});
|
|
198
|
+
if (!config.continueOnFailure) {
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
success: errors.length === 0,
|
|
205
|
+
agentResults: context.previousResults,
|
|
206
|
+
steps,
|
|
207
|
+
finalOutput,
|
|
208
|
+
errors,
|
|
209
|
+
duration: Date.now() - context.metadata.startTime,
|
|
210
|
+
metadata: {
|
|
211
|
+
executionId: context.metadata.executionId,
|
|
212
|
+
strategy: "sequential",
|
|
213
|
+
agentsExecuted: context.previousResults.size,
|
|
214
|
+
agentsFailed: errors.length,
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Execute agents in parallel
|
|
220
|
+
*/
|
|
221
|
+
async executeParallel(task, context, config) {
|
|
222
|
+
const agents = this.getAgents();
|
|
223
|
+
if (agents.length === 0) {
|
|
224
|
+
return {
|
|
225
|
+
success: false,
|
|
226
|
+
agentResults: context.previousResults,
|
|
227
|
+
steps: [],
|
|
228
|
+
finalOutput: "",
|
|
229
|
+
errors: [{ agentId: "coordinator", error: "No agents registered" }],
|
|
230
|
+
duration: Date.now() - context.metadata.startTime,
|
|
231
|
+
metadata: {
|
|
232
|
+
executionId: context.metadata.executionId,
|
|
233
|
+
strategy: config.strategy ?? "parallel",
|
|
234
|
+
agentsExecuted: 0,
|
|
235
|
+
agentsFailed: 0,
|
|
236
|
+
},
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
const errors = [];
|
|
240
|
+
const steps = [];
|
|
241
|
+
const maxConcurrency = Math.max(1, config.maxConcurrency ?? 3);
|
|
242
|
+
// Split agents into batches based on concurrency
|
|
243
|
+
const batches = [];
|
|
244
|
+
for (let i = 0; i < agents.length; i += maxConcurrency) {
|
|
245
|
+
batches.push(agents.slice(i, i + maxConcurrency));
|
|
246
|
+
}
|
|
247
|
+
let stepIndex = 0;
|
|
248
|
+
const allResults = [];
|
|
249
|
+
for (const batch of batches) {
|
|
250
|
+
const batchPromises = batch.map(async (agent) => {
|
|
251
|
+
const stepStart = Date.now();
|
|
252
|
+
const currentIndex = stepIndex++;
|
|
253
|
+
try {
|
|
254
|
+
const result = await this.executeAgentWithTimeout(agent, task, context);
|
|
255
|
+
context.previousResults.set(agent.id, result);
|
|
256
|
+
steps.push({
|
|
257
|
+
index: currentIndex,
|
|
258
|
+
primitive: { type: "agent", id: agent.id, name: agent.name },
|
|
259
|
+
input: task,
|
|
260
|
+
output: result.content,
|
|
261
|
+
duration: Date.now() - stepStart,
|
|
262
|
+
usage: result.usage,
|
|
263
|
+
timestamp: stepStart,
|
|
264
|
+
});
|
|
265
|
+
if (result.status === "success") {
|
|
266
|
+
allResults.push(result.content);
|
|
267
|
+
}
|
|
268
|
+
else if (result.error) {
|
|
269
|
+
errors.push({ agentId: agent.id, error: result.error });
|
|
270
|
+
}
|
|
271
|
+
return result;
|
|
272
|
+
}
|
|
273
|
+
catch (error) {
|
|
274
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
275
|
+
errors.push({ agentId: agent.id, error: errorMsg });
|
|
276
|
+
steps.push({
|
|
277
|
+
index: currentIndex,
|
|
278
|
+
primitive: { type: "agent", id: agent.id, name: agent.name },
|
|
279
|
+
input: task,
|
|
280
|
+
error: errorMsg,
|
|
281
|
+
duration: Date.now() - stepStart,
|
|
282
|
+
timestamp: stepStart,
|
|
283
|
+
});
|
|
284
|
+
return null;
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
await Promise.all(batchPromises);
|
|
288
|
+
}
|
|
289
|
+
// Combine results
|
|
290
|
+
const finalOutput = allResults.join("\n\n---\n\n");
|
|
291
|
+
return {
|
|
292
|
+
success: errors.length === 0,
|
|
293
|
+
agentResults: context.previousResults,
|
|
294
|
+
steps,
|
|
295
|
+
finalOutput,
|
|
296
|
+
errors,
|
|
297
|
+
duration: Date.now() - context.metadata.startTime,
|
|
298
|
+
metadata: {
|
|
299
|
+
executionId: context.metadata.executionId,
|
|
300
|
+
strategy: "parallel",
|
|
301
|
+
agentsExecuted: context.previousResults.size,
|
|
302
|
+
agentsFailed: errors.length,
|
|
303
|
+
},
|
|
304
|
+
};
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Execute agents in a pipeline (output feeds into next)
|
|
308
|
+
*/
|
|
309
|
+
async executePipeline(task, context, config) {
|
|
310
|
+
// Pipeline is essentially sequential with explicit input chaining
|
|
311
|
+
return this.executeSequential(task, context, config);
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Execute using round-robin distribution
|
|
315
|
+
*/
|
|
316
|
+
async executeRoundRobin(task, context, _config) {
|
|
317
|
+
const agents = this.getAgents();
|
|
318
|
+
if (agents.length === 0) {
|
|
319
|
+
return {
|
|
320
|
+
success: false,
|
|
321
|
+
agentResults: new Map(),
|
|
322
|
+
steps: [],
|
|
323
|
+
errors: [{ agentId: "coordinator", error: "No agents registered" }],
|
|
324
|
+
duration: 0,
|
|
325
|
+
metadata: {
|
|
326
|
+
executionId: context.metadata.executionId,
|
|
327
|
+
strategy: "roundRobin",
|
|
328
|
+
agentsExecuted: 0,
|
|
329
|
+
agentsFailed: 0,
|
|
330
|
+
},
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
// For round robin, select the next agent in rotation using persistent cursor
|
|
334
|
+
const selectedIndex = this.roundRobinCursor % agents.length;
|
|
335
|
+
this.roundRobinCursor++;
|
|
336
|
+
const agent = agents[selectedIndex];
|
|
337
|
+
const stepStart = Date.now();
|
|
338
|
+
const result = await this.executeAgentWithTimeout(agent, task, context);
|
|
339
|
+
context.previousResults.set(agent.id, result);
|
|
340
|
+
const step = {
|
|
341
|
+
index: 0,
|
|
342
|
+
primitive: { type: "agent", id: agent.id, name: agent.name },
|
|
343
|
+
input: task,
|
|
344
|
+
output: result.content,
|
|
345
|
+
duration: Date.now() - stepStart,
|
|
346
|
+
usage: result.usage,
|
|
347
|
+
timestamp: stepStart,
|
|
348
|
+
};
|
|
349
|
+
return {
|
|
350
|
+
success: result.status === "success",
|
|
351
|
+
agentResults: context.previousResults,
|
|
352
|
+
steps: [step],
|
|
353
|
+
finalOutput: result.content,
|
|
354
|
+
errors: result.error ? [{ agentId: agent.id, error: result.error }] : [],
|
|
355
|
+
duration: Date.now() - context.metadata.startTime,
|
|
356
|
+
metadata: {
|
|
357
|
+
executionId: context.metadata.executionId,
|
|
358
|
+
strategy: "roundRobin",
|
|
359
|
+
agentsExecuted: 1,
|
|
360
|
+
agentsFailed: result.status === "error" ? 1 : 0,
|
|
361
|
+
},
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Execute using least busy agent
|
|
366
|
+
*/
|
|
367
|
+
async executeLeastBusy(task, context, _config) {
|
|
368
|
+
const agents = this.getAgents();
|
|
369
|
+
if (agents.length === 0) {
|
|
370
|
+
return {
|
|
371
|
+
success: false,
|
|
372
|
+
agentResults: new Map(),
|
|
373
|
+
steps: [],
|
|
374
|
+
errors: [{ agentId: "coordinator", error: "No agents registered" }],
|
|
375
|
+
duration: 0,
|
|
376
|
+
metadata: {
|
|
377
|
+
executionId: context.metadata.executionId,
|
|
378
|
+
strategy: "leastBusy",
|
|
379
|
+
agentsExecuted: 0,
|
|
380
|
+
agentsFailed: 0,
|
|
381
|
+
},
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
// Find the least busy agent (fewest active executions or lowest execution count)
|
|
385
|
+
let leastBusyAgent = agents[0];
|
|
386
|
+
let lowestCount = leastBusyAgent.getStatus().executionCount;
|
|
387
|
+
for (const agent of agents) {
|
|
388
|
+
const status = agent.getStatus();
|
|
389
|
+
if (status.executionCount < lowestCount) {
|
|
390
|
+
lowestCount = status.executionCount;
|
|
391
|
+
leastBusyAgent = agent;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
const stepStart = Date.now();
|
|
395
|
+
const result = await this.executeAgentWithTimeout(leastBusyAgent, task, context);
|
|
396
|
+
context.previousResults.set(leastBusyAgent.id, result);
|
|
397
|
+
const step = {
|
|
398
|
+
index: 0,
|
|
399
|
+
primitive: {
|
|
400
|
+
type: "agent",
|
|
401
|
+
id: leastBusyAgent.id,
|
|
402
|
+
name: leastBusyAgent.name,
|
|
403
|
+
},
|
|
404
|
+
input: task,
|
|
405
|
+
output: result.content,
|
|
406
|
+
duration: Date.now() - stepStart,
|
|
407
|
+
usage: result.usage,
|
|
408
|
+
timestamp: stepStart,
|
|
409
|
+
};
|
|
410
|
+
return {
|
|
411
|
+
success: result.status === "success",
|
|
412
|
+
agentResults: context.previousResults,
|
|
413
|
+
steps: [step],
|
|
414
|
+
finalOutput: result.content,
|
|
415
|
+
errors: result.error
|
|
416
|
+
? [{ agentId: leastBusyAgent.id, error: result.error }]
|
|
417
|
+
: [],
|
|
418
|
+
duration: Date.now() - context.metadata.startTime,
|
|
419
|
+
metadata: {
|
|
420
|
+
executionId: context.metadata.executionId,
|
|
421
|
+
strategy: "leastBusy",
|
|
422
|
+
agentsExecuted: 1,
|
|
423
|
+
agentsFailed: result.status === "error" ? 1 : 0,
|
|
424
|
+
},
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Execute an agent with timeout
|
|
429
|
+
*/
|
|
430
|
+
async executeAgentWithTimeout(agent, input, context) {
|
|
431
|
+
const timeout = this.config.agentTimeout ?? 60000;
|
|
432
|
+
const executionPromise = agent.execute(input, {
|
|
433
|
+
context: Object.fromEntries(context.sharedState),
|
|
434
|
+
traceId: context.metadata.executionId,
|
|
435
|
+
});
|
|
436
|
+
// Track active execution
|
|
437
|
+
this.activeExecutions.set(agent.id, executionPromise);
|
|
438
|
+
try {
|
|
439
|
+
return await withTimeout(executionPromise, timeout, `Agent execution timeout after ${timeout}ms`);
|
|
440
|
+
}
|
|
441
|
+
finally {
|
|
442
|
+
this.activeExecutions.delete(agent.id);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Execute multiple task assignments with dependencies
|
|
447
|
+
*/
|
|
448
|
+
async executeWithDependencies(assignments) {
|
|
449
|
+
const startTime = Date.now();
|
|
450
|
+
const executionId = randomUUID();
|
|
451
|
+
const context = {
|
|
452
|
+
currentStep: 0,
|
|
453
|
+
previousResults: new Map(),
|
|
454
|
+
sharedState: new Map(),
|
|
455
|
+
metadata: {
|
|
456
|
+
startTime,
|
|
457
|
+
strategy: "custom",
|
|
458
|
+
executionId,
|
|
459
|
+
},
|
|
460
|
+
};
|
|
461
|
+
const errors = [];
|
|
462
|
+
const steps = [];
|
|
463
|
+
const completed = new Set();
|
|
464
|
+
const failed = new Set();
|
|
465
|
+
const pending = new Map(assignments.map((a) => [a.agent.id, a]));
|
|
466
|
+
let stepCounter = 0;
|
|
467
|
+
while (pending.size > 0) {
|
|
468
|
+
// Find assignments whose dependencies are satisfied
|
|
469
|
+
const ready = [];
|
|
470
|
+
for (const [_agentId, assignment] of pending) {
|
|
471
|
+
const deps = assignment.dependencies ?? [];
|
|
472
|
+
if (deps.every((d) => completed.has(d))) {
|
|
473
|
+
ready.push(assignment);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (ready.length === 0 && pending.size > 0) {
|
|
477
|
+
// Circular dependency or unmet dependency
|
|
478
|
+
errors.push({
|
|
479
|
+
agentId: "coordinator",
|
|
480
|
+
error: "Unresolvable dependencies detected",
|
|
481
|
+
});
|
|
482
|
+
break;
|
|
483
|
+
}
|
|
484
|
+
// Sort by priority and execute
|
|
485
|
+
ready.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
|
|
486
|
+
// Execute in parallel batches
|
|
487
|
+
const maxConcurrency = Math.max(1, this.config.maxConcurrency ?? 3);
|
|
488
|
+
for (let i = 0; i < ready.length; i += maxConcurrency) {
|
|
489
|
+
const batch = ready.slice(i, i + maxConcurrency);
|
|
490
|
+
const batchPromises = batch.map(async (assignment) => {
|
|
491
|
+
const stepStart = Date.now();
|
|
492
|
+
const stepIndex = stepCounter++;
|
|
493
|
+
// Fail fast if any dependency already failed
|
|
494
|
+
const deps = assignment.dependencies ?? [];
|
|
495
|
+
const hasFailedDep = deps.some((d) => failed.has(d));
|
|
496
|
+
if (hasFailedDep) {
|
|
497
|
+
const failedDepId = deps.find((d) => failed.has(d));
|
|
498
|
+
errors.push({
|
|
499
|
+
agentId: assignment.agent.id,
|
|
500
|
+
error: `Dependency '${failedDepId}' failed`,
|
|
501
|
+
});
|
|
502
|
+
failed.add(assignment.agent.id);
|
|
503
|
+
pending.delete(assignment.agent.id);
|
|
504
|
+
return null;
|
|
505
|
+
}
|
|
506
|
+
try {
|
|
507
|
+
const result = await this.executeAgentWithTimeout(assignment.agent, assignment.input, context);
|
|
508
|
+
context.previousResults.set(assignment.agent.id, result);
|
|
509
|
+
pending.delete(assignment.agent.id);
|
|
510
|
+
steps.push({
|
|
511
|
+
index: stepIndex,
|
|
512
|
+
primitive: {
|
|
513
|
+
type: "agent",
|
|
514
|
+
id: assignment.agent.id,
|
|
515
|
+
name: assignment.agent.name,
|
|
516
|
+
},
|
|
517
|
+
input: assignment.input,
|
|
518
|
+
output: result.content,
|
|
519
|
+
duration: Date.now() - stepStart,
|
|
520
|
+
usage: result.usage,
|
|
521
|
+
timestamp: stepStart,
|
|
522
|
+
});
|
|
523
|
+
if (result.error) {
|
|
524
|
+
errors.push({
|
|
525
|
+
agentId: assignment.agent.id,
|
|
526
|
+
error: result.error,
|
|
527
|
+
});
|
|
528
|
+
failed.add(assignment.agent.id);
|
|
529
|
+
}
|
|
530
|
+
else {
|
|
531
|
+
completed.add(assignment.agent.id);
|
|
532
|
+
}
|
|
533
|
+
return result;
|
|
534
|
+
}
|
|
535
|
+
catch (error) {
|
|
536
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
537
|
+
errors.push({ agentId: assignment.agent.id, error: errorMsg });
|
|
538
|
+
failed.add(assignment.agent.id);
|
|
539
|
+
pending.delete(assignment.agent.id);
|
|
540
|
+
steps.push({
|
|
541
|
+
index: stepIndex,
|
|
542
|
+
primitive: {
|
|
543
|
+
type: "agent",
|
|
544
|
+
id: assignment.agent.id,
|
|
545
|
+
name: assignment.agent.name,
|
|
546
|
+
},
|
|
547
|
+
input: assignment.input,
|
|
548
|
+
error: errorMsg,
|
|
549
|
+
duration: Date.now() - stepStart,
|
|
550
|
+
timestamp: stepStart,
|
|
551
|
+
});
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
await Promise.all(batchPromises);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
// Combine final outputs
|
|
559
|
+
const finalOutputs = [];
|
|
560
|
+
for (const result of context.previousResults.values()) {
|
|
561
|
+
if (result.content) {
|
|
562
|
+
finalOutputs.push(result.content);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
return {
|
|
566
|
+
success: errors.length === 0,
|
|
567
|
+
agentResults: context.previousResults,
|
|
568
|
+
steps,
|
|
569
|
+
finalOutput: finalOutputs.join("\n\n"),
|
|
570
|
+
errors,
|
|
571
|
+
duration: Date.now() - startTime,
|
|
572
|
+
metadata: {
|
|
573
|
+
executionId,
|
|
574
|
+
strategy: "custom",
|
|
575
|
+
agentsExecuted: completed.size,
|
|
576
|
+
agentsFailed: errors.length,
|
|
577
|
+
},
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Update coordinator configuration
|
|
582
|
+
*/
|
|
583
|
+
updateConfig(config) {
|
|
584
|
+
this.config = { ...this.config, ...config };
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Subscribe to coordinator events
|
|
588
|
+
*/
|
|
589
|
+
on(event, handler) {
|
|
590
|
+
this.emitter.on(event, handler);
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Unsubscribe from coordinator events
|
|
594
|
+
*/
|
|
595
|
+
off(event, handler) {
|
|
596
|
+
this.emitter.off(event, handler);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Coordination Module
|
|
3
|
+
*
|
|
4
|
+
* Provides coordination and task distribution capabilities for multi-agent networks.
|
|
5
|
+
*
|
|
6
|
+
* Types for this module live in src/lib/types/agentNetwork.ts and are
|
|
7
|
+
* re-exported via the central barrel at src/lib/types/index.ts.
|
|
8
|
+
*/
|
|
9
|
+
export { AgentCoordinator } from "./coordinator.js";
|
|
10
|
+
export { TaskDistributor } from "./task-distributor.js";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Coordination Module
|
|
3
|
+
*
|
|
4
|
+
* Provides coordination and task distribution capabilities for multi-agent networks.
|
|
5
|
+
*
|
|
6
|
+
* Types for this module live in src/lib/types/agentNetwork.ts and are
|
|
7
|
+
* re-exported via the central barrel at src/lib/types/index.ts.
|
|
8
|
+
*/
|
|
9
|
+
export { AgentCoordinator } from "./coordinator.js";
|
|
10
|
+
export { TaskDistributor } from "./task-distributor.js";
|