@eko-ai/eko 2.1.7 → 2.1.8-alpha.2

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
@@ -363,8 +363,10 @@ function fixXmlTag(code) {
363
363
  const top = stack.pop();
364
364
  if (top.startsWith("<")) {
365
365
  let arr = top.match(/<(\w+)/);
366
- const tagName = arr[1];
367
- missingParts.push(`</${tagName}>`);
366
+ if (arr) {
367
+ const tagName = arr[1];
368
+ missingParts.push(`</${tagName}>`);
369
+ }
368
370
  }
369
371
  else {
370
372
  missingParts.push(top);
@@ -376,8 +378,9 @@ function fixXmlTag(code) {
376
378
 
377
379
  class Context {
378
380
  constructor(taskId, config, agents, chain) {
379
- this.paused = false;
380
381
  this.conversation = [];
382
+ this.pauseStatus = 0;
383
+ this.currentStepControllers = new Set();
381
384
  this.taskId = taskId;
382
385
  this.config = config;
383
386
  this.agents = agents;
@@ -385,15 +388,20 @@ class Context {
385
388
  this.variables = new Map();
386
389
  this.controller = new AbortController();
387
390
  }
388
- async checkAborted() {
389
- // this.controller.signal.throwIfAborted();
391
+ async checkAborted(noCheckPause) {
390
392
  if (this.controller.signal.aborted) {
391
393
  const error = new Error("Operation was interrupted");
392
394
  error.name = "AbortError";
393
395
  throw error;
394
396
  }
395
- while (this.paused) {
397
+ while (this.pauseStatus > 0 && !noCheckPause) {
396
398
  await sleep(500);
399
+ if (this.pauseStatus == 2) {
400
+ this.currentStepControllers.forEach((c) => {
401
+ c.abort("Pause");
402
+ });
403
+ this.currentStepControllers.clear();
404
+ }
397
405
  if (this.controller.signal.aborted) {
398
406
  const error = new Error("Operation was interrupted");
399
407
  error.name = "AbortError";
@@ -410,9 +418,21 @@ class Context {
410
418
  if (!agent) {
411
419
  return null;
412
420
  }
413
- const agentContext = agent["agentContext"];
421
+ const agentContext = agent.AgentContext;
414
422
  return [agent, agentNode.agent, agentContext];
415
423
  }
424
+ get pause() {
425
+ return this.pauseStatus > 0;
426
+ }
427
+ setPause(pause, abortCurrentStep) {
428
+ this.pauseStatus = pause ? (abortCurrentStep ? 2 : 1) : 0;
429
+ if (this.pauseStatus == 2) {
430
+ this.currentStepControllers.forEach((c) => {
431
+ c.abort("Pause");
432
+ });
433
+ this.currentStepControllers.clear();
434
+ }
435
+ }
416
436
  }
417
437
  class AgentContext {
418
438
  constructor(context, agent, agentChain) {
@@ -14137,10 +14157,11 @@ createOpenRouter({
14137
14157
  });
14138
14158
 
14139
14159
  class RetryLanguageModel {
14140
- constructor(llms, names, stream_first_timeout) {
14160
+ constructor(llms, names, stream_first_timeout, stream_token_timeout) {
14141
14161
  this.llms = llms;
14142
14162
  this.names = names || [];
14143
14163
  this.stream_first_timeout = stream_first_timeout || 30000;
14164
+ this.stream_token_timeout = stream_token_timeout || 180000;
14144
14165
  if (this.names.indexOf("default") == -1) {
14145
14166
  this.names.push("default");
14146
14167
  }
@@ -14165,41 +14186,49 @@ class RetryLanguageModel {
14165
14186
  const maxTokens = options.maxTokens;
14166
14187
  const providerMetadata = options.providerMetadata;
14167
14188
  const names = [...this.names, ...this.names];
14189
+ let lastError;
14168
14190
  for (let i = 0; i < names.length; i++) {
14169
14191
  const name = names[i];
14192
+ const llmConfig = this.llms[name];
14170
14193
  const llm = await this.getLLM(name);
14171
14194
  if (!llm) {
14172
14195
  continue;
14173
14196
  }
14174
14197
  if (!maxTokens) {
14175
- options.maxTokens =
14176
- this.llms[name].config?.maxTokens || config.maxTokens;
14198
+ options.maxTokens = llmConfig.config?.maxTokens || config.maxTokens;
14177
14199
  }
14178
14200
  if (!providerMetadata) {
14179
14201
  options.providerMetadata = {};
14180
- options.providerMetadata[llm.provider] = this.llms[name].options || {};
14202
+ options.providerMetadata[llm.provider] = llmConfig.options || {};
14203
+ }
14204
+ let _options = options;
14205
+ if (llmConfig.handler) {
14206
+ _options = await llmConfig.handler(_options);
14181
14207
  }
14182
14208
  try {
14183
- let result = await llm.doGenerate(options);
14209
+ let result = (await llm.doGenerate(_options));
14184
14210
  if (Log.isEnableDebug()) {
14185
14211
  Log.debug(`LLM nonstream body, name: ${name} => `, result.request?.body);
14186
14212
  }
14213
+ result.llm = name;
14214
+ result.llmConfig = llmConfig;
14187
14215
  return result;
14188
14216
  }
14189
14217
  catch (e) {
14190
14218
  if (e?.name === "AbortError") {
14191
14219
  throw e;
14192
14220
  }
14221
+ lastError = e;
14193
14222
  if (Log.isEnableInfo()) {
14194
14223
  Log.info(`LLM nonstream request, name: ${name} => `, {
14195
- tools: options.mode?.tools,
14196
- messages: options.prompt,
14224
+ tools: _options.mode?.tools,
14225
+ messages: _options.prompt,
14197
14226
  });
14198
14227
  }
14199
14228
  Log.error(`LLM error, name: ${name} => `, e);
14200
14229
  }
14201
14230
  }
14202
- return Promise.reject(new Error("No LLM available"));
14231
+ return Promise.reject(lastError ? lastError : new Error("No LLM available"));
14203
14232
  }
14204
14233
  async callStream(request) {
14205
14234
  return await this.doStream({
@@ -14221,28 +14250,33 @@ class RetryLanguageModel {
14221
14250
  const maxTokens = options.maxTokens;
14222
14251
  const providerMetadata = options.providerMetadata;
14223
14252
  const names = [...this.names, ...this.names];
14253
+ let lastError;
14224
14254
  for (let i = 0; i < names.length; i++) {
14225
14255
  const name = names[i];
14256
+ const llmConfig = this.llms[name];
14226
14257
  const llm = await this.getLLM(name);
14227
14258
  if (!llm) {
14228
14259
  continue;
14229
14260
  }
14230
14261
  if (!maxTokens) {
14231
- options.maxTokens =
14232
- this.llms[name].config?.maxTokens || config.maxTokens;
14262
+ options.maxTokens = llmConfig.config?.maxTokens || config.maxTokens;
14233
14263
  }
14234
14264
  if (!providerMetadata) {
14235
14265
  options.providerMetadata = {};
14236
- options.providerMetadata[llm.provider] = this.llms[name].options || {};
14266
+ options.providerMetadata[llm.provider] = llmConfig.options || {};
14267
+ }
14268
+ let _options = options;
14269
+ if (llmConfig.handler) {
14270
+ _options = await llmConfig.handler(_options);
14237
14271
  }
14238
14272
  try {
14239
14273
  const controller = new AbortController();
14240
- const signal = options.abortSignal
14241
- ? AbortSignal.any([options.abortSignal, controller.signal])
14274
+ const signal = _options.abortSignal
14275
+ ? AbortSignal.any([_options.abortSignal, controller.signal])
14242
14276
  : controller.signal;
14243
- const result = await call_timeout(async () => await llm.doStream({ ...options, abortSignal: signal }), this.stream_first_timeout, (e) => {
14277
+ const result = (await call_timeout(async () => await llm.doStream({ ..._options, abortSignal: signal }), this.stream_first_timeout, (e) => {
14244
14278
  controller.abort();
14245
- });
14279
+ }));
14246
14280
  const stream = result.stream;
14247
14281
  const reader = stream.getReader();
14248
14282
  const { done, value } = await call_timeout(async () => await reader.read(), this.stream_first_timeout, (e) => {
@@ -14264,23 +14298,26 @@ class RetryLanguageModel {
14264
14298
  reader.releaseLock();
14265
14299
  continue;
14266
14300
  }
14267
- result.stream = this.streamWrapper([chunk], reader);
14301
+ result.llm = name;
14302
+ result.llmConfig = llmConfig;
14303
+ result.stream = this.streamWrapper([chunk], reader, controller);
14268
14304
  return result;
14269
14305
  }
14270
14306
  catch (e) {
14271
14307
  if (e?.name === "AbortError") {
14272
14308
  throw e;
14273
14309
  }
14310
+ lastError = e;
14274
14311
  if (Log.isEnableInfo()) {
14275
14312
  Log.info(`LLM stream request, name: ${name} => `, {
14276
- tools: options.mode?.tools,
14277
- messages: options.prompt,
14313
+ tools: _options.mode?.tools,
14314
+ messages: _options.prompt,
14278
14315
  });
14279
14316
  }
14280
14317
  Log.error(`LLM error, name: ${name} => `, e);
14281
14318
  }
14282
14319
  }
14283
- return Promise.reject(new Error("No LLM available"));
14320
+ return Promise.reject(lastError ? lastError : new Error("No LLM available"));
14284
14321
  }
14285
14322
  async getLLM(name) {
14286
14323
  const llm = this.llms[name];
@@ -14355,7 +14392,8 @@ class RetryLanguageModel {
14355
14392
  return llm.provider.languageModel(llm.model);
14356
14393
  }
14357
14394
  }
14358
- streamWrapper(parts, reader) {
14395
+ streamWrapper(parts, reader, abortController) {
14396
+ let timer = null;
14359
14397
  return new ReadableStream({
14360
14398
  start: (controller) => {
14361
14399
  if (parts != null && parts.length > 0) {
@@ -14365,7 +14403,11 @@ class RetryLanguageModel {
14365
14403
  }
14366
14404
  },
14367
14405
  pull: async (controller) => {
14406
+ timer = setTimeout(() => {
14407
+ abortController.abort("Streaming request timeout");
14408
+ }, this.stream_token_timeout);
14368
14409
  const { done, value } = await reader.read();
14410
+ clearTimeout(timer);
14369
14411
  if (done) {
14370
14412
  controller.close();
14371
14413
  reader.releaseLock();
@@ -14374,10 +14416,17 @@ class RetryLanguageModel {
14374
14416
  controller.enqueue(value);
14375
14417
  },
14376
14418
  cancel: (reason) => {
14419
+ timer && clearTimeout(timer);
14377
14420
  reader.cancel(reason);
14378
14421
  },
14379
14422
  });
14380
14423
  }
14424
+ get Llms() {
14425
+ return this.llms;
14426
+ }
14427
+ get Names() {
14428
+ return this.names;
14429
+ }
14381
14430
  }
14382
14431
 
14383
14432
  var domParser = {};
@@ -16825,11 +16874,21 @@ function requireDomParser () {
16825
16874
 
16826
16875
  var domParserExports = requireDomParser();
16827
16876
 
16828
- function parseWorkflow(taskId, xml, done) {
16877
+ function parseWorkflow(taskId, xml, done, thinking) {
16878
+ let _workflow = null;
16829
16879
  try {
16880
+ if (thinking) {
16881
+ _workflow = {
16882
+ taskId: taskId,
16883
+ name: "",
16884
+ thought: thinking,
16885
+ agents: [],
16886
+ xml: xml,
16887
+ };
16888
+ }
16830
16889
  let sIdx = xml.indexOf("<root>");
16831
16890
  if (sIdx == -1) {
16832
- return null;
16891
+ return _workflow;
16833
16892
  }
16834
16893
  xml = xml.substring(sIdx);
16835
16894
  let eIdx = xml.indexOf("</root>");
@@ -16843,13 +16902,14 @@ function parseWorkflow(taskId, xml, done) {
16843
16902
  const doc = parser.parseFromString(xml, "text/xml");
16844
16903
  let root = doc.documentElement;
16845
16904
  if (root.tagName !== "root") {
16846
- return null;
16905
+ return _workflow;
16847
16906
  }
16848
- let agents = [];
16907
+ const agents = [];
16908
+ const thought = root.getElementsByTagName("thought")[0]?.textContent || "";
16849
16909
  const workflow = {
16850
16910
  taskId: taskId,
16851
16911
  name: root.getElementsByTagName("name")[0]?.textContent || "",
16852
- thought: root.getElementsByTagName("thought")[0]?.textContent || "",
16912
+ thought: thinking ? thinking + "\n" + thought : thought,
16853
16913
  agents: agents,
16854
16914
  xml: xml,
16855
16915
  };
@@ -16882,7 +16942,7 @@ function parseWorkflow(taskId, xml, done) {
16882
16942
  throw e;
16883
16943
  }
16884
16944
  else {
16885
- return null;
16945
+ return _workflow;
16886
16946
  }
16887
16947
  }
16888
16948
  }
@@ -16960,7 +17020,7 @@ function buildAgentRootXml(agentXml, mainTaskPrompt, nodeCallback) {
16960
17020
  .replace("<task>", "<currentTask>")
16961
17021
  .replace("</task>", "</currentTask>");
16962
17022
  const xmlPrompt = `<root>${prefix}<mainTask>${mainTaskPrompt}</mainTask>${agentInnerHTML}</root>`;
16963
- return xmlPrompt.replace(/ /g, " ").replace(' </root>', '</root>');
17023
+ return xmlPrompt.replace(/ /g, " ").replace(" </root>", "</root>");
16964
17024
  }
16965
17025
  function extractAgentXmlNode(agentXml, nodeId) {
16966
17026
  const parser = new domParserExports.DOMParser();
@@ -16992,6 +17052,92 @@ function getInnerXML(node) {
16992
17052
  }
16993
17053
  return result;
16994
17054
  }
17055
+ function buildSimpleAgentWorkflow({ taskId, name, agentName, task, taskNodes, }) {
17056
+ if (!taskNodes || taskNodes.length == 0) {
17057
+ taskNodes = [task];
17058
+ }
17059
+ const workflow = {
17060
+ taskId: taskId,
17061
+ name: name,
17062
+ thought: "",
17063
+ agents: [
17064
+ {
17065
+ id: taskId + "-00",
17066
+ name: agentName,
17067
+ task: task,
17068
+ nodes: taskNodes.map((node) => {
17069
+ return {
17070
+ type: "normal",
17071
+ text: node,
17072
+ };
17073
+ }),
17074
+ xml: "",
17075
+ },
17076
+ ],
17077
+ xml: "",
17078
+ };
17079
+ workflow.taskPrompt = task;
17080
+ resetWorkflowXml(workflow);
17081
+ return workflow;
17082
+ }
17083
+ function resetWorkflowXml(workflow) {
17084
+ const agents = [];
17085
+ for (let i = 0; i < workflow.agents.length; i++) {
17086
+ const agent = workflow.agents[i];
17087
+ const nodes = agent.nodes
17088
+ .map((node) => {
17089
+ if (node.type == "forEach") {
17090
+ const forEachNodes = [];
17091
+ for (let j = 0; j < node.nodes.length; j++) {
17092
+ const _node = node.nodes[j];
17093
+ const input = _node.input ? ` input="${_node.input}"` : "";
17094
+ const output = _node.output ? ` output="${_node.output}"` : "";
17095
+ forEachNodes.push(` <node${input}${output}>${_node.text}</node>`);
17096
+ }
17097
+ return ` <forEach items="${node.items || ""}">
17098
+ ${forEachNodes.join("\n")}
17099
+ </forEach>`;
17100
+ }
17101
+ else if (node.type == "watch") {
17102
+ const watchNodes = [];
17103
+ for (let j = 0; j < node.triggerNodes.length; j++) {
17104
+ const _node = node.triggerNodes[j];
17105
+ const input = _node.input ? ` input="${_node.input}"` : "";
17106
+ const output = _node.output ? ` output="${_node.output}"` : "";
17107
+ watchNodes.push(` <node${input}${output}>${_node.text}</node>`);
17108
+ }
17109
+ return ` <watch event="${node.event || "dom"}" loop="${node.loop ? "true" : "false"}">
17110
+ <description>${node.description}</description>
17111
+ <trigger>
17112
+ ${watchNodes.join("\n")}
17113
+ </trigger>
17114
+ </watch>`;
17115
+ }
17116
+ else {
17117
+ const input = node.input ? ` input="${node.input}"` : "";
17118
+ const output = node.output ? ` output="${node.output}"` : "";
17119
+ return ` <node${input}${output}>${node.text}</node>`;
17120
+ }
17121
+ })
17122
+ .join("\n");
17123
+ const agentXml = ` <agent name="${agent.name}">
17124
+ <task>${agent.task}</task>
17125
+ <nodes>
17126
+ ${nodes}
17127
+ </nodes>
17128
+ </agent>`;
17129
+ agent.xml = agentXml;
17130
+ agents.push(agentXml);
17131
+ }
17132
+ const xml = `<root>
17133
+ <name>${workflow.name}</name>
17134
+ <thought>${workflow.thought}</thought>
17135
+ <agents>
17136
+ ${agents.join("\n")}
17137
+ </agents>
17138
+ </root>`;
17139
+ workflow.xml = xml;
17140
+ }
16995
17141
 
16996
17142
  const TOOL_NAME$5 = "task_snapshot";
16997
17143
  class TaskSnapshotTool {
@@ -17041,158 +17187,424 @@ class TaskSnapshotTool {
17041
17187
  }
17042
17188
  }
17043
17189
 
17044
- function extractUsedTool(messages, agentTools) {
17045
- let tools = [];
17046
- let toolNames = [];
17047
- for (let i = 0; i < messages.length; i++) {
17048
- let message = messages[i];
17049
- if (message.role == "tool") {
17050
- for (let j = 0; j < message.content.length; j++) {
17051
- let toolName = message.content[j].toolName;
17052
- if (toolNames.indexOf(toolName) > -1) {
17053
- continue;
17054
- }
17055
- toolNames.push(toolName);
17056
- let tool = agentTools.filter((tool) => tool.name === toolName)[0];
17057
- if (tool) {
17058
- tools.push(tool);
17059
- }
17060
- }
17061
- }
17062
- }
17063
- return tools;
17064
- }
17065
- function removeDuplicateToolUse(results) {
17066
- if (results.length <= 1 ||
17067
- results.filter((r) => r.type == "tool-call").length <= 1) {
17068
- return results;
17069
- }
17070
- let _results = [];
17071
- let tool_uniques = [];
17072
- for (let i = 0; i < results.length; i++) {
17073
- if (results[i].type === "tool-call") {
17074
- let tool = results[i];
17075
- let key = tool.toolName + tool.args;
17076
- if (tool_uniques.indexOf(key) == -1) {
17077
- _results.push(results[i]);
17078
- tool_uniques.push(key);
17079
- }
17080
- }
17081
- else {
17082
- _results.push(results[i]);
17083
- }
17190
+ async function callAgentLLM(agentContext, rlm, messages, tools, noCompress, toolChoice, retry, callback) {
17191
+ await agentContext.context.checkAborted();
17192
+ if (messages.length >= config.compressThreshold && !noCompress) {
17193
+ await compressAgentMessages(agentContext, rlm, messages, tools);
17084
17194
  }
17085
- return _results;
17086
- }
17087
- async function compressAgentMessages(agentContext, rlm, messages, tools) {
17088
- if (messages.length < 10) {
17089
- return;
17195
+ if (!toolChoice) {
17196
+ // Append user dialogue
17197
+ appendUserConversation(agentContext, messages);
17090
17198
  }
17091
- // extract used tool
17092
- let usedTools = extractUsedTool(messages, tools);
17093
- let snapshotTool = new TaskSnapshotTool();
17094
- let newTools = mergeTools(usedTools, [
17095
- {
17096
- type: "function",
17097
- name: snapshotTool.name,
17098
- description: snapshotTool.description,
17099
- parameters: snapshotTool.parameters,
17100
- },
17199
+ let context = agentContext.context;
17200
+ let agentChain = agentContext.agentChain;
17201
+ let agentNode = agentChain.agent;
17202
+ let streamCallback = callback ||
17203
+ context.config.callback || {
17204
+ onMessage: async () => { },
17205
+ };
17206
+ const stepController = new AbortController();
17207
+ const signal = AbortSignal.any([
17208
+ context.controller.signal,
17209
+ stepController.signal,
17101
17210
  ]);
17102
- // handle messages
17103
- let lastToolIndex = messages.length - 1;
17104
- let newMessages = messages;
17105
- for (let r = newMessages.length - 1; r > 3; r--) {
17106
- if (newMessages[r].role == "tool") {
17107
- newMessages = newMessages.slice(0, r + 1);
17108
- lastToolIndex = r;
17109
- break;
17110
- }
17111
- }
17112
- newMessages.push({
17113
- role: "user",
17114
- content: [
17115
- {
17116
- type: "text",
17117
- text: "Please create a snapshot backup of the current task, keeping only key important information and node completion status.",
17118
- },
17119
- ],
17120
- });
17121
- // compress snapshot
17122
- let result = await callLLM(agentContext, rlm, newMessages, newTools, true, {
17123
- type: "tool",
17124
- toolName: snapshotTool.name,
17125
- });
17126
- let toolCall = result.filter((s) => s.type == "tool-call")[0];
17127
- let args = typeof toolCall.args == "string"
17128
- ? JSON.parse(toolCall.args || "{}")
17129
- : toolCall.args || {};
17130
- let toolResult = await snapshotTool.execute(args, agentContext);
17131
- let callback = agentContext.context.config.callback;
17132
- if (callback) {
17133
- await callback.onMessage({
17134
- taskId: agentContext.context.taskId,
17135
- agentName: agentContext.agent.Name,
17136
- nodeId: agentContext.agentChain.agent.id,
17137
- type: "tool_result",
17138
- toolId: toolCall.toolCallId,
17139
- toolName: toolCall.toolName,
17140
- params: args,
17141
- toolResult: toolResult,
17142
- }, agentContext);
17211
+ let request = {
17212
+ tools: tools,
17213
+ toolChoice,
17214
+ messages: messages,
17215
+ abortSignal: signal,
17216
+ };
17217
+ agentChain.agentRequest = request;
17218
+ let result;
17219
+ try {
17220
+ context.currentStepControllers.add(stepController);
17221
+ result = await rlm.callStream(request);
17143
17222
  }
17144
- // handle original messages
17145
- let firstToolIndex = 3;
17146
- for (let i = 0; i < messages.length; i++) {
17147
- if (messages[0].role == "tool") {
17148
- firstToolIndex = i;
17149
- break;
17223
+ catch (e) {
17224
+ context.currentStepControllers.delete(stepController);
17225
+ await context.checkAborted();
17226
+ if (!noCompress &&
17227
+ messages.length > 10 &&
17228
+ ((e + "").indexOf("tokens") > -1 || (e + "").indexOf("too long") > -1)) {
17229
+ await compressAgentMessages(agentContext, rlm, messages, tools);
17230
+ }
17231
+ if (!retry) {
17232
+ await sleep(200);
17233
+ return callAgentLLM(agentContext, rlm, messages, tools, noCompress, toolChoice, true, streamCallback);
17150
17234
  }
17235
+ throw e;
17151
17236
  }
17152
- // system, user, assistant, tool(first), [...], <user>, assistant, tool(last), ...
17153
- messages.splice(firstToolIndex + 1, lastToolIndex - firstToolIndex - 2, {
17154
- role: "user",
17155
- content: toolResult.content.filter((s) => s.type == "text"),
17156
- });
17157
- }
17158
- function handleLargeContextMessages(messages) {
17159
- let imageNum = 0;
17160
- let fileNum = 0;
17161
- let maxNum = config.maxDialogueImgFileNum;
17162
- let longTextTools = {};
17163
- for (let i = messages.length - 1; i >= 0; i--) {
17164
- let message = messages[i];
17165
- if (message.role == "user") {
17166
- for (let j = 0; j < message.content.length; j++) {
17167
- let content = message.content[j];
17168
- if (content.type == "image") {
17169
- if (++imageNum <= maxNum) {
17170
- break;
17237
+ let streamText = "";
17238
+ let thinkText = "";
17239
+ let toolArgsText = "";
17240
+ let streamId = uuidv4();
17241
+ let textStreamDone = false;
17242
+ let toolParts = [];
17243
+ const reader = result.stream.getReader();
17244
+ try {
17245
+ let toolPart = null;
17246
+ while (true) {
17247
+ await context.checkAborted();
17248
+ const { done, value } = await reader.read();
17249
+ if (done) {
17250
+ break;
17251
+ }
17252
+ let chunk = value;
17253
+ switch (chunk.type) {
17254
+ case "text-delta": {
17255
+ if (toolPart && !chunk.textDelta) {
17256
+ continue;
17171
17257
  }
17172
- content = {
17258
+ streamText += chunk.textDelta || "";
17259
+ await streamCallback.onMessage({
17260
+ taskId: context.taskId,
17261
+ agentName: agentNode.name,
17262
+ nodeId: agentNode.id,
17173
17263
  type: "text",
17174
- text: "[image]",
17175
- };
17176
- message.content[j] = content;
17177
- }
17178
- else if (content.type == "file") {
17179
- if (++fileNum <= maxNum) {
17180
- break;
17264
+ streamId,
17265
+ streamDone: false,
17266
+ text: streamText,
17267
+ }, agentContext);
17268
+ if (toolPart) {
17269
+ await streamCallback.onMessage({
17270
+ taskId: context.taskId,
17271
+ agentName: agentNode.name,
17272
+ nodeId: agentNode.id,
17273
+ type: "tool_use",
17274
+ toolId: toolPart.toolCallId,
17275
+ toolName: toolPart.toolName,
17276
+ params: toolPart.args || {},
17277
+ }, agentContext);
17278
+ toolPart = null;
17181
17279
  }
17182
- content = {
17183
- type: "text",
17184
- text: "[file]",
17185
- };
17186
- message.content[j] = content;
17280
+ break;
17187
17281
  }
17188
- }
17189
- }
17190
- else if (message.role == "tool") {
17191
- for (let j = 0; j < message.content.length; j++) {
17192
- let toolResult = message.content[j];
17193
- let toolContent = toolResult.content;
17194
- if (!toolContent || toolContent.length == 0) {
17195
- continue;
17282
+ case "reasoning": {
17283
+ thinkText += chunk.textDelta || "";
17284
+ await streamCallback.onMessage({
17285
+ taskId: context.taskId,
17286
+ agentName: agentNode.name,
17287
+ nodeId: agentNode.id,
17288
+ type: "thinking",
17289
+ streamId,
17290
+ streamDone: false,
17291
+ text: thinkText,
17292
+ }, agentContext);
17293
+ break;
17294
+ }
17295
+ case "tool-call-delta": {
17296
+ if (!textStreamDone) {
17297
+ textStreamDone = true;
17298
+ await streamCallback.onMessage({
17299
+ taskId: context.taskId,
17300
+ agentName: agentNode.name,
17301
+ nodeId: agentNode.id,
17302
+ type: "text",
17303
+ streamId,
17304
+ streamDone: true,
17305
+ text: streamText,
17306
+ }, agentContext);
17307
+ }
17308
+ toolArgsText += chunk.argsTextDelta || "";
17309
+ await streamCallback.onMessage({
17310
+ taskId: context.taskId,
17311
+ agentName: agentNode.name,
17312
+ nodeId: agentNode.id,
17313
+ type: "tool_streaming",
17314
+ toolId: chunk.toolCallId,
17315
+ toolName: chunk.toolName,
17316
+ paramsText: toolArgsText,
17317
+ }, agentContext);
17318
+ if (toolPart == null) {
17319
+ toolPart = {
17320
+ type: "tool-call",
17321
+ toolCallId: chunk.toolCallId,
17322
+ toolName: chunk.toolName,
17323
+ args: {},
17324
+ };
17325
+ toolParts.push(toolPart);
17326
+ }
17327
+ break;
17328
+ }
17329
+ case "tool-call": {
17330
+ toolArgsText = "";
17331
+ let args = chunk.args ? JSON.parse(chunk.args) : {};
17332
+ let message = {
17333
+ taskId: context.taskId,
17334
+ agentName: agentNode.name,
17335
+ nodeId: agentNode.id,
17336
+ type: "tool_use",
17337
+ toolId: chunk.toolCallId,
17338
+ toolName: chunk.toolName,
17339
+ params: args,
17340
+ };
17341
+ await streamCallback.onMessage(message, agentContext);
17342
+ if (toolPart == null) {
17343
+ toolParts.push({
17344
+ type: "tool-call",
17345
+ toolCallId: chunk.toolCallId,
17346
+ toolName: chunk.toolName,
17347
+ args: message.params || args,
17348
+ });
17349
+ }
17350
+ else {
17351
+ toolPart.args = message.params || args;
17352
+ toolPart = null;
17353
+ }
17354
+ break;
17355
+ }
17356
+ case "file": {
17357
+ await streamCallback.onMessage({
17358
+ taskId: context.taskId,
17359
+ agentName: agentNode.name,
17360
+ nodeId: agentNode.id,
17361
+ type: "file",
17362
+ mimeType: chunk.mimeType,
17363
+ data: chunk.data,
17364
+ }, agentContext);
17365
+ break;
17366
+ }
17367
+ case "error": {
17368
+ Log.error(`${agentNode.name} agent error: `, chunk);
17369
+ await streamCallback.onMessage({
17370
+ taskId: context.taskId,
17371
+ agentName: agentNode.name,
17372
+ nodeId: agentNode.id,
17373
+ type: "error",
17374
+ error: chunk.error,
17375
+ }, agentContext);
17376
+ throw new Error("LLM Error: " + chunk.error);
17377
+ }
17378
+ case "finish": {
17379
+ if (!textStreamDone) {
17380
+ textStreamDone = true;
17381
+ await streamCallback.onMessage({
17382
+ taskId: context.taskId,
17383
+ agentName: agentNode.name,
17384
+ nodeId: agentNode.id,
17385
+ type: "text",
17386
+ streamId,
17387
+ streamDone: true,
17388
+ text: streamText,
17389
+ }, agentContext);
17390
+ }
17391
+ if (toolPart) {
17392
+ await streamCallback.onMessage({
17393
+ taskId: context.taskId,
17394
+ agentName: agentNode.name,
17395
+ nodeId: agentNode.id,
17396
+ type: "tool_use",
17397
+ toolId: toolPart.toolCallId,
17398
+ toolName: toolPart.toolName,
17399
+ params: toolPart.args || {},
17400
+ }, agentContext);
17401
+ toolPart = null;
17402
+ }
17403
+ await streamCallback.onMessage({
17404
+ taskId: context.taskId,
17405
+ agentName: agentNode.name,
17406
+ nodeId: agentNode.id,
17407
+ type: "finish",
17408
+ finishReason: chunk.finishReason,
17409
+ usage: chunk.usage,
17410
+ }, agentContext);
17411
+ if (chunk.finishReason === "length" &&
17412
+ messages.length >= 10 &&
17413
+ !noCompress &&
17414
+ !retry) {
17415
+ await compressAgentMessages(agentContext, rlm, messages, tools);
17416
+ return callAgentLLM(agentContext, rlm, messages, tools, noCompress, toolChoice, true, streamCallback);
17417
+ }
17418
+ break;
17419
+ }
17420
+ }
17421
+ }
17422
+ }
17423
+ catch (e) {
17424
+ await context.checkAborted();
17425
+ if (!retry) {
17426
+ await sleep(200);
17427
+ return callAgentLLM(agentContext, rlm, messages, tools, noCompress, toolChoice, true, streamCallback);
17428
+ }
17429
+ throw e;
17430
+ }
17431
+ finally {
17432
+ reader.releaseLock();
17433
+ context.currentStepControllers.delete(stepController);
17434
+ }
17435
+ agentChain.agentResult = streamText;
17436
+ return streamText
17437
+ ? [
17438
+ { type: "text", text: streamText },
17439
+ ...toolParts,
17440
+ ]
17441
+ : toolParts;
17442
+ }
17443
+ function appendUserConversation(agentContext, messages) {
17444
+ const userPrompts = agentContext.context.conversation
17445
+ .splice(0, agentContext.context.conversation.length)
17446
+ .filter((s) => !!s);
17447
+ if (userPrompts.length > 0) {
17448
+ 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");
17449
+ messages.push({
17450
+ role: "user",
17451
+ content: [{ type: "text", text: prompt }],
17452
+ });
17453
+ }
17454
+ }
17455
+
17456
+ function extractUsedTool(messages, agentTools) {
17457
+ let tools = [];
17458
+ let toolNames = [];
17459
+ for (let i = 0; i < messages.length; i++) {
17460
+ let message = messages[i];
17461
+ if (message.role == "tool") {
17462
+ for (let j = 0; j < message.content.length; j++) {
17463
+ let toolName = message.content[j].toolName;
17464
+ if (toolNames.indexOf(toolName) > -1) {
17465
+ continue;
17466
+ }
17467
+ toolNames.push(toolName);
17468
+ let tool = agentTools.filter((tool) => tool.name === toolName)[0];
17469
+ if (tool) {
17470
+ tools.push(tool);
17471
+ }
17472
+ }
17473
+ }
17474
+ }
17475
+ return tools;
17476
+ }
17477
+ function removeDuplicateToolUse(results) {
17478
+ if (results.length <= 1 ||
17479
+ results.filter((r) => r.type == "tool-call").length <= 1) {
17480
+ return results;
17481
+ }
17482
+ let _results = [];
17483
+ let tool_uniques = [];
17484
+ for (let i = 0; i < results.length; i++) {
17485
+ if (results[i].type === "tool-call") {
17486
+ let tool = results[i];
17487
+ let key = tool.toolName + tool.args;
17488
+ if (tool_uniques.indexOf(key) == -1) {
17489
+ _results.push(results[i]);
17490
+ tool_uniques.push(key);
17491
+ }
17492
+ }
17493
+ else {
17494
+ _results.push(results[i]);
17495
+ }
17496
+ }
17497
+ return _results;
17498
+ }
17499
+ async function compressAgentMessages(agentContext, rlm, messages, tools) {
17500
+ if (messages.length < 10) {
17501
+ return;
17502
+ }
17503
+ // extract used tool
17504
+ let usedTools = extractUsedTool(messages, tools);
17505
+ let snapshotTool = new TaskSnapshotTool();
17506
+ let newTools = mergeTools(usedTools, [
17507
+ {
17508
+ type: "function",
17509
+ name: snapshotTool.name,
17510
+ description: snapshotTool.description,
17511
+ parameters: snapshotTool.parameters,
17512
+ },
17513
+ ]);
17514
+ // handle messages
17515
+ let lastToolIndex = messages.length - 1;
17516
+ let newMessages = messages;
17517
+ for (let r = newMessages.length - 1; r > 3; r--) {
17518
+ if (newMessages[r].role == "tool") {
17519
+ newMessages = newMessages.slice(0, r + 1);
17520
+ lastToolIndex = r;
17521
+ break;
17522
+ }
17523
+ }
17524
+ newMessages.push({
17525
+ role: "user",
17526
+ content: [
17527
+ {
17528
+ type: "text",
17529
+ text: "Please create a snapshot backup of the current task, keeping only key important information and node completion status.",
17530
+ },
17531
+ ],
17532
+ });
17533
+ // compress snapshot
17534
+ let result = await callAgentLLM(agentContext, rlm, newMessages, newTools, true, {
17535
+ type: "tool",
17536
+ toolName: snapshotTool.name,
17537
+ });
17538
+ let toolCall = result.filter((s) => s.type == "tool-call")[0];
17539
+ let args = typeof toolCall.args == "string"
17540
+ ? JSON.parse(toolCall.args || "{}")
17541
+ : toolCall.args || {};
17542
+ let toolResult = await snapshotTool.execute(args, agentContext);
17543
+ let callback = agentContext.context.config.callback;
17544
+ if (callback) {
17545
+ await callback.onMessage({
17546
+ taskId: agentContext.context.taskId,
17547
+ agentName: agentContext.agent.Name,
17548
+ nodeId: agentContext.agentChain.agent.id,
17549
+ type: "tool_result",
17550
+ toolId: toolCall.toolCallId,
17551
+ toolName: toolCall.toolName,
17552
+ params: args,
17553
+ toolResult: toolResult,
17554
+ }, agentContext);
17555
+ }
17556
+ // handle original messages
17557
+ let firstToolIndex = 3;
17558
+ for (let i = 0; i < messages.length; i++) {
17559
+ if (messages[0].role == "tool") {
17560
+ firstToolIndex = i;
17561
+ break;
17562
+ }
17563
+ }
17564
+ // system, user, assistant, tool(first), [...], <user>, assistant, tool(last), ...
17565
+ messages.splice(firstToolIndex + 1, lastToolIndex - firstToolIndex - 2, {
17566
+ role: "user",
17567
+ content: toolResult.content.filter((s) => s.type == "text"),
17568
+ });
17569
+ }
17570
+ function handleLargeContextMessages(messages) {
17571
+ let imageNum = 0;
17572
+ let fileNum = 0;
17573
+ let maxNum = config.maxDialogueImgFileNum;
17574
+ let longTextTools = {};
17575
+ for (let i = messages.length - 1; i >= 0; i--) {
17576
+ let message = messages[i];
17577
+ if (message.role == "user") {
17578
+ for (let j = 0; j < message.content.length; j++) {
17579
+ let content = message.content[j];
17580
+ if (content.type == "image") {
17581
+ if (++imageNum <= maxNum) {
17582
+ break;
17583
+ }
17584
+ content = {
17585
+ type: "text",
17586
+ text: "[image]",
17587
+ };
17588
+ message.content[j] = content;
17589
+ }
17590
+ else if (content.type == "file") {
17591
+ if (++fileNum <= maxNum) {
17592
+ break;
17593
+ }
17594
+ content = {
17595
+ type: "text",
17596
+ text: "[file]",
17597
+ };
17598
+ message.content[j] = content;
17599
+ }
17600
+ }
17601
+ }
17602
+ else if (message.role == "tool") {
17603
+ for (let j = 0; j < message.content.length; j++) {
17604
+ let toolResult = message.content[j];
17605
+ let toolContent = toolResult.content;
17606
+ if (!toolContent || toolContent.length == 0) {
17607
+ continue;
17196
17608
  }
17197
17609
  for (let r = 0; r < toolContent.length; r++) {
17198
17610
  let _content = toolContent[r];
@@ -17995,21 +18407,24 @@ class Agent {
17995
18407
  mcpClient && (await mcpClient.close());
17996
18408
  }
17997
18409
  }
17998
- async runWithContext(agentContext, mcpClient, maxReactNum = 100) {
18410
+ async runWithContext(agentContext, mcpClient, maxReactNum = 100, historyMessages = []) {
17999
18411
  let loopNum = 0;
18412
+ this.agentContext = agentContext;
18000
18413
  let context = agentContext.context;
18001
18414
  let agentNode = agentContext.agentChain.agent;
18002
18415
  const tools = [...this.tools, ...this.system_auto_tools(agentNode)];
18003
- let messages = [
18416
+ const messages = [
18004
18417
  {
18005
18418
  role: "system",
18006
18419
  content: await this.buildSystemPrompt(agentContext, tools),
18007
18420
  },
18421
+ ...historyMessages,
18008
18422
  {
18009
18423
  role: "user",
18010
18424
  content: await this.buildUserPrompt(agentContext, tools),
18011
18425
  },
18012
18426
  ];
18427
+ agentContext.messages = messages;
18013
18428
  let rlm = new RetryLanguageModel(context.config.llms, this.llms);
18014
18429
  let agentTools = tools;
18015
18430
  while (loopNum < maxReactNum) {
@@ -18024,7 +18439,7 @@ class Agent {
18024
18439
  }
18025
18440
  }
18026
18441
  await this.handleMessages(agentContext, messages, tools);
18027
- let results = await callLLM(agentContext, rlm, messages, this.convertTools(agentTools), false, undefined, false, this.callback);
18442
+ let results = await callAgentLLM(agentContext, rlm, messages, this.convertTools(agentTools), false, undefined, false, this.callback);
18028
18443
  let finalResult = await this.handleCallResult(agentContext, messages, agentTools, results);
18029
18444
  if (finalResult) {
18030
18445
  return finalResult;
@@ -18034,6 +18449,10 @@ class Agent {
18034
18449
  return "Unfinished";
18035
18450
  }
18036
18451
  async handleCallResult(agentContext, messages, agentTools, results) {
18452
+ const forceStop = agentContext.variables.get("forceStop");
18453
+ if (forceStop) {
18454
+ return forceStop;
18455
+ }
18037
18456
  let text = null;
18038
18457
  let context = agentContext.context;
18039
18458
  let user_messages = [];
@@ -18266,29 +18685,6 @@ class Agent {
18266
18685
  async handleMessages(agentContext, messages, tools) {
18267
18686
  // Only keep the last image / file, large tool-text-result
18268
18687
  handleLargeContextMessages(messages);
18269
- // User dialogue
18270
- const userPrompts = agentContext.context.conversation
18271
- .splice(0, agentContext.context.conversation.length)
18272
- .filter((s) => !!s);
18273
- if (userPrompts.length > 0) {
18274
- const lastMessage = messages[messages.length - 1];
18275
- if (lastMessage.role == "user") {
18276
- for (let i = 0; i < userPrompts.length; i++) {
18277
- lastMessage.content.push({
18278
- type: "text",
18279
- text: userPrompts[i],
18280
- });
18281
- }
18282
- }
18283
- else {
18284
- messages.push({
18285
- role: "user",
18286
- content: userPrompts.map((s) => {
18287
- return { type: "text", text: s };
18288
- }),
18289
- });
18290
- }
18291
- }
18292
18688
  }
18293
18689
  async callInnerTool(fun) {
18294
18690
  let result = await fun();
@@ -18340,222 +18736,9 @@ class Agent {
18340
18736
  get McpClient() {
18341
18737
  return this.mcpClient;
18342
18738
  }
18343
- }
18344
- async function callLLM(agentContext, rlm, messages, tools, noCompress, toolChoice, retry, callback) {
18345
- if (messages.length >= config.compressThreshold && !noCompress) {
18346
- await compressAgentMessages(agentContext, rlm, messages, tools);
18347
- }
18348
- let context = agentContext.context;
18349
- let agentChain = agentContext.agentChain;
18350
- let agentNode = agentChain.agent;
18351
- let streamCallback = callback ||
18352
- context.config.callback || {
18353
- onMessage: async () => { },
18354
- };
18355
- let request = {
18356
- tools: tools,
18357
- toolChoice,
18358
- messages: messages,
18359
- abortSignal: context.controller.signal,
18360
- };
18361
- agentChain.agentRequest = request;
18362
- let result = await rlm.callStream(request);
18363
- let streamText = "";
18364
- let thinkText = "";
18365
- let toolArgsText = "";
18366
- let streamId = uuidv4();
18367
- let textStreamDone = false;
18368
- let toolParts = [];
18369
- const reader = result.stream.getReader();
18370
- try {
18371
- let toolPart = null;
18372
- while (true) {
18373
- await context.checkAborted();
18374
- const { done, value } = await reader.read();
18375
- if (done) {
18376
- break;
18377
- }
18378
- let chunk = value;
18379
- switch (chunk.type) {
18380
- case "text-delta": {
18381
- if (toolPart && !chunk.textDelta) {
18382
- continue;
18383
- }
18384
- streamText += chunk.textDelta || "";
18385
- await streamCallback.onMessage({
18386
- taskId: context.taskId,
18387
- agentName: agentNode.name,
18388
- nodeId: agentNode.id,
18389
- type: "text",
18390
- streamId,
18391
- streamDone: false,
18392
- text: streamText,
18393
- }, agentContext);
18394
- if (toolPart) {
18395
- await streamCallback.onMessage({
18396
- taskId: context.taskId,
18397
- agentName: agentNode.name,
18398
- nodeId: agentNode.id,
18399
- type: "tool_use",
18400
- toolId: toolPart.toolCallId,
18401
- toolName: toolPart.toolName,
18402
- params: toolPart.args || {},
18403
- }, agentContext);
18404
- toolPart = null;
18405
- }
18406
- break;
18407
- }
18408
- case "reasoning": {
18409
- thinkText += chunk.textDelta || "";
18410
- await streamCallback.onMessage({
18411
- taskId: context.taskId,
18412
- agentName: agentNode.name,
18413
- nodeId: agentNode.id,
18414
- type: "thinking",
18415
- streamId,
18416
- streamDone: false,
18417
- text: thinkText,
18418
- }, agentContext);
18419
- break;
18420
- }
18421
- case "tool-call-delta": {
18422
- if (!textStreamDone) {
18423
- textStreamDone = true;
18424
- await streamCallback.onMessage({
18425
- taskId: context.taskId,
18426
- agentName: agentNode.name,
18427
- nodeId: agentNode.id,
18428
- type: "text",
18429
- streamId,
18430
- streamDone: true,
18431
- text: streamText,
18432
- }, agentContext);
18433
- }
18434
- toolArgsText += chunk.argsTextDelta || "";
18435
- await streamCallback.onMessage({
18436
- taskId: context.taskId,
18437
- agentName: agentNode.name,
18438
- nodeId: agentNode.id,
18439
- type: "tool_streaming",
18440
- toolId: chunk.toolCallId,
18441
- toolName: chunk.toolName,
18442
- paramsText: toolArgsText,
18443
- }, agentContext);
18444
- if (toolPart == null) {
18445
- toolPart = {
18446
- type: "tool-call",
18447
- toolCallId: chunk.toolCallId,
18448
- toolName: chunk.toolName,
18449
- args: {},
18450
- };
18451
- toolParts.push(toolPart);
18452
- }
18453
- break;
18454
- }
18455
- case "tool-call": {
18456
- toolArgsText = "";
18457
- let args = chunk.args ? JSON.parse(chunk.args) : {};
18458
- let message = {
18459
- taskId: context.taskId,
18460
- agentName: agentNode.name,
18461
- nodeId: agentNode.id,
18462
- type: "tool_use",
18463
- toolId: chunk.toolCallId,
18464
- toolName: chunk.toolName,
18465
- params: args,
18466
- };
18467
- await streamCallback.onMessage(message, agentContext);
18468
- if (toolPart == null) {
18469
- toolParts.push({
18470
- type: "tool-call",
18471
- toolCallId: chunk.toolCallId,
18472
- toolName: chunk.toolName,
18473
- args: message.params || args,
18474
- });
18475
- }
18476
- else {
18477
- toolPart.args = message.params || args;
18478
- toolPart = null;
18479
- }
18480
- break;
18481
- }
18482
- case "file": {
18483
- await streamCallback.onMessage({
18484
- taskId: context.taskId,
18485
- agentName: agentNode.name,
18486
- nodeId: agentNode.id,
18487
- type: "file",
18488
- mimeType: chunk.mimeType,
18489
- data: chunk.data,
18490
- }, agentContext);
18491
- break;
18492
- }
18493
- case "error": {
18494
- Log.error(`${agentNode.name} agent error: `, chunk);
18495
- await streamCallback.onMessage({
18496
- taskId: context.taskId,
18497
- agentName: agentNode.name,
18498
- nodeId: agentNode.id,
18499
- type: "error",
18500
- error: chunk.error,
18501
- }, agentContext);
18502
- throw new Error("LLM Error: " + chunk.error);
18503
- }
18504
- case "finish": {
18505
- if (!textStreamDone) {
18506
- textStreamDone = true;
18507
- await streamCallback.onMessage({
18508
- taskId: context.taskId,
18509
- agentName: agentNode.name,
18510
- nodeId: agentNode.id,
18511
- type: "text",
18512
- streamId,
18513
- streamDone: true,
18514
- text: streamText,
18515
- }, agentContext);
18516
- }
18517
- if (toolPart) {
18518
- await streamCallback.onMessage({
18519
- taskId: context.taskId,
18520
- agentName: agentNode.name,
18521
- nodeId: agentNode.id,
18522
- type: "tool_use",
18523
- toolId: toolPart.toolCallId,
18524
- toolName: toolPart.toolName,
18525
- params: toolPart.args || {},
18526
- }, agentContext);
18527
- toolPart = null;
18528
- }
18529
- await streamCallback.onMessage({
18530
- taskId: context.taskId,
18531
- agentName: agentNode.name,
18532
- nodeId: agentNode.id,
18533
- type: "finish",
18534
- finishReason: chunk.finishReason,
18535
- usage: chunk.usage,
18536
- }, agentContext);
18537
- if (chunk.finishReason === "length" &&
18538
- messages.length >= 10 &&
18539
- !noCompress &&
18540
- !retry) {
18541
- await compressAgentMessages(agentContext, rlm, messages, tools);
18542
- return callLLM(agentContext, rlm, messages, tools, noCompress, toolChoice, true, streamCallback);
18543
- }
18544
- break;
18545
- }
18546
- }
18547
- }
18548
- }
18549
- finally {
18550
- reader.releaseLock();
18739
+ get AgentContext() {
18740
+ return this.agentContext;
18551
18741
  }
18552
- agentChain.agentResult = streamText;
18553
- return streamText
18554
- ? [
18555
- { type: "text", text: streamText },
18556
- ...toolParts,
18557
- ]
18558
- : toolParts;
18559
18742
  }
18560
18743
 
18561
18744
  const AGENT_NAME$5 = "Chat";
@@ -18590,7 +18773,9 @@ Your task is to understand the user's requirements, dynamically plan the user's
18590
18773
 
18591
18774
  ## Output Rules and Format
18592
18775
  <root>
18776
+ <!-- Task Name (Short) -->
18593
18777
  <name>Task Name</name>
18778
+ <!-- Need to break down the task into multi-agent collaboration. Please think step by step and output a detailed thought process. -->
18594
18779
  <thought>Your thought process on user demand planning</thought>
18595
18780
  <!-- Multiple Agents work together to complete the task -->
18596
18781
  <agents>
@@ -18788,21 +18973,39 @@ function getPlanUserPrompt(task_prompt, task_website, ext_prompt) {
18788
18973
  class Planner {
18789
18974
  constructor(context, taskId) {
18790
18975
  this.context = context;
18791
- this.taskId = taskId;
18792
- }
18793
- async plan(taskPrompt) {
18794
- return await this.doPlan(taskPrompt, false);
18795
- }
18796
- async replan(taskPrompt) {
18797
- return await this.doPlan(taskPrompt, true);
18976
+ this.taskId = taskId || context.taskId;
18977
+ }
18978
+ async plan(taskPrompt, saveHistory = true) {
18979
+ let taskPromptStr;
18980
+ let userPrompt;
18981
+ if (typeof taskPrompt === "string") {
18982
+ taskPromptStr = taskPrompt;
18983
+ userPrompt = {
18984
+ type: "text",
18985
+ text: getPlanUserPrompt(taskPrompt, this.context.variables.get("task_website"), this.context.variables.get("plan_ext_prompt")),
18986
+ };
18987
+ }
18988
+ else {
18989
+ userPrompt = taskPrompt;
18990
+ taskPromptStr = taskPrompt.text || "";
18991
+ }
18992
+ const messages = [
18993
+ {
18994
+ role: "system",
18995
+ content: this.context.variables.get("plan_sys_prompt") ||
18996
+ (await getPlanSystemPrompt(this.context)),
18997
+ },
18998
+ {
18999
+ role: "user",
19000
+ content: [userPrompt],
19001
+ },
19002
+ ];
19003
+ return await this.doPlan(taskPromptStr, messages, saveHistory);
18798
19004
  }
18799
- async doPlan(taskPrompt, replan = false) {
18800
- let config = this.context.config;
18801
- let chain = this.context.chain;
18802
- let rlm = new RetryLanguageModel(config.llms, config.planLlms);
18803
- let messages;
18804
- if (replan && chain.planRequest && chain.planResult) {
18805
- messages = [
19005
+ async replan(taskPrompt, saveHistory = true) {
19006
+ const chain = this.context.chain;
19007
+ if (chain.planRequest && chain.planResult) {
19008
+ const messages = [
18806
19009
  ...chain.planRequest.messages,
18807
19010
  {
18808
19011
  role: "assistant",
@@ -18813,37 +19016,28 @@ class Planner {
18813
19016
  content: [{ type: "text", text: taskPrompt }],
18814
19017
  },
18815
19018
  ];
19019
+ return await this.doPlan(taskPrompt, messages, saveHistory);
18816
19020
  }
18817
19021
  else {
18818
- messages = [
18819
- {
18820
- role: "system",
18821
- content: this.context.variables.get("plan_sys_prompt") ||
18822
- (await getPlanSystemPrompt(this.context)),
18823
- },
18824
- {
18825
- role: "user",
18826
- content: [
18827
- {
18828
- type: "text",
18829
- text: getPlanUserPrompt(taskPrompt, this.context.variables.get("task_website"), this.context.variables.get("plan_ext_prompt")),
18830
- },
18831
- ],
18832
- },
18833
- ];
19022
+ return this.plan(taskPrompt, saveHistory);
18834
19023
  }
18835
- let request = {
19024
+ }
19025
+ async doPlan(taskPrompt, messages, saveHistory) {
19026
+ const config = this.context.config;
19027
+ const rlm = new RetryLanguageModel(config.llms, config.planLlms);
19028
+ const request = {
18836
19029
  maxTokens: 4096,
18837
19030
  temperature: 0.7,
18838
19031
  messages: messages,
18839
19032
  abortSignal: this.context.controller.signal,
18840
19033
  };
18841
- let result = await rlm.callStream(request);
19034
+ const result = await rlm.callStream(request);
18842
19035
  const reader = result.stream.getReader();
18843
19036
  let streamText = "";
19037
+ let thinkingText = "";
18844
19038
  try {
18845
19039
  while (true) {
18846
- await this.context.checkAborted();
19040
+ await this.context.checkAborted(true);
18847
19041
  const { done, value } = await reader.read();
18848
19042
  if (done) {
18849
19043
  break;
@@ -18853,11 +19047,14 @@ class Planner {
18853
19047
  Log.error("Plan, LLM Error: ", chunk);
18854
19048
  throw new Error("LLM Error: " + chunk.error);
18855
19049
  }
19050
+ if (chunk.type == "reasoning") {
19051
+ thinkingText += chunk.textDelta || "";
19052
+ }
18856
19053
  if (chunk.type == "text-delta") {
18857
19054
  streamText += chunk.textDelta || "";
18858
19055
  }
18859
19056
  if (config.callback) {
18860
- let workflow = parseWorkflow(this.taskId, streamText, false);
19057
+ let workflow = parseWorkflow(this.taskId, streamText, false, thinkingText);
18861
19058
  if (workflow) {
18862
19059
  await config.callback.onMessage({
18863
19060
  taskId: this.taskId,
@@ -18872,11 +19069,16 @@ class Planner {
18872
19069
  }
18873
19070
  finally {
18874
19071
  reader.releaseLock();
18875
- Log.info("Planner result: \n" + streamText);
19072
+ if (Log.isEnableInfo()) {
19073
+ Log.info("Planner result: \n" + streamText);
19074
+ }
18876
19075
  }
18877
- chain.planRequest = request;
18878
- chain.planResult = streamText;
18879
- let workflow = parseWorkflow(this.taskId, streamText, true);
19076
+ if (saveHistory) {
19077
+ const chain = this.context.chain;
19078
+ chain.planRequest = request;
19079
+ chain.planResult = streamText;
19080
+ }
19081
+ let workflow = parseWorkflow(this.taskId, streamText, true, thinkingText);
18880
19082
  if (config.callback) {
18881
19083
  await config.callback.onMessage({
18882
19084
  taskId: this.taskId,
@@ -18886,7 +19088,12 @@ class Planner {
18886
19088
  workflow: workflow,
18887
19089
  });
18888
19090
  }
18889
- workflow.taskPrompt = taskPrompt;
19091
+ if (workflow.taskPrompt) {
19092
+ workflow.taskPrompt += "\n" + taskPrompt.trim();
19093
+ }
19094
+ else {
19095
+ workflow.taskPrompt = taskPrompt.trim();
19096
+ }
18890
19097
  return workflow;
18891
19098
  }
18892
19099
  }
@@ -18936,8 +19143,8 @@ class Eko {
18936
19143
  if (!context) {
18937
19144
  throw new Error("The task does not exist");
18938
19145
  }
18939
- if (context.paused) {
18940
- context.paused = false;
19146
+ if (context.pause) {
19147
+ context.setPause(false);
18941
19148
  }
18942
19149
  context.conversation = [];
18943
19150
  if (context.controller.signal.aborted) {
@@ -19025,7 +19232,7 @@ class Eko {
19025
19232
  abortTask(taskId, reason) {
19026
19233
  let context = this.taskMap.get(taskId);
19027
19234
  if (context) {
19028
- context.paused = false;
19235
+ context.setPause(false);
19029
19236
  this.onTaskStatus(context, "abort", reason);
19030
19237
  context.controller.abort(reason);
19031
19238
  return true;
@@ -19034,11 +19241,11 @@ class Eko {
19034
19241
  return false;
19035
19242
  }
19036
19243
  }
19037
- pauseTask(taskId, paused, reason) {
19244
+ pauseTask(taskId, pause, abortCurrentStep, reason) {
19038
19245
  let context = this.taskMap.get(taskId);
19039
19246
  if (context) {
19040
- this.onTaskStatus(context, paused ? "pause" : "resume-pause", reason);
19041
- context.paused = paused;
19247
+ this.onTaskStatus(context, pause ? "pause" : "resume-pause", reason);
19248
+ context.setPause(pause, abortCurrentStep);
19042
19249
  return true;
19043
19250
  }
19044
19251
  else {
@@ -21788,17 +21995,21 @@ exports.Eko = Eko;
21788
21995
  exports.ForeachTaskTool = ForeachTaskTool;
21789
21996
  exports.HumanInteractTool = HumanInteractTool;
21790
21997
  exports.Log = Log;
21998
+ exports.Planner = Planner;
21791
21999
  exports.RetryLanguageModel = RetryLanguageModel;
21792
22000
  exports.SimpleSseMcpClient = SimpleSseMcpClient;
21793
22001
  exports.TaskNodeStatusTool = TaskNodeStatusTool;
21794
22002
  exports.VariableStorageTool = VariableStorageTool;
21795
22003
  exports.WatchTriggerTool = WatchTriggerTool;
22004
+ exports.buildSimpleAgentWorkflow = buildSimpleAgentWorkflow;
21796
22005
  exports.call_timeout = call_timeout;
21797
22006
  exports.config = config;
21798
22007
  exports.convertToolSchema = convertToolSchema;
21799
22008
  exports.default = Eko;
21800
22009
  exports.extract_page_content = extract_page_content;
21801
22010
  exports.mergeTools = mergeTools;
22011
+ exports.parseWorkflow = parseWorkflow;
22012
+ exports.resetWorkflowXml = resetWorkflowXml;
21802
22013
  exports.toImage = toImage;
21803
22014
  exports.uuidv4 = uuidv4;
21804
22015
  //# sourceMappingURL=index.cjs.js.map