@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/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] = this.llms[name].options || {};
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(options));
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 = this.llms[name];
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: options.mode?.tools,
14220
- messages: options.prompt,
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] = this.llms[name].options || {};
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 = options.abortSignal
14266
- ? AbortSignal.any([options.abortSignal, controller.signal])
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({ ...options, abortSignal: signal }), this.stream_first_timeout, (e) => {
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 = this.llms[name];
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: options.mode?.tools,
14305
- messages: options.prompt,
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 + "-" + (i < 10 ? "0" + i : i),
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, retry, callback) {
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 > 10 &&
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 (!retry) {
17217
- await sleep(200);
17218
- return callAgentLLM(agentContext, rlm, messages, tools, noCompress, toolChoice, true, streamCallback);
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 >= 10 &&
17427
+ messages.length >= 5 &&
17398
17428
  !noCompress &&
17399
- !retry) {
17429
+ retryNum < config.maxRetryNum) {
17400
17430
  await compressAgentMessages(agentContext, rlm, messages, tools);
17401
- return callAgentLLM(agentContext, rlm, messages, tools, noCompress, toolChoice, true, streamCallback);
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 (!retry) {
17411
- return callAgentLLM(agentContext, rlm, messages, tools, noCompress, toolChoice, true, streamCallback);
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. Please replan and execute according to the following instructions:\n" + userPrompts.map(s => `- ${s.trim()}`).join("\n");
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 < 10) {
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" && _content.text?.length > config.largeTextLength) {
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, false, this.callback);
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$5 = "Chat";
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$5,
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
- <!-- The required Agent, where the name can only be an available name in the Agent list -->
18763
- <agent name="Agent name">
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$5).length > 0;
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, taskId) {
19074
+ constructor(context, callback) {
18955
19075
  this.context = context;
18956
- this.taskId = taskId || context.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 (config.callback) {
19157
+ if (this.callback) {
19037
19158
  let workflow = parseWorkflow(this.taskId, streamText, false, thinkingText);
19038
19159
  if (workflow) {
19039
- await config.callback.onMessage({
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 (config.callback) {
19063
- await config.callback.onMessage({
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
- let chain = new Chain(taskPrompt);
19089
- let context = new Context(taskId, this.config, agents, chain);
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
- let a2aList = await this.config.a2aClient.listAgents(taskPrompt);
19374
+ const a2aList = await this.config.a2aClient.listAgents(taskPrompt);
19097
19375
  context.agents = mergeAgents(context.agents, a2aList);
19098
19376
  }
19099
- let planner = new Planner(context, taskId);
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
- let context = this.taskMap.get(taskId);
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
- let a2aList = await this.config.a2aClient.listAgents(modifyTaskPrompt);
19392
+ const a2aList = await this.config.a2aClient.listAgents(modifyTaskPrompt);
19115
19393
  context.agents = mergeAgents(context.agents, a2aList);
19116
19394
  }
19117
- let planner = new Planner(context, taskId);
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
- let context = this.getTask(taskId);
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
- let chain = new Chain(workflow.taskPrompt || workflow.name);
19153
- let context = new Context(workflow.taskId, this.config, agents, chain);
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
- let a2aList = await this.config.a2aClient.listAgents(workflow.taskPrompt || workflow.name);
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
- let agents = context.agents;
19167
- let workflow = context.workflow;
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
- let agentMap = agents.reduce((map, item) => {
19449
+ const agentNameMap = agents.reduce((map, item) => {
19172
19450
  map[item.Name] = item;
19173
19451
  return map;
19174
19452
  }, {});
19175
- let results = [];
19176
- for (let i = 0; i < workflow.agents.length; i++) {
19453
+ let agentTree = buildAgentTree(workflow.agents);
19454
+ const results = [];
19455
+ while (true) {
19177
19456
  await context.checkAborted();
19178
- let agentNode = workflow.agents[i];
19179
- let agent = agentMap[agentNode.name];
19180
- if (!agent) {
19181
- throw new Error("Unknown Agent: " + agentNode.name);
19182
- }
19183
- let agentChain = new AgentChain(agentNode);
19184
- context.chain.push(agentChain);
19185
- agent.result = await agent.run(context, agentChain);
19186
- results.push(agent.result);
19187
- if (agentNode.name === "Timer") {
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
- let context = this.taskMap.get(taskId);
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
- let context = this.taskMap.get(taskId);
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$4 = "File";
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$4,
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$3 = "Shell";
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$3,
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;