@eko-ai/eko 1.3.1 → 1.3.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.
@@ -0,0 +1,10 @@
1
+ import { Message } from "@/types";
2
+ export declare abstract class ContextComporessor {
3
+ abstract comporess(messages: Message[]): Message[];
4
+ }
5
+ export declare class NoComporess extends ContextComporessor {
6
+ comporess(messages: Message[]): Message[];
7
+ }
8
+ export declare class SimpleQAComporess extends ContextComporessor {
9
+ comporess(messages: Message[]): Message[];
10
+ }
@@ -694,6 +694,7 @@ async function getTabId(context) {
694
694
  tabId = await getCurrentTabId(context.ekoConfig.chromeProxy);
695
695
  logger.debug("getCurrentTabId(context.ekoConfig.chromeProxy) #2 returns " + tabId);
696
696
  }
697
+ logger.debug("tabId:", tabId);
697
698
  if (!tabId) {
698
699
  const fellouTabId = window.__FELLOU_TAB_ID__;
699
700
  if (fellouTabId) {
@@ -721,7 +722,7 @@ function getCurrentTabId(chromeProxy, windowId) {
721
722
  logger.debug(`get the active tabId on current window`);
722
723
  queryInfo = { active: true, currentWindow: true };
723
724
  }
724
- chrome.tabs.query(queryInfo, (tabs) => {
725
+ chromeProxy.tabs.query(queryInfo, (tabs) => {
725
726
  if (chromeProxy.runtime.lastError) {
726
727
  logger.error(`failed to get: `, chromeProxy.runtime.lastError);
727
728
  reject(chromeProxy.runtime.lastError);
@@ -2092,7 +2093,7 @@ class WebSearch {
2092
2093
  let searchs = [{ url: url, keyword: query }];
2093
2094
  let searchInfo = await deepSearch(context, taskId, searchs, maxResults || 5, context.ekoConfig.workingWindowId);
2094
2095
  let links = ((_b = searchInfo.result[0]) === null || _b === void 0 ? void 0 : _b.links) || [];
2095
- return links.filter((s) => s.content);
2096
+ return links.filter((s) => s.content.slice(0, 8000));
2096
2097
  }
2097
2098
  }
2098
2099
  const deepSearchInjects = {
@@ -692,6 +692,7 @@ async function getTabId(context) {
692
692
  tabId = await getCurrentTabId(context.ekoConfig.chromeProxy);
693
693
  logger.debug("getCurrentTabId(context.ekoConfig.chromeProxy) #2 returns " + tabId);
694
694
  }
695
+ logger.debug("tabId:", tabId);
695
696
  if (!tabId) {
696
697
  const fellouTabId = window.__FELLOU_TAB_ID__;
697
698
  if (fellouTabId) {
@@ -719,7 +720,7 @@ function getCurrentTabId(chromeProxy, windowId) {
719
720
  logger.debug(`get the active tabId on current window`);
720
721
  queryInfo = { active: true, currentWindow: true };
721
722
  }
722
- chrome.tabs.query(queryInfo, (tabs) => {
723
+ chromeProxy.tabs.query(queryInfo, (tabs) => {
723
724
  if (chromeProxy.runtime.lastError) {
724
725
  logger.error(`failed to get: `, chromeProxy.runtime.lastError);
725
726
  reject(chromeProxy.runtime.lastError);
@@ -2090,7 +2091,7 @@ class WebSearch {
2090
2091
  let searchs = [{ url: url, keyword: query }];
2091
2092
  let searchInfo = await deepSearch(context, taskId, searchs, maxResults || 5, context.ekoConfig.workingWindowId);
2092
2093
  let links = ((_b = searchInfo.result[0]) === null || _b === void 0 ? void 0 : _b.links) || [];
2093
- return links.filter((s) => s.content);
2094
+ return links.filter((s) => s.content.slice(0, 8000));
2094
2095
  }
2095
2096
  }
2096
2097
  const deepSearchInjects = {
package/dist/index.cjs.js CHANGED
@@ -1140,7 +1140,7 @@ let APIClient$1 = class APIClient {
1140
1140
  const maxRetries = options.maxRetries ?? this.maxRetries;
1141
1141
  timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);
1142
1142
  }
1143
- await sleep$1(timeoutMillis);
1143
+ await sleep$2(timeoutMillis);
1144
1144
  return this.makeRequest(options, retriesRemaining - 1);
1145
1145
  }
1146
1146
  calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {
@@ -1411,7 +1411,7 @@ const startsWithSchemeRegexp$1 = /^[a-z][a-z0-9+.-]*:/i;
1411
1411
  const isAbsoluteURL$1 = (url) => {
1412
1412
  return startsWithSchemeRegexp$1.test(url);
1413
1413
  };
1414
- const sleep$1 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1414
+ const sleep$2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1415
1415
  const validatePositiveInteger$1 = (name, n) => {
1416
1416
  if (typeof n !== 'number' || !Number.isInteger(n)) {
1417
1417
  throw new AnthropicError(`${name} must be an integer`);
@@ -5102,7 +5102,7 @@ class APIClient {
5102
5102
  const maxRetries = options.maxRetries ?? this.maxRetries;
5103
5103
  timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);
5104
5104
  }
5105
- await sleep(timeoutMillis);
5105
+ await sleep$1(timeoutMillis);
5106
5106
  return this.makeRequest(options, retriesRemaining - 1);
5107
5107
  }
5108
5108
  calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {
@@ -5374,7 +5374,7 @@ const startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;
5374
5374
  const isAbsoluteURL = (url) => {
5375
5375
  return startsWithSchemeRegexp.test(url);
5376
5376
  };
5377
- const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
5377
+ const sleep$1 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
5378
5378
  const validatePositiveInteger = (name, n) => {
5379
5379
  if (typeof n !== 'number' || !Number.isInteger(n)) {
5380
5380
  throw new OpenAIError(`${name} must be an integer`);
@@ -8056,7 +8056,7 @@ class Runs extends APIResource {
8056
8056
  }
8057
8057
  }
8058
8058
  }
8059
- await sleep(sleepInterval);
8059
+ await sleep$1(sleepInterval);
8060
8060
  break;
8061
8061
  //We return the run in any terminal state.
8062
8062
  case 'requires_action':
@@ -8285,7 +8285,7 @@ let Files$1 = class Files extends APIResource {
8285
8285
  const start = Date.now();
8286
8286
  let file = await this.retrieve(id);
8287
8287
  while (!file.status || !TERMINAL_STATES.has(file.status)) {
8288
- await sleep(pollInterval);
8288
+ await sleep$1(pollInterval);
8289
8289
  file = await this.retrieve(id);
8290
8290
  if (Date.now() - start > maxWait) {
8291
8291
  throw new APIConnectionTimeoutError({
@@ -9052,7 +9052,7 @@ class Files extends APIResource {
9052
9052
  }
9053
9053
  }
9054
9054
  }
9055
- await sleep(sleepInterval);
9055
+ await sleep$1(sleepInterval);
9056
9056
  break;
9057
9057
  case 'failed':
9058
9058
  case 'completed':
@@ -9169,7 +9169,7 @@ class FileBatches extends APIResource {
9169
9169
  }
9170
9170
  }
9171
9171
  }
9172
- await sleep(sleepInterval);
9172
+ await sleep$1(sleepInterval);
9173
9173
  break;
9174
9174
  case 'failed':
9175
9175
  case 'cancelled':
@@ -10238,6 +10238,84 @@ class WriteContextTool {
10238
10238
  }
10239
10239
  }
10240
10240
 
10241
+ class ContextComporessor {
10242
+ }
10243
+ class NoComporess extends ContextComporessor {
10244
+ comporess(messages) {
10245
+ logger.debug("ContextComporessor = NoComporess");
10246
+ let comporessed = JSON.parse(JSON.stringify(messages));
10247
+ logger.debug("comporessed:", comporessed);
10248
+ return comporessed;
10249
+ }
10250
+ }
10251
+ class SimpleQAComporess extends ContextComporessor {
10252
+ comporess(messages) {
10253
+ logger.debug("ContextComporessor = SimpleQAComporess");
10254
+ messages = JSON.parse(JSON.stringify(messages));
10255
+ let comporessed = [];
10256
+ const compress = (msg, idx) => {
10257
+ if (msg.role == "system") {
10258
+ return msg;
10259
+ }
10260
+ else if (msg.role == "assistant") {
10261
+ if (idx == messages.length - 2) {
10262
+ return msg;
10263
+ }
10264
+ else if (typeof msg.content == "string") {
10265
+ const nextMessage = messages[idx + 1];
10266
+ if (nextMessage.role == "assistant" && Array.isArray(nextMessage.content)) {
10267
+ return null;
10268
+ }
10269
+ else {
10270
+ return msg;
10271
+ }
10272
+ }
10273
+ else {
10274
+ const task = msg.content[0].input.userSidePrompt;
10275
+ const details = msg.content[0].input.thinking;
10276
+ return {
10277
+ "role": "assistant",
10278
+ "content": `<task>${task}</task><details>${details}</details>`,
10279
+ };
10280
+ }
10281
+ }
10282
+ else if (msg.role == "user" || typeof msg.content == "string") {
10283
+ if (idx == messages.length - 1 || idx == 1) {
10284
+ return msg;
10285
+ }
10286
+ else {
10287
+ let aiResponseMsg = messages[idx + 1];
10288
+ if (typeof aiResponseMsg.content == "string") {
10289
+ aiResponseMsg = messages[idx + 2];
10290
+ }
10291
+ const result = aiResponseMsg.content[0].input.observation;
10292
+ return {
10293
+ "role": "user",
10294
+ "content": `<result>${result}</result>`,
10295
+ };
10296
+ }
10297
+ }
10298
+ else {
10299
+ logger.warn("unknown message type, return null");
10300
+ return null;
10301
+ }
10302
+ };
10303
+ messages.forEach((msg, idx) => {
10304
+ logger.debug({ idx, msg });
10305
+ const compressedMsg = compress(msg, idx);
10306
+ logger.debug(compressedMsg);
10307
+ if (compressedMsg) {
10308
+ comporessed.push(compressedMsg);
10309
+ }
10310
+ });
10311
+ return comporessed;
10312
+ }
10313
+ }
10314
+
10315
+ function sleep(time) {
10316
+ return new Promise((resolve) => setTimeout(() => resolve(), time));
10317
+ }
10318
+
10241
10319
  // src/models/action.ts
10242
10320
  function createReturnTool(actionName, outputDescription, outputSchema) {
10243
10321
  return {
@@ -10283,7 +10361,7 @@ class ActionImpl {
10283
10361
  this.tools = tools;
10284
10362
  this.llmProvider = llmProvider;
10285
10363
  this.llmConfig = llmConfig;
10286
- this.maxRounds = 100; // Default max rounds
10364
+ this.maxRounds = 25; // Default max rounds
10287
10365
  this.toolResults = new Map();
10288
10366
  this.logger = new ExecutionLogger();
10289
10367
  this.tabs = [];
@@ -10300,6 +10378,7 @@ class ActionImpl {
10300
10378
  let roundMessages = [];
10301
10379
  let params_copy = JSON.parse(JSON.stringify(params));
10302
10380
  params_copy.tools = (_a = params_copy.tools) === null || _a === void 0 ? void 0 : _a.map(this.wrapToolInputSchema);
10381
+ let retry_counter = 3;
10303
10382
  while (!((_b = context.signal) === null || _b === void 0 ? void 0 : _b.aborted)) {
10304
10383
  roundMessages = [];
10305
10384
  hasToolUse = false;
@@ -10395,7 +10474,7 @@ class ActionImpl {
10395
10474
  // unwrap the toolCall
10396
10475
  let unwrapped = this.unwrapToolCall(toolCall);
10397
10476
  let input = unwrapped.toolCall.input;
10398
- logger.debug("unwrapped", unwrapped);
10477
+ logger.info("LLM Response:", unwrapped);
10399
10478
  if (unwrapped.thinking) {
10400
10479
  (_d = (_b = context.callback) === null || _b === void 0 ? void 0 : (_c = _b.hooks).onLlmMessage) === null || _d === void 0 ? void 0 : _d.call(_c, unwrapped.thinking);
10401
10480
  }
@@ -10499,11 +10578,43 @@ class ActionImpl {
10499
10578
  throw new Error('LLM provider not set');
10500
10579
  }
10501
10580
  try {
10502
- await this.llmProvider.generateStream(messages, params_copy, handler);
10581
+ let compressedMessages;
10582
+ try {
10583
+ const comporessor = new SimpleQAComporess();
10584
+ logger.debug("uncompressed messages:", messages);
10585
+ compressedMessages = comporessor.comporess(messages);
10586
+ }
10587
+ catch (e) {
10588
+ logger.error("an error occurs when comporess context, use NoComporess");
10589
+ logger.error(e);
10590
+ const comporessor = new NoComporess();
10591
+ compressedMessages = comporessor.comporess(messages);
10592
+ }
10593
+ logger.debug("compressed messages:", compressedMessages);
10594
+ await sleep(5000);
10595
+ try {
10596
+ await this.llmProvider.generateStream(compressedMessages, params_copy, handler);
10597
+ }
10598
+ catch (e) {
10599
+ logger.warn("LLM API raise an error, try to use NoComporess");
10600
+ const comporessor = new NoComporess();
10601
+ compressedMessages = comporessor.comporess(messages);
10602
+ logger.debug("compressed messages:", compressedMessages);
10603
+ await sleep(5000);
10604
+ await this.llmProvider.generateStream(compressedMessages, params_copy, handler);
10605
+ }
10503
10606
  }
10504
10607
  catch (e) {
10505
- logger.warn("an error occurs when LLM generate response, retry...", e);
10506
- continue;
10608
+ logger.warn(`an error occurs when LLM generate response, retry(n=${retry_counter})...`, e);
10609
+ await sleep(3000);
10610
+ retry_counter -= 1;
10611
+ if (retry_counter > 0) {
10612
+ continue;
10613
+ }
10614
+ else {
10615
+ logger.error("too many errors when calling LLM API in executing");
10616
+ throw e;
10617
+ }
10507
10618
  }
10508
10619
  // Wait for tool execution to complete if it was started
10509
10620
  if (toolExecutionPromise) {
@@ -10585,9 +10696,11 @@ class ActionImpl {
10585
10696
  toolMap.set(returnTool.name, returnTool);
10586
10697
  // get already existing tabs as task background
10587
10698
  const currentWindow = await context.ekoConfig.chromeProxy.windows.getCurrent();
10588
- const existingTabs = await context.ekoConfig.chromeProxy.tabs.query({
10699
+ let existingTabs = await context.ekoConfig.chromeProxy.tabs.query({
10589
10700
  windowId: currentWindow.id,
10590
10701
  });
10702
+ existingTabs = existingTabs.filter((tab) => { tab.title && tab.url; });
10703
+ logger.debug("existingTabs:", existingTabs);
10591
10704
  // get patchs for task
10592
10705
  let patchs = [];
10593
10706
  if (context.ekoConfig.patchServerUrl) {
@@ -10825,22 +10938,9 @@ Navigation Bar or Menu Changes: After logging in, the navigation bar will includ
10825
10938
  definition.input_schema = {
10826
10939
  type: "object",
10827
10940
  properties: {
10828
- // comment for backup
10829
- // observation: {
10830
- // "type": "string",
10831
- // "description": 'Your observation of the previous steps. Should start with "In the previous step, I\'ve ...".',
10832
- // },
10833
- evaluate_previous_goal: {
10834
- "type": "string",
10835
- "description": "Success|Failed|Unknown - Analyze the current elements and the image to check if the previous goals/actions are successful like intended by the task. Mention if something unexpected happened. Shortly state why/why not"
10836
- },
10837
- memory: {
10838
- "type": "string",
10839
- "description": "Description of what has been done and what you need to remember. Be very specific. Count here ALWAYS how many times you have done something and how many remain. E.g. 0 out of 10 websites analyzed. Continue with abc and xyz",
10840
- },
10841
- next_goal: {
10941
+ observation: {
10842
10942
  "type": "string",
10843
- "description": "What needs to be done with the next immediate action",
10943
+ "description": 'Your observation of the previous steps. Should start with "In the previous step, I\'ve ...".',
10844
10944
  },
10845
10945
  thinking: {
10846
10946
  "type": "string",
@@ -10854,12 +10954,9 @@ Navigation Bar or Menu Changes: After logging in, the navigation bar will includ
10854
10954
  },
10855
10955
  required: [
10856
10956
  // comment for backup
10857
- // "observation",
10957
+ "observation",
10858
10958
  "thinking",
10859
10959
  "userSidePrompt",
10860
- "memory",
10861
- "next_goal",
10862
- "evaluate_previous_goal",
10863
10960
  "toolCall",
10864
10961
  ],
10865
10962
  };
@@ -10870,15 +10967,15 @@ Navigation Bar or Menu Changes: After logging in, the navigation bar will includ
10870
10967
  observation: toolCall.input.observation,
10871
10968
  thinking: toolCall.input.thinking,
10872
10969
  userSidePrompt: toolCall.input.userSidePrompt,
10873
- evaluate_previous_goal: toolCall.input.evaluate_previous_goal,
10874
- memory: toolCall.input.memory,
10875
- next_goal: toolCall.input.next_goal,
10876
10970
  toolCall: {
10877
10971
  id: toolCall.id,
10878
10972
  name: toolCall.name,
10879
10973
  input: toolCall.input.toolCall,
10880
10974
  },
10881
10975
  };
10976
+ if (!toolCall.input.toolCall) {
10977
+ logger.error("LLM returned a broken function call:", toolCall);
10978
+ }
10882
10979
  return result;
10883
10980
  }
10884
10981
  }
@@ -10989,6 +11086,7 @@ class WorkflowGenerator {
10989
11086
  catch (e) {
10990
11087
  logger.warn("an error occured when generating workflow:", e);
10991
11088
  logger.info(`retry...${retry_counter}`);
11089
+ await sleep(3000);
10992
11090
  retry_counter -= 1;
10993
11091
  }
10994
11092
  }
@@ -11063,44 +11161,23 @@ const workflowSchema = {
11063
11161
  type: "array",
11064
11162
  items: {
11065
11163
  type: "object",
11066
- required: ["id", "type", "action"],
11164
+ required: ["id", "action"],
11067
11165
  properties: {
11068
11166
  id: { type: "string" },
11069
- type: {
11070
- type: "string",
11071
- enum: ["action"], // only action nodes for now; reserved for future types like condition, loop, etc.
11072
- },
11073
- dependencies: {
11074
- type: "array",
11075
- items: { type: "string" },
11076
- },
11077
- output: {
11078
- type: "object",
11079
- properties: {
11080
- name: { type: "string" },
11081
- description: { type: "string" },
11082
- },
11083
- },
11084
11167
  action: {
11085
11168
  type: "object",
11086
- required: ["type", "name", "description"],
11169
+ required: ["name", "description"],
11087
11170
  properties: {
11088
- type: {
11171
+ name: { type: "string" },
11172
+ description: {
11089
11173
  type: "string",
11090
- // enum: ["prompt", "script", "hybrid"],
11091
- enum: ["prompt"],
11174
+ description: "Note that do not use \" mark.",
11092
11175
  },
11093
- name: { type: "string" },
11094
- description: { type: "string" },
11095
11176
  },
11096
11177
  },
11097
11178
  },
11098
11179
  },
11099
11180
  },
11100
- variables: {
11101
- type: "object",
11102
- additionalProperties: true,
11103
- },
11104
11181
  },
11105
11182
  };
11106
11183
 
@@ -11163,7 +11240,7 @@ class Eko {
11163
11240
  this.llmProvider = LLMProviderFactory.buildLLMProvider(llmConfig);
11164
11241
  this.ekoConfig = this.buildEkoConfig(ekoConfig);
11165
11242
  this.registerTools();
11166
- logger.info("using Eko@" + "a5c3c50087c75ad4abcf1d0dbb58aa4bf0227c13");
11243
+ logger.info("using Eko@" + "8aef68f294c16840224e6656e0a04a2b87b4ac96");
11167
11244
  logger.debug("caller's ekoConfig:", ekoConfig);
11168
11245
  }
11169
11246
  static getLogger() {
package/dist/index.esm.js CHANGED
@@ -1136,7 +1136,7 @@ let APIClient$1 = class APIClient {
1136
1136
  const maxRetries = options.maxRetries ?? this.maxRetries;
1137
1137
  timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);
1138
1138
  }
1139
- await sleep$1(timeoutMillis);
1139
+ await sleep$2(timeoutMillis);
1140
1140
  return this.makeRequest(options, retriesRemaining - 1);
1141
1141
  }
1142
1142
  calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {
@@ -1407,7 +1407,7 @@ const startsWithSchemeRegexp$1 = /^[a-z][a-z0-9+.-]*:/i;
1407
1407
  const isAbsoluteURL$1 = (url) => {
1408
1408
  return startsWithSchemeRegexp$1.test(url);
1409
1409
  };
1410
- const sleep$1 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1410
+ const sleep$2 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1411
1411
  const validatePositiveInteger$1 = (name, n) => {
1412
1412
  if (typeof n !== 'number' || !Number.isInteger(n)) {
1413
1413
  throw new AnthropicError(`${name} must be an integer`);
@@ -5098,7 +5098,7 @@ class APIClient {
5098
5098
  const maxRetries = options.maxRetries ?? this.maxRetries;
5099
5099
  timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);
5100
5100
  }
5101
- await sleep(timeoutMillis);
5101
+ await sleep$1(timeoutMillis);
5102
5102
  return this.makeRequest(options, retriesRemaining - 1);
5103
5103
  }
5104
5104
  calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries) {
@@ -5370,7 +5370,7 @@ const startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;
5370
5370
  const isAbsoluteURL = (url) => {
5371
5371
  return startsWithSchemeRegexp.test(url);
5372
5372
  };
5373
- const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
5373
+ const sleep$1 = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
5374
5374
  const validatePositiveInteger = (name, n) => {
5375
5375
  if (typeof n !== 'number' || !Number.isInteger(n)) {
5376
5376
  throw new OpenAIError(`${name} must be an integer`);
@@ -8052,7 +8052,7 @@ class Runs extends APIResource {
8052
8052
  }
8053
8053
  }
8054
8054
  }
8055
- await sleep(sleepInterval);
8055
+ await sleep$1(sleepInterval);
8056
8056
  break;
8057
8057
  //We return the run in any terminal state.
8058
8058
  case 'requires_action':
@@ -8281,7 +8281,7 @@ let Files$1 = class Files extends APIResource {
8281
8281
  const start = Date.now();
8282
8282
  let file = await this.retrieve(id);
8283
8283
  while (!file.status || !TERMINAL_STATES.has(file.status)) {
8284
- await sleep(pollInterval);
8284
+ await sleep$1(pollInterval);
8285
8285
  file = await this.retrieve(id);
8286
8286
  if (Date.now() - start > maxWait) {
8287
8287
  throw new APIConnectionTimeoutError({
@@ -9048,7 +9048,7 @@ class Files extends APIResource {
9048
9048
  }
9049
9049
  }
9050
9050
  }
9051
- await sleep(sleepInterval);
9051
+ await sleep$1(sleepInterval);
9052
9052
  break;
9053
9053
  case 'failed':
9054
9054
  case 'completed':
@@ -9165,7 +9165,7 @@ class FileBatches extends APIResource {
9165
9165
  }
9166
9166
  }
9167
9167
  }
9168
- await sleep(sleepInterval);
9168
+ await sleep$1(sleepInterval);
9169
9169
  break;
9170
9170
  case 'failed':
9171
9171
  case 'cancelled':
@@ -10234,6 +10234,84 @@ class WriteContextTool {
10234
10234
  }
10235
10235
  }
10236
10236
 
10237
+ class ContextComporessor {
10238
+ }
10239
+ class NoComporess extends ContextComporessor {
10240
+ comporess(messages) {
10241
+ logger.debug("ContextComporessor = NoComporess");
10242
+ let comporessed = JSON.parse(JSON.stringify(messages));
10243
+ logger.debug("comporessed:", comporessed);
10244
+ return comporessed;
10245
+ }
10246
+ }
10247
+ class SimpleQAComporess extends ContextComporessor {
10248
+ comporess(messages) {
10249
+ logger.debug("ContextComporessor = SimpleQAComporess");
10250
+ messages = JSON.parse(JSON.stringify(messages));
10251
+ let comporessed = [];
10252
+ const compress = (msg, idx) => {
10253
+ if (msg.role == "system") {
10254
+ return msg;
10255
+ }
10256
+ else if (msg.role == "assistant") {
10257
+ if (idx == messages.length - 2) {
10258
+ return msg;
10259
+ }
10260
+ else if (typeof msg.content == "string") {
10261
+ const nextMessage = messages[idx + 1];
10262
+ if (nextMessage.role == "assistant" && Array.isArray(nextMessage.content)) {
10263
+ return null;
10264
+ }
10265
+ else {
10266
+ return msg;
10267
+ }
10268
+ }
10269
+ else {
10270
+ const task = msg.content[0].input.userSidePrompt;
10271
+ const details = msg.content[0].input.thinking;
10272
+ return {
10273
+ "role": "assistant",
10274
+ "content": `<task>${task}</task><details>${details}</details>`,
10275
+ };
10276
+ }
10277
+ }
10278
+ else if (msg.role == "user" || typeof msg.content == "string") {
10279
+ if (idx == messages.length - 1 || idx == 1) {
10280
+ return msg;
10281
+ }
10282
+ else {
10283
+ let aiResponseMsg = messages[idx + 1];
10284
+ if (typeof aiResponseMsg.content == "string") {
10285
+ aiResponseMsg = messages[idx + 2];
10286
+ }
10287
+ const result = aiResponseMsg.content[0].input.observation;
10288
+ return {
10289
+ "role": "user",
10290
+ "content": `<result>${result}</result>`,
10291
+ };
10292
+ }
10293
+ }
10294
+ else {
10295
+ logger.warn("unknown message type, return null");
10296
+ return null;
10297
+ }
10298
+ };
10299
+ messages.forEach((msg, idx) => {
10300
+ logger.debug({ idx, msg });
10301
+ const compressedMsg = compress(msg, idx);
10302
+ logger.debug(compressedMsg);
10303
+ if (compressedMsg) {
10304
+ comporessed.push(compressedMsg);
10305
+ }
10306
+ });
10307
+ return comporessed;
10308
+ }
10309
+ }
10310
+
10311
+ function sleep(time) {
10312
+ return new Promise((resolve) => setTimeout(() => resolve(), time));
10313
+ }
10314
+
10237
10315
  // src/models/action.ts
10238
10316
  function createReturnTool(actionName, outputDescription, outputSchema) {
10239
10317
  return {
@@ -10279,7 +10357,7 @@ class ActionImpl {
10279
10357
  this.tools = tools;
10280
10358
  this.llmProvider = llmProvider;
10281
10359
  this.llmConfig = llmConfig;
10282
- this.maxRounds = 100; // Default max rounds
10360
+ this.maxRounds = 25; // Default max rounds
10283
10361
  this.toolResults = new Map();
10284
10362
  this.logger = new ExecutionLogger();
10285
10363
  this.tabs = [];
@@ -10296,6 +10374,7 @@ class ActionImpl {
10296
10374
  let roundMessages = [];
10297
10375
  let params_copy = JSON.parse(JSON.stringify(params));
10298
10376
  params_copy.tools = (_a = params_copy.tools) === null || _a === void 0 ? void 0 : _a.map(this.wrapToolInputSchema);
10377
+ let retry_counter = 3;
10299
10378
  while (!((_b = context.signal) === null || _b === void 0 ? void 0 : _b.aborted)) {
10300
10379
  roundMessages = [];
10301
10380
  hasToolUse = false;
@@ -10391,7 +10470,7 @@ class ActionImpl {
10391
10470
  // unwrap the toolCall
10392
10471
  let unwrapped = this.unwrapToolCall(toolCall);
10393
10472
  let input = unwrapped.toolCall.input;
10394
- logger.debug("unwrapped", unwrapped);
10473
+ logger.info("LLM Response:", unwrapped);
10395
10474
  if (unwrapped.thinking) {
10396
10475
  (_d = (_b = context.callback) === null || _b === void 0 ? void 0 : (_c = _b.hooks).onLlmMessage) === null || _d === void 0 ? void 0 : _d.call(_c, unwrapped.thinking);
10397
10476
  }
@@ -10495,11 +10574,43 @@ class ActionImpl {
10495
10574
  throw new Error('LLM provider not set');
10496
10575
  }
10497
10576
  try {
10498
- await this.llmProvider.generateStream(messages, params_copy, handler);
10577
+ let compressedMessages;
10578
+ try {
10579
+ const comporessor = new SimpleQAComporess();
10580
+ logger.debug("uncompressed messages:", messages);
10581
+ compressedMessages = comporessor.comporess(messages);
10582
+ }
10583
+ catch (e) {
10584
+ logger.error("an error occurs when comporess context, use NoComporess");
10585
+ logger.error(e);
10586
+ const comporessor = new NoComporess();
10587
+ compressedMessages = comporessor.comporess(messages);
10588
+ }
10589
+ logger.debug("compressed messages:", compressedMessages);
10590
+ await sleep(5000);
10591
+ try {
10592
+ await this.llmProvider.generateStream(compressedMessages, params_copy, handler);
10593
+ }
10594
+ catch (e) {
10595
+ logger.warn("LLM API raise an error, try to use NoComporess");
10596
+ const comporessor = new NoComporess();
10597
+ compressedMessages = comporessor.comporess(messages);
10598
+ logger.debug("compressed messages:", compressedMessages);
10599
+ await sleep(5000);
10600
+ await this.llmProvider.generateStream(compressedMessages, params_copy, handler);
10601
+ }
10499
10602
  }
10500
10603
  catch (e) {
10501
- logger.warn("an error occurs when LLM generate response, retry...", e);
10502
- continue;
10604
+ logger.warn(`an error occurs when LLM generate response, retry(n=${retry_counter})...`, e);
10605
+ await sleep(3000);
10606
+ retry_counter -= 1;
10607
+ if (retry_counter > 0) {
10608
+ continue;
10609
+ }
10610
+ else {
10611
+ logger.error("too many errors when calling LLM API in executing");
10612
+ throw e;
10613
+ }
10503
10614
  }
10504
10615
  // Wait for tool execution to complete if it was started
10505
10616
  if (toolExecutionPromise) {
@@ -10581,9 +10692,11 @@ class ActionImpl {
10581
10692
  toolMap.set(returnTool.name, returnTool);
10582
10693
  // get already existing tabs as task background
10583
10694
  const currentWindow = await context.ekoConfig.chromeProxy.windows.getCurrent();
10584
- const existingTabs = await context.ekoConfig.chromeProxy.tabs.query({
10695
+ let existingTabs = await context.ekoConfig.chromeProxy.tabs.query({
10585
10696
  windowId: currentWindow.id,
10586
10697
  });
10698
+ existingTabs = existingTabs.filter((tab) => { tab.title && tab.url; });
10699
+ logger.debug("existingTabs:", existingTabs);
10587
10700
  // get patchs for task
10588
10701
  let patchs = [];
10589
10702
  if (context.ekoConfig.patchServerUrl) {
@@ -10821,22 +10934,9 @@ Navigation Bar or Menu Changes: After logging in, the navigation bar will includ
10821
10934
  definition.input_schema = {
10822
10935
  type: "object",
10823
10936
  properties: {
10824
- // comment for backup
10825
- // observation: {
10826
- // "type": "string",
10827
- // "description": 'Your observation of the previous steps. Should start with "In the previous step, I\'ve ...".',
10828
- // },
10829
- evaluate_previous_goal: {
10830
- "type": "string",
10831
- "description": "Success|Failed|Unknown - Analyze the current elements and the image to check if the previous goals/actions are successful like intended by the task. Mention if something unexpected happened. Shortly state why/why not"
10832
- },
10833
- memory: {
10834
- "type": "string",
10835
- "description": "Description of what has been done and what you need to remember. Be very specific. Count here ALWAYS how many times you have done something and how many remain. E.g. 0 out of 10 websites analyzed. Continue with abc and xyz",
10836
- },
10837
- next_goal: {
10937
+ observation: {
10838
10938
  "type": "string",
10839
- "description": "What needs to be done with the next immediate action",
10939
+ "description": 'Your observation of the previous steps. Should start with "In the previous step, I\'ve ...".',
10840
10940
  },
10841
10941
  thinking: {
10842
10942
  "type": "string",
@@ -10850,12 +10950,9 @@ Navigation Bar or Menu Changes: After logging in, the navigation bar will includ
10850
10950
  },
10851
10951
  required: [
10852
10952
  // comment for backup
10853
- // "observation",
10953
+ "observation",
10854
10954
  "thinking",
10855
10955
  "userSidePrompt",
10856
- "memory",
10857
- "next_goal",
10858
- "evaluate_previous_goal",
10859
10956
  "toolCall",
10860
10957
  ],
10861
10958
  };
@@ -10866,15 +10963,15 @@ Navigation Bar or Menu Changes: After logging in, the navigation bar will includ
10866
10963
  observation: toolCall.input.observation,
10867
10964
  thinking: toolCall.input.thinking,
10868
10965
  userSidePrompt: toolCall.input.userSidePrompt,
10869
- evaluate_previous_goal: toolCall.input.evaluate_previous_goal,
10870
- memory: toolCall.input.memory,
10871
- next_goal: toolCall.input.next_goal,
10872
10966
  toolCall: {
10873
10967
  id: toolCall.id,
10874
10968
  name: toolCall.name,
10875
10969
  input: toolCall.input.toolCall,
10876
10970
  },
10877
10971
  };
10972
+ if (!toolCall.input.toolCall) {
10973
+ logger.error("LLM returned a broken function call:", toolCall);
10974
+ }
10878
10975
  return result;
10879
10976
  }
10880
10977
  }
@@ -10985,6 +11082,7 @@ class WorkflowGenerator {
10985
11082
  catch (e) {
10986
11083
  logger.warn("an error occured when generating workflow:", e);
10987
11084
  logger.info(`retry...${retry_counter}`);
11085
+ await sleep(3000);
10988
11086
  retry_counter -= 1;
10989
11087
  }
10990
11088
  }
@@ -11059,44 +11157,23 @@ const workflowSchema = {
11059
11157
  type: "array",
11060
11158
  items: {
11061
11159
  type: "object",
11062
- required: ["id", "type", "action"],
11160
+ required: ["id", "action"],
11063
11161
  properties: {
11064
11162
  id: { type: "string" },
11065
- type: {
11066
- type: "string",
11067
- enum: ["action"], // only action nodes for now; reserved for future types like condition, loop, etc.
11068
- },
11069
- dependencies: {
11070
- type: "array",
11071
- items: { type: "string" },
11072
- },
11073
- output: {
11074
- type: "object",
11075
- properties: {
11076
- name: { type: "string" },
11077
- description: { type: "string" },
11078
- },
11079
- },
11080
11163
  action: {
11081
11164
  type: "object",
11082
- required: ["type", "name", "description"],
11165
+ required: ["name", "description"],
11083
11166
  properties: {
11084
- type: {
11167
+ name: { type: "string" },
11168
+ description: {
11085
11169
  type: "string",
11086
- // enum: ["prompt", "script", "hybrid"],
11087
- enum: ["prompt"],
11170
+ description: "Note that do not use \" mark.",
11088
11171
  },
11089
- name: { type: "string" },
11090
- description: { type: "string" },
11091
11172
  },
11092
11173
  },
11093
11174
  },
11094
11175
  },
11095
11176
  },
11096
- variables: {
11097
- type: "object",
11098
- additionalProperties: true,
11099
- },
11100
11177
  },
11101
11178
  };
11102
11179
 
@@ -11159,7 +11236,7 @@ class Eko {
11159
11236
  this.llmProvider = LLMProviderFactory.buildLLMProvider(llmConfig);
11160
11237
  this.ekoConfig = this.buildEkoConfig(ekoConfig);
11161
11238
  this.registerTools();
11162
- logger.info("using Eko@" + "a5c3c50087c75ad4abcf1d0dbb58aa4bf0227c13");
11239
+ logger.info("using Eko@" + "8aef68f294c16840224e6656e0a04a2b87b4ac96");
11163
11240
  logger.debug("caller's ekoConfig:", ekoConfig);
11164
11241
  }
11165
11242
  static getLogger() {
@@ -24,49 +24,21 @@ export declare const workflowSchema: {
24
24
  id: {
25
25
  type: string;
26
26
  };
27
- type: {
28
- type: string;
29
- enum: string[];
30
- };
31
- dependencies: {
32
- type: string;
33
- items: {
34
- type: string;
35
- };
36
- };
37
- output: {
38
- type: string;
39
- properties: {
40
- name: {
41
- type: string;
42
- };
43
- description: {
44
- type: string;
45
- };
46
- };
47
- };
48
27
  action: {
49
28
  type: string;
50
29
  required: string[];
51
30
  properties: {
52
- type: {
53
- type: string;
54
- enum: string[];
55
- };
56
31
  name: {
57
32
  type: string;
58
33
  };
59
34
  description: {
60
35
  type: string;
36
+ description: string;
61
37
  };
62
38
  };
63
39
  };
64
40
  };
65
41
  };
66
42
  };
67
- variables: {
68
- type: string;
69
- additionalProperties: boolean;
70
- };
71
43
  };
72
44
  };
@@ -0,0 +1 @@
1
+ export declare function sleep(time: number): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eko-ai/eko",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "description": "Empowering language to transform human words into action.",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.js",