@eko-ai/eko 1.3.0 → 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.
@@ -1,10 +1,10 @@
1
- import { BrowserUseParam, BrowserUseResult } from '../../types/tools.types';
1
+ import { BrowserActionParam, BrowserActionResult } from '../../types/tools.types';
2
2
  import { InputSchema, ExecutionContext } from '../../types/action.types';
3
3
  import { ToolReturnsScreenshot } from './tool_returns_screenshot';
4
4
  /**
5
5
  * Browser Use for general
6
6
  */
7
- export declare class BrowserUse extends ToolReturnsScreenshot<BrowserUseParam> {
7
+ export declare class BrowserAction extends ToolReturnsScreenshot<BrowserActionParam> {
8
8
  name: string;
9
9
  description: string;
10
10
  input_schema: InputSchema;
@@ -15,6 +15,6 @@ export declare class BrowserUse extends ToolReturnsScreenshot<BrowserUseParam> {
15
15
  * @param {*} params { action: 'input_text', index: 1, text: 'string' }
16
16
  * @returns > { success: true, image?: { type: 'base64', media_type: 'image/jpeg', data: '/9j...' }, text?: string }
17
17
  */
18
- realExecute(context: ExecutionContext, params: BrowserUseParam): Promise<BrowserUseResult>;
18
+ realExecute(context: ExecutionContext, params: BrowserActionParam): Promise<BrowserActionResult>;
19
19
  destroy(context: ExecutionContext): void;
20
20
  }
@@ -1,4 +1,4 @@
1
- import { BrowserUse } from './browser_use';
1
+ import { BrowserAction } from './browser_action';
2
2
  import { ExportFile } from './export_file';
3
3
  import { ExtractContent } from './extract_content';
4
4
  import { GetAllTabs } from './get_all_tabs';
@@ -9,4 +9,4 @@ import { WebSearch } from './web_search';
9
9
  import { RequestLogin } from './request_login';
10
10
  import { SwitchTab } from './switch_tab';
11
11
  export * from '../../common/tools';
12
- export { BrowserUse, ExportFile, ExtractContent, OpenUrl, GetAllTabs, Screenshot, TabManagement, WebSearch, RequestLogin, SwitchTab, };
12
+ export { BrowserAction, ExportFile, ExtractContent, OpenUrl, GetAllTabs, Screenshot, TabManagement, WebSearch, RequestLogin, SwitchTab, };
@@ -1,8 +1,8 @@
1
- import { BrowserUseResult, ExecutionContext, InputSchema, Tool } from "@/types";
2
- export declare abstract class ToolReturnsScreenshot<T> implements Tool<T, BrowserUseResult> {
1
+ import { BrowserActionResult, ExecutionContext, InputSchema, Tool } from "@/types";
2
+ export declare abstract class ToolReturnsScreenshot<T> implements Tool<T, BrowserActionResult> {
3
3
  abstract name: string;
4
4
  abstract description: string;
5
5
  abstract input_schema: InputSchema;
6
6
  abstract realExecute(context: ExecutionContext, params: T): Promise<any>;
7
- execute(context: ExecutionContext, params: T): Promise<BrowserUseResult>;
7
+ execute(context: ExecutionContext, params: T): Promise<BrowserActionResult>;
8
8
  }
@@ -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);
@@ -1405,7 +1406,7 @@ class ToolReturnsScreenshot {
1405
1406
  logger.debug("debug realResult...");
1406
1407
  logger.debug(realResult);
1407
1408
  await sleep(3000); // wait for page loding
1408
- let instance = new BrowserUse();
1409
+ let instance = new BrowserAction();
1409
1410
  const image = await instance.realExecute(context, { action: "screenshot_extract_element" });
1410
1411
  return image;
1411
1412
  }
@@ -1414,10 +1415,10 @@ class ToolReturnsScreenshot {
1414
1415
  /**
1415
1416
  * Browser Use for general
1416
1417
  */
1417
- class BrowserUse extends ToolReturnsScreenshot {
1418
+ class BrowserAction extends ToolReturnsScreenshot {
1418
1419
  constructor() {
1419
1420
  super();
1420
- this.name = 'browser_use';
1421
+ this.name = 'browser_action';
1421
1422
  this.description = `Use structured commands to interact with the browser, manipulating page elements through screenshots and webpage element extraction.
1422
1423
  * This is a browser GUI interface where you need to analyze webpages by taking screenshots and extracting page element structures, and specify action sequences to complete designated tasks.
1423
1424
  * Before any operation, you must first call the \`screenshot_extract_element\` command, which will return the browser page screenshot and structured element information, both specially processed.
@@ -1481,7 +1482,7 @@ class BrowserUse extends ToolReturnsScreenshot {
1481
1482
  */
1482
1483
  async realExecute(context, params) {
1483
1484
  var _a;
1484
- logger.debug("debug 'browser_use'...");
1485
+ logger.debug("debug 'browser_action'...");
1485
1486
  logger.debug(params);
1486
1487
  try {
1487
1488
  if (params === null || !params.action) {
@@ -1606,7 +1607,7 @@ class BrowserUse extends ToolReturnsScreenshot {
1606
1607
  default:
1607
1608
  throw Error(`Invalid parameters. The "${params.action}" value is not included in the "action" enumeration.`);
1608
1609
  }
1609
- logger.debug(`execute 'browser_use'...done, result=${result}`);
1610
+ logger.debug(`execute 'browser_action'...done, result=${result}`);
1610
1611
  return result;
1611
1612
  }
1612
1613
  catch (e) {
@@ -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 = {
@@ -2755,7 +2756,7 @@ class DocumentAgentTool {
2755
2756
 
2756
2757
  var tools = /*#__PURE__*/Object.freeze({
2757
2758
  __proto__: null,
2758
- BrowserUse: BrowserUse,
2759
+ BrowserAction: BrowserAction,
2759
2760
  CancelWorkflow: CancelWorkflow,
2760
2761
  DocumentAgentTool: DocumentAgentTool,
2761
2762
  ExportFile: ExportFile,
@@ -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);
@@ -1403,7 +1404,7 @@ class ToolReturnsScreenshot {
1403
1404
  logger.debug("debug realResult...");
1404
1405
  logger.debug(realResult);
1405
1406
  await sleep(3000); // wait for page loding
1406
- let instance = new BrowserUse();
1407
+ let instance = new BrowserAction();
1407
1408
  const image = await instance.realExecute(context, { action: "screenshot_extract_element" });
1408
1409
  return image;
1409
1410
  }
@@ -1412,10 +1413,10 @@ class ToolReturnsScreenshot {
1412
1413
  /**
1413
1414
  * Browser Use for general
1414
1415
  */
1415
- class BrowserUse extends ToolReturnsScreenshot {
1416
+ class BrowserAction extends ToolReturnsScreenshot {
1416
1417
  constructor() {
1417
1418
  super();
1418
- this.name = 'browser_use';
1419
+ this.name = 'browser_action';
1419
1420
  this.description = `Use structured commands to interact with the browser, manipulating page elements through screenshots and webpage element extraction.
1420
1421
  * This is a browser GUI interface where you need to analyze webpages by taking screenshots and extracting page element structures, and specify action sequences to complete designated tasks.
1421
1422
  * Before any operation, you must first call the \`screenshot_extract_element\` command, which will return the browser page screenshot and structured element information, both specially processed.
@@ -1479,7 +1480,7 @@ class BrowserUse extends ToolReturnsScreenshot {
1479
1480
  */
1480
1481
  async realExecute(context, params) {
1481
1482
  var _a;
1482
- logger.debug("debug 'browser_use'...");
1483
+ logger.debug("debug 'browser_action'...");
1483
1484
  logger.debug(params);
1484
1485
  try {
1485
1486
  if (params === null || !params.action) {
@@ -1604,7 +1605,7 @@ class BrowserUse extends ToolReturnsScreenshot {
1604
1605
  default:
1605
1606
  throw Error(`Invalid parameters. The "${params.action}" value is not included in the "action" enumeration.`);
1606
1607
  }
1607
- logger.debug(`execute 'browser_use'...done, result=${result}`);
1608
+ logger.debug(`execute 'browser_action'...done, result=${result}`);
1608
1609
  return result;
1609
1610
  }
1610
1611
  catch (e) {
@@ -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 = {
@@ -2753,7 +2754,7 @@ class DocumentAgentTool {
2753
2754
 
2754
2755
  var tools = /*#__PURE__*/Object.freeze({
2755
2756
  __proto__: null,
2756
- BrowserUse: BrowserUse,
2757
+ BrowserAction: BrowserAction,
2757
2758
  CancelWorkflow: CancelWorkflow,
2758
2759
  DocumentAgentTool: DocumentAgentTool,
2759
2760
  ExportFile: ExportFile,
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;
@@ -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) {
@@ -10827,22 +10938,9 @@ Navigation Bar or Menu Changes: After logging in, the navigation bar will includ
10827
10938
  definition.input_schema = {
10828
10939
  type: "object",
10829
10940
  properties: {
10830
- // comment for backup
10831
- // observation: {
10832
- // "type": "string",
10833
- // "description": 'Your observation of the previous steps. Should start with "In the previous step, I\'ve ...".',
10834
- // },
10835
- evaluate_previous_goal: {
10836
- "type": "string",
10837
- "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"
10838
- },
10839
- memory: {
10941
+ observation: {
10840
10942
  "type": "string",
10841
- "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",
10842
- },
10843
- next_goal: {
10844
- "type": "string",
10845
- "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 ...".',
10846
10944
  },
10847
10945
  thinking: {
10848
10946
  "type": "string",
@@ -10856,12 +10954,9 @@ Navigation Bar or Menu Changes: After logging in, the navigation bar will includ
10856
10954
  },
10857
10955
  required: [
10858
10956
  // comment for backup
10859
- // "observation",
10957
+ "observation",
10860
10958
  "thinking",
10861
10959
  "userSidePrompt",
10862
- "memory",
10863
- "next_goal",
10864
- "evaluate_previous_goal",
10865
10960
  "toolCall",
10866
10961
  ],
10867
10962
  };
@@ -10872,15 +10967,15 @@ Navigation Bar or Menu Changes: After logging in, the navigation bar will includ
10872
10967
  observation: toolCall.input.observation,
10873
10968
  thinking: toolCall.input.thinking,
10874
10969
  userSidePrompt: toolCall.input.userSidePrompt,
10875
- evaluate_previous_goal: toolCall.input.evaluate_previous_goal,
10876
- memory: toolCall.input.memory,
10877
- next_goal: toolCall.input.next_goal,
10878
10970
  toolCall: {
10879
10971
  id: toolCall.id,
10880
10972
  name: toolCall.name,
10881
10973
  input: toolCall.input.toolCall,
10882
10974
  },
10883
10975
  };
10976
+ if (!toolCall.input.toolCall) {
10977
+ logger.error("LLM returned a broken function call:", toolCall);
10978
+ }
10884
10979
  return result;
10885
10980
  }
10886
10981
  }
@@ -10991,6 +11086,7 @@ class WorkflowGenerator {
10991
11086
  catch (e) {
10992
11087
  logger.warn("an error occured when generating workflow:", e);
10993
11088
  logger.info(`retry...${retry_counter}`);
11089
+ await sleep(3000);
10994
11090
  retry_counter -= 1;
10995
11091
  }
10996
11092
  }
@@ -11034,7 +11130,7 @@ class WorkflowGenerator {
11034
11130
  // Add nodes to workflow
11035
11131
  if (Array.isArray(data.nodes)) {
11036
11132
  data.nodes.forEach((nodeData) => {
11037
- const action = ActionImpl.createPromptAction(nodeData.action.name, nodeData.action.description, [this.toolRegistry.getTool('browser_use')], this.llmProvider, { maxTokens: 8192 });
11133
+ const action = ActionImpl.createPromptAction(nodeData.action.name, nodeData.action.description, [this.toolRegistry.getTool('browser_action')], this.llmProvider, { maxTokens: 8192 });
11038
11134
  const node = {
11039
11135
  id: nodeData.id,
11040
11136
  name: nodeData.name || nodeData.id,
@@ -11144,7 +11240,7 @@ class Eko {
11144
11240
  this.llmProvider = LLMProviderFactory.buildLLMProvider(llmConfig);
11145
11241
  this.ekoConfig = this.buildEkoConfig(ekoConfig);
11146
11242
  this.registerTools();
11147
- logger.info("using Eko@" + "416349eaa1535085d74b14170d4e0741756da46f");
11243
+ logger.info("using Eko@" + "8aef68f294c16840224e6656e0a04a2b87b4ac96");
11148
11244
  logger.debug("caller's ekoConfig:", ekoConfig);
11149
11245
  }
11150
11246
  static getLogger() {
@@ -11237,7 +11333,7 @@ class Eko {
11237
11333
  'name': prompt,
11238
11334
  'description': description,
11239
11335
  'tools': [
11240
- 'browser_use',
11336
+ 'browser_action',
11241
11337
  'document_agent',
11242
11338
  'export_file',
11243
11339
  'extract_content',
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;
@@ -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) {
@@ -10823,22 +10934,9 @@ Navigation Bar or Menu Changes: After logging in, the navigation bar will includ
10823
10934
  definition.input_schema = {
10824
10935
  type: "object",
10825
10936
  properties: {
10826
- // comment for backup
10827
- // observation: {
10828
- // "type": "string",
10829
- // "description": 'Your observation of the previous steps. Should start with "In the previous step, I\'ve ...".',
10830
- // },
10831
- evaluate_previous_goal: {
10832
- "type": "string",
10833
- "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"
10834
- },
10835
- memory: {
10937
+ observation: {
10836
10938
  "type": "string",
10837
- "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",
10838
- },
10839
- next_goal: {
10840
- "type": "string",
10841
- "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 ...".',
10842
10940
  },
10843
10941
  thinking: {
10844
10942
  "type": "string",
@@ -10852,12 +10950,9 @@ Navigation Bar or Menu Changes: After logging in, the navigation bar will includ
10852
10950
  },
10853
10951
  required: [
10854
10952
  // comment for backup
10855
- // "observation",
10953
+ "observation",
10856
10954
  "thinking",
10857
10955
  "userSidePrompt",
10858
- "memory",
10859
- "next_goal",
10860
- "evaluate_previous_goal",
10861
10956
  "toolCall",
10862
10957
  ],
10863
10958
  };
@@ -10868,15 +10963,15 @@ Navigation Bar or Menu Changes: After logging in, the navigation bar will includ
10868
10963
  observation: toolCall.input.observation,
10869
10964
  thinking: toolCall.input.thinking,
10870
10965
  userSidePrompt: toolCall.input.userSidePrompt,
10871
- evaluate_previous_goal: toolCall.input.evaluate_previous_goal,
10872
- memory: toolCall.input.memory,
10873
- next_goal: toolCall.input.next_goal,
10874
10966
  toolCall: {
10875
10967
  id: toolCall.id,
10876
10968
  name: toolCall.name,
10877
10969
  input: toolCall.input.toolCall,
10878
10970
  },
10879
10971
  };
10972
+ if (!toolCall.input.toolCall) {
10973
+ logger.error("LLM returned a broken function call:", toolCall);
10974
+ }
10880
10975
  return result;
10881
10976
  }
10882
10977
  }
@@ -10987,6 +11082,7 @@ class WorkflowGenerator {
10987
11082
  catch (e) {
10988
11083
  logger.warn("an error occured when generating workflow:", e);
10989
11084
  logger.info(`retry...${retry_counter}`);
11085
+ await sleep(3000);
10990
11086
  retry_counter -= 1;
10991
11087
  }
10992
11088
  }
@@ -11030,7 +11126,7 @@ class WorkflowGenerator {
11030
11126
  // Add nodes to workflow
11031
11127
  if (Array.isArray(data.nodes)) {
11032
11128
  data.nodes.forEach((nodeData) => {
11033
- const action = ActionImpl.createPromptAction(nodeData.action.name, nodeData.action.description, [this.toolRegistry.getTool('browser_use')], this.llmProvider, { maxTokens: 8192 });
11129
+ const action = ActionImpl.createPromptAction(nodeData.action.name, nodeData.action.description, [this.toolRegistry.getTool('browser_action')], this.llmProvider, { maxTokens: 8192 });
11034
11130
  const node = {
11035
11131
  id: nodeData.id,
11036
11132
  name: nodeData.name || nodeData.id,
@@ -11140,7 +11236,7 @@ class Eko {
11140
11236
  this.llmProvider = LLMProviderFactory.buildLLMProvider(llmConfig);
11141
11237
  this.ekoConfig = this.buildEkoConfig(ekoConfig);
11142
11238
  this.registerTools();
11143
- logger.info("using Eko@" + "416349eaa1535085d74b14170d4e0741756da46f");
11239
+ logger.info("using Eko@" + "8aef68f294c16840224e6656e0a04a2b87b4ac96");
11144
11240
  logger.debug("caller's ekoConfig:", ekoConfig);
11145
11241
  }
11146
11242
  static getLogger() {
@@ -11233,7 +11329,7 @@ class Eko {
11233
11329
  'name': prompt,
11234
11330
  'description': description,
11235
11331
  'tools': [
11236
- 'browser_use',
11332
+ 'browser_action',
11237
11333
  'document_agent',
11238
11334
  'export_file',
11239
11335
  'extract_content',
@@ -1,9 +1,9 @@
1
- import { BrowserUseParam, BrowserUseResult } from '../../types/tools.types';
1
+ import { BrowserActionParam, BrowserActionResult } from '../../types/tools.types';
2
2
  import { Tool, InputSchema, ExecutionContext } from '../../types/action.types';
3
3
  /**
4
4
  * Browser Use => `npx playwright install`
5
5
  */
6
- export declare class BrowserUse implements Tool<BrowserUseParam, BrowserUseResult> {
6
+ export declare class BrowserUse implements Tool<BrowserActionParam, BrowserActionResult> {
7
7
  name: string;
8
8
  description: string;
9
9
  input_schema: InputSchema;
@@ -17,7 +17,7 @@ export declare class BrowserUse implements Tool<BrowserUseParam, BrowserUseResul
17
17
  * @param {*} params { action: 'input_text', index: 1, text: 'string' }
18
18
  * @returns > { success: true, image?: { type: 'base64', media_type: 'image/jpeg', data: '/9j...' }, text?: string }
19
19
  */
20
- execute(context: ExecutionContext, params: BrowserUseParam): Promise<BrowserUseResult>;
20
+ execute(context: ExecutionContext, params: BrowserActionParam): Promise<BrowserActionResult>;
21
21
  private open_url;
22
22
  private injectScript;
23
23
  private get_highlight_element;
@@ -8,12 +8,12 @@ export interface ComputerUseResult {
8
8
  image?: ScreenshotImage;
9
9
  [key: string]: any;
10
10
  }
11
- export interface BrowserUseParam {
11
+ export interface BrowserActionParam {
12
12
  action: string;
13
13
  index?: number;
14
14
  text?: string;
15
15
  }
16
- export interface BrowserUseResult {
16
+ export interface BrowserActionResult {
17
17
  success: boolean;
18
18
  image?: ScreenshotImage;
19
19
  text?: string;
@@ -0,0 +1 @@
1
+ export declare function sleep(time: number): Promise<void>;
@@ -1,9 +1,9 @@
1
- import { BrowserUseParam, BrowserUseResult } from '../../types/tools.types';
1
+ import { BrowserActionParam, BrowserActionResult } from '../../types/tools.types';
2
2
  import { Tool, InputSchema, ExecutionContext } from '../../types/action.types';
3
3
  /**
4
4
  * Browser Use for general
5
5
  */
6
- export declare class BrowserUse implements Tool<BrowserUseParam, BrowserUseResult> {
6
+ export declare class BrowserUse implements Tool<BrowserActionParam, BrowserActionResult> {
7
7
  name: string;
8
8
  description: string;
9
9
  input_schema: InputSchema;
@@ -14,6 +14,6 @@ export declare class BrowserUse implements Tool<BrowserUseParam, BrowserUseResul
14
14
  * @param {*} params { action: 'input_text', index: 1, text: 'string' }
15
15
  * @returns > { success: true, image?: { type: 'base64', media_type: 'image/jpeg', data: '/9j...' }, text?: string }
16
16
  */
17
- execute(context: ExecutionContext, params: BrowserUseParam): Promise<BrowserUseResult>;
17
+ execute(context: ExecutionContext, params: BrowserActionParam): Promise<BrowserActionResult>;
18
18
  destroy(context: ExecutionContext): void;
19
19
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eko-ai/eko",
3
- "version": "1.3.0",
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",