@eko-ai/eko 1.0.1 → 1.0.3

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.
Files changed (44) hide show
  1. package/README.md +56 -44
  2. package/dist/core/eko.d.ts +1 -0
  3. package/dist/core/tool-registry.d.ts +1 -1
  4. package/dist/extension/content/index.d.ts +12 -4
  5. package/dist/extension/index.d.ts +0 -2
  6. package/dist/extension/script/build_dom_tree.d.ts +38 -0
  7. package/dist/extension/script/build_dom_tree.js +7 -3
  8. package/dist/extension/tools/browser.d.ts +8 -8
  9. package/dist/extension/tools/browser_use.d.ts +1 -0
  10. package/dist/extension/tools/html_script.d.ts +1 -12
  11. package/dist/extension/tools/index.d.ts +1 -2
  12. package/dist/extension.cjs.js +171 -346
  13. package/dist/extension.esm.js +172 -346
  14. package/dist/extension_content_script.js +105 -76
  15. package/dist/index.cjs.js +59 -49
  16. package/dist/index.esm.js +59 -49
  17. package/dist/models/action.d.ts +3 -2
  18. package/dist/nodejs/core.d.ts +2 -0
  19. package/dist/nodejs/index.d.ts +1 -0
  20. package/dist/nodejs/tools/command_execute.d.ts +12 -0
  21. package/dist/nodejs/tools/file_read.d.ts +11 -0
  22. package/dist/nodejs/tools/file_write.d.ts +15 -0
  23. package/dist/nodejs/tools/index.d.ts +3 -1
  24. package/dist/nodejs.cjs.js +227 -3
  25. package/dist/nodejs.esm.js +226 -3
  26. package/dist/schemas/workflow.schema.d.ts +3 -0
  27. package/dist/services/llm/claude-provider.d.ts +1 -0
  28. package/dist/services/llm/openai-provider.d.ts +1 -0
  29. package/dist/types/action.types.d.ts +2 -0
  30. package/dist/web/core.d.ts +2 -0
  31. package/dist/web/index.d.ts +1 -0
  32. package/dist/web/script/build_dom_tree.d.ts +10 -0
  33. package/dist/web/tools/browser.d.ts +20 -0
  34. package/dist/web/tools/browser_use.d.ts +19 -0
  35. package/dist/web/tools/element_click.d.ts +12 -0
  36. package/dist/web/tools/export_file.d.ts +18 -0
  37. package/dist/web/tools/extract_content.d.ts +17 -0
  38. package/dist/web/tools/find_element_position.d.ts +12 -0
  39. package/dist/web/tools/html_script.d.ts +10 -0
  40. package/dist/web/tools/index.d.ts +7 -1
  41. package/dist/web/tools/screenshot.d.ts +18 -0
  42. package/dist/web.cjs.js +9377 -3
  43. package/dist/web.esm.js +9376 -3
  44. package/package.json +2 -1
@@ -40,10 +40,6 @@ chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
40
40
  sendResponse(result);
41
41
  break;
42
42
  }
43
- case 'computer:key': {
44
- sendResponse(key(request));
45
- break;
46
- }
47
43
  case 'computer:type': {
48
44
  sendResponse(type(request));
49
45
  break;
@@ -64,10 +60,6 @@ chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
64
60
  sendResponse(simulateMouseEvent(request, ['mousedown', 'mouseup', 'click', 'mousedown', 'mouseup', 'click', 'dblclick'], 0));
65
61
  break;
66
62
  }
67
- case 'computer:left_click_drag': {
68
- sendResponse(left_click_drag(request));
69
- break;
70
- }
71
63
  case 'computer:scroll_to': {
72
64
  sendResponse(scroll_to(request));
73
65
  break;
@@ -76,6 +68,14 @@ chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
76
68
  sendResponse({ coordinate: [eko.lastMouseX, eko.lastMouseY] });
77
69
  break;
78
70
  }
71
+ case 'computer:get_dropdown_options': {
72
+ sendResponse(get_dropdown_options(request));
73
+ break;
74
+ }
75
+ case 'computer:select_dropdown_option': {
76
+ sendResponse(select_dropdown_option(request));
77
+ break;
78
+ }
79
79
  }
80
80
  }
81
81
  catch (e) {
@@ -85,30 +85,22 @@ chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
85
85
  })();
86
86
  return true;
87
87
  });
88
- function key(request) {
89
- const event = new KeyboardEvent(request.keyEventType || 'keydown', {
90
- key: request.key,
91
- ctrlKey: request.ctrlKey,
92
- altKey: request.altKey,
93
- shiftKey: request.shiftKey,
94
- metaKey: request.metaKey,
95
- bubbles: true,
96
- cancelable: true,
97
- });
98
- let coordinate = request.coordinate;
99
- let element = (document.activeElement ||
100
- document.elementFromPoint(coordinate[0], coordinate[1]));
101
- if (element && element.focus) {
102
- element.focus();
103
- }
104
- let result = element === null || element === void 0 ? void 0 : element.dispatchEvent(event);
105
- console.log('key', element, request, result);
106
- return result;
107
- }
108
88
  function type(request) {
109
89
  let text = request.text;
90
+ let enter = false;
91
+ if (text.endsWith('\\n')) {
92
+ enter = true;
93
+ text = text.substring(0, text.length - 2);
94
+ }
95
+ else if (text.endsWith('\n')) {
96
+ enter = true;
97
+ text = text.substring(0, text.length - 1);
98
+ }
110
99
  let element;
111
- if (request.xpath) {
100
+ if (request.highlightIndex != null) {
101
+ element = window.get_highlight_element(request.highlightIndex);
102
+ }
103
+ else if (request.xpath) {
112
104
  let xpath = request.xpath;
113
105
  let result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
114
106
  element = result.singleNodeValue;
@@ -118,7 +110,7 @@ function type(request) {
118
110
  element = document.elementFromPoint(coordinate[0], coordinate[1]) || document.activeElement;
119
111
  }
120
112
  if (!element) {
121
- return;
113
+ return false;
122
114
  }
123
115
  let input;
124
116
  if (element.tagName == 'INPUT' ||
@@ -137,8 +129,20 @@ function type(request) {
137
129
  input.value += text;
138
130
  }
139
131
  let result = input.dispatchEvent(new Event('input', { bubbles: true }));
132
+ if (enter) {
133
+ ['keydown', 'keypress', 'keyup'].forEach((eventType) => {
134
+ const event = new KeyboardEvent(eventType, {
135
+ key: 'Enter',
136
+ code: 'Enter',
137
+ keyCode: 13,
138
+ bubbles: true,
139
+ cancelable: true,
140
+ });
141
+ input.dispatchEvent(event);
142
+ });
143
+ }
140
144
  console.log('type', input, request, result);
141
- return result;
145
+ return true;
142
146
  }
143
147
  function mouse_move(request) {
144
148
  let coordinate = request.coordinate;
@@ -155,11 +159,14 @@ function mouse_move(request) {
155
159
  });
156
160
  let result = document.body.dispatchEvent(event);
157
161
  console.log('mouse_move', document.body, request, result);
158
- return result;
162
+ return true;
159
163
  }
160
164
  function simulateMouseEvent(request, eventTypes, button) {
161
165
  let element;
162
- if (request.xpath) {
166
+ if (request.highlightIndex != null) {
167
+ element = window.get_highlight_element(request.highlightIndex);
168
+ }
169
+ else if (request.xpath) {
163
170
  let xpath = request.xpath;
164
171
  let result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
165
172
  element = result.singleNodeValue;
@@ -168,9 +175,11 @@ function simulateMouseEvent(request, eventTypes, button) {
168
175
  let coordinate = request.coordinate;
169
176
  element = document.elementFromPoint(coordinate[0], coordinate[1]) || document.body;
170
177
  }
178
+ if (!element) {
179
+ return false;
180
+ }
171
181
  const x = undefined;
172
182
  const y = undefined;
173
- let result = false;
174
183
  for (let i = 0; i < eventTypes.length; i++) {
175
184
  const event = new MouseEvent(eventTypes[i], {
176
185
  view: window,
@@ -180,16 +189,28 @@ function simulateMouseEvent(request, eventTypes, button) {
180
189
  clientY: y,
181
190
  button, // 0 left; 2 right
182
191
  });
183
- result = element.dispatchEvent(event);
192
+ let result = element.dispatchEvent(event);
184
193
  console.log('simulateMouse', element, { ...request, eventTypes, button }, result);
185
194
  }
186
- return result;
195
+ return true;
187
196
  }
188
197
  function scroll_to(request) {
189
- if (request.xpath) {
198
+ if (request.highlightIndex != null) {
199
+ let element = window.get_highlight_element(request.highlightIndex);
200
+ if (!element) {
201
+ return false;
202
+ }
203
+ element.scrollIntoView({
204
+ behavior: 'smooth'
205
+ });
206
+ }
207
+ else if (request.xpath) {
190
208
  let xpath = request.xpath;
191
209
  let result = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
192
210
  let element = result.singleNodeValue;
211
+ if (!element) {
212
+ return false;
213
+ }
193
214
  element.scrollIntoView({
194
215
  behavior: 'smooth'
195
216
  });
@@ -203,45 +224,53 @@ function scroll_to(request) {
203
224
  });
204
225
  }
205
226
  console.log('scroll_to', request);
227
+ return true;
206
228
  }
207
- function left_click_drag(request, steps = 10) {
208
- const from_coordinate = request.from_coordinate;
209
- const to_coordinate = request.to_coordinate;
210
- let startX = from_coordinate[0];
211
- let startY = from_coordinate[1];
212
- let endX = to_coordinate[0];
213
- let endY = to_coordinate[1];
214
- let element = document.elementFromPoint(startX, startY) || document.body;
215
- const mouseDownEvent = new MouseEvent('mousedown', {
216
- bubbles: true,
217
- cancelable: true,
218
- view: window,
219
- clientX: startX,
220
- clientY: startY,
221
- button: 0,
222
- });
223
- element.dispatchEvent(mouseDownEvent);
224
- for (let i = 1; i <= steps; i++) {
225
- const intermediateX = startX + (endX - startX) * (i / steps);
226
- const intermediateY = startY + (endY - startY) * (i / steps);
227
- const dragEvent = new MouseEvent('mousemove', {
228
- bubbles: true,
229
- cancelable: true,
230
- view: window,
231
- clientX: intermediateX,
232
- clientY: intermediateY,
233
- button: 0,
234
- });
235
- element.dispatchEvent(dragEvent);
229
+ function get_dropdown_options(request) {
230
+ let select;
231
+ if (request.highlightIndex != null) {
232
+ select = window.get_highlight_element(request.highlightIndex);
236
233
  }
237
- const mouseUpEvent = new MouseEvent('mouseup', {
238
- bubbles: true,
239
- cancelable: true,
240
- view: window,
241
- clientX: endX,
242
- clientY: endY,
243
- button: 0,
244
- });
245
- console.log('left_click_drag', request);
246
- return element.dispatchEvent(mouseUpEvent);
234
+ else if (request.xpath) {
235
+ select = document.evaluate(request.xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
236
+ }
237
+ if (!select) {
238
+ return null;
239
+ }
240
+ return {
241
+ options: Array.from(select.options).map((opt) => ({
242
+ index: opt.index,
243
+ text: opt.text.trim(),
244
+ value: opt.value,
245
+ })),
246
+ id: select.id,
247
+ name: select.name,
248
+ };
249
+ }
250
+ function select_dropdown_option(request) {
251
+ let select;
252
+ if (request.highlightIndex != null) {
253
+ select = window.get_highlight_element(request.highlightIndex);
254
+ }
255
+ else if (request.xpath) {
256
+ select = document.evaluate(request.xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
257
+ }
258
+ if (!select || select.tagName.toUpperCase() !== 'SELECT') {
259
+ return { success: false, error: 'Select not found or invalid element type' };
260
+ }
261
+ const option = Array.from(select.options).find((opt) => opt.text.trim() === request.text);
262
+ if (!option) {
263
+ return {
264
+ success: false,
265
+ error: 'Option not found',
266
+ availableOptions: Array.from(select.options).map((o) => o.text.trim()),
267
+ };
268
+ }
269
+ select.value = option.value;
270
+ select.dispatchEvent(new Event('change'));
271
+ return {
272
+ success: true,
273
+ selectedValue: option.value,
274
+ selectedText: option.text.trim(),
275
+ };
247
276
  }
package/dist/index.cjs.js CHANGED
@@ -169,9 +169,10 @@ function createReturnTool(outputSchema) {
169
169
  }
170
170
  class ActionImpl {
171
171
  constructor(type, // Only support prompt type
172
- name, tools, llmProvider, llmConfig, config) {
172
+ name, description, tools, llmProvider, llmConfig, config) {
173
173
  this.type = type;
174
174
  this.name = name;
175
+ this.description = description;
175
176
  this.tools = tools;
176
177
  this.llmProvider = llmProvider;
177
178
  this.llmConfig = llmConfig;
@@ -195,7 +196,6 @@ class ActionImpl {
195
196
  const handler = {
196
197
  onContent: (content) => {
197
198
  if (content.trim()) {
198
- console.log('LLM:', content);
199
199
  assistantTextMessage += content;
200
200
  }
201
201
  },
@@ -313,12 +313,10 @@ class ActionImpl {
313
313
  (_a = context.tools) === null || _a === void 0 ? void 0 : _a.forEach((tool) => toolMap.set(tool.name, tool));
314
314
  toolMap.set(returnTool.name, returnTool);
315
315
  // Prepare initial messages
316
- const messages = input && Object.keys(input).length > 0
317
- ? [
318
- { role: 'system', content: this.formatSystemPrompt(context) },
319
- { role: 'user', content: this.formatUserPrompt(input) },
320
- ]
321
- : [{ role: 'user', content: this.formatSystemPrompt(context) }];
316
+ const messages = [
317
+ { role: 'system', content: this.formatSystemPrompt() },
318
+ { role: 'user', content: this.formatUserPrompt(context, input) },
319
+ ];
322
320
  console.log('Starting LLM conversation...');
323
321
  console.log('Initial messages:', messages);
324
322
  console.log('Output schema:', outputSchema);
@@ -343,6 +341,7 @@ class ActionImpl {
343
341
  if (!hasToolUse && response) {
344
342
  // LLM sent a message without using tools - request explicit return
345
343
  console.log('No tool use detected, requesting explicit return');
344
+ console.log('Response:', response);
346
345
  const returnOnlyParams = {
347
346
  ...params,
348
347
  tools: [
@@ -395,32 +394,30 @@ class ActionImpl {
395
394
  }
396
395
  return output;
397
396
  }
398
- formatSystemPrompt(context) {
397
+ formatSystemPrompt() {
398
+ return `You are a task executor. You need to complete the task specified by the user, using the tools provided. When you need to store results or outputs, use the write_context tool. When you are ready to return the final output, use the return_output tool.
399
+
400
+ Remember to:
401
+ 1. Use tools when needed to accomplish the task
402
+ 2. Store important results using write_context, including intermediate and final results
403
+ 3. Think step by step about what needs to be done`;
404
+ }
405
+ formatUserPrompt(context, input) {
399
406
  // Create a description of the current context
400
407
  const contextDescription = Array.from(context.variables.entries())
401
408
  .map(([key, value]) => `${key}: ${JSON.stringify(value)}`)
402
409
  .join('\n');
403
- return `You are executing the action "${this.name}". You have access to the following context:
404
-
405
- ${contextDescription || 'No context variables set'}
410
+ return `You are executing the action "${this.name}". The specific instructions are: "${this.description}". You have access to the following context:
406
411
 
407
- You can use the provided tools to accomplish your task. When you need to store results or outputs,
408
- use the write_context tool to save them to the workflow context.
412
+ ${contextDescription || 'No context variables set'}
409
413
 
410
- Remember to:
411
- 1. Use tools when needed to accomplish the task
412
- 2. Store important results using write_context
413
- 3. Think step by step about what needs to be done`;
414
- }
415
- formatUserPrompt(input) {
416
- if (typeof input === 'string') {
417
- return input;
418
- }
419
- return JSON.stringify(input, null, 2);
414
+ You have been provided with the following input:
415
+ ${(typeof input === 'string' ? input : JSON.stringify(input, null, 2)) || 'No additional input provided'}
416
+ `;
420
417
  }
421
418
  // Static factory method
422
- static createPromptAction(name, tools, llmProvider, llmConfig) {
423
- return new ActionImpl('prompt', name, tools, llmProvider, llmConfig);
419
+ static createPromptAction(name, description, tools, llmProvider, llmConfig) {
420
+ return new ActionImpl('prompt', name, description, tools, llmProvider, llmConfig);
424
421
  }
425
422
  }
426
423
 
@@ -444,7 +441,8 @@ Generate a complete workflow that:
444
441
  1. Only uses the tools listed above
445
442
  2. Properly sequences tool usage based on dependencies
446
443
  3. Ensures each action has appropriate input/output schemas
447
- 4. Creates a clear, logical flow to accomplish the user's goal`;
444
+ 4. Creates a clear, logical flow to accomplish the user's goal
445
+ 5. Includes detailed descriptions for each action, ensuring that the actions, when combined, is a complete solution to the user's problem`;
448
446
  },
449
447
  formatUserPrompt: (requirement) => `Create a workflow for the following requirement: ${requirement}`,
450
448
  };
@@ -564,7 +562,7 @@ class WorkflowGenerator {
564
562
  if (Array.isArray(data.nodes)) {
565
563
  data.nodes.forEach((nodeData) => {
566
564
  const tools = nodeData.action.tools.map((toolName) => this.toolRegistry.getTool(toolName));
567
- const action = ActionImpl.createPromptAction(nodeData.action.name, tools, this.llmProvider, { maxTokens: 1000 });
565
+ const action = ActionImpl.createPromptAction(nodeData.action.name, nodeData.action.description, tools, this.llmProvider, { maxTokens: 1000 });
568
566
  const node = {
569
567
  id: nodeData.id,
570
568
  name: nodeData.name || nodeData.id,
@@ -3286,16 +3284,21 @@ Anthropic.ModelInfosPage = ModelInfosPage;
3286
3284
  Anthropic.Beta = Beta$1;
3287
3285
 
3288
3286
  class ClaudeProvider {
3289
- constructor(apiKey, defaultModel, options) {
3287
+ constructor(param, defaultModel, options) {
3290
3288
  this.defaultModel = 'claude-3-5-sonnet-20241022';
3291
3289
  if (defaultModel) {
3292
3290
  this.defaultModel = defaultModel;
3293
3291
  }
3294
- this.client = new Anthropic({
3295
- apiKey: apiKey,
3296
- dangerouslyAllowBrowser: true,
3297
- ...options,
3298
- });
3292
+ if (typeof param == 'string') {
3293
+ this.client = new Anthropic({
3294
+ apiKey: param,
3295
+ dangerouslyAllowBrowser: true,
3296
+ ...options,
3297
+ });
3298
+ }
3299
+ else {
3300
+ this.client = new Anthropic(param);
3301
+ }
3299
3302
  }
3300
3303
  processResponse(response) {
3301
3304
  const toolCalls = response.content
@@ -3389,7 +3392,7 @@ class ClaudeProvider {
3389
3392
  const toolCall = {
3390
3393
  id: currentToolUse.id,
3391
3394
  name: currentToolUse.name,
3392
- input: JSON.parse(currentToolUse.accumulatedJson),
3395
+ input: JSON.parse(currentToolUse.accumulatedJson || '{}'),
3393
3396
  };
3394
3397
  (_d = handler.onToolUse) === null || _d === void 0 ? void 0 : _d.call(handler, toolCall);
3395
3398
  currentToolUse = null;
@@ -8688,16 +8691,21 @@ OpenAI.BatchesPage = BatchesPage;
8688
8691
  OpenAI.Uploads = Uploads;
8689
8692
 
8690
8693
  class OpenaiProvider {
8691
- constructor(apiKey, defaultModel, options) {
8694
+ constructor(param, defaultModel, options) {
8692
8695
  this.defaultModel = 'gpt-4o';
8693
8696
  if (defaultModel) {
8694
8697
  this.defaultModel = defaultModel;
8695
8698
  }
8696
- this.client = new OpenAI({
8697
- apiKey,
8698
- dangerouslyAllowBrowser: true,
8699
- ...options,
8700
- });
8699
+ if (typeof param == 'string') {
8700
+ this.client = new OpenAI({
8701
+ apiKey: param,
8702
+ dangerouslyAllowBrowser: true,
8703
+ ...options,
8704
+ });
8705
+ }
8706
+ else {
8707
+ this.client = new OpenAI(param);
8708
+ }
8701
8709
  }
8702
8710
  buildParams(messages, params, stream) {
8703
8711
  let tools = undefined;
@@ -8975,7 +8983,7 @@ const workflowSchema = {
8975
8983
  },
8976
8984
  action: {
8977
8985
  type: "object",
8978
- required: ["type", "name"],
8986
+ required: ["type", "name", "description"],
8979
8987
  properties: {
8980
8988
  type: {
8981
8989
  type: "string",
@@ -8983,6 +8991,7 @@ const workflowSchema = {
8983
8991
  enum: ["prompt"],
8984
8992
  },
8985
8993
  name: { type: "string" },
8994
+ description: { type: "string" },
8986
8995
  params: { type: "object" },
8987
8996
  tools: {
8988
8997
  type: "array",
@@ -9006,16 +9015,10 @@ class ToolRegistry {
9006
9015
  this.tools = new Map();
9007
9016
  }
9008
9017
  registerTool(tool) {
9009
- if (this.tools.has(tool.name)) {
9010
- throw new Error(`Tool with name ${tool.name} already registered`);
9011
- }
9012
9018
  this.tools.set(tool.name, tool);
9013
9019
  }
9014
9020
  unregisterTool(toolName) {
9015
- if (!this.tools.has(toolName)) {
9016
- throw new Error(`Tool with name ${toolName} not found`);
9017
- }
9018
- this.tools.delete(toolName);
9021
+ return this.tools.delete(toolName);
9019
9022
  }
9020
9023
  getTool(toolName) {
9021
9024
  const tool = this.tools.get(toolName);
@@ -9081,6 +9084,7 @@ class Eko {
9081
9084
  else {
9082
9085
  this.llmProvider = config;
9083
9086
  }
9087
+ Eko.tools.forEach((tool) => this.toolRegistry.registerTool(tool));
9084
9088
  }
9085
9089
  async generateWorkflow(prompt, param) {
9086
9090
  let toolRegistry = this.toolRegistry;
@@ -9107,6 +9111,9 @@ class Eko {
9107
9111
  if (this.toolRegistry.hasTools([toolName])) {
9108
9112
  tool = this.toolRegistry.getTool(toolName);
9109
9113
  }
9114
+ else if (Eko.tools.has(toolName)) {
9115
+ tool = Eko.tools.get(toolName);
9116
+ }
9110
9117
  else {
9111
9118
  throw new Error(`Tool with name ${toolName} not found`);
9112
9119
  }
@@ -9135,6 +9142,7 @@ class Eko {
9135
9142
  this.toolRegistry.unregisterTool(toolName);
9136
9143
  }
9137
9144
  }
9145
+ Eko.tools = new Map();
9138
9146
 
9139
9147
  class WorkflowParser {
9140
9148
  /**
@@ -9293,6 +9301,7 @@ class WorkflowParser {
9293
9301
  action: {
9294
9302
  type: nodeJson.action.type,
9295
9303
  name: nodeJson.action.name,
9304
+ description: nodeJson.action.description,
9296
9305
  tools: nodeJson.action.tools || [],
9297
9306
  execute: async (input, context) => {
9298
9307
  // Default implementation - should be overridden by specific action types
@@ -9323,6 +9332,7 @@ class WorkflowParser {
9323
9332
  action: {
9324
9333
  type: node.action.type,
9325
9334
  name: node.action.name,
9335
+ description: node.action.description,
9326
9336
  tools: node.action.tools,
9327
9337
  },
9328
9338
  })),