@eko-ai/eko 2.1.8 → 2.1.9
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/dist/agent/base.d.ts +3 -1
- package/dist/agent/base.d.ts.map +1 -1
- package/dist/agent/browser/browser_labels.d.ts +2 -2
- package/dist/agent/browser/browser_labels.d.ts.map +1 -1
- package/dist/agent/index.d.ts +1 -2
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/llm.d.ts +2 -2
- package/dist/agent/llm.d.ts.map +1 -1
- package/dist/common/tree.d.ts +3 -0
- package/dist/common/tree.d.ts.map +1 -0
- package/dist/common/utils.d.ts +2 -2
- package/dist/common/utils.d.ts.map +1 -1
- package/dist/common/xml.d.ts.map +1 -1
- package/dist/config/index.d.ts +2 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/core/context.d.ts +1 -1
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/plan.d.ts +5 -4
- package/dist/core/plan.d.ts.map +1 -1
- package/dist/index.cjs.js +409 -130
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +409 -130
- package/dist/index.esm.js.map +1 -1
- package/dist/llm/index.d.ts +2 -1
- package/dist/llm/index.d.ts.map +1 -1
- package/dist/memory/index.d.ts.map +1 -1
- package/dist/prompt/plan.d.ts.map +1 -1
- package/dist/types/core.types.d.ts +14 -0
- package/dist/types/core.types.d.ts.map +1 -1
- package/dist/types/llm.types.d.ts +3 -1
- package/dist/types/llm.types.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -9,6 +9,8 @@ const config = {
|
|
|
9
9
|
platform: "mac",
|
|
10
10
|
maxReactNum: 500,
|
|
11
11
|
maxTokens: 16000,
|
|
12
|
+
maxRetryNum: 3,
|
|
13
|
+
agentParallel: false,
|
|
12
14
|
compressThreshold: 80,
|
|
13
15
|
largeTextLength: 5000,
|
|
14
16
|
fileTextMaxLength: 20000,
|
|
@@ -323,6 +325,8 @@ function fixXmlTag(code) {
|
|
|
323
325
|
code += '""';
|
|
324
326
|
}
|
|
325
327
|
else if (endStr == "name" ||
|
|
328
|
+
endStr == "id" ||
|
|
329
|
+
endStr == "dependsOn" ||
|
|
326
330
|
endStr == "input" ||
|
|
327
331
|
endStr == "output" ||
|
|
328
332
|
endStr == "items" ||
|
|
@@ -388,13 +392,13 @@ class Context {
|
|
|
388
392
|
this.variables = new Map();
|
|
389
393
|
this.controller = new AbortController();
|
|
390
394
|
}
|
|
391
|
-
async checkAborted() {
|
|
395
|
+
async checkAborted(noCheckPause) {
|
|
392
396
|
if (this.controller.signal.aborted) {
|
|
393
397
|
const error = new Error("Operation was interrupted");
|
|
394
398
|
error.name = "AbortError";
|
|
395
399
|
throw error;
|
|
396
400
|
}
|
|
397
|
-
while (this.pauseStatus > 0) {
|
|
401
|
+
while (this.pauseStatus > 0 && !noCheckPause) {
|
|
398
402
|
await sleep(500);
|
|
399
403
|
if (this.pauseStatus == 2) {
|
|
400
404
|
this.currentStepControllers.forEach((c) => {
|
|
@@ -14157,10 +14161,11 @@ createOpenRouter({
|
|
|
14157
14161
|
});
|
|
14158
14162
|
|
|
14159
14163
|
class RetryLanguageModel {
|
|
14160
|
-
constructor(llms, names, stream_first_timeout) {
|
|
14164
|
+
constructor(llms, names, stream_first_timeout, stream_token_timeout) {
|
|
14161
14165
|
this.llms = llms;
|
|
14162
14166
|
this.names = names || [];
|
|
14163
14167
|
this.stream_first_timeout = stream_first_timeout || 30000;
|
|
14168
|
+
this.stream_token_timeout = stream_token_timeout || 180000;
|
|
14164
14169
|
if (this.names.indexOf("default") == -1) {
|
|
14165
14170
|
this.names.push("default");
|
|
14166
14171
|
}
|
|
@@ -14178,6 +14183,7 @@ class RetryLanguageModel {
|
|
|
14178
14183
|
temperature: request.temperature,
|
|
14179
14184
|
topP: request.topP,
|
|
14180
14185
|
topK: request.topK,
|
|
14186
|
+
stopSequences: request.stopSequences,
|
|
14181
14187
|
abortSignal: request.abortSignal,
|
|
14182
14188
|
});
|
|
14183
14189
|
}
|
|
@@ -14188,25 +14194,29 @@ class RetryLanguageModel {
|
|
|
14188
14194
|
let lastError;
|
|
14189
14195
|
for (let i = 0; i < names.length; i++) {
|
|
14190
14196
|
const name = names[i];
|
|
14197
|
+
const llmConfig = this.llms[name];
|
|
14191
14198
|
const llm = await this.getLLM(name);
|
|
14192
14199
|
if (!llm) {
|
|
14193
14200
|
continue;
|
|
14194
14201
|
}
|
|
14195
14202
|
if (!maxTokens) {
|
|
14196
|
-
options.maxTokens =
|
|
14197
|
-
this.llms[name].config?.maxTokens || config.maxTokens;
|
|
14203
|
+
options.maxTokens = llmConfig.config?.maxTokens || config.maxTokens;
|
|
14198
14204
|
}
|
|
14199
14205
|
if (!providerMetadata) {
|
|
14200
14206
|
options.providerMetadata = {};
|
|
14201
|
-
options.providerMetadata[llm.provider] =
|
|
14207
|
+
options.providerMetadata[llm.provider] = llmConfig.options || {};
|
|
14208
|
+
}
|
|
14209
|
+
let _options = options;
|
|
14210
|
+
if (llmConfig.handler) {
|
|
14211
|
+
_options = await llmConfig.handler(_options);
|
|
14202
14212
|
}
|
|
14203
14213
|
try {
|
|
14204
|
-
let result = (await llm.doGenerate(
|
|
14214
|
+
let result = (await llm.doGenerate(_options));
|
|
14205
14215
|
if (Log.isEnableDebug()) {
|
|
14206
14216
|
Log.debug(`LLM nonstream body, name: ${name} => `, result.request?.body);
|
|
14207
14217
|
}
|
|
14208
14218
|
result.llm = name;
|
|
14209
|
-
result.llmConfig =
|
|
14219
|
+
result.llmConfig = llmConfig;
|
|
14210
14220
|
return result;
|
|
14211
14221
|
}
|
|
14212
14222
|
catch (e) {
|
|
@@ -14216,8 +14226,8 @@ class RetryLanguageModel {
|
|
|
14216
14226
|
lastError = e;
|
|
14217
14227
|
if (Log.isEnableInfo()) {
|
|
14218
14228
|
Log.info(`LLM nonstream request, name: ${name} => `, {
|
|
14219
|
-
tools:
|
|
14220
|
-
messages:
|
|
14229
|
+
tools: _options.mode?.tools,
|
|
14230
|
+
messages: _options.prompt,
|
|
14221
14231
|
});
|
|
14222
14232
|
}
|
|
14223
14233
|
Log.error(`LLM error, name: ${name} => `, e);
|
|
@@ -14238,6 +14248,7 @@ class RetryLanguageModel {
|
|
|
14238
14248
|
temperature: request.temperature,
|
|
14239
14249
|
topP: request.topP,
|
|
14240
14250
|
topK: request.topK,
|
|
14251
|
+
stopSequences: request.stopSequences,
|
|
14241
14252
|
abortSignal: request.abortSignal,
|
|
14242
14253
|
});
|
|
14243
14254
|
}
|
|
@@ -14248,24 +14259,28 @@ class RetryLanguageModel {
|
|
|
14248
14259
|
let lastError;
|
|
14249
14260
|
for (let i = 0; i < names.length; i++) {
|
|
14250
14261
|
const name = names[i];
|
|
14262
|
+
const llmConfig = this.llms[name];
|
|
14251
14263
|
const llm = await this.getLLM(name);
|
|
14252
14264
|
if (!llm) {
|
|
14253
14265
|
continue;
|
|
14254
14266
|
}
|
|
14255
14267
|
if (!maxTokens) {
|
|
14256
|
-
options.maxTokens =
|
|
14257
|
-
this.llms[name].config?.maxTokens || config.maxTokens;
|
|
14268
|
+
options.maxTokens = llmConfig.config?.maxTokens || config.maxTokens;
|
|
14258
14269
|
}
|
|
14259
14270
|
if (!providerMetadata) {
|
|
14260
14271
|
options.providerMetadata = {};
|
|
14261
|
-
options.providerMetadata[llm.provider] =
|
|
14272
|
+
options.providerMetadata[llm.provider] = llmConfig.options || {};
|
|
14273
|
+
}
|
|
14274
|
+
let _options = options;
|
|
14275
|
+
if (llmConfig.handler) {
|
|
14276
|
+
_options = await llmConfig.handler(_options);
|
|
14262
14277
|
}
|
|
14263
14278
|
try {
|
|
14264
14279
|
const controller = new AbortController();
|
|
14265
|
-
const signal =
|
|
14266
|
-
? AbortSignal.any([
|
|
14280
|
+
const signal = _options.abortSignal
|
|
14281
|
+
? AbortSignal.any([_options.abortSignal, controller.signal])
|
|
14267
14282
|
: controller.signal;
|
|
14268
|
-
const result = (await call_timeout(async () => await llm.doStream({ ...
|
|
14283
|
+
const result = (await call_timeout(async () => await llm.doStream({ ..._options, abortSignal: signal }), this.stream_first_timeout, (e) => {
|
|
14269
14284
|
controller.abort();
|
|
14270
14285
|
}));
|
|
14271
14286
|
const stream = result.stream;
|
|
@@ -14290,8 +14305,8 @@ class RetryLanguageModel {
|
|
|
14290
14305
|
continue;
|
|
14291
14306
|
}
|
|
14292
14307
|
result.llm = name;
|
|
14293
|
-
result.llmConfig =
|
|
14294
|
-
result.stream = this.streamWrapper([chunk], reader);
|
|
14308
|
+
result.llmConfig = llmConfig;
|
|
14309
|
+
result.stream = this.streamWrapper([chunk], reader, controller);
|
|
14295
14310
|
return result;
|
|
14296
14311
|
}
|
|
14297
14312
|
catch (e) {
|
|
@@ -14301,8 +14316,8 @@ class RetryLanguageModel {
|
|
|
14301
14316
|
lastError = e;
|
|
14302
14317
|
if (Log.isEnableInfo()) {
|
|
14303
14318
|
Log.info(`LLM stream request, name: ${name} => `, {
|
|
14304
|
-
tools:
|
|
14305
|
-
messages:
|
|
14319
|
+
tools: _options.mode?.tools,
|
|
14320
|
+
messages: _options.prompt,
|
|
14306
14321
|
});
|
|
14307
14322
|
}
|
|
14308
14323
|
Log.error(`LLM error, name: ${name} => `, e);
|
|
@@ -14383,7 +14398,8 @@ class RetryLanguageModel {
|
|
|
14383
14398
|
return llm.provider.languageModel(llm.model);
|
|
14384
14399
|
}
|
|
14385
14400
|
}
|
|
14386
|
-
streamWrapper(parts, reader) {
|
|
14401
|
+
streamWrapper(parts, reader, abortController) {
|
|
14402
|
+
let timer = null;
|
|
14387
14403
|
return new ReadableStream({
|
|
14388
14404
|
start: (controller) => {
|
|
14389
14405
|
if (parts != null && parts.length > 0) {
|
|
@@ -14393,7 +14409,11 @@ class RetryLanguageModel {
|
|
|
14393
14409
|
}
|
|
14394
14410
|
},
|
|
14395
14411
|
pull: async (controller) => {
|
|
14412
|
+
timer = setTimeout(() => {
|
|
14413
|
+
abortController.abort("Streaming request timeout");
|
|
14414
|
+
}, this.stream_token_timeout);
|
|
14396
14415
|
const { done, value } = await reader.read();
|
|
14416
|
+
clearTimeout(timer);
|
|
14397
14417
|
if (done) {
|
|
14398
14418
|
controller.close();
|
|
14399
14419
|
reader.releaseLock();
|
|
@@ -14402,6 +14422,7 @@ class RetryLanguageModel {
|
|
|
14402
14422
|
controller.enqueue(value);
|
|
14403
14423
|
},
|
|
14404
14424
|
cancel: (reason) => {
|
|
14425
|
+
timer && clearTimeout(timer);
|
|
14405
14426
|
reader.cancel(reason);
|
|
14406
14427
|
},
|
|
14407
14428
|
});
|
|
@@ -16906,10 +16927,13 @@ function parseWorkflow(taskId, xml, done, thinking) {
|
|
|
16906
16927
|
if (!name) {
|
|
16907
16928
|
break;
|
|
16908
16929
|
}
|
|
16930
|
+
let index = agentNode.getAttribute("id") || i;
|
|
16931
|
+
let dependsOn = agentNode.getAttribute("dependsOn") || "";
|
|
16909
16932
|
let nodes = [];
|
|
16910
16933
|
let agent = {
|
|
16911
16934
|
name: name,
|
|
16912
|
-
id: taskId
|
|
16935
|
+
id: getAgentId(taskId, index),
|
|
16936
|
+
dependsOn: dependsOn.split(",").filter(idx => idx.trim() != "").map(idx => getAgentId(taskId, idx)),
|
|
16913
16937
|
task: agentNode.getElementsByTagName("task")[0]?.textContent || "",
|
|
16914
16938
|
nodes: nodes,
|
|
16915
16939
|
xml: agentNode.toString(),
|
|
@@ -16931,6 +16955,9 @@ function parseWorkflow(taskId, xml, done, thinking) {
|
|
|
16931
16955
|
}
|
|
16932
16956
|
}
|
|
16933
16957
|
}
|
|
16958
|
+
function getAgentId(taskId, index) {
|
|
16959
|
+
return taskId + "-" + (+index < 10 ? "0" + index : index);
|
|
16960
|
+
}
|
|
16934
16961
|
function parseWorkflowNodes(nodes, xmlNodes) {
|
|
16935
16962
|
for (let i = 0; i < xmlNodes.length; i++) {
|
|
16936
16963
|
if (xmlNodes[i].nodeType !== 1) {
|
|
@@ -17048,6 +17075,7 @@ function buildSimpleAgentWorkflow({ taskId, name, agentName, task, taskNodes, })
|
|
|
17048
17075
|
agents: [
|
|
17049
17076
|
{
|
|
17050
17077
|
id: taskId + "-00",
|
|
17078
|
+
dependsOn: [],
|
|
17051
17079
|
name: agentName,
|
|
17052
17080
|
task: task,
|
|
17053
17081
|
nodes: taskNodes.map((node) => {
|
|
@@ -17069,6 +17097,7 @@ function resetWorkflowXml(workflow) {
|
|
|
17069
17097
|
const agents = [];
|
|
17070
17098
|
for (let i = 0; i < workflow.agents.length; i++) {
|
|
17071
17099
|
const agent = workflow.agents[i];
|
|
17100
|
+
const agentDependsAttr = ` id="${i}" dependsOn="${(agent.dependsOn || []).filter(s => parseInt(s.split("-")[s.split("-").length - 1])).join(",")}"`;
|
|
17072
17101
|
const nodes = agent.nodes
|
|
17073
17102
|
.map((node) => {
|
|
17074
17103
|
if (node.type == "forEach") {
|
|
@@ -17105,7 +17134,7 @@ ${watchNodes.join("\n")}
|
|
|
17105
17134
|
}
|
|
17106
17135
|
})
|
|
17107
17136
|
.join("\n");
|
|
17108
|
-
const agentXml = ` <agent name="${agent.name}">
|
|
17137
|
+
const agentXml = ` <agent name="${agent.name}"${agentDependsAttr}>
|
|
17109
17138
|
<task>${agent.task}</task>
|
|
17110
17139
|
<nodes>
|
|
17111
17140
|
${nodes}
|
|
@@ -17172,7 +17201,7 @@ class TaskSnapshotTool {
|
|
|
17172
17201
|
}
|
|
17173
17202
|
}
|
|
17174
17203
|
|
|
17175
|
-
async function callAgentLLM(agentContext, rlm, messages, tools, noCompress, toolChoice,
|
|
17204
|
+
async function callAgentLLM(agentContext, rlm, messages, tools, noCompress, toolChoice, retryNum = 0, callback, requestHandler) {
|
|
17176
17205
|
await agentContext.context.checkAborted();
|
|
17177
17206
|
if (messages.length >= config.compressThreshold && !noCompress) {
|
|
17178
17207
|
await compressAgentMessages(agentContext, rlm, messages, tools);
|
|
@@ -17199,6 +17228,7 @@ async function callAgentLLM(agentContext, rlm, messages, tools, noCompress, tool
|
|
|
17199
17228
|
messages: messages,
|
|
17200
17229
|
abortSignal: signal,
|
|
17201
17230
|
};
|
|
17231
|
+
requestHandler && requestHandler(request);
|
|
17202
17232
|
agentChain.agentRequest = request;
|
|
17203
17233
|
let result;
|
|
17204
17234
|
try {
|
|
@@ -17209,13 +17239,13 @@ async function callAgentLLM(agentContext, rlm, messages, tools, noCompress, tool
|
|
|
17209
17239
|
context.currentStepControllers.delete(stepController);
|
|
17210
17240
|
await context.checkAborted();
|
|
17211
17241
|
if (!noCompress &&
|
|
17212
|
-
messages.length
|
|
17242
|
+
messages.length >= 5 &&
|
|
17213
17243
|
((e + "").indexOf("tokens") > -1 || (e + "").indexOf("too long") > -1)) {
|
|
17214
17244
|
await compressAgentMessages(agentContext, rlm, messages, tools);
|
|
17215
17245
|
}
|
|
17216
|
-
if (
|
|
17217
|
-
await sleep(200);
|
|
17218
|
-
return callAgentLLM(agentContext, rlm, messages, tools, noCompress, toolChoice,
|
|
17246
|
+
if (retryNum < config.maxRetryNum) {
|
|
17247
|
+
await sleep(200 * (retryNum + 1) * (retryNum + 1));
|
|
17248
|
+
return callAgentLLM(agentContext, rlm, messages, tools, noCompress, toolChoice, ++retryNum, streamCallback);
|
|
17219
17249
|
}
|
|
17220
17250
|
throw e;
|
|
17221
17251
|
}
|
|
@@ -17394,11 +17424,11 @@ async function callAgentLLM(agentContext, rlm, messages, tools, noCompress, tool
|
|
|
17394
17424
|
usage: chunk.usage,
|
|
17395
17425
|
}, agentContext);
|
|
17396
17426
|
if (chunk.finishReason === "length" &&
|
|
17397
|
-
messages.length >=
|
|
17427
|
+
messages.length >= 5 &&
|
|
17398
17428
|
!noCompress &&
|
|
17399
|
-
|
|
17429
|
+
retryNum < config.maxRetryNum) {
|
|
17400
17430
|
await compressAgentMessages(agentContext, rlm, messages, tools);
|
|
17401
|
-
return callAgentLLM(agentContext, rlm, messages, tools, noCompress, toolChoice,
|
|
17431
|
+
return callAgentLLM(agentContext, rlm, messages, tools, noCompress, toolChoice, ++retryNum, streamCallback);
|
|
17402
17432
|
}
|
|
17403
17433
|
break;
|
|
17404
17434
|
}
|
|
@@ -17407,8 +17437,9 @@ async function callAgentLLM(agentContext, rlm, messages, tools, noCompress, tool
|
|
|
17407
17437
|
}
|
|
17408
17438
|
catch (e) {
|
|
17409
17439
|
await context.checkAborted();
|
|
17410
|
-
if (
|
|
17411
|
-
|
|
17440
|
+
if (retryNum < config.maxRetryNum) {
|
|
17441
|
+
await sleep(200 * (retryNum + 1) * (retryNum + 1));
|
|
17442
|
+
return callAgentLLM(agentContext, rlm, messages, tools, noCompress, toolChoice, ++retryNum, streamCallback);
|
|
17412
17443
|
}
|
|
17413
17444
|
throw e;
|
|
17414
17445
|
}
|
|
@@ -17429,7 +17460,8 @@ function appendUserConversation(agentContext, messages) {
|
|
|
17429
17460
|
.splice(0, agentContext.context.conversation.length)
|
|
17430
17461
|
.filter((s) => !!s);
|
|
17431
17462
|
if (userPrompts.length > 0) {
|
|
17432
|
-
const prompt = "The user is intervening in the current task
|
|
17463
|
+
const prompt = "The user is intervening in the current task, please replan and execute according to the following instructions:\n" +
|
|
17464
|
+
userPrompts.map((s) => `- ${s.trim()}`).join("\n");
|
|
17433
17465
|
messages.push({
|
|
17434
17466
|
role: "user",
|
|
17435
17467
|
content: [{ type: "text", text: prompt }],
|
|
@@ -17481,9 +17513,17 @@ function removeDuplicateToolUse(results) {
|
|
|
17481
17513
|
return _results;
|
|
17482
17514
|
}
|
|
17483
17515
|
async function compressAgentMessages(agentContext, rlm, messages, tools) {
|
|
17484
|
-
if (messages.length <
|
|
17516
|
+
if (messages.length < 5) {
|
|
17485
17517
|
return;
|
|
17486
17518
|
}
|
|
17519
|
+
try {
|
|
17520
|
+
doCompressAgentMessages(agentContext, rlm, messages, tools);
|
|
17521
|
+
}
|
|
17522
|
+
catch (e) {
|
|
17523
|
+
Log.error("Error compressing agent messages:", e);
|
|
17524
|
+
}
|
|
17525
|
+
}
|
|
17526
|
+
async function doCompressAgentMessages(agentContext, rlm, messages, tools) {
|
|
17487
17527
|
// extract used tool
|
|
17488
17528
|
let usedTools = extractUsedTool(messages, tools);
|
|
17489
17529
|
let snapshotTool = new TaskSnapshotTool();
|
|
@@ -17605,7 +17645,8 @@ function handleLargeContextMessages(messages) {
|
|
|
17605
17645
|
}
|
|
17606
17646
|
for (let r = 0; r < toolContent.length; r++) {
|
|
17607
17647
|
let _content = toolContent[r];
|
|
17608
|
-
if (_content.type == "text" &&
|
|
17648
|
+
if (_content.type == "text" &&
|
|
17649
|
+
_content.text?.length > config.largeTextLength) {
|
|
17609
17650
|
if (!longTextTools[toolResult.toolName]) {
|
|
17610
17651
|
longTextTools[toolResult.toolName] = 1;
|
|
17611
17652
|
break;
|
|
@@ -18378,6 +18419,7 @@ class Agent {
|
|
|
18378
18419
|
this.llms = params.llms;
|
|
18379
18420
|
this.mcpClient = params.mcpClient;
|
|
18380
18421
|
this.planDescription = params.planDescription;
|
|
18422
|
+
this.requestHandler = params.requestHandler;
|
|
18381
18423
|
}
|
|
18382
18424
|
async run(context, agentChain) {
|
|
18383
18425
|
let mcpClient = this.mcpClient || context.config.defaultMcpClient;
|
|
@@ -18423,7 +18465,7 @@ class Agent {
|
|
|
18423
18465
|
}
|
|
18424
18466
|
}
|
|
18425
18467
|
await this.handleMessages(agentContext, messages, tools);
|
|
18426
|
-
let results = await callAgentLLM(agentContext, rlm, messages, this.convertTools(agentTools), false, undefined,
|
|
18468
|
+
let results = await callAgentLLM(agentContext, rlm, messages, this.convertTools(agentTools), false, undefined, 0, this.callback, this.requestHandler);
|
|
18427
18469
|
let finalResult = await this.handleCallResult(agentContext, messages, agentTools, results);
|
|
18428
18470
|
if (finalResult) {
|
|
18429
18471
|
return finalResult;
|
|
@@ -18433,6 +18475,10 @@ class Agent {
|
|
|
18433
18475
|
return "Unfinished";
|
|
18434
18476
|
}
|
|
18435
18477
|
async handleCallResult(agentContext, messages, agentTools, results) {
|
|
18478
|
+
const forceStop = agentContext.variables.get("forceStop");
|
|
18479
|
+
if (forceStop) {
|
|
18480
|
+
return forceStop;
|
|
18481
|
+
}
|
|
18436
18482
|
let text = null;
|
|
18437
18483
|
let context = agentContext.context;
|
|
18438
18484
|
let user_messages = [];
|
|
@@ -18721,11 +18767,11 @@ class Agent {
|
|
|
18721
18767
|
}
|
|
18722
18768
|
}
|
|
18723
18769
|
|
|
18724
|
-
const AGENT_NAME$
|
|
18770
|
+
const AGENT_NAME$4 = "Chat";
|
|
18725
18771
|
class BaseChatAgent extends Agent {
|
|
18726
18772
|
constructor(llms, ext_tools, mcpClient) {
|
|
18727
18773
|
super({
|
|
18728
|
-
name: AGENT_NAME$
|
|
18774
|
+
name: AGENT_NAME$4,
|
|
18729
18775
|
description: "You are a helpful assistant.",
|
|
18730
18776
|
tools: ext_tools || [],
|
|
18731
18777
|
llms: llms,
|
|
@@ -18759,8 +18805,13 @@ Your task is to understand the user's requirements, dynamically plan the user's
|
|
|
18759
18805
|
<thought>Your thought process on user demand planning</thought>
|
|
18760
18806
|
<!-- Multiple Agents work together to complete the task -->
|
|
18761
18807
|
<agents>
|
|
18762
|
-
<!--
|
|
18763
|
-
|
|
18808
|
+
<!--
|
|
18809
|
+
Multi-Agent supports parallelism, coordinating parallel tasks through dependencies, and passing dependent context information through node variables.
|
|
18810
|
+
name: The name of the Agent, where the name can only be an available name in the Agent list.
|
|
18811
|
+
id: Use subscript order as ID for dependency relationships between multiple agents.
|
|
18812
|
+
dependsOn: The IDs of agents that the current agent depends on, separated by commas when there are multiple dependencies.
|
|
18813
|
+
-->
|
|
18814
|
+
<agent name="Agent name" id="0" dependsOn="">
|
|
18764
18815
|
<!-- The current Agent needs to complete the task -->
|
|
18765
18816
|
<task>current agent task</task>
|
|
18766
18817
|
<nodes>
|
|
@@ -18782,6 +18833,22 @@ Your task is to understand the user's requirements, dynamically plan the user's
|
|
|
18782
18833
|
</watch>
|
|
18783
18834
|
</nodes>
|
|
18784
18835
|
</agent>
|
|
18836
|
+
<!--
|
|
18837
|
+
Multi-agent Collaboration Dependency Example:
|
|
18838
|
+
|
|
18839
|
+
Execution Flow:
|
|
18840
|
+
1. Agent 0: Initial agent with no dependencies (executes first)
|
|
18841
|
+
2. Agent 1: Depends on Agent 0 completion (executes after Agent 0)
|
|
18842
|
+
3. Agent 2 & 3: Both depend on Agent 1 completion (execute in parallel after Agent 1)
|
|
18843
|
+
4. Agent 4: Depends on both Agent 2 and Agent 3 completion (executes last)
|
|
18844
|
+
|
|
18845
|
+
Dependency Chain: Agent 0 → Agent 1 → (Agent 2 ∥ Agent 3) → Agent 4
|
|
18846
|
+
-->
|
|
18847
|
+
<agent name="Agent name" id="0" dependsOn="">...</agent>
|
|
18848
|
+
<agent name="Agent name" id="1" dependsOn="0">...</agent>
|
|
18849
|
+
<agent name="Agent name" id="2" dependsOn="1">...</agent>
|
|
18850
|
+
<agent name="Agent name" id="3" dependsOn="1">...</agent>
|
|
18851
|
+
<agent name="Agent name" id="4" dependsOn="2,3">...</agent>
|
|
18785
18852
|
</agents>
|
|
18786
18853
|
</root>
|
|
18787
18854
|
|
|
@@ -18794,7 +18861,7 @@ Output result:
|
|
|
18794
18861
|
<thought>Alright, the user wrote "hello". That's pretty straightforward. I need to respond in a friendly and welcoming manner.</thought>
|
|
18795
18862
|
<agents>
|
|
18796
18863
|
<!-- Chat agents can exist without the <task> and <nodes> nodes. -->
|
|
18797
|
-
<agent name="Chat"></agent>
|
|
18864
|
+
<agent name="Chat" id="0" dependsOn=""></agent>
|
|
18798
18865
|
</agents>
|
|
18799
18866
|
</root>`;
|
|
18800
18867
|
const PLAN_EXAMPLE_LIST = [
|
|
@@ -18804,7 +18871,7 @@ Output result:
|
|
|
18804
18871
|
<name>Submit resume</name>
|
|
18805
18872
|
<thought>OK, now the user requests me to create a workflow that involves opening the Boss Zhipin website, finding 10 operation positions in Chengdu, and sending personal resumes to the recruiters based on the job information.</thought>
|
|
18806
18873
|
<agents>
|
|
18807
|
-
<agent name="Browser">
|
|
18874
|
+
<agent name="Browser" id="0" dependsOn="">
|
|
18808
18875
|
<task>Open Boss Zhipin, find 10 operation positions in Chengdu, and send a personal introduction to the recruiters based on the page information.</task>
|
|
18809
18876
|
<nodes>
|
|
18810
18877
|
<node>Open Boss Zhipin, enter the job search page</node>
|
|
@@ -18824,7 +18891,7 @@ Output result:
|
|
|
18824
18891
|
<name>Latest AI News</name>
|
|
18825
18892
|
<thought>OK, users need to collect the latest AI news, summarize it, and send it to a WeChat group named "AI news information" This requires automation, including the steps of data collection, processing, and distribution.</thought>
|
|
18826
18893
|
<agents>
|
|
18827
|
-
<agent name="Browser">
|
|
18894
|
+
<agent name="Browser" id="0" dependsOn="">
|
|
18828
18895
|
<task>Search for the latest updates on AI</task>
|
|
18829
18896
|
<nodes>
|
|
18830
18897
|
<node>Open Google</node>
|
|
@@ -18835,7 +18902,7 @@ Output result:
|
|
|
18835
18902
|
<node output="summaryInfo">Summarize search information</node>
|
|
18836
18903
|
</nodes>
|
|
18837
18904
|
</agent>
|
|
18838
|
-
<agent name="Computer">
|
|
18905
|
+
<agent name="Computer" id="1" dependsOn="0">
|
|
18839
18906
|
<task>Send a message to the WeChat group chat "AI news information"</task>
|
|
18840
18907
|
<nodes>
|
|
18841
18908
|
<node>Open WeChat</node>
|
|
@@ -18851,7 +18918,7 @@ Output result:
|
|
|
18851
18918
|
<name>Statistics of Google Team Developers' Geographic Distribution</name>
|
|
18852
18919
|
<thought>Okay, I need to first visit GitHub, then find Google's organization page on GitHub, extract the team member list, and individually visit each developer's homepage to obtain location information for each developer. This requires using a browser to complete all operations.</thought>
|
|
18853
18920
|
<agents>
|
|
18854
|
-
<agent name="Browser">
|
|
18921
|
+
<agent name="Browser" id="0" dependsOn="">
|
|
18855
18922
|
<task>Visit Google GitHub Organization Page and Analyze Developer Geographic Distribution</task>
|
|
18856
18923
|
<nodes>
|
|
18857
18924
|
<node>Visit https://github.com/google</node>
|
|
@@ -18873,7 +18940,7 @@ Output result:
|
|
|
18873
18940
|
<name>Automatic reply to Discord messages</name>
|
|
18874
18941
|
<thought>OK, monitor the chat messages in Discord group A and automatically reply.</thought>
|
|
18875
18942
|
<agents>
|
|
18876
|
-
<agent name="Browser">
|
|
18943
|
+
<agent name="Browser" id="0" dependsOn="">
|
|
18877
18944
|
<task>Open Group A in Discord</task>
|
|
18878
18945
|
<nodes>
|
|
18879
18946
|
<node>Open Discord page</node>
|
|
@@ -18888,6 +18955,59 @@ Output result:
|
|
|
18888
18955
|
</nodes>
|
|
18889
18956
|
</agent>
|
|
18890
18957
|
</agents>
|
|
18958
|
+
</root>`,
|
|
18959
|
+
`User: Search for information about "fellou," compile the results into a summary profile, then share it across social media platforms including Twitter, Facebook, and Reddit. Finally, export the platform sharing operation results to an Excel file.
|
|
18960
|
+
Output result:
|
|
18961
|
+
<root>
|
|
18962
|
+
<name>Fellou Research and Social Media Campaign</name>
|
|
18963
|
+
<thought>The user wants me to research information about 'Fellou', create a summary profile, share it on multiple social media platforms (Twitter, Facebook, Reddit), and then compile the results into an Excel file. This requires multiple agents working together: Browser for research, Browser for social media posting (Twitter, Facebook, and Reddit in parallel), and File for creating the Excel export. I need to break this down into sequential steps with proper variable passing between agents.</thought>
|
|
18964
|
+
<agents>
|
|
18965
|
+
<agent name="Browser" id="0" dependsOn="">
|
|
18966
|
+
<task>Research comprehensive information about 'Fellou'</task>
|
|
18967
|
+
<nodes>
|
|
18968
|
+
<node>Search for the latest information about 'Fellou' - its identity, purpose, and core features</node>
|
|
18969
|
+
<node>Search for Fellou's functionalities, capabilities, and technical specifications</node>
|
|
18970
|
+
<node>Search for recent news, updates, announcements, and developments related to Fellou</node>
|
|
18971
|
+
<node>Search for user reviews, feedback, and community discussions about Fellou</node>
|
|
18972
|
+
<node>Search for Fellou's market position, competitors, and industry context</node>
|
|
18973
|
+
<node output="researchData">Compile all research findings into a comprehensive summary profile</node>
|
|
18974
|
+
</nodes>
|
|
18975
|
+
</agent>
|
|
18976
|
+
<agent name="Browser" id="1" dependsOn="0">
|
|
18977
|
+
<task>Share Fellou's summary and collected interaction data on Twitter/X</task>
|
|
18978
|
+
<nodes>
|
|
18979
|
+
<node>Navigate to Twitter/X platform</node>
|
|
18980
|
+
<node input="researchData">Create and post Twitter-optimized content about Fellou (within character limits, using hashtags)</node>
|
|
18981
|
+
<node output="twitterResults">Capture Twitter post URL and initial engagement metrics</node>
|
|
18982
|
+
</nodes>
|
|
18983
|
+
</agent>
|
|
18984
|
+
<agent name="Browser" id="2" dependsOn="0">
|
|
18985
|
+
<task>Share Fellou's summary and collected interaction data on Facebook</task>
|
|
18986
|
+
<nodes>
|
|
18987
|
+
<node>Navigate to Facebook platform</node>
|
|
18988
|
+
<node input="researchData">Create and post Facebook-optimized content about Fellou (longer format, engaging description)</node>
|
|
18989
|
+
<node output="facebookResults">Capture Facebook post URL and initial engagement metrics</node>
|
|
18990
|
+
</nodes>
|
|
18991
|
+
</agent>
|
|
18992
|
+
<agent name="Browser" id="3" dependsOn="0">
|
|
18993
|
+
<task>Share Fellou's summary and collected interaction data on Reddit</task>
|
|
18994
|
+
<nodes>
|
|
18995
|
+
<node>Navigate to Reddit platform</node>
|
|
18996
|
+
<node input="researchData">Find appropriate subreddit and create Reddit-optimized post about Fellou (community-focused, informative)</node>
|
|
18997
|
+
<node output="redditResults">Capture Reddit post URL and initial engagement metrics</node>
|
|
18998
|
+
</nodes>
|
|
18999
|
+
</agent>
|
|
19000
|
+
<agent name="File" id="4" dependsOn="1,2,3">
|
|
19001
|
+
<task>Compile social media results into Excel file</task>
|
|
19002
|
+
<nodes>
|
|
19003
|
+
<node input="twitterResults,facebookResults,redditResults">Create Excel file with social media campaign results</node>
|
|
19004
|
+
<node>Include columns for Platform, Post URL, Content Summary, Timestamp, Initial Likes/Shares/Comments</node>
|
|
19005
|
+
<node>Format the Excel file with proper headers and styling</node>
|
|
19006
|
+
<node>Save the file as 'Fellou_Social_Media_Campaign_Results.xlsx'</node>
|
|
19007
|
+
</nodes>
|
|
19008
|
+
</agent>
|
|
19009
|
+
</agents>
|
|
19010
|
+
</agents>
|
|
18891
19011
|
</root>`,
|
|
18892
19012
|
];
|
|
18893
19013
|
const PLAN_USER_TEMPLATE = `
|
|
@@ -18918,7 +19038,7 @@ async function getPlanSystemPrompt(context) {
|
|
|
18918
19038
|
"\n</agent>\n\n";
|
|
18919
19039
|
}
|
|
18920
19040
|
let plan_example_list = context.variables.get("plan_example_list") || PLAN_EXAMPLE_LIST;
|
|
18921
|
-
let hasChatAgent = context.agents.filter((a) => a.Name == AGENT_NAME$
|
|
19041
|
+
let hasChatAgent = context.agents.filter((a) => a.Name == AGENT_NAME$4).length > 0;
|
|
18922
19042
|
let example_prompt = "";
|
|
18923
19043
|
const example_list = hasChatAgent
|
|
18924
19044
|
? [PLAN_CHAT_EXAMPLE, ...plan_example_list]
|
|
@@ -18951,9 +19071,10 @@ function getPlanUserPrompt(task_prompt, task_website, ext_prompt) {
|
|
|
18951
19071
|
}
|
|
18952
19072
|
|
|
18953
19073
|
class Planner {
|
|
18954
|
-
constructor(context,
|
|
19074
|
+
constructor(context, callback) {
|
|
18955
19075
|
this.context = context;
|
|
18956
|
-
this.taskId =
|
|
19076
|
+
this.taskId = context.taskId;
|
|
19077
|
+
this.callback = callback || context.config.callback;
|
|
18957
19078
|
}
|
|
18958
19079
|
async plan(taskPrompt, saveHistory = true) {
|
|
18959
19080
|
let taskPromptStr;
|
|
@@ -19017,7 +19138,7 @@ class Planner {
|
|
|
19017
19138
|
let thinkingText = "";
|
|
19018
19139
|
try {
|
|
19019
19140
|
while (true) {
|
|
19020
|
-
await this.context.checkAborted();
|
|
19141
|
+
await this.context.checkAborted(true);
|
|
19021
19142
|
const { done, value } = await reader.read();
|
|
19022
19143
|
if (done) {
|
|
19023
19144
|
break;
|
|
@@ -19033,10 +19154,10 @@ class Planner {
|
|
|
19033
19154
|
if (chunk.type == "text-delta") {
|
|
19034
19155
|
streamText += chunk.textDelta || "";
|
|
19035
19156
|
}
|
|
19036
|
-
if (
|
|
19157
|
+
if (this.callback) {
|
|
19037
19158
|
let workflow = parseWorkflow(this.taskId, streamText, false, thinkingText);
|
|
19038
19159
|
if (workflow) {
|
|
19039
|
-
await
|
|
19160
|
+
await this.callback.onMessage({
|
|
19040
19161
|
taskId: this.taskId,
|
|
19041
19162
|
agentName: "Planer",
|
|
19042
19163
|
type: "workflow",
|
|
@@ -19059,8 +19180,8 @@ class Planner {
|
|
|
19059
19180
|
chain.planResult = streamText;
|
|
19060
19181
|
}
|
|
19061
19182
|
let workflow = parseWorkflow(this.taskId, streamText, true, thinkingText);
|
|
19062
|
-
if (
|
|
19063
|
-
await
|
|
19183
|
+
if (this.callback) {
|
|
19184
|
+
await this.callback.onMessage({
|
|
19064
19185
|
taskId: this.taskId,
|
|
19065
19186
|
agentName: "Planer",
|
|
19066
19187
|
type: "workflow",
|
|
@@ -19078,6 +19199,163 @@ class Planner {
|
|
|
19078
19199
|
}
|
|
19079
19200
|
}
|
|
19080
19201
|
|
|
19202
|
+
function buildAgentTree(agents) {
|
|
19203
|
+
// Detect and handle circular dependencies
|
|
19204
|
+
const safeAgents = detectAndBreakCycles(agents);
|
|
19205
|
+
if (safeAgents.length === 0) {
|
|
19206
|
+
throw new Error("No executable agent");
|
|
19207
|
+
}
|
|
19208
|
+
// Establish dependency relationship mapping
|
|
19209
|
+
const agentMap = new Map();
|
|
19210
|
+
const dependents = new Map();
|
|
19211
|
+
for (const agent of safeAgents) {
|
|
19212
|
+
agentMap.set(agent.id, agent);
|
|
19213
|
+
dependents.set(agent.id, []);
|
|
19214
|
+
}
|
|
19215
|
+
for (const agent of safeAgents) {
|
|
19216
|
+
for (const depId of agent.dependsOn) {
|
|
19217
|
+
if (dependents.has(depId)) {
|
|
19218
|
+
dependents.get(depId).push(agent);
|
|
19219
|
+
}
|
|
19220
|
+
}
|
|
19221
|
+
}
|
|
19222
|
+
let entryAgents = safeAgents.filter((agent) => agent.dependsOn.length === 0);
|
|
19223
|
+
if (entryAgents.length === 0) {
|
|
19224
|
+
entryAgents = safeAgents.filter((agent) => agent.dependsOn.length == 1 && agent.dependsOn[0].endsWith("00"));
|
|
19225
|
+
}
|
|
19226
|
+
const processedAgents = new Set();
|
|
19227
|
+
function buildNodeRecursive(currentAgents) {
|
|
19228
|
+
if (currentAgents.length === 0) {
|
|
19229
|
+
return undefined;
|
|
19230
|
+
}
|
|
19231
|
+
for (const agent of currentAgents) {
|
|
19232
|
+
processedAgents.add(agent.id);
|
|
19233
|
+
}
|
|
19234
|
+
const nextLevelAgents = [];
|
|
19235
|
+
const nextLevelSet = new Set();
|
|
19236
|
+
for (const agent of currentAgents) {
|
|
19237
|
+
const dependentAgents = dependents.get(agent.id) || [];
|
|
19238
|
+
for (const dependentAgent of dependentAgents) {
|
|
19239
|
+
const allDependenciesProcessed = dependentAgent.dependsOn.every((depId) => processedAgents.has(depId));
|
|
19240
|
+
if (allDependenciesProcessed && !nextLevelSet.has(dependentAgent.id)) {
|
|
19241
|
+
nextLevelAgents.push(dependentAgent);
|
|
19242
|
+
nextLevelSet.add(dependentAgent.id);
|
|
19243
|
+
}
|
|
19244
|
+
}
|
|
19245
|
+
}
|
|
19246
|
+
const nextNode = buildNodeRecursive(nextLevelAgents);
|
|
19247
|
+
if (currentAgents.length === 1) {
|
|
19248
|
+
return {
|
|
19249
|
+
type: "normal",
|
|
19250
|
+
agent: currentAgents[0],
|
|
19251
|
+
nextAgent: nextNode,
|
|
19252
|
+
};
|
|
19253
|
+
}
|
|
19254
|
+
else {
|
|
19255
|
+
const parallelNodes = currentAgents.map((agent) => ({
|
|
19256
|
+
type: "normal",
|
|
19257
|
+
agent: agent,
|
|
19258
|
+
nextAgent: undefined,
|
|
19259
|
+
}));
|
|
19260
|
+
return {
|
|
19261
|
+
type: "parallel",
|
|
19262
|
+
agents: parallelNodes,
|
|
19263
|
+
nextAgent: nextNode,
|
|
19264
|
+
};
|
|
19265
|
+
}
|
|
19266
|
+
}
|
|
19267
|
+
const rootNode = buildNodeRecursive(entryAgents);
|
|
19268
|
+
if (!rootNode) {
|
|
19269
|
+
throw new Error("Unable to build execution tree");
|
|
19270
|
+
}
|
|
19271
|
+
return rootNode;
|
|
19272
|
+
}
|
|
19273
|
+
function detectAndBreakCycles(agents) {
|
|
19274
|
+
// Detect cyclic dependencies and return a safe dependency relationship
|
|
19275
|
+
// Use topological sorting algorithm to detect cycles, if a cycle is found, break some dependencies.
|
|
19276
|
+
const agentMap = new Map();
|
|
19277
|
+
const inDegree = new Map();
|
|
19278
|
+
const adjList = new Map();
|
|
19279
|
+
for (const agent of agents) {
|
|
19280
|
+
agentMap.set(agent.id, agent);
|
|
19281
|
+
inDegree.set(agent.id, 0);
|
|
19282
|
+
adjList.set(agent.id, []);
|
|
19283
|
+
}
|
|
19284
|
+
for (const agent of agents) {
|
|
19285
|
+
for (const depId of agent.dependsOn) {
|
|
19286
|
+
if (agentMap.has(depId)) {
|
|
19287
|
+
// depId -> agent.id indicates that the agent depends on depId.
|
|
19288
|
+
adjList.get(depId).push(agent.id);
|
|
19289
|
+
inDegree.set(agent.id, inDegree.get(agent.id) + 1);
|
|
19290
|
+
}
|
|
19291
|
+
}
|
|
19292
|
+
}
|
|
19293
|
+
// Topological Sorting Detects Cycles
|
|
19294
|
+
const queue = [];
|
|
19295
|
+
const processedCount = new Map();
|
|
19296
|
+
for (const [agentId, degree] of inDegree.entries()) {
|
|
19297
|
+
if (degree === 0) {
|
|
19298
|
+
queue.push(agentId);
|
|
19299
|
+
}
|
|
19300
|
+
processedCount.set(agentId, 0);
|
|
19301
|
+
}
|
|
19302
|
+
let processedNodes = 0;
|
|
19303
|
+
while (queue.length > 0) {
|
|
19304
|
+
const currentId = queue.shift();
|
|
19305
|
+
processedNodes++;
|
|
19306
|
+
for (const neighborId of adjList.get(currentId)) {
|
|
19307
|
+
const newInDegree = inDegree.get(neighborId) - 1;
|
|
19308
|
+
inDegree.set(neighborId, newInDegree);
|
|
19309
|
+
if (newInDegree === 0) {
|
|
19310
|
+
queue.push(neighborId);
|
|
19311
|
+
}
|
|
19312
|
+
}
|
|
19313
|
+
}
|
|
19314
|
+
if (processedNodes < agents.length) {
|
|
19315
|
+
console.warn("Detected a circular dependency, automatically disconnecting the circular link...");
|
|
19316
|
+
const cyclicNodes = new Set();
|
|
19317
|
+
for (const [agentId, degree] of inDegree.entries()) {
|
|
19318
|
+
if (degree > 0) {
|
|
19319
|
+
cyclicNodes.add(agentId);
|
|
19320
|
+
}
|
|
19321
|
+
}
|
|
19322
|
+
const fixedAgents = [];
|
|
19323
|
+
for (const agent of agents) {
|
|
19324
|
+
if (cyclicNodes.has(agent.id)) {
|
|
19325
|
+
const filteredDependsOn = agent.dependsOn.filter((depId) => !cyclicNodes.has(depId) || !agentMap.has(depId));
|
|
19326
|
+
// Preserve the shortest path dependency
|
|
19327
|
+
if (filteredDependsOn.length === 0 && agent.dependsOn.length > 0) {
|
|
19328
|
+
const firstValidDep = agent.dependsOn.find((depId) => agentMap.has(depId));
|
|
19329
|
+
if (firstValidDep && !cyclicNodes.has(firstValidDep)) {
|
|
19330
|
+
filteredDependsOn.push(firstValidDep);
|
|
19331
|
+
}
|
|
19332
|
+
}
|
|
19333
|
+
fixedAgents.push({
|
|
19334
|
+
...agent,
|
|
19335
|
+
dependsOn: filteredDependsOn,
|
|
19336
|
+
});
|
|
19337
|
+
if (filteredDependsOn.length !== agent.dependsOn.length) {
|
|
19338
|
+
console.warn(`The partial cyclic dependency of agent ${agent.id} has been disconnected.`);
|
|
19339
|
+
}
|
|
19340
|
+
}
|
|
19341
|
+
else {
|
|
19342
|
+
// Non-cyclic node, filter out non-existent dependencies
|
|
19343
|
+
const validDependsOn = agent.dependsOn.filter((depId) => agentMap.has(depId));
|
|
19344
|
+
fixedAgents.push({
|
|
19345
|
+
...agent,
|
|
19346
|
+
dependsOn: validDependsOn,
|
|
19347
|
+
});
|
|
19348
|
+
}
|
|
19349
|
+
}
|
|
19350
|
+
return fixedAgents;
|
|
19351
|
+
}
|
|
19352
|
+
// No loops, just need to filter out non-existent dependencies
|
|
19353
|
+
return agents.map((agent) => ({
|
|
19354
|
+
...agent,
|
|
19355
|
+
dependsOn: agent.dependsOn.filter((depId) => agentMap.has(depId)),
|
|
19356
|
+
}));
|
|
19357
|
+
}
|
|
19358
|
+
|
|
19081
19359
|
class Eko {
|
|
19082
19360
|
constructor(config) {
|
|
19083
19361
|
this.config = config;
|
|
@@ -19085,18 +19363,18 @@ class Eko {
|
|
|
19085
19363
|
}
|
|
19086
19364
|
async generate(taskPrompt, taskId = uuidv4(), contextParams) {
|
|
19087
19365
|
const agents = [...(this.config.agents || [])];
|
|
19088
|
-
|
|
19089
|
-
|
|
19366
|
+
const chain = new Chain(taskPrompt);
|
|
19367
|
+
const context = new Context(taskId, this.config, agents, chain);
|
|
19090
19368
|
if (contextParams) {
|
|
19091
19369
|
Object.keys(contextParams).forEach((key) => context.variables.set(key, contextParams[key]));
|
|
19092
19370
|
}
|
|
19093
19371
|
try {
|
|
19094
19372
|
this.taskMap.set(taskId, context);
|
|
19095
19373
|
if (this.config.a2aClient) {
|
|
19096
|
-
|
|
19374
|
+
const a2aList = await this.config.a2aClient.listAgents(taskPrompt);
|
|
19097
19375
|
context.agents = mergeAgents(context.agents, a2aList);
|
|
19098
19376
|
}
|
|
19099
|
-
|
|
19377
|
+
const planner = new Planner(context);
|
|
19100
19378
|
context.workflow = await planner.plan(taskPrompt);
|
|
19101
19379
|
return context.workflow;
|
|
19102
19380
|
}
|
|
@@ -19106,20 +19384,20 @@ class Eko {
|
|
|
19106
19384
|
}
|
|
19107
19385
|
}
|
|
19108
19386
|
async modify(taskId, modifyTaskPrompt) {
|
|
19109
|
-
|
|
19387
|
+
const context = this.taskMap.get(taskId);
|
|
19110
19388
|
if (!context) {
|
|
19111
19389
|
return await this.generate(modifyTaskPrompt, taskId);
|
|
19112
19390
|
}
|
|
19113
19391
|
if (this.config.a2aClient) {
|
|
19114
|
-
|
|
19392
|
+
const a2aList = await this.config.a2aClient.listAgents(modifyTaskPrompt);
|
|
19115
19393
|
context.agents = mergeAgents(context.agents, a2aList);
|
|
19116
19394
|
}
|
|
19117
|
-
|
|
19395
|
+
const planner = new Planner(context);
|
|
19118
19396
|
context.workflow = await planner.replan(modifyTaskPrompt);
|
|
19119
19397
|
return context.workflow;
|
|
19120
19398
|
}
|
|
19121
19399
|
async execute(taskId) {
|
|
19122
|
-
|
|
19400
|
+
const context = this.getTask(taskId);
|
|
19123
19401
|
if (!context) {
|
|
19124
19402
|
throw new Error("The task does not exist");
|
|
19125
19403
|
}
|
|
@@ -19149,10 +19427,10 @@ class Eko {
|
|
|
19149
19427
|
}
|
|
19150
19428
|
async initContext(workflow, contextParams) {
|
|
19151
19429
|
const agents = this.config.agents || [];
|
|
19152
|
-
|
|
19153
|
-
|
|
19430
|
+
const chain = new Chain(workflow.taskPrompt || workflow.name);
|
|
19431
|
+
const context = new Context(workflow.taskId, this.config, agents, chain);
|
|
19154
19432
|
if (this.config.a2aClient) {
|
|
19155
|
-
|
|
19433
|
+
const a2aList = await this.config.a2aClient.listAgents(workflow.taskPrompt || workflow.name);
|
|
19156
19434
|
context.agents = mergeAgents(context.agents, a2aList);
|
|
19157
19435
|
}
|
|
19158
19436
|
if (contextParams) {
|
|
@@ -19163,30 +19441,72 @@ class Eko {
|
|
|
19163
19441
|
return context;
|
|
19164
19442
|
}
|
|
19165
19443
|
async doRunWorkflow(context) {
|
|
19166
|
-
|
|
19167
|
-
|
|
19444
|
+
const agents = context.agents;
|
|
19445
|
+
const workflow = context.workflow;
|
|
19168
19446
|
if (!workflow || workflow.agents.length == 0) {
|
|
19169
19447
|
throw new Error("Workflow error");
|
|
19170
19448
|
}
|
|
19171
|
-
|
|
19449
|
+
const agentNameMap = agents.reduce((map, item) => {
|
|
19172
19450
|
map[item.Name] = item;
|
|
19173
19451
|
return map;
|
|
19174
19452
|
}, {});
|
|
19175
|
-
let
|
|
19176
|
-
|
|
19453
|
+
let agentTree = buildAgentTree(workflow.agents);
|
|
19454
|
+
const results = [];
|
|
19455
|
+
while (true) {
|
|
19177
19456
|
await context.checkAborted();
|
|
19178
|
-
|
|
19179
|
-
|
|
19180
|
-
|
|
19181
|
-
|
|
19182
|
-
|
|
19183
|
-
|
|
19184
|
-
|
|
19185
|
-
|
|
19186
|
-
|
|
19187
|
-
|
|
19457
|
+
if (agentTree.type === "normal") {
|
|
19458
|
+
// normal agent
|
|
19459
|
+
const agent = agentNameMap[agentTree.agent.name];
|
|
19460
|
+
if (!agent) {
|
|
19461
|
+
throw new Error("Unknown Agent: " + agentTree.agent.name);
|
|
19462
|
+
}
|
|
19463
|
+
const agentNode = agentTree.agent;
|
|
19464
|
+
const agentChain = new AgentChain(agentNode);
|
|
19465
|
+
context.chain.push(agentChain);
|
|
19466
|
+
agentTree.result = await agent.run(context, agentChain);
|
|
19467
|
+
results.push(agentTree.result);
|
|
19468
|
+
}
|
|
19469
|
+
else {
|
|
19470
|
+
// parallel agent
|
|
19471
|
+
const parallelAgents = agentTree.agents;
|
|
19472
|
+
const doRunAgent = async (agentNode, index) => {
|
|
19473
|
+
const agent = agentNameMap[agentNode.agent.name];
|
|
19474
|
+
if (!agent) {
|
|
19475
|
+
throw new Error("Unknown Agent: " + agentNode.agent.name);
|
|
19476
|
+
}
|
|
19477
|
+
const agentChain = new AgentChain(agentNode.agent);
|
|
19478
|
+
agentNode.result = await agent.run(context, agentChain);
|
|
19479
|
+
return { result: agentNode.result, agentChain, index };
|
|
19480
|
+
};
|
|
19481
|
+
let agent_results = [];
|
|
19482
|
+
let agentParallel = context.variables.get("agentParallel");
|
|
19483
|
+
if (agentParallel === undefined) {
|
|
19484
|
+
agentParallel = config.agentParallel;
|
|
19485
|
+
}
|
|
19486
|
+
if (agentParallel) {
|
|
19487
|
+
// parallel execution
|
|
19488
|
+
const parallelResults = await Promise.all(parallelAgents.map((agent, index) => doRunAgent(agent, index)));
|
|
19489
|
+
parallelResults.sort((a, b) => a.index - b.index);
|
|
19490
|
+
parallelResults.forEach(({ agentChain }) => {
|
|
19491
|
+
context.chain.push(agentChain);
|
|
19492
|
+
});
|
|
19493
|
+
agent_results = parallelResults.map(({ result }) => result);
|
|
19494
|
+
}
|
|
19495
|
+
else {
|
|
19496
|
+
// serial execution
|
|
19497
|
+
for (let i = 0; i < parallelAgents.length; i++) {
|
|
19498
|
+
const { result, agentChain } = await doRunAgent(parallelAgents[i], i);
|
|
19499
|
+
context.chain.push(agentChain);
|
|
19500
|
+
agent_results.push(result);
|
|
19501
|
+
}
|
|
19502
|
+
}
|
|
19503
|
+
results.push(agent_results.join("\n\n"));
|
|
19504
|
+
}
|
|
19505
|
+
context.conversation.splice(0, context.conversation.length);
|
|
19506
|
+
if (!agentTree.nextAgent) {
|
|
19188
19507
|
break;
|
|
19189
19508
|
}
|
|
19509
|
+
agentTree = agentTree.nextAgent;
|
|
19190
19510
|
}
|
|
19191
19511
|
return {
|
|
19192
19512
|
success: true,
|
|
@@ -19222,7 +19542,7 @@ class Eko {
|
|
|
19222
19542
|
}
|
|
19223
19543
|
}
|
|
19224
19544
|
pauseTask(taskId, pause, abortCurrentStep, reason) {
|
|
19225
|
-
|
|
19545
|
+
const context = this.taskMap.get(taskId);
|
|
19226
19546
|
if (context) {
|
|
19227
19547
|
this.onTaskStatus(context, pause ? "pause" : "resume-pause", reason);
|
|
19228
19548
|
context.setPause(pause, abortCurrentStep);
|
|
@@ -19233,7 +19553,7 @@ class Eko {
|
|
|
19233
19553
|
}
|
|
19234
19554
|
}
|
|
19235
19555
|
chatTask(taskId, userPrompt) {
|
|
19236
|
-
|
|
19556
|
+
const context = this.taskMap.get(taskId);
|
|
19237
19557
|
if (context) {
|
|
19238
19558
|
context.conversation.push(userPrompt);
|
|
19239
19559
|
return context.conversation;
|
|
@@ -19476,7 +19796,7 @@ function parseChunk(chunk) {
|
|
|
19476
19796
|
return chunk_obj;
|
|
19477
19797
|
}
|
|
19478
19798
|
|
|
19479
|
-
const AGENT_NAME$
|
|
19799
|
+
const AGENT_NAME$3 = "File";
|
|
19480
19800
|
class BaseFileAgent extends Agent {
|
|
19481
19801
|
constructor(work_path, llms, ext_tools, mcpClient, planDescription) {
|
|
19482
19802
|
const _tools_ = [];
|
|
@@ -19484,7 +19804,7 @@ class BaseFileAgent extends Agent {
|
|
|
19484
19804
|
? `Your default working path is: ${work_path}`
|
|
19485
19805
|
: "";
|
|
19486
19806
|
super({
|
|
19487
|
-
name: AGENT_NAME$
|
|
19807
|
+
name: AGENT_NAME$3,
|
|
19488
19808
|
description: `You are a file agent, handling file-related tasks such as creating, finding, reading, modifying files, etc.${prompt}`,
|
|
19489
19809
|
tools: _tools_,
|
|
19490
19810
|
llms: llms,
|
|
@@ -19636,7 +19956,7 @@ class BaseFileAgent extends Agent {
|
|
|
19636
19956
|
},
|
|
19637
19957
|
glob: {
|
|
19638
19958
|
type: "string",
|
|
19639
|
-
description: "Filename pattern using glob syntax wildcards",
|
|
19959
|
+
description: "Filename pattern using glob syntax wildcards, Example: **/*.txt",
|
|
19640
19960
|
},
|
|
19641
19961
|
},
|
|
19642
19962
|
required: ["path", "glob"],
|
|
@@ -19649,12 +19969,12 @@ class BaseFileAgent extends Agent {
|
|
|
19649
19969
|
}
|
|
19650
19970
|
}
|
|
19651
19971
|
|
|
19652
|
-
const AGENT_NAME$
|
|
19972
|
+
const AGENT_NAME$2 = "Shell";
|
|
19653
19973
|
class BaseShellAgent extends Agent {
|
|
19654
19974
|
constructor(llms, ext_tools, mcpClient, planDescription) {
|
|
19655
19975
|
const _tools_ = [];
|
|
19656
19976
|
super({
|
|
19657
|
-
name: AGENT_NAME$
|
|
19977
|
+
name: AGENT_NAME$2,
|
|
19658
19978
|
description: `Run commands in a bash shell,
|
|
19659
19979
|
* You must first call create_session to create a new session when using it for the first time.
|
|
19660
19980
|
* Please execute delete commands with caution, and never perform dangerous operations like \`rm -rf /\`.
|
|
@@ -19731,47 +20051,6 @@ class BaseShellAgent extends Agent {
|
|
|
19731
20051
|
}
|
|
19732
20052
|
}
|
|
19733
20053
|
|
|
19734
|
-
const AGENT_NAME$2 = "Timer";
|
|
19735
|
-
class BaseTimerAgent extends Agent {
|
|
19736
|
-
constructor(llms, ext_tools, mcpClient) {
|
|
19737
|
-
super({
|
|
19738
|
-
name: AGENT_NAME$2,
|
|
19739
|
-
description: "You are a scheduled task scheduling agent.",
|
|
19740
|
-
tools: ext_tools || [],
|
|
19741
|
-
llms: llms,
|
|
19742
|
-
mcpClient: mcpClient,
|
|
19743
|
-
});
|
|
19744
|
-
this.addTool(this.schedule_tool());
|
|
19745
|
-
}
|
|
19746
|
-
schedule_tool() {
|
|
19747
|
-
return {
|
|
19748
|
-
name: "task_schedule",
|
|
19749
|
-
description: "Task scheduled trigger, the task is triggered at a scheduled time and will automatically create a scheduled task for execution.",
|
|
19750
|
-
parameters: {
|
|
19751
|
-
type: "object",
|
|
19752
|
-
properties: {
|
|
19753
|
-
trigger_description: {
|
|
19754
|
-
type: "string",
|
|
19755
|
-
description: "Trigger time description.",
|
|
19756
|
-
},
|
|
19757
|
-
task_description: {
|
|
19758
|
-
type: "string",
|
|
19759
|
-
description: "Main task description, excluding trigger time.",
|
|
19760
|
-
},
|
|
19761
|
-
cron: {
|
|
19762
|
-
type: "string",
|
|
19763
|
-
description: "The cron expression of the trigger, for example, '0 9 * * *' indicates that it triggers at 9 a.m. every day.",
|
|
19764
|
-
},
|
|
19765
|
-
},
|
|
19766
|
-
required: ["cron"],
|
|
19767
|
-
},
|
|
19768
|
-
execute: async (args, agentContext) => {
|
|
19769
|
-
return await this.callInnerTool(() => this.task_schedule(agentContext, args.trigger_description, args.task_description, args.cron));
|
|
19770
|
-
},
|
|
19771
|
-
};
|
|
19772
|
-
}
|
|
19773
|
-
}
|
|
19774
|
-
|
|
19775
20054
|
const AGENT_NAME$1 = "Computer";
|
|
19776
20055
|
class BaseComputerAgent extends Agent {
|
|
19777
20056
|
constructor(llms, ext_tools, mcpClient, keyboardKeys) {
|
|
@@ -21968,7 +22247,6 @@ exports.BaseChatAgent = BaseChatAgent;
|
|
|
21968
22247
|
exports.BaseComputerAgent = BaseComputerAgent;
|
|
21969
22248
|
exports.BaseFileAgent = BaseFileAgent;
|
|
21970
22249
|
exports.BaseShellAgent = BaseShellAgent;
|
|
21971
|
-
exports.BaseTimerAgent = BaseTimerAgent;
|
|
21972
22250
|
exports.Chain = Chain;
|
|
21973
22251
|
exports.Context = Context;
|
|
21974
22252
|
exports.Eko = Eko;
|
|
@@ -21981,6 +22259,7 @@ exports.SimpleSseMcpClient = SimpleSseMcpClient;
|
|
|
21981
22259
|
exports.TaskNodeStatusTool = TaskNodeStatusTool;
|
|
21982
22260
|
exports.VariableStorageTool = VariableStorageTool;
|
|
21983
22261
|
exports.WatchTriggerTool = WatchTriggerTool;
|
|
22262
|
+
exports.buildAgentTree = buildAgentTree;
|
|
21984
22263
|
exports.buildSimpleAgentWorkflow = buildSimpleAgentWorkflow;
|
|
21985
22264
|
exports.call_timeout = call_timeout;
|
|
21986
22265
|
exports.config = config;
|