browser-use 0.0.1 → 0.1.0

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 (200) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +761 -0
  3. package/dist/agent/cloud-events.d.ts +264 -0
  4. package/dist/agent/cloud-events.js +318 -0
  5. package/dist/agent/gif.d.ts +15 -0
  6. package/dist/agent/gif.js +215 -0
  7. package/dist/agent/index.d.ts +8 -0
  8. package/dist/agent/index.js +8 -0
  9. package/dist/agent/message-manager/service.d.ts +30 -0
  10. package/dist/agent/message-manager/service.js +208 -0
  11. package/dist/agent/message-manager/utils.d.ts +2 -0
  12. package/dist/agent/message-manager/utils.js +41 -0
  13. package/dist/agent/message-manager/views.d.ts +26 -0
  14. package/dist/agent/message-manager/views.js +73 -0
  15. package/dist/agent/prompts.d.ts +52 -0
  16. package/dist/agent/prompts.js +259 -0
  17. package/dist/agent/service.d.ts +290 -0
  18. package/dist/agent/service.js +2200 -0
  19. package/dist/agent/views.d.ts +741 -0
  20. package/dist/agent/views.js +537 -0
  21. package/dist/browser/browser.d.ts +7 -0
  22. package/dist/browser/browser.js +5 -0
  23. package/dist/browser/context.d.ts +8 -0
  24. package/dist/browser/context.js +4 -0
  25. package/dist/browser/dvd-screensaver.d.ts +101 -0
  26. package/dist/browser/dvd-screensaver.js +270 -0
  27. package/dist/browser/extensions.d.ts +63 -0
  28. package/dist/browser/extensions.js +359 -0
  29. package/dist/browser/index.d.ts +10 -0
  30. package/dist/browser/index.js +9 -0
  31. package/dist/browser/playwright-manager.d.ts +47 -0
  32. package/dist/browser/playwright-manager.js +146 -0
  33. package/dist/browser/profile.d.ts +196 -0
  34. package/dist/browser/profile.js +815 -0
  35. package/dist/browser/session.d.ts +505 -0
  36. package/dist/browser/session.js +3409 -0
  37. package/dist/browser/types.d.ts +1184 -0
  38. package/dist/browser/types.js +1 -0
  39. package/dist/browser/utils.d.ts +1 -0
  40. package/dist/browser/utils.js +19 -0
  41. package/dist/browser/views.d.ts +78 -0
  42. package/dist/browser/views.js +72 -0
  43. package/dist/cli.d.ts +2 -0
  44. package/dist/cli.js +44 -0
  45. package/dist/config.d.ts +108 -0
  46. package/dist/config.js +430 -0
  47. package/dist/controller/index.d.ts +3 -0
  48. package/dist/controller/index.js +3 -0
  49. package/dist/controller/registry/index.d.ts +2 -0
  50. package/dist/controller/registry/index.js +2 -0
  51. package/dist/controller/registry/service.d.ts +45 -0
  52. package/dist/controller/registry/service.js +184 -0
  53. package/dist/controller/registry/views.d.ts +55 -0
  54. package/dist/controller/registry/views.js +174 -0
  55. package/dist/controller/service.d.ts +49 -0
  56. package/dist/controller/service.js +1176 -0
  57. package/dist/controller/views.d.ts +241 -0
  58. package/dist/controller/views.js +88 -0
  59. package/dist/dom/clickable-element-processor/service.d.ts +11 -0
  60. package/dist/dom/clickable-element-processor/service.js +60 -0
  61. package/dist/dom/dom_tree/index.js +1400 -0
  62. package/dist/dom/history-tree-processor/service.d.ts +14 -0
  63. package/dist/dom/history-tree-processor/service.js +75 -0
  64. package/dist/dom/history-tree-processor/view.d.ts +54 -0
  65. package/dist/dom/history-tree-processor/view.js +56 -0
  66. package/dist/dom/playground/extraction.d.ts +19 -0
  67. package/dist/dom/playground/extraction.js +187 -0
  68. package/dist/dom/playground/process-dom.d.ts +1 -0
  69. package/dist/dom/playground/process-dom.js +5 -0
  70. package/dist/dom/playground/test-accessibility.d.ts +44 -0
  71. package/dist/dom/playground/test-accessibility.js +111 -0
  72. package/dist/dom/service.d.ts +19 -0
  73. package/dist/dom/service.js +227 -0
  74. package/dist/dom/utils.d.ts +1 -0
  75. package/dist/dom/utils.js +6 -0
  76. package/dist/dom/views.d.ts +61 -0
  77. package/dist/dom/views.js +247 -0
  78. package/dist/event-bus.d.ts +11 -0
  79. package/dist/event-bus.js +19 -0
  80. package/dist/exceptions.d.ts +10 -0
  81. package/dist/exceptions.js +22 -0
  82. package/dist/filesystem/file-system.d.ts +68 -0
  83. package/dist/filesystem/file-system.js +412 -0
  84. package/dist/filesystem/index.d.ts +1 -0
  85. package/dist/filesystem/index.js +1 -0
  86. package/dist/index.d.ts +31 -0
  87. package/dist/index.js +33 -0
  88. package/dist/integrations/gmail/actions.d.ts +12 -0
  89. package/dist/integrations/gmail/actions.js +113 -0
  90. package/dist/integrations/gmail/index.d.ts +2 -0
  91. package/dist/integrations/gmail/index.js +2 -0
  92. package/dist/integrations/gmail/service.d.ts +61 -0
  93. package/dist/integrations/gmail/service.js +260 -0
  94. package/dist/llm/anthropic/chat.d.ts +28 -0
  95. package/dist/llm/anthropic/chat.js +126 -0
  96. package/dist/llm/anthropic/index.d.ts +2 -0
  97. package/dist/llm/anthropic/index.js +2 -0
  98. package/dist/llm/anthropic/serializer.d.ts +68 -0
  99. package/dist/llm/anthropic/serializer.js +285 -0
  100. package/dist/llm/aws/chat-anthropic.d.ts +61 -0
  101. package/dist/llm/aws/chat-anthropic.js +176 -0
  102. package/dist/llm/aws/chat-bedrock.d.ts +15 -0
  103. package/dist/llm/aws/chat-bedrock.js +80 -0
  104. package/dist/llm/aws/index.d.ts +3 -0
  105. package/dist/llm/aws/index.js +3 -0
  106. package/dist/llm/aws/serializer.d.ts +5 -0
  107. package/dist/llm/aws/serializer.js +68 -0
  108. package/dist/llm/azure/chat.d.ts +15 -0
  109. package/dist/llm/azure/chat.js +83 -0
  110. package/dist/llm/azure/index.d.ts +1 -0
  111. package/dist/llm/azure/index.js +1 -0
  112. package/dist/llm/base.d.ts +16 -0
  113. package/dist/llm/base.js +1 -0
  114. package/dist/llm/deepseek/chat.d.ts +15 -0
  115. package/dist/llm/deepseek/chat.js +51 -0
  116. package/dist/llm/deepseek/index.d.ts +2 -0
  117. package/dist/llm/deepseek/index.js +2 -0
  118. package/dist/llm/deepseek/serializer.d.ts +6 -0
  119. package/dist/llm/deepseek/serializer.js +57 -0
  120. package/dist/llm/exceptions.d.ts +10 -0
  121. package/dist/llm/exceptions.js +18 -0
  122. package/dist/llm/google/chat.d.ts +20 -0
  123. package/dist/llm/google/chat.js +144 -0
  124. package/dist/llm/google/index.d.ts +2 -0
  125. package/dist/llm/google/index.js +2 -0
  126. package/dist/llm/google/serializer.d.ts +6 -0
  127. package/dist/llm/google/serializer.js +64 -0
  128. package/dist/llm/groq/chat.d.ts +15 -0
  129. package/dist/llm/groq/chat.js +52 -0
  130. package/dist/llm/groq/index.d.ts +3 -0
  131. package/dist/llm/groq/index.js +3 -0
  132. package/dist/llm/groq/parser.d.ts +32 -0
  133. package/dist/llm/groq/parser.js +189 -0
  134. package/dist/llm/groq/serializer.d.ts +6 -0
  135. package/dist/llm/groq/serializer.js +56 -0
  136. package/dist/llm/messages.d.ts +77 -0
  137. package/dist/llm/messages.js +157 -0
  138. package/dist/llm/ollama/chat.d.ts +15 -0
  139. package/dist/llm/ollama/chat.js +77 -0
  140. package/dist/llm/ollama/index.d.ts +2 -0
  141. package/dist/llm/ollama/index.js +2 -0
  142. package/dist/llm/ollama/serializer.d.ts +6 -0
  143. package/dist/llm/ollama/serializer.js +53 -0
  144. package/dist/llm/openai/chat.d.ts +38 -0
  145. package/dist/llm/openai/chat.js +174 -0
  146. package/dist/llm/openai/index.d.ts +3 -0
  147. package/dist/llm/openai/index.js +3 -0
  148. package/dist/llm/openai/like.d.ts +17 -0
  149. package/dist/llm/openai/like.js +19 -0
  150. package/dist/llm/openai/serializer.d.ts +6 -0
  151. package/dist/llm/openai/serializer.js +57 -0
  152. package/dist/llm/openrouter/chat.d.ts +15 -0
  153. package/dist/llm/openrouter/chat.js +74 -0
  154. package/dist/llm/openrouter/index.d.ts +2 -0
  155. package/dist/llm/openrouter/index.js +2 -0
  156. package/dist/llm/openrouter/serializer.d.ts +3 -0
  157. package/dist/llm/openrouter/serializer.js +3 -0
  158. package/dist/llm/schema.d.ts +6 -0
  159. package/dist/llm/schema.js +77 -0
  160. package/dist/llm/views.d.ts +15 -0
  161. package/dist/llm/views.js +12 -0
  162. package/dist/logging-config.d.ts +25 -0
  163. package/dist/logging-config.js +89 -0
  164. package/dist/mcp/client.d.ts +142 -0
  165. package/dist/mcp/client.js +638 -0
  166. package/dist/mcp/controller.d.ts +6 -0
  167. package/dist/mcp/controller.js +38 -0
  168. package/dist/mcp/index.d.ts +3 -0
  169. package/dist/mcp/index.js +3 -0
  170. package/dist/mcp/server.d.ts +134 -0
  171. package/dist/mcp/server.js +759 -0
  172. package/dist/observability-decorators.d.ts +158 -0
  173. package/dist/observability-decorators.js +286 -0
  174. package/dist/observability.d.ts +23 -0
  175. package/dist/observability.js +58 -0
  176. package/dist/screenshots/index.d.ts +1 -0
  177. package/dist/screenshots/index.js +1 -0
  178. package/dist/screenshots/service.d.ts +6 -0
  179. package/dist/screenshots/service.js +28 -0
  180. package/dist/sync/auth.d.ts +27 -0
  181. package/dist/sync/auth.js +205 -0
  182. package/dist/sync/index.d.ts +2 -0
  183. package/dist/sync/index.js +2 -0
  184. package/dist/sync/service.d.ts +21 -0
  185. package/dist/sync/service.js +146 -0
  186. package/dist/telemetry/index.d.ts +2 -0
  187. package/dist/telemetry/index.js +2 -0
  188. package/dist/telemetry/service.d.ts +12 -0
  189. package/dist/telemetry/service.js +85 -0
  190. package/dist/telemetry/views.d.ts +112 -0
  191. package/dist/telemetry/views.js +112 -0
  192. package/dist/tokens/index.d.ts +2 -0
  193. package/dist/tokens/index.js +2 -0
  194. package/dist/tokens/service.d.ts +35 -0
  195. package/dist/tokens/service.js +423 -0
  196. package/dist/tokens/views.d.ts +58 -0
  197. package/dist/tokens/views.js +1 -0
  198. package/dist/utils.d.ts +128 -0
  199. package/dist/utils.js +529 -0
  200. package/package.json +94 -5
@@ -0,0 +1,14 @@
1
+ import { DOMHistoryElement, HashedDomElement } from './view.js';
2
+ import { DOMElementNode } from '../views.js';
3
+ export declare class HistoryTreeProcessor {
4
+ static convert_dom_element_to_history_element(dom_element: DOMElementNode, css_selector?: string | null): DOMHistoryElement;
5
+ static find_history_element_in_tree(dom_history_element: DOMHistoryElement, tree: DOMElementNode): DOMElementNode | null;
6
+ static compare_history_element_and_dom_element(dom_history_element: DOMHistoryElement, dom_element: DOMElementNode): boolean;
7
+ static _hash_dom_history_element(dom_history_element: DOMHistoryElement): HashedDomElement;
8
+ static _hash_dom_element(dom_element: DOMElementNode): HashedDomElement;
9
+ static _get_parent_branch_path(dom_element: DOMElementNode): string[];
10
+ static _parent_branch_path_hash(parent_branch_path: string[]): string;
11
+ static _attributes_hash(attributes: Record<string, string>): string;
12
+ static _xpath_hash(xpath: string): string;
13
+ static _text_hash(dom_element: DOMElementNode): string;
14
+ }
@@ -0,0 +1,75 @@
1
+ import crypto from 'node:crypto';
2
+ import { DOMHistoryElement, HashedDomElement } from './view.js';
3
+ import { DOMElementNode } from '../views.js';
4
+ const sha256 = (value) => crypto.createHash('sha256').update(value).digest('hex');
5
+ export class HistoryTreeProcessor {
6
+ static convert_dom_element_to_history_element(dom_element, css_selector = null) {
7
+ const parent_branch_path = this._get_parent_branch_path(dom_element);
8
+ return new DOMHistoryElement(dom_element.tag_name, dom_element.xpath, dom_element.highlight_index ?? null, parent_branch_path, dom_element.attributes, dom_element.shadow_root, css_selector, dom_element.page_coordinates, dom_element.viewport_coordinates, dom_element.viewport_info);
9
+ }
10
+ static find_history_element_in_tree(dom_history_element, tree) {
11
+ const hashed = this._hash_dom_history_element(dom_history_element);
12
+ const process_node = (node) => {
13
+ if (node.highlight_index !== null && node.highlight_index !== undefined) {
14
+ const hashed_node = this._hash_dom_element(node);
15
+ if (hashed_node.equals(hashed)) {
16
+ return node;
17
+ }
18
+ }
19
+ for (const child of node.children) {
20
+ if (child instanceof DOMElementNode) {
21
+ const result = process_node(child);
22
+ if (result) {
23
+ return result;
24
+ }
25
+ }
26
+ }
27
+ return null;
28
+ };
29
+ return process_node(tree);
30
+ }
31
+ static compare_history_element_and_dom_element(dom_history_element, dom_element) {
32
+ const hashed_history = this._hash_dom_history_element(dom_history_element);
33
+ const hashed_dom = this._hash_dom_element(dom_element);
34
+ return hashed_history.equals(hashed_dom);
35
+ }
36
+ static _hash_dom_history_element(dom_history_element) {
37
+ const branch_path_hash = this._parent_branch_path_hash(dom_history_element.entire_parent_branch_path);
38
+ const attributes_hash = this._attributes_hash(dom_history_element.attributes);
39
+ const xpath_hash = this._xpath_hash(dom_history_element.xpath);
40
+ return new HashedDomElement(branch_path_hash, attributes_hash, xpath_hash);
41
+ }
42
+ static _hash_dom_element(dom_element) {
43
+ const parent_branch_path = this._get_parent_branch_path(dom_element);
44
+ const branch_path_hash = this._parent_branch_path_hash(parent_branch_path);
45
+ const attributes_hash = this._attributes_hash(dom_element.attributes);
46
+ const xpath_hash = this._xpath_hash(dom_element.xpath);
47
+ return new HashedDomElement(branch_path_hash, attributes_hash, xpath_hash);
48
+ }
49
+ static _get_parent_branch_path(dom_element) {
50
+ const parents = [];
51
+ let current = dom_element;
52
+ while (current && current.parent) {
53
+ parents.push(current);
54
+ current = current.parent;
55
+ }
56
+ parents.reverse();
57
+ return parents.map((parent) => parent.tag_name);
58
+ }
59
+ static _parent_branch_path_hash(parent_branch_path) {
60
+ return sha256(parent_branch_path.join('/'));
61
+ }
62
+ static _attributes_hash(attributes) {
63
+ const attributes_string = Object.entries(attributes)
64
+ .map(([key, value]) => `${key}=${value}`)
65
+ .join('');
66
+ return sha256(attributes_string);
67
+ }
68
+ static _xpath_hash(xpath) {
69
+ return sha256(xpath);
70
+ }
71
+ static _text_hash(dom_element) {
72
+ const text = dom_element.get_all_text_till_next_clickable_element();
73
+ return sha256(text);
74
+ }
75
+ }
@@ -0,0 +1,54 @@
1
+ export declare class HashedDomElement {
2
+ branch_path_hash: string;
3
+ attributes_hash: string;
4
+ xpath_hash: string;
5
+ constructor(branch_path_hash: string, attributes_hash: string, xpath_hash: string);
6
+ /**
7
+ * Check equality with another HashedDomElement
8
+ */
9
+ equals(other: HashedDomElement): boolean;
10
+ }
11
+ export interface Coordinates {
12
+ x: number;
13
+ y: number;
14
+ }
15
+ export interface CoordinateSet {
16
+ top_left: Coordinates;
17
+ top_right: Coordinates;
18
+ bottom_left: Coordinates;
19
+ bottom_right: Coordinates;
20
+ center: Coordinates;
21
+ width: number;
22
+ height: number;
23
+ }
24
+ export interface ViewportInfo {
25
+ scroll_x?: number | null;
26
+ scroll_y?: number | null;
27
+ width: number;
28
+ height: number;
29
+ }
30
+ export declare class DOMHistoryElement {
31
+ tag_name: string;
32
+ xpath: string;
33
+ highlight_index: number | null;
34
+ entire_parent_branch_path: string[];
35
+ attributes: Record<string, string>;
36
+ shadow_root: boolean;
37
+ css_selector: string | null;
38
+ page_coordinates: CoordinateSet | null;
39
+ viewport_coordinates: CoordinateSet | null;
40
+ viewport_info: ViewportInfo | null;
41
+ constructor(tag_name: string, xpath: string, highlight_index: number | null, entire_parent_branch_path: string[], attributes: Record<string, string>, shadow_root?: boolean, css_selector?: string | null, page_coordinates?: CoordinateSet | null, viewport_coordinates?: CoordinateSet | null, viewport_info?: ViewportInfo | null);
42
+ to_dict(): {
43
+ tag_name: string;
44
+ xpath: string;
45
+ highlight_index: number | null;
46
+ entire_parent_branch_path: string[];
47
+ attributes: Record<string, string>;
48
+ shadow_root: boolean;
49
+ css_selector: string | null;
50
+ page_coordinates: CoordinateSet | null;
51
+ viewport_coordinates: CoordinateSet | null;
52
+ viewport_info: ViewportInfo | null;
53
+ };
54
+ }
@@ -0,0 +1,56 @@
1
+ export class HashedDomElement {
2
+ branch_path_hash;
3
+ attributes_hash;
4
+ xpath_hash;
5
+ constructor(branch_path_hash, attributes_hash, xpath_hash) {
6
+ this.branch_path_hash = branch_path_hash;
7
+ this.attributes_hash = attributes_hash;
8
+ this.xpath_hash = xpath_hash;
9
+ }
10
+ /**
11
+ * Check equality with another HashedDomElement
12
+ */
13
+ equals(other) {
14
+ return (this.branch_path_hash === other.branch_path_hash &&
15
+ this.attributes_hash === other.attributes_hash &&
16
+ this.xpath_hash === other.xpath_hash);
17
+ }
18
+ }
19
+ export class DOMHistoryElement {
20
+ tag_name;
21
+ xpath;
22
+ highlight_index;
23
+ entire_parent_branch_path;
24
+ attributes;
25
+ shadow_root;
26
+ css_selector;
27
+ page_coordinates;
28
+ viewport_coordinates;
29
+ viewport_info;
30
+ constructor(tag_name, xpath, highlight_index, entire_parent_branch_path, attributes, shadow_root = false, css_selector = null, page_coordinates = null, viewport_coordinates = null, viewport_info = null) {
31
+ this.tag_name = tag_name;
32
+ this.xpath = xpath;
33
+ this.highlight_index = highlight_index;
34
+ this.entire_parent_branch_path = entire_parent_branch_path;
35
+ this.attributes = attributes;
36
+ this.shadow_root = shadow_root;
37
+ this.css_selector = css_selector;
38
+ this.page_coordinates = page_coordinates;
39
+ this.viewport_coordinates = viewport_coordinates;
40
+ this.viewport_info = viewport_info;
41
+ }
42
+ to_dict() {
43
+ return {
44
+ tag_name: this.tag_name,
45
+ xpath: this.xpath,
46
+ highlight_index: this.highlight_index,
47
+ entire_parent_branch_path: this.entire_parent_branch_path,
48
+ attributes: this.attributes,
49
+ shadow_root: this.shadow_root,
50
+ css_selector: this.css_selector,
51
+ page_coordinates: this.page_coordinates,
52
+ viewport_coordinates: this.viewport_coordinates,
53
+ viewport_info: this.viewport_info,
54
+ };
55
+ }
56
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Interactive DOM element testing tool.
3
+ *
4
+ * This playground allows you to:
5
+ * - Navigate to websites
6
+ * - Extract DOM state and clickable elements
7
+ * - Interactively click elements by index
8
+ * - Input text into elements
9
+ * - Copy element JSON to clipboard
10
+ * - Analyze token counts for LLM prompts
11
+ *
12
+ * Usage:
13
+ * - Enter an element index to click it
14
+ * - Enter 'index,text' to input text into an element
15
+ * - Enter 'c,index' to copy element JSON to clipboard
16
+ * - Enter 'q' to quit
17
+ */
18
+ declare function testFocusVsAllElements(): Promise<void>;
19
+ export { testFocusVsAllElements };
@@ -0,0 +1,187 @@
1
+ import * as fs from 'fs/promises';
2
+ import * as readline from 'readline';
3
+ import { promisify } from 'util';
4
+ import { BrowserProfile, BrowserSession } from '../../browser/index.js';
5
+ import { DomService } from '../service.js';
6
+ import { DEFAULT_INCLUDE_ATTRIBUTES } from '../views.js';
7
+ import { AgentMessagePrompt } from '../../agent/prompts.js';
8
+ import { FileSystem } from '../../filesystem/file-system.js';
9
+ const TIMEOUT = 60;
10
+ /**
11
+ * Interactive DOM element testing tool.
12
+ *
13
+ * This playground allows you to:
14
+ * - Navigate to websites
15
+ * - Extract DOM state and clickable elements
16
+ * - Interactively click elements by index
17
+ * - Input text into elements
18
+ * - Copy element JSON to clipboard
19
+ * - Analyze token counts for LLM prompts
20
+ *
21
+ * Usage:
22
+ * - Enter an element index to click it
23
+ * - Enter 'index,text' to input text into an element
24
+ * - Enter 'c,index' to copy element JSON to clipboard
25
+ * - Enter 'q' to quit
26
+ */
27
+ async function testFocusVsAllElements() {
28
+ const browserSession = new BrowserSession({
29
+ browser_profile: new BrowserProfile({
30
+ window_size: { width: 1100, height: 1000 },
31
+ disable_security: true,
32
+ wait_for_network_idle_page_load_time: 1,
33
+ headless: false,
34
+ }),
35
+ });
36
+ const websites = [
37
+ 'https://google.com',
38
+ 'https://www.ycombinator.com/companies',
39
+ 'https://kayak.com/flights',
40
+ 'https://docs.google.com/spreadsheets/d/1INaIcfpYXlMRWO__de61SHFCaqt1lfHlcvtXZPItlpI/edit',
41
+ 'https://www.zeiss.com/career/en/job-search.html?page=1',
42
+ 'https://www.mlb.com/yankees/stats/',
43
+ 'https://www.amazon.com/s?k=laptop&s=review-rank',
44
+ 'https://reddit.com',
45
+ 'https://codepen.io/geheimschriftstift/pen/mPLvQz',
46
+ 'https://www.google.com/search?q=google+hi',
47
+ 'https://amazon.com',
48
+ 'https://github.com',
49
+ ];
50
+ await browserSession.start();
51
+ const page = await browserSession.getCurrentPage();
52
+ if (!page) {
53
+ throw new Error('No page available');
54
+ }
55
+ const domService = new DomService(page);
56
+ const rl = readline.createInterface({
57
+ input: process.stdin,
58
+ output: process.stdout,
59
+ });
60
+ const question = promisify(rl.question).bind(rl);
61
+ for (const website of websites) {
62
+ await page.goto(website);
63
+ await new Promise((resolve) => setTimeout(resolve, 1000));
64
+ let lastClickedIndex = null;
65
+ while (true) {
66
+ try {
67
+ console.log(`\n${'='.repeat(50)}\nTesting ${website}\n${'='.repeat(50)}`);
68
+ console.log('\nGetting page state...');
69
+ const startTime = Date.now();
70
+ const allElementsState = await browserSession.get_state_summary(true);
71
+ const endTime = Date.now();
72
+ console.log(`get_state_summary took ${((endTime - startTime) / 1000).toFixed(2)} seconds`);
73
+ const selectorMap = allElementsState.selector_map;
74
+ const totalElements = Object.keys(selectorMap).length;
75
+ console.log(`Total number of elements: ${totalElements}`);
76
+ const prompt = new AgentMessagePrompt({
77
+ browser_state_summary: allElementsState,
78
+ file_system: new FileSystem('./tmp'),
79
+ include_attributes: DEFAULT_INCLUDE_ATTRIBUTES,
80
+ step_info: null,
81
+ });
82
+ const userMessage = prompt.get_user_message(false).text || '';
83
+ const textToSave = userMessage;
84
+ await fs.mkdir('./tmp', { recursive: true });
85
+ await fs.writeFile('./tmp/user_message.txt', textToSave, 'utf-8');
86
+ await fs.writeFile('./tmp/element_tree.json', JSON.stringify(allElementsState.element_tree.toJSON(), null, 0), 'utf-8');
87
+ try {
88
+ // Optional: tiktoken is not installed by default
89
+ // @ts-ignore - tiktoken is an optional dependency
90
+ const { encoding_for_model } = await import('tiktoken');
91
+ const encoding = encoding_for_model('gpt-4o');
92
+ const tokenCount = encoding.encode(textToSave).length;
93
+ console.log(`Token count: ${tokenCount}`);
94
+ }
95
+ catch (error) {
96
+ console.log('Could not calculate token count (tiktoken not installed):', error.message);
97
+ }
98
+ console.log('User message written to ./tmp/user_message.txt');
99
+ console.log('Element tree written to ./tmp/element_tree.json');
100
+ const answer = String(await question("Enter element index to click, 'index,text' to input, 'c,index' to copy element JSON, or 'q' to quit: "));
101
+ if (answer.toLowerCase().trim() === 'q') {
102
+ break;
103
+ }
104
+ try {
105
+ if (answer.toLowerCase().startsWith('c,')) {
106
+ const parts = answer.split(',', 2);
107
+ if (parts.length === 2) {
108
+ try {
109
+ const targetIndex = parseInt(parts[1].trim(), 10);
110
+ if (targetIndex in selectorMap) {
111
+ const elementNode = selectorMap[targetIndex];
112
+ const elementJson = JSON.stringify(elementNode.toJSON(), null, 2);
113
+ console.log(`Element ${targetIndex} JSON:`);
114
+ console.log(elementJson);
115
+ console.log(`\nElement: ${elementNode.tag_name}`);
116
+ }
117
+ else {
118
+ console.log(`Invalid index: ${targetIndex}`);
119
+ }
120
+ }
121
+ catch {
122
+ console.log(`Invalid index format: ${parts[1]}`);
123
+ }
124
+ }
125
+ else {
126
+ console.log("Invalid input format. Use 'c,index'.");
127
+ }
128
+ }
129
+ else if (answer.includes(',')) {
130
+ const parts = answer.split(',', 2);
131
+ if (parts.length === 2) {
132
+ try {
133
+ const targetIndex = parseInt(parts[0].trim(), 10);
134
+ const textToInput = parts[1];
135
+ if (targetIndex in selectorMap) {
136
+ const elementNode = selectorMap[targetIndex];
137
+ console.log(`Inputting text '${textToInput}' into element ${targetIndex}: ${elementNode.tag_name}`);
138
+ await browserSession._inputTextElementNode(elementNode, textToInput);
139
+ console.log('Input successful.');
140
+ }
141
+ else {
142
+ console.log(`Invalid index: ${targetIndex}`);
143
+ }
144
+ }
145
+ catch {
146
+ console.log(`Invalid index format: ${parts[0]}`);
147
+ }
148
+ }
149
+ else {
150
+ console.log("Invalid input format. Use 'index,text'.");
151
+ }
152
+ }
153
+ else {
154
+ try {
155
+ const clickedIndex = parseInt(answer, 10);
156
+ if (clickedIndex in selectorMap) {
157
+ const elementNode = selectorMap[clickedIndex];
158
+ console.log(`Clicking element ${clickedIndex}: ${elementNode.tag_name}`);
159
+ await browserSession._clickElementNode(elementNode);
160
+ console.log('Click successful.');
161
+ }
162
+ else {
163
+ console.log(`Invalid index: ${clickedIndex}`);
164
+ }
165
+ }
166
+ catch {
167
+ console.log(`Invalid input: '${answer}'. Enter an index, 'index,text', 'c,index', or 'q'.`);
168
+ }
169
+ }
170
+ }
171
+ catch (actionError) {
172
+ console.log(`Action failed: ${actionError.message}`);
173
+ }
174
+ }
175
+ catch (error) {
176
+ console.log(`Error in loop: ${error.message}`);
177
+ await new Promise((resolve) => setTimeout(resolve, 1000));
178
+ }
179
+ }
180
+ }
181
+ rl.close();
182
+ await browserSession.close();
183
+ }
184
+ if (require.main === module) {
185
+ testFocusVsAllElements().catch(console.error);
186
+ }
187
+ export { testFocusVsAllElements };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ async function main() {
2
+ console.log('Process DOM playground');
3
+ }
4
+ main();
5
+ export {};
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Accessibility Tree Playground for browser-use
3
+ *
4
+ * - Launches a browser and navigates to a target URL (default: amazon.com)
5
+ * - Extracts both the full and interesting-only accessibility trees using Playwright
6
+ * - Prints and saves both trees to JSON files
7
+ * - Recursively prints relevant info for each node (role, name, value, description, focusable, focused, checked, selected, disabled, children count)
8
+ * - Explains the difference between the accessibility tree and the DOM tree
9
+ * - Notes on React/Vue/SPA apps
10
+ * - Easy to modify for your own experiments
11
+ *
12
+ * Run with: npx tsx src/dom/playground/test-accessibility.ts
13
+ */
14
+ type AXNode = {
15
+ role?: string;
16
+ name?: string;
17
+ value?: string | number;
18
+ description?: string;
19
+ focusable?: boolean;
20
+ focused?: boolean;
21
+ checked?: boolean | 'mixed';
22
+ selected?: boolean;
23
+ disabled?: boolean;
24
+ children?: AXNode[];
25
+ [key: string]: any;
26
+ };
27
+ /**
28
+ * Helper to recursively print relevant info from the accessibility tree
29
+ */
30
+ declare function printAxTree(node: AXNode | null, depth?: number): void;
31
+ /**
32
+ * Helper to print all available accessibility node attributes
33
+ * Prints all key-value pairs for each node (except 'children'), then recurses into children
34
+ */
35
+ declare function printAllFields(node: AXNode | null, depth?: number): void;
36
+ /**
37
+ * Flatten the accessibility tree into a list of "role name" strings
38
+ */
39
+ declare function flattenAxTree(node: AXNode | null, lines: string[]): void;
40
+ /**
41
+ * Get and analyze the accessibility tree for a given URL
42
+ */
43
+ declare function getAxTree(targetUrl: string): Promise<void>;
44
+ export { printAxTree, printAllFields, flattenAxTree, getAxTree };
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Accessibility Tree Playground for browser-use
3
+ *
4
+ * - Launches a browser and navigates to a target URL (default: amazon.com)
5
+ * - Extracts both the full and interesting-only accessibility trees using Playwright
6
+ * - Prints and saves both trees to JSON files
7
+ * - Recursively prints relevant info for each node (role, name, value, description, focusable, focused, checked, selected, disabled, children count)
8
+ * - Explains the difference between the accessibility tree and the DOM tree
9
+ * - Notes on React/Vue/SPA apps
10
+ * - Easy to modify for your own experiments
11
+ *
12
+ * Run with: npx tsx src/dom/playground/test-accessibility.ts
13
+ */
14
+ import { chromium } from 'playwright';
15
+ /**
16
+ * Helper to recursively print relevant info from the accessibility tree
17
+ */
18
+ function printAxTree(node, depth = 0) {
19
+ if (!node) {
20
+ return;
21
+ }
22
+ const indent = ' '.repeat(depth);
23
+ const info = [
24
+ `role=${JSON.stringify(node.role)}`,
25
+ node.name ? `name=${JSON.stringify(node.name)}` : null,
26
+ node.value !== undefined ? `value=${JSON.stringify(node.value)}` : null,
27
+ node.description ? `desc=${JSON.stringify(node.description)}` : null,
28
+ 'focusable' in node ? `focusable=${JSON.stringify(node.focusable)}` : null,
29
+ 'focused' in node ? `focused=${JSON.stringify(node.focused)}` : null,
30
+ 'checked' in node ? `checked=${JSON.stringify(node.checked)}` : null,
31
+ 'selected' in node ? `selected=${JSON.stringify(node.selected)}` : null,
32
+ 'disabled' in node ? `disabled=${JSON.stringify(node.disabled)}` : null,
33
+ node.children ? `children=${node.children.length}` : null,
34
+ ];
35
+ console.log('--------------------------------');
36
+ console.log(indent + info.filter((x) => x !== null).join(', '));
37
+ for (const child of node.children || []) {
38
+ printAxTree(child, depth + 1);
39
+ }
40
+ }
41
+ /**
42
+ * Helper to print all available accessibility node attributes
43
+ * Prints all key-value pairs for each node (except 'children'), then recurses into children
44
+ */
45
+ function printAllFields(node, depth = 0) {
46
+ if (!node) {
47
+ return;
48
+ }
49
+ const indent = ' '.repeat(depth);
50
+ for (const [k, v] of Object.entries(node)) {
51
+ if (k !== 'children') {
52
+ console.log(`${indent}${k}: ${JSON.stringify(v)}`);
53
+ }
54
+ }
55
+ if ('children' in node && node.children) {
56
+ console.log(`${indent}children: ${node.children.length}`);
57
+ for (const child of node.children) {
58
+ printAllFields(child, depth + 1);
59
+ }
60
+ }
61
+ }
62
+ /**
63
+ * Flatten the accessibility tree into a list of "role name" strings
64
+ */
65
+ function flattenAxTree(node, lines) {
66
+ if (!node) {
67
+ return;
68
+ }
69
+ const role = node.role || '';
70
+ const name = node.name || '';
71
+ lines.push(`${role} ${name}`);
72
+ for (const child of node.children || []) {
73
+ flattenAxTree(child, lines);
74
+ }
75
+ }
76
+ /**
77
+ * Get and analyze the accessibility tree for a given URL
78
+ */
79
+ async function getAxTree(targetUrl) {
80
+ const browser = await chromium.launch({ headless: true });
81
+ const page = await browser.newPage();
82
+ console.log(`Navigating to ${targetUrl}`);
83
+ await page.goto(targetUrl, { waitUntil: 'load' });
84
+ const axTreeInteresting = await page.accessibility.snapshot({
85
+ interestingOnly: true,
86
+ });
87
+ const lines = [];
88
+ flattenAxTree(axTreeInteresting, lines);
89
+ console.log(lines);
90
+ console.log(`length of ax_tree_interesting: ${lines.length}`);
91
+ await browser.close();
92
+ }
93
+ /**
94
+ * Main execution
95
+ */
96
+ async function main() {
97
+ const TARGET_URLS = [
98
+ // 'https://amazon.com/',
99
+ // 'https://www.google.com/',
100
+ // 'https://www.facebook.com/',
101
+ // 'https://platform.openai.com/tokenizer',
102
+ 'https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/input/checkbox',
103
+ ];
104
+ for (const url of TARGET_URLS) {
105
+ await getAxTree(url);
106
+ }
107
+ }
108
+ if (require.main === module) {
109
+ main().catch(console.error);
110
+ }
111
+ export { printAxTree, printAllFields, flattenAxTree, getAxTree };
@@ -0,0 +1,19 @@
1
+ import type { Page } from '../browser/types.js';
2
+ import { DOMState } from './views.js';
3
+ export declare class DomService {
4
+ private readonly page;
5
+ private readonly logger;
6
+ private readonly jsCode;
7
+ constructor(page: Page, logger?: import("../logging-config.js").Logger);
8
+ get_clickable_elements(highlight_elements?: boolean, focus_element?: number, viewport_expansion?: number): Promise<DOMState>;
9
+ get_cross_origin_iframes(): Promise<any>;
10
+ private _build_dom_tree;
11
+ private _construct_dom_tree;
12
+ private _parse_node;
13
+ private safeHostname;
14
+ private getFrames;
15
+ private getFrameUrl;
16
+ private isAdUrl;
17
+ private getPageUrl;
18
+ private isDebugEnabled;
19
+ }