@eko-ai/eko 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -44
- package/dist/core/eko.d.ts +1 -0
- package/dist/core/tool-registry.d.ts +1 -1
- package/dist/extension/script/build_dom_tree.d.ts +40 -0
- package/dist/extension/tools/index.d.ts +1 -2
- package/dist/extension.cjs.js +171 -190
- package/dist/extension.esm.js +171 -190
- package/dist/index.cjs.js +59 -49
- package/dist/index.esm.js +59 -49
- package/dist/models/action.d.ts +3 -2
- package/dist/nodejs/core.d.ts +2 -0
- package/dist/nodejs/index.d.ts +1 -0
- package/dist/nodejs/tools/command_execute.d.ts +12 -0
- package/dist/nodejs/tools/file_read.d.ts +11 -0
- package/dist/nodejs/tools/file_write.d.ts +15 -0
- package/dist/nodejs/tools/index.d.ts +3 -1
- package/dist/nodejs.cjs.js +227 -3
- package/dist/nodejs.esm.js +226 -3
- package/dist/schemas/workflow.schema.d.ts +3 -0
- package/dist/services/llm/claude-provider.d.ts +1 -0
- package/dist/services/llm/openai-provider.d.ts +1 -0
- package/dist/types/action.types.d.ts +1 -0
- package/dist/web/core.d.ts +2 -0
- package/dist/web/index.d.ts +3 -0
- package/dist/web/script/build_dom_tree.d.ts +12 -0
- package/dist/web/tools/browser.d.ts +10 -0
- package/dist/web/tools/browser_use.d.ts +18 -0
- package/dist/web/tools/element_click.d.ts +12 -0
- package/dist/web/tools/export_file.d.ts +18 -0
- package/dist/web/tools/extract_content.d.ts +17 -0
- package/dist/web/tools/find_element_position.d.ts +12 -0
- package/dist/web/tools/html_script.d.ts +21 -0
- package/dist/web/tools/index.d.ts +7 -1
- package/dist/web/tools/screenshot.d.ts +18 -0
- package/dist/web.cjs.js +9307 -3
- package/dist/web.esm.js +9305 -3
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,70 +1,82 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Eko
|
|
2
2
|
|
|
3
|
-
[](LICENSE)
|
|
3
|
+
[](LICENSE) [](https://example.com/build-status) [](https://example.com/version)
|
|
4
4
|
|
|
5
5
|
**Eko** is a revolutionary framework designed to empower developers and users alike to program their browser and operating system using natural language. With seamless integration of browser APIs, OS-level capabilities, and cutting-edge AI tools like Claude 3.5, Eko redefines how we interact with technology, making it intuitive, powerful, and accessible.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## Key Features
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
- **Natural Language Programming**: Transform human instructions into executable actions using advanced AI models
|
|
10
|
+
- **Cross-Platform Operation**: Run in browser extensions, web applications, or Node.js environments
|
|
11
|
+
- **Powerful Tooling**: Built-in tools for browser automation, OS operations, and system control
|
|
12
|
+
- **Flexible Integration**: Seamless integration with Claude 3.5 and other LLM models
|
|
13
|
+
- **Developer-Friendly**: Comprehensive TypeScript support and extensive documentation
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
2. [Features](#features)
|
|
13
|
-
3. [Installation](#installation)
|
|
14
|
-
4. [Usage](#usage)
|
|
15
|
-
5. [API Documentation](#api-documentation)
|
|
16
|
-
6. [Contributing](#contributing)
|
|
17
|
-
7. [License](#license)
|
|
15
|
+
## Quick Start
|
|
18
16
|
|
|
19
|
-
|
|
17
|
+
```bash
|
|
18
|
+
npm install @eko-ai/eko
|
|
19
|
+
```
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
```typescript
|
|
22
|
+
import { Eko } from '@eko-ai/eko';
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
const eko = new Eko({
|
|
25
|
+
apiKey: 'your_anthropic_api_key',
|
|
26
|
+
});
|
|
24
27
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
- **Eko** changes the paradigm of programming, shifting from developers telling computers how to do something to developers telling computers what to do and what goals to achieve.
|
|
28
|
+
// Example: Browser automation
|
|
29
|
+
await eko.run("Search for 'Eko framework' on Google and save the first result");
|
|
28
30
|
|
|
31
|
+
// Example: System operation
|
|
32
|
+
await eko.run("Create a new folder named 'reports' and move all PDF files there");
|
|
33
|
+
```
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
- **Language as Code**: Use natural language to write commands and create workflows.
|
|
32
|
-
- **Cross-Platform Integration**: Access browser and operating system APIs seamlessly.
|
|
33
|
-
- **AI-Powered**: Harness the capabilities of AI systems like Claude 3.5, OpenAI for advanced automation.
|
|
34
|
-
- **Developer-Friendly**: Simplify complex tasks with an intuitive and flexible framework.
|
|
35
|
+
## Use Cases
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
- Browser automation and web scraping
|
|
38
|
+
- System file and process management
|
|
39
|
+
- Workflow automation
|
|
40
|
+
- Data processing and organization
|
|
41
|
+
- GUI automation
|
|
42
|
+
- Multi-step task orchestration
|
|
37
43
|
|
|
38
|
-
##
|
|
44
|
+
## Documentation
|
|
39
45
|
|
|
40
|
-
|
|
41
|
-
- **Unified API Access**: A single interface for browser APIs, OS-level operations, and AI tools.
|
|
42
|
-
- **Event-Driven Automation**: Trigger workflows based on browser or system events.
|
|
43
|
-
- **Customizable Agents**: Build intelligent agents to perform repetitive or complex tasks.
|
|
44
|
-
- **AI Integration**: Leverage advanced AI models to understand and execute complex commands.
|
|
46
|
+
Visit our [documentation site](https://eko.fellou.ai/docs) for:
|
|
45
47
|
|
|
46
|
-
|
|
48
|
+
- Getting started guide
|
|
49
|
+
- API reference
|
|
50
|
+
- Usage examples
|
|
51
|
+
- Best practices
|
|
52
|
+
- Configuration options
|
|
47
53
|
|
|
48
|
-
##
|
|
54
|
+
## Development Environments
|
|
49
55
|
|
|
50
|
-
|
|
56
|
+
Eko can be used in multiple environments:
|
|
51
57
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
58
|
+
- Browser Extension
|
|
59
|
+
- Web Applications
|
|
60
|
+
- Node.js Applications
|
|
61
|
+
- [Fellou AI Browser](https://fellou.ai)
|
|
62
|
+
|
|
63
|
+
## Community and Support
|
|
64
|
+
|
|
65
|
+
- Report issues on [GitHub Issues](https://github.com/FellouAI/eko/issues)
|
|
66
|
+
- Contribute tools and improvements
|
|
67
|
+
- Share your use cases and feedback
|
|
68
|
+
- Join our community discussions
|
|
55
69
|
|
|
56
70
|
## Contributing
|
|
57
71
|
|
|
58
|
-
|
|
72
|
+
We welcome contributions! See our [Contributing Guide](CONTRIBUTING.md) for details on:
|
|
59
73
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
6. For detailed guidelines, see CONTRIBUTING.md.
|
|
74
|
+
- Setting up the development environment
|
|
75
|
+
- Code style guidelines
|
|
76
|
+
- Submission process
|
|
77
|
+
- Tool development
|
|
78
|
+
- Use case optimization
|
|
66
79
|
|
|
67
80
|
## License
|
|
68
|
-
This project is licensed under the MIT License.
|
|
69
81
|
|
|
70
|
-
|
|
82
|
+
Eko is released under the MIT License. See the [LICENSE](LICENSE) file for details.
|
package/dist/core/eko.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { ToolDefinition } from '../types/llm.types';
|
|
|
3
3
|
export declare class ToolRegistry {
|
|
4
4
|
private tools;
|
|
5
5
|
registerTool(tool: Tool<any, any>): void;
|
|
6
|
-
unregisterTool(toolName: string):
|
|
6
|
+
unregisterTool(toolName: string): boolean;
|
|
7
7
|
getTool(toolName: string): Tool<any, any>;
|
|
8
8
|
hasTools(toolNames: string[]): boolean;
|
|
9
9
|
getAllTools(): Tool<any, any>[];
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Get clickable elements on the page
|
|
3
|
+
*
|
|
4
|
+
* @param {*} doHighlightElements Is highlighted
|
|
5
|
+
* @param {*} includeAttributes [attr_names...]
|
|
6
|
+
* @returns { element_str, selector_map }
|
|
7
|
+
*/
|
|
8
|
+
declare function get_clickable_elements(doHighlightElements: any | undefined, includeAttributes: any): string;
|
|
9
|
+
/**
|
|
10
|
+
* Remove highlight
|
|
11
|
+
*/
|
|
12
|
+
declare function remove_highlight(): void;
|
|
13
|
+
declare function clickable_elements_to_string(element_tree: any, includeAttributes: any): string;
|
|
14
|
+
declare function create_selector_map(element_tree: any): {};
|
|
15
|
+
declare function parse_node(node_data: any, parent: any): {
|
|
16
|
+
tagName: any;
|
|
17
|
+
xpath: any;
|
|
18
|
+
highlightIndex: any;
|
|
19
|
+
attributes: any;
|
|
20
|
+
isVisible: any;
|
|
21
|
+
isInteractive: any;
|
|
22
|
+
isTopElement: any;
|
|
23
|
+
shadowRoot: any;
|
|
24
|
+
children: never[];
|
|
25
|
+
parent: any;
|
|
26
|
+
} | {
|
|
27
|
+
text: any;
|
|
28
|
+
isVisible: any;
|
|
29
|
+
parent: any;
|
|
30
|
+
} | undefined;
|
|
31
|
+
declare function build_dom_tree(doHighlightElements: any): {
|
|
32
|
+
tagName: any;
|
|
33
|
+
attributes: {};
|
|
34
|
+
xpath: string | null;
|
|
35
|
+
children: never[];
|
|
36
|
+
} | {
|
|
37
|
+
type: string;
|
|
38
|
+
text: any;
|
|
39
|
+
isVisible: boolean;
|
|
40
|
+
} | null;
|
|
@@ -3,9 +3,8 @@ import { ElementClick } from './element_click';
|
|
|
3
3
|
import { ExportFile } from './export_file';
|
|
4
4
|
import { ExtractContent } from './extract_content';
|
|
5
5
|
import { FindElementPosition } from './find_element_position';
|
|
6
|
-
import { FormAutofill } from './form_autofill';
|
|
7
6
|
import { OpenUrl } from './open_url';
|
|
8
7
|
import { Screenshot } from './screenshot';
|
|
9
8
|
import { TabManagement } from './tab_management';
|
|
10
9
|
import { WebSearch } from './web_search';
|
|
11
|
-
export { BrowserUse, ElementClick, ExportFile, ExtractContent, FindElementPosition,
|
|
10
|
+
export { BrowserUse, ElementClick, ExportFile, ExtractContent, FindElementPosition, OpenUrl, Screenshot, TabManagement, WebSearch, };
|
package/dist/extension.cjs.js
CHANGED
|
@@ -235,6 +235,177 @@ var utils = /*#__PURE__*/Object.freeze({
|
|
|
235
235
|
waitForTabComplete: waitForTabComplete
|
|
236
236
|
});
|
|
237
237
|
|
|
238
|
+
function exportFile(filename, type, content) {
|
|
239
|
+
const blob = new Blob([content], { type: type });
|
|
240
|
+
const link = document.createElement('a');
|
|
241
|
+
link.href = URL.createObjectURL(blob);
|
|
242
|
+
link.download = filename;
|
|
243
|
+
document.body.appendChild(link);
|
|
244
|
+
link.click();
|
|
245
|
+
document.body.removeChild(link);
|
|
246
|
+
URL.revokeObjectURL(link.href);
|
|
247
|
+
}
|
|
248
|
+
function getDropdownOptions(xpath) {
|
|
249
|
+
const select = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)
|
|
250
|
+
.singleNodeValue;
|
|
251
|
+
if (!select) {
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
options: Array.from(select.options).map((opt) => ({
|
|
256
|
+
index: opt.index,
|
|
257
|
+
text: opt.text.trim(),
|
|
258
|
+
value: opt.value,
|
|
259
|
+
})),
|
|
260
|
+
id: select.id,
|
|
261
|
+
name: select.name,
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function selectDropdownOption(xpath, text) {
|
|
265
|
+
const select = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)
|
|
266
|
+
.singleNodeValue;
|
|
267
|
+
if (!select || select.tagName.toUpperCase() !== 'SELECT') {
|
|
268
|
+
return { success: false, error: 'Select not found or invalid element type' };
|
|
269
|
+
}
|
|
270
|
+
const option = Array.from(select.options).find((opt) => opt.text.trim() === text);
|
|
271
|
+
if (!option) {
|
|
272
|
+
return {
|
|
273
|
+
success: false,
|
|
274
|
+
error: 'Option not found',
|
|
275
|
+
availableOptions: Array.from(select.options).map((o) => o.text.trim()),
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
select.value = option.value;
|
|
279
|
+
select.dispatchEvent(new Event('change'));
|
|
280
|
+
return {
|
|
281
|
+
success: true,
|
|
282
|
+
selectedValue: option.value,
|
|
283
|
+
selectedText: option.text.trim(),
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Extract the elements related to html operability and wrap them into pseudo-html code.
|
|
288
|
+
*/
|
|
289
|
+
function extractOperableElements() {
|
|
290
|
+
// visible
|
|
291
|
+
const isElementVisible = (element) => {
|
|
292
|
+
const style = window.getComputedStyle(element);
|
|
293
|
+
return (style.display !== 'none' &&
|
|
294
|
+
style.visibility !== 'hidden' &&
|
|
295
|
+
style.opacity !== '0' &&
|
|
296
|
+
element.offsetWidth > 0 &&
|
|
297
|
+
element.offsetHeight > 0);
|
|
298
|
+
};
|
|
299
|
+
// element original index
|
|
300
|
+
const getElementIndex = (element) => {
|
|
301
|
+
const xpath = document.evaluate('preceding::*', element, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
|
302
|
+
return xpath.snapshotLength;
|
|
303
|
+
};
|
|
304
|
+
// exclude
|
|
305
|
+
const addExclude = (excludes, children) => {
|
|
306
|
+
for (let i = 0; i < children.length; i++) {
|
|
307
|
+
excludes.push(children[i]);
|
|
308
|
+
if (children[i].children) {
|
|
309
|
+
addExclude(excludes, children[i].children);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
// { pseudoId: element }
|
|
314
|
+
let elementMap = {};
|
|
315
|
+
let nextId = 1;
|
|
316
|
+
let elements = [];
|
|
317
|
+
let excludes = [];
|
|
318
|
+
// operable element
|
|
319
|
+
const operableSelectors = 'a, button, input, textarea, select';
|
|
320
|
+
document.querySelectorAll(operableSelectors).forEach((element) => {
|
|
321
|
+
if (isElementVisible(element) && excludes.indexOf(element) == -1) {
|
|
322
|
+
const id = nextId++;
|
|
323
|
+
elementMap[id.toString()] = element;
|
|
324
|
+
const tagName = element.tagName.toLowerCase();
|
|
325
|
+
const attributes = Array.from(element.attributes)
|
|
326
|
+
.filter((attr) => ['id', 'name', 'type', 'value', 'href', 'title', 'placeholder'].includes(attr.name))
|
|
327
|
+
.map((attr) => `${attr.name == 'id' ? 'target' : attr.name}="${attr.value}"`)
|
|
328
|
+
.join(' ');
|
|
329
|
+
elements.push({
|
|
330
|
+
originalIndex: getElementIndex(element),
|
|
331
|
+
id: id,
|
|
332
|
+
html: `<${tagName} id="${id}" ${attributes}>${tagName == 'select' ? element.innerHTML : element.innerText || ''}</${tagName}>`,
|
|
333
|
+
});
|
|
334
|
+
addExclude(excludes, element.children);
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
// short text element
|
|
338
|
+
const textWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT, {
|
|
339
|
+
acceptNode: function (node) {
|
|
340
|
+
var _a;
|
|
341
|
+
if (node.matches(operableSelectors) || excludes.indexOf(node) != -1) {
|
|
342
|
+
// skip
|
|
343
|
+
return NodeFilter.FILTER_SKIP;
|
|
344
|
+
}
|
|
345
|
+
// text <= 100
|
|
346
|
+
const text = (_a = node.innerText) === null || _a === void 0 ? void 0 : _a.trim();
|
|
347
|
+
if (isElementVisible(node) &&
|
|
348
|
+
text &&
|
|
349
|
+
text.length <= 100 &&
|
|
350
|
+
text.length > 0 &&
|
|
351
|
+
node.children.length === 0) {
|
|
352
|
+
return NodeFilter.FILTER_ACCEPT;
|
|
353
|
+
}
|
|
354
|
+
// skip
|
|
355
|
+
return NodeFilter.FILTER_SKIP;
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
let currentNode;
|
|
359
|
+
while ((currentNode = textWalker.nextNode())) {
|
|
360
|
+
const id = nextId++;
|
|
361
|
+
elementMap[id.toString()] = currentNode;
|
|
362
|
+
const tagName = currentNode.tagName.toLowerCase();
|
|
363
|
+
elements.push({
|
|
364
|
+
originalIndex: getElementIndex(currentNode),
|
|
365
|
+
id: id,
|
|
366
|
+
html: `<${tagName} id="${id}">${currentNode.innerText.trim()}</${tagName}>`,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
// element sort
|
|
370
|
+
elements.sort((a, b) => a.originalIndex - b.originalIndex);
|
|
371
|
+
// cache
|
|
372
|
+
window.operableElementMap = elementMap;
|
|
373
|
+
// pseudo html
|
|
374
|
+
return elements.map((e) => e.html).join('\n');
|
|
375
|
+
}
|
|
376
|
+
function clickOperableElement(id) {
|
|
377
|
+
let element = window.operableElementMap[id];
|
|
378
|
+
if (!element) {
|
|
379
|
+
return false;
|
|
380
|
+
}
|
|
381
|
+
if (element.click) {
|
|
382
|
+
element.click();
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
element.dispatchEvent(new MouseEvent('click', {
|
|
386
|
+
view: window,
|
|
387
|
+
bubbles: true,
|
|
388
|
+
cancelable: true,
|
|
389
|
+
}));
|
|
390
|
+
}
|
|
391
|
+
return true;
|
|
392
|
+
}
|
|
393
|
+
function getOperableElementRect(id) {
|
|
394
|
+
let element = window.operableElementMap[id];
|
|
395
|
+
if (!element) {
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
const rect = element.getBoundingClientRect();
|
|
399
|
+
return {
|
|
400
|
+
left: rect.left + window.scrollX,
|
|
401
|
+
top: rect.top + window.scrollY,
|
|
402
|
+
right: rect.right + window.scrollX,
|
|
403
|
+
bottom: rect.bottom + window.scrollY,
|
|
404
|
+
width: rect.right - rect.left,
|
|
405
|
+
height: rect.bottom - rect.top,
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
|
|
238
409
|
async function key(tabId, key, coordinate) {
|
|
239
410
|
if (!coordinate) {
|
|
240
411
|
coordinate = (await cursor_position(tabId)).coordinate;
|
|
@@ -444,177 +615,6 @@ var browser = /*#__PURE__*/Object.freeze({
|
|
|
444
615
|
type_by_xpath: type_by_xpath
|
|
445
616
|
});
|
|
446
617
|
|
|
447
|
-
function exportFile(filename, type, content) {
|
|
448
|
-
const blob = new Blob([content], { type: type });
|
|
449
|
-
const link = document.createElement('a');
|
|
450
|
-
link.href = URL.createObjectURL(blob);
|
|
451
|
-
link.download = filename;
|
|
452
|
-
document.body.appendChild(link);
|
|
453
|
-
link.click();
|
|
454
|
-
document.body.removeChild(link);
|
|
455
|
-
URL.revokeObjectURL(link.href);
|
|
456
|
-
}
|
|
457
|
-
function getDropdownOptions(xpath) {
|
|
458
|
-
const select = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)
|
|
459
|
-
.singleNodeValue;
|
|
460
|
-
if (!select) {
|
|
461
|
-
return null;
|
|
462
|
-
}
|
|
463
|
-
return {
|
|
464
|
-
options: Array.from(select.options).map((opt) => ({
|
|
465
|
-
index: opt.index,
|
|
466
|
-
text: opt.text.trim(),
|
|
467
|
-
value: opt.value,
|
|
468
|
-
})),
|
|
469
|
-
id: select.id,
|
|
470
|
-
name: select.name,
|
|
471
|
-
};
|
|
472
|
-
}
|
|
473
|
-
function selectDropdownOption(xpath, text) {
|
|
474
|
-
const select = document.evaluate(xpath, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)
|
|
475
|
-
.singleNodeValue;
|
|
476
|
-
if (!select || select.tagName.toUpperCase() !== 'SELECT') {
|
|
477
|
-
return { success: false, error: 'Select not found or invalid element type' };
|
|
478
|
-
}
|
|
479
|
-
const option = Array.from(select.options).find((opt) => opt.text.trim() === text);
|
|
480
|
-
if (!option) {
|
|
481
|
-
return {
|
|
482
|
-
success: false,
|
|
483
|
-
error: 'Option not found',
|
|
484
|
-
availableOptions: Array.from(select.options).map((o) => o.text.trim()),
|
|
485
|
-
};
|
|
486
|
-
}
|
|
487
|
-
select.value = option.value;
|
|
488
|
-
select.dispatchEvent(new Event('change'));
|
|
489
|
-
return {
|
|
490
|
-
success: true,
|
|
491
|
-
selectedValue: option.value,
|
|
492
|
-
selectedText: option.text.trim(),
|
|
493
|
-
};
|
|
494
|
-
}
|
|
495
|
-
/**
|
|
496
|
-
* Extract the elements related to html operability and wrap them into pseudo-html code.
|
|
497
|
-
*/
|
|
498
|
-
function extractOperableElements() {
|
|
499
|
-
// visible
|
|
500
|
-
const isElementVisible = (element) => {
|
|
501
|
-
const style = window.getComputedStyle(element);
|
|
502
|
-
return (style.display !== 'none' &&
|
|
503
|
-
style.visibility !== 'hidden' &&
|
|
504
|
-
style.opacity !== '0' &&
|
|
505
|
-
element.offsetWidth > 0 &&
|
|
506
|
-
element.offsetHeight > 0);
|
|
507
|
-
};
|
|
508
|
-
// element original index
|
|
509
|
-
const getElementIndex = (element) => {
|
|
510
|
-
const xpath = document.evaluate('preceding::*', element, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
|
|
511
|
-
return xpath.snapshotLength;
|
|
512
|
-
};
|
|
513
|
-
// exclude
|
|
514
|
-
const addExclude = (excludes, children) => {
|
|
515
|
-
for (let i = 0; i < children.length; i++) {
|
|
516
|
-
excludes.push(children[i]);
|
|
517
|
-
if (children[i].children) {
|
|
518
|
-
addExclude(excludes, children[i].children);
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
};
|
|
522
|
-
// { pseudoId: element }
|
|
523
|
-
let elementMap = {};
|
|
524
|
-
let nextId = 1;
|
|
525
|
-
let elements = [];
|
|
526
|
-
let excludes = [];
|
|
527
|
-
// operable element
|
|
528
|
-
const operableSelectors = 'a, button, input, textarea, select';
|
|
529
|
-
document.querySelectorAll(operableSelectors).forEach((element) => {
|
|
530
|
-
if (isElementVisible(element) && excludes.indexOf(element) == -1) {
|
|
531
|
-
const id = nextId++;
|
|
532
|
-
elementMap[id.toString()] = element;
|
|
533
|
-
const tagName = element.tagName.toLowerCase();
|
|
534
|
-
const attributes = Array.from(element.attributes)
|
|
535
|
-
.filter((attr) => ['id', 'name', 'type', 'value', 'href', 'title', 'placeholder'].includes(attr.name))
|
|
536
|
-
.map((attr) => `${attr.name == 'id' ? 'target' : attr.name}="${attr.value}"`)
|
|
537
|
-
.join(' ');
|
|
538
|
-
elements.push({
|
|
539
|
-
originalIndex: getElementIndex(element),
|
|
540
|
-
id: id,
|
|
541
|
-
html: `<${tagName} id="${id}" ${attributes}>${tagName == 'select' ? element.innerHTML : element.innerText || ''}</${tagName}>`,
|
|
542
|
-
});
|
|
543
|
-
addExclude(excludes, element.children);
|
|
544
|
-
}
|
|
545
|
-
});
|
|
546
|
-
// short text element
|
|
547
|
-
const textWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT, {
|
|
548
|
-
acceptNode: function (node) {
|
|
549
|
-
var _a;
|
|
550
|
-
if (node.matches(operableSelectors) || excludes.indexOf(node) != -1) {
|
|
551
|
-
// skip
|
|
552
|
-
return NodeFilter.FILTER_SKIP;
|
|
553
|
-
}
|
|
554
|
-
// text <= 100
|
|
555
|
-
const text = (_a = node.innerText) === null || _a === void 0 ? void 0 : _a.trim();
|
|
556
|
-
if (isElementVisible(node) &&
|
|
557
|
-
text &&
|
|
558
|
-
text.length <= 100 &&
|
|
559
|
-
text.length > 0 &&
|
|
560
|
-
node.children.length === 0) {
|
|
561
|
-
return NodeFilter.FILTER_ACCEPT;
|
|
562
|
-
}
|
|
563
|
-
// skip
|
|
564
|
-
return NodeFilter.FILTER_SKIP;
|
|
565
|
-
},
|
|
566
|
-
});
|
|
567
|
-
let currentNode;
|
|
568
|
-
while ((currentNode = textWalker.nextNode())) {
|
|
569
|
-
const id = nextId++;
|
|
570
|
-
elementMap[id.toString()] = currentNode;
|
|
571
|
-
const tagName = currentNode.tagName.toLowerCase();
|
|
572
|
-
elements.push({
|
|
573
|
-
originalIndex: getElementIndex(currentNode),
|
|
574
|
-
id: id,
|
|
575
|
-
html: `<${tagName} id="${id}">${currentNode.innerText.trim()}</${tagName}>`,
|
|
576
|
-
});
|
|
577
|
-
}
|
|
578
|
-
// element sort
|
|
579
|
-
elements.sort((a, b) => a.originalIndex - b.originalIndex);
|
|
580
|
-
// cache
|
|
581
|
-
window.operableElementMap = elementMap;
|
|
582
|
-
// pseudo html
|
|
583
|
-
return elements.map((e) => e.html).join('\n');
|
|
584
|
-
}
|
|
585
|
-
function clickOperableElement(id) {
|
|
586
|
-
let element = window.operableElementMap[id];
|
|
587
|
-
if (!element) {
|
|
588
|
-
return false;
|
|
589
|
-
}
|
|
590
|
-
if (element.click) {
|
|
591
|
-
element.click();
|
|
592
|
-
}
|
|
593
|
-
else {
|
|
594
|
-
element.dispatchEvent(new MouseEvent('click', {
|
|
595
|
-
view: window,
|
|
596
|
-
bubbles: true,
|
|
597
|
-
cancelable: true,
|
|
598
|
-
}));
|
|
599
|
-
}
|
|
600
|
-
return true;
|
|
601
|
-
}
|
|
602
|
-
function getOperableElementRect(id) {
|
|
603
|
-
let element = window.operableElementMap[id];
|
|
604
|
-
if (!element) {
|
|
605
|
-
return null;
|
|
606
|
-
}
|
|
607
|
-
const rect = element.getBoundingClientRect();
|
|
608
|
-
return {
|
|
609
|
-
left: rect.left + window.scrollX,
|
|
610
|
-
top: rect.top + window.scrollY,
|
|
611
|
-
right: rect.right + window.scrollX,
|
|
612
|
-
bottom: rect.bottom + window.scrollY,
|
|
613
|
-
width: rect.right - rect.left,
|
|
614
|
-
height: rect.bottom - rect.top,
|
|
615
|
-
};
|
|
616
|
-
}
|
|
617
|
-
|
|
618
618
|
/**
|
|
619
619
|
* Browser Use for general
|
|
620
620
|
*/
|
|
@@ -1185,24 +1185,6 @@ async function executeWithBrowserUse(context, task_prompt) {
|
|
|
1185
1185
|
};
|
|
1186
1186
|
}
|
|
1187
1187
|
|
|
1188
|
-
/**
|
|
1189
|
-
* Form Autofill
|
|
1190
|
-
*/
|
|
1191
|
-
class FormAutofill {
|
|
1192
|
-
constructor() {
|
|
1193
|
-
this.name = 'form_autofill';
|
|
1194
|
-
this.description = 'Automatically fill in form data on web pages';
|
|
1195
|
-
this.input_schema = {
|
|
1196
|
-
type: 'object',
|
|
1197
|
-
properties: {}
|
|
1198
|
-
};
|
|
1199
|
-
}
|
|
1200
|
-
async execute(context, params) {
|
|
1201
|
-
// form -> input, textarea, select ...
|
|
1202
|
-
throw new Error('Not implemented');
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
|
-
|
|
1206
1188
|
/**
|
|
1207
1189
|
* Open Url
|
|
1208
1190
|
*/
|
|
@@ -1740,7 +1722,6 @@ var tools = /*#__PURE__*/Object.freeze({
|
|
|
1740
1722
|
ExportFile: ExportFile,
|
|
1741
1723
|
ExtractContent: ExtractContent,
|
|
1742
1724
|
FindElementPosition: FindElementPosition,
|
|
1743
|
-
FormAutofill: FormAutofill,
|
|
1744
1725
|
OpenUrl: OpenUrl,
|
|
1745
1726
|
Screenshot: Screenshot,
|
|
1746
1727
|
TabManagement: TabManagement,
|