@eko-ai/eko 1.0.7 → 1.0.8

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.
@@ -40,6 +40,11 @@ chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
40
40
  sendResponse(result);
41
41
  break;
42
42
  }
43
+ case 'request_user_help': {
44
+ request_user_help(request.task_id, request.failure_type, request.failure_message);
45
+ sendResponse(true);
46
+ break;
47
+ }
43
48
  case 'computer:type': {
44
49
  sendResponse(type(request));
45
50
  break;
@@ -204,7 +209,7 @@ function scroll_to(request) {
204
209
  return false;
205
210
  }
206
211
  element.scrollIntoView({
207
- behavior: 'smooth'
212
+ behavior: 'smooth',
208
213
  });
209
214
  }
210
215
  else if (request.xpath) {
@@ -215,7 +220,7 @@ function scroll_to(request) {
215
220
  return false;
216
221
  }
217
222
  element.scrollIntoView({
218
- behavior: 'smooth'
223
+ behavior: 'smooth',
219
224
  });
220
225
  }
221
226
  else {
@@ -277,3 +282,125 @@ function select_dropdown_option(request) {
277
282
  selectedText: option.text.trim(),
278
283
  };
279
284
  }
285
+ function request_user_help(task_id, failure_type, failure_message) {
286
+ const domId = 'eko-request-user-help';
287
+ if (document.getElementById(domId)) {
288
+ return;
289
+ }
290
+ const failureTitleMap = {
291
+ login_required: 'Login Required',
292
+ captcha: 'Captcha Detected',
293
+ blocked: 'Blocked',
294
+ other: 'Error',
295
+ rate_limited: 'Rate Limited',
296
+ };
297
+ const notification = document.createElement('div');
298
+ notification.id = domId;
299
+ notification.style.cssText = `
300
+ position: fixed;
301
+ top: 5px;
302
+ left: 18px;
303
+ z-index: 9999;
304
+ background-color: #FEF0ED;
305
+ color: white;
306
+ padding: 16px;
307
+ border-radius: 12px;
308
+ border: 1px solid #FBB8A5;
309
+ font-family: Arial, sans-serif;
310
+ width: 350px;
311
+ display: flex;
312
+ flex-direction: row;
313
+ gap: 10px;
314
+ cursor: move;
315
+ user-select: none;
316
+ `;
317
+ let isDragging = false;
318
+ let xOffset = 0;
319
+ let yOffset = 0;
320
+ let initialX = 0;
321
+ let initialY = 0;
322
+ notification.addEventListener('mousedown', (e) => {
323
+ isDragging = true;
324
+ initialX = e.clientX - xOffset;
325
+ initialY = e.clientY - yOffset;
326
+ e.preventDefault();
327
+ });
328
+ document.addEventListener('mousemove', (e) => {
329
+ if (!isDragging)
330
+ return;
331
+ const currentX = e.clientX - initialX;
332
+ const currentY = e.clientY - initialY;
333
+ xOffset = currentX;
334
+ yOffset = currentY;
335
+ notification.style.transform = `translate(${xOffset}px, ${yOffset}px)`;
336
+ });
337
+ document.addEventListener('mouseup', () => {
338
+ isDragging = false;
339
+ });
340
+ const leftContainer = document.createElement('div');
341
+ leftContainer.style.cssText = `
342
+ width: 28px;
343
+ height: 28px;
344
+ display: flex;
345
+ flex-direction: column;
346
+ align-items: center;
347
+ border-radius: 99px;
348
+ background: #FDCCCC;
349
+ justify-content: center;
350
+ `;
351
+ leftContainer.innerHTML = ``;
352
+ const rightContainer = document.createElement('div');
353
+ rightContainer.style.cssText = `
354
+ flex: 1;
355
+ display: flex;
356
+ flex-direction: column;
357
+ `;
358
+ const title = document.createElement('div');
359
+ title.style.cssText = `
360
+ font-size: 16px;
361
+ font-weight: 700;
362
+ line-height: 22px;
363
+ color: #DD342D;
364
+ text-align: left;
365
+ `;
366
+ title.innerText = failureTitleMap[failure_type] || failure_type;
367
+ const message2 = document.createElement('div');
368
+ message2.style.cssText = `
369
+ font-size: 16px;
370
+ font-weight: 400;
371
+ line-height: 22px;
372
+ color: #DD342D;
373
+ text-align: left;
374
+ `;
375
+ message2.innerText = failure_message + '\nWhen you resolve the issue, click the button below.';
376
+ const buttonDiv = document.createElement('div');
377
+ buttonDiv.style.cssText = `
378
+ margin-top: 16px;
379
+ display: flex;
380
+ flex-direction: row-reverse;
381
+ justify-content: flex-start;
382
+ align-items: center;
383
+ `;
384
+ const resolvedBut = document.createElement('div');
385
+ resolvedBut.innerText = 'Resolved';
386
+ resolvedBut.style.cssText = `
387
+ border-radius: 8px;
388
+ background: #DD342D;
389
+ color: white;
390
+ padding: 10px;
391
+ border: none;
392
+ cursor: pointer;
393
+ `;
394
+ resolvedBut.onclick = () => {
395
+ chrome.runtime.sendMessage({ type: 'issue_resolved', task_id, failure_type }, () => {
396
+ notification.remove();
397
+ });
398
+ };
399
+ buttonDiv.appendChild(resolvedBut);
400
+ rightContainer.appendChild(title);
401
+ rightContainer.appendChild(message2);
402
+ rightContainer.appendChild(buttonDiv);
403
+ notification.appendChild(leftContainer);
404
+ notification.appendChild(rightContainer);
405
+ document.body.appendChild(notification);
406
+ }
package/dist/index.cjs.js CHANGED
@@ -313,6 +313,7 @@ class ActionImpl {
313
313
  console.error('Stream Error:', error);
314
314
  },
315
315
  };
316
+ this.handleHistoryImageMessages(messages);
316
317
  // Wait for stream to complete
317
318
  await this.llmProvider.generateStream(messages, params, handler);
318
319
  // Wait for tool execution to complete if it was started
@@ -320,7 +321,7 @@ class ActionImpl {
320
321
  await toolExecutionPromise;
321
322
  }
322
323
  if (context.__abort) {
323
- throw new Error("Abort");
324
+ throw new Error('Abort');
324
325
  }
325
326
  // Add messages in the correct order after everything is complete
326
327
  if (assistantTextMessage) {
@@ -334,6 +335,37 @@ class ActionImpl {
334
335
  }
335
336
  return { response, hasToolUse, roundMessages };
336
337
  }
338
+ handleHistoryImageMessages(messages) {
339
+ // Remove all images of the historical tool call results, except for the last one.
340
+ let last_user = true;
341
+ for (let i = messages.length - 1; i >= 0; i--) {
342
+ const message = messages[i];
343
+ if (message.role === 'user') {
344
+ if (last_user) {
345
+ last_user = false;
346
+ continue;
347
+ }
348
+ if (message.content instanceof Array) {
349
+ let content = message.content;
350
+ for (let j = 0; j < content.length; j++) {
351
+ if (content[j].type === 'tool_result' && content[j].content instanceof Array) {
352
+ let tool_content = content[j].content;
353
+ if (tool_content.length > 0) {
354
+ for (let k = tool_content.length - 1; k >= 0; k--) {
355
+ if (tool_content[k].type === 'image') {
356
+ tool_content.splice(k, 1);
357
+ }
358
+ }
359
+ }
360
+ else if (tool_content[0].type === 'image') {
361
+ tool_content = [{ type: 'text', text: 'ok' }];
362
+ }
363
+ }
364
+ }
365
+ }
366
+ }
367
+ }
368
+ }
337
369
  async execute(input, context, outputSchema) {
338
370
  var _a;
339
371
  // Create return tool with output schema
@@ -8876,13 +8908,61 @@ class OpenaiProvider {
8876
8908
  content: content.text,
8877
8909
  });
8878
8910
  }
8879
- else if (content.type == 'tool_result') {
8911
+ else if (content.type == 'image') {
8880
8912
  _messages.push({
8881
- role: 'tool',
8882
- content: content.content,
8883
- tool_call_id: content.tool_call_id || content.tool_use_id,
8913
+ role: 'user',
8914
+ content: [
8915
+ {
8916
+ type: 'image_url',
8917
+ image_url: {
8918
+ url: `data:${content.source.media_type};base64,${content.source.data}`,
8919
+ },
8920
+ },
8921
+ ],
8884
8922
  });
8885
8923
  }
8924
+ else if (content.type == 'tool_result') {
8925
+ let _content = [];
8926
+ if (content.content == 'string') {
8927
+ _content.push({ type: 'text', text: content.content });
8928
+ }
8929
+ else {
8930
+ for (let k = 0; k < content.content.length; k++) {
8931
+ let item = content.content[k];
8932
+ if (item.type == 'text') {
8933
+ _content.push({ ...item });
8934
+ }
8935
+ else if (item.type == 'image') {
8936
+ _content.push({
8937
+ type: 'image_url',
8938
+ image_url: {
8939
+ url: `data:${item.source.media_type};base64,${item.source.data}`,
8940
+ },
8941
+ });
8942
+ }
8943
+ }
8944
+ }
8945
+ let hasImage = _content.filter((s) => s.type == 'image_url').length > 0;
8946
+ if (hasImage) {
8947
+ // OpenAI does not support images returned by the tool.
8948
+ _messages.push({
8949
+ role: 'tool',
8950
+ content: 'ok',
8951
+ tool_call_id: content.tool_call_id || content.tool_use_id,
8952
+ });
8953
+ _messages.push({
8954
+ role: 'user',
8955
+ content: _content,
8956
+ });
8957
+ }
8958
+ else {
8959
+ _messages.push({
8960
+ role: 'tool',
8961
+ content: _content,
8962
+ tool_call_id: content.tool_call_id || content.tool_use_id,
8963
+ });
8964
+ }
8965
+ }
8886
8966
  }
8887
8967
  }
8888
8968
  else {
package/dist/index.esm.js CHANGED
@@ -309,6 +309,7 @@ class ActionImpl {
309
309
  console.error('Stream Error:', error);
310
310
  },
311
311
  };
312
+ this.handleHistoryImageMessages(messages);
312
313
  // Wait for stream to complete
313
314
  await this.llmProvider.generateStream(messages, params, handler);
314
315
  // Wait for tool execution to complete if it was started
@@ -316,7 +317,7 @@ class ActionImpl {
316
317
  await toolExecutionPromise;
317
318
  }
318
319
  if (context.__abort) {
319
- throw new Error("Abort");
320
+ throw new Error('Abort');
320
321
  }
321
322
  // Add messages in the correct order after everything is complete
322
323
  if (assistantTextMessage) {
@@ -330,6 +331,37 @@ class ActionImpl {
330
331
  }
331
332
  return { response, hasToolUse, roundMessages };
332
333
  }
334
+ handleHistoryImageMessages(messages) {
335
+ // Remove all images of the historical tool call results, except for the last one.
336
+ let last_user = true;
337
+ for (let i = messages.length - 1; i >= 0; i--) {
338
+ const message = messages[i];
339
+ if (message.role === 'user') {
340
+ if (last_user) {
341
+ last_user = false;
342
+ continue;
343
+ }
344
+ if (message.content instanceof Array) {
345
+ let content = message.content;
346
+ for (let j = 0; j < content.length; j++) {
347
+ if (content[j].type === 'tool_result' && content[j].content instanceof Array) {
348
+ let tool_content = content[j].content;
349
+ if (tool_content.length > 0) {
350
+ for (let k = tool_content.length - 1; k >= 0; k--) {
351
+ if (tool_content[k].type === 'image') {
352
+ tool_content.splice(k, 1);
353
+ }
354
+ }
355
+ }
356
+ else if (tool_content[0].type === 'image') {
357
+ tool_content = [{ type: 'text', text: 'ok' }];
358
+ }
359
+ }
360
+ }
361
+ }
362
+ }
363
+ }
364
+ }
333
365
  async execute(input, context, outputSchema) {
334
366
  var _a;
335
367
  // Create return tool with output schema
@@ -8872,13 +8904,61 @@ class OpenaiProvider {
8872
8904
  content: content.text,
8873
8905
  });
8874
8906
  }
8875
- else if (content.type == 'tool_result') {
8907
+ else if (content.type == 'image') {
8876
8908
  _messages.push({
8877
- role: 'tool',
8878
- content: content.content,
8879
- tool_call_id: content.tool_call_id || content.tool_use_id,
8909
+ role: 'user',
8910
+ content: [
8911
+ {
8912
+ type: 'image_url',
8913
+ image_url: {
8914
+ url: `data:${content.source.media_type};base64,${content.source.data}`,
8915
+ },
8916
+ },
8917
+ ],
8880
8918
  });
8881
8919
  }
8920
+ else if (content.type == 'tool_result') {
8921
+ let _content = [];
8922
+ if (content.content == 'string') {
8923
+ _content.push({ type: 'text', text: content.content });
8924
+ }
8925
+ else {
8926
+ for (let k = 0; k < content.content.length; k++) {
8927
+ let item = content.content[k];
8928
+ if (item.type == 'text') {
8929
+ _content.push({ ...item });
8930
+ }
8931
+ else if (item.type == 'image') {
8932
+ _content.push({
8933
+ type: 'image_url',
8934
+ image_url: {
8935
+ url: `data:${item.source.media_type};base64,${item.source.data}`,
8936
+ },
8937
+ });
8938
+ }
8939
+ }
8940
+ }
8941
+ let hasImage = _content.filter((s) => s.type == 'image_url').length > 0;
8942
+ if (hasImage) {
8943
+ // OpenAI does not support images returned by the tool.
8944
+ _messages.push({
8945
+ role: 'tool',
8946
+ content: 'ok',
8947
+ tool_call_id: content.tool_call_id || content.tool_use_id,
8948
+ });
8949
+ _messages.push({
8950
+ role: 'user',
8951
+ content: _content,
8952
+ });
8953
+ }
8954
+ else {
8955
+ _messages.push({
8956
+ role: 'tool',
8957
+ content: _content,
8958
+ tool_call_id: content.tool_call_id || content.tool_use_id,
8959
+ });
8960
+ }
8961
+ }
8882
8962
  }
8883
8963
  }
8884
8964
  else {
@@ -14,6 +14,7 @@ export declare class ActionImpl implements Action {
14
14
  maxRounds?: number;
15
15
  });
16
16
  private executeSingleRound;
17
+ private handleHistoryImageMessages;
17
18
  execute(input: unknown, context: ExecutionContext, outputSchema?: unknown): Promise<unknown>;
18
19
  private formatSystemPrompt;
19
20
  private formatUserPrompt;
@@ -0,0 +1 @@
1
+ export function run_build_dom_tree(): void;
@@ -0,0 +1,28 @@
1
+ import { BrowserUseParam, BrowserUseResult } from '../../types/tools.types';
2
+ import { Tool, InputSchema, ExecutionContext } from '../../types/action.types';
3
+ /**
4
+ * Browser Use => `npx playwright install`
5
+ */
6
+ export declare class BrowserUse implements Tool<BrowserUseParam, BrowserUseResult> {
7
+ name: string;
8
+ description: string;
9
+ input_schema: InputSchema;
10
+ private browser;
11
+ private browser_context;
12
+ private current_page;
13
+ constructor();
14
+ /**
15
+ * browser
16
+ *
17
+ * @param {*} params { action: 'input_text', index: 1, text: 'string' }
18
+ * @returns > { success: true, image?: { type: 'base64', media_type: 'image/jpeg', data: '/9j...' }, text?: string }
19
+ */
20
+ execute(context: ExecutionContext, params: BrowserUseParam): Promise<BrowserUseResult>;
21
+ private open_url;
22
+ private injectScript;
23
+ private get_highlight_element;
24
+ private extractHtmlContent;
25
+ private get_dropdown_options;
26
+ private select_dropdown_option;
27
+ destroy(context: ExecutionContext): void;
28
+ }
@@ -1,3 +1,4 @@
1
1
  export { CommandExecute } from './command_execute';
2
2
  export { FileRead } from './file_read';
3
3
  export { FileWrite } from './file_write';
4
+ export { BrowserUse } from './browser_use';