@usecrow/client 0.1.24 → 0.1.26

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/dist/browser.d.ts CHANGED
@@ -1,52 +1,342 @@
1
- export { PageController } from '@page-agent/page-controller';
2
- import { e as ToolResult } from './browserUse-CZNpayEF.js';
3
- export { g as CrowBrowserUse } from './browserUse-CZNpayEF.js';
4
-
5
- /**
6
- * @usecrow/client/browser - Browser automation module with PageController
7
- *
8
- * This module statically imports @page-agent/page-controller, making it
9
- * suitable for bundled contexts (widget, webpack, vite) where the import
10
- * can be resolved at build time.
11
- *
12
- * Usage:
13
- * ```typescript
14
- * import { createBrowserUseTool, CrowBrowserUse } from '@usecrow/client/browser';
15
- *
16
- * // Option 1: Create a tool handler for registration
17
- * const browserUseTool = createBrowserUseTool({ productId, apiUrl });
18
- * client.registerTools({ browser_use: browserUseTool });
19
- *
20
- * // Option 2: Use CrowBrowserUse directly
21
- * const browserUse = new CrowBrowserUse({ productId, apiUrl });
22
- * await browserUse.execute('Click the login button');
23
- * ```
24
- */
25
-
26
- interface BrowserUseToolConfig {
27
- productId: string;
28
- apiUrl: string;
29
- }
30
- interface BrowserUseToolArgs {
31
- instruction: string;
32
- }
33
- /**
34
- * Create a browser_use tool handler for registration with CrowClient or widget.
35
- *
36
- * @param config - Configuration with productId and apiUrl
37
- * @returns Async function that executes browser automation tasks
38
- *
39
- * @example
40
- * ```typescript
41
- * // Widget usage
42
- * window.__crow_client_tools.browser_use = createBrowserUseTool({ productId, apiUrl });
43
- *
44
- * // SDK usage
45
- * client.registerTools({
46
- * browser_use: createBrowserUseTool({ productId, apiUrl })
47
- * });
48
- * ```
49
- */
50
- declare function createBrowserUseTool(config: BrowserUseToolConfig): (args: BrowserUseToolArgs | Record<string, unknown>) => Promise<ToolResult>;
51
-
52
- export { type BrowserUseToolArgs, type BrowserUseToolConfig, createBrowserUseTool };
1
+ declare interface ActionResult {
2
+ success: boolean;
3
+ message: string;
4
+ }
5
+
6
+ /**
7
+ * Structured browser state for LLM consumption
8
+ */
9
+ declare interface BrowserState {
10
+ url: string;
11
+ title: string;
12
+ /** Page info + scroll position hint (e.g. "Page info: 1920x1080px...\n[Start of page]") */
13
+ header: string;
14
+ /** Simplified HTML of interactive elements */
15
+ content: string;
16
+ /** Page footer hint (e.g. "... 300 pixels below ..." or "[End of page]") */
17
+ footer: string;
18
+ }
19
+
20
+ declare interface BrowserUseConfig {
21
+ productId: string;
22
+ apiUrl: string;
23
+ }
24
+
25
+ export declare interface BrowserUseToolArgs {
26
+ instruction: string;
27
+ }
28
+
29
+ export declare interface BrowserUseToolConfig {
30
+ productId: string;
31
+ apiUrl: string;
32
+ }
33
+
34
+ declare function cleanUpHighlights(): void;
35
+
36
+ /**
37
+ * Create a browser_use tool handler for registration with CrowClient or widget.
38
+ *
39
+ * @param config - Configuration with productId and apiUrl
40
+ * @returns Async function that executes browser automation tasks
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * // Widget usage
45
+ * window.__crow_client_tools.browser_use = createBrowserUseTool({ productId, apiUrl });
46
+ *
47
+ * // SDK usage
48
+ * client.registerTools({
49
+ * browser_use: createBrowserUseTool({ productId, apiUrl })
50
+ * });
51
+ * ```
52
+ */
53
+ export declare function createBrowserUseTool(config: BrowserUseToolConfig): (args: BrowserUseToolArgs | Record<string, unknown>) => Promise<ToolResult>;
54
+
55
+ export declare class CrowBrowserUse {
56
+ private config;
57
+ private pageController;
58
+ private sessionId;
59
+ private maxSteps;
60
+ constructor(config: BrowserUseConfig);
61
+ /**
62
+ * Initialize PageController with non-blocking pointer
63
+ */
64
+ private initPageController;
65
+ /**
66
+ * Execute a browser automation task
67
+ */
68
+ execute(task: string): Promise<ToolResult>;
69
+ /**
70
+ * Start a browser-use session on the server
71
+ */
72
+ private startSession;
73
+ /**
74
+ * Process a step on the server
75
+ */
76
+ private processStep;
77
+ /**
78
+ * Execute an action using PageController
79
+ */
80
+ private executeAction;
81
+ /**
82
+ * Cleanup resources
83
+ */
84
+ private cleanup;
85
+ /**
86
+ * Stop the current task
87
+ */
88
+ stop(): Promise<void>;
89
+ }
90
+
91
+ declare namespace dom {
92
+ export {
93
+ getFlatTree,
94
+ flatTreeToString,
95
+ getSelectorMap,
96
+ getElementTextMap,
97
+ cleanUpHighlights,
98
+ DomConfig,
99
+ getAllTextTillNextClickableElement
100
+ }
101
+ }
102
+
103
+ declare interface DomConfig {
104
+ interactiveBlacklist?: (Element | (() => Element))[];
105
+ interactiveWhitelist?: (Element | (() => Element))[];
106
+ include_attributes?: string[];
107
+ highlightOpacity?: number;
108
+ highlightLabelOpacity?: number;
109
+ }
110
+
111
+ declare type DomNode = TextDomNode | ElementDomNode | InteractiveElementDomNode;
112
+
113
+ declare interface ElementDomNode {
114
+ tagName: string;
115
+ attributes?: Record<string, string>;
116
+ xpath?: string;
117
+ children?: string[];
118
+ isVisible?: boolean;
119
+ isTopElement?: boolean;
120
+ isInViewport?: boolean;
121
+ isNew?: boolean;
122
+ isInteractive?: false;
123
+ highlightIndex?: number;
124
+ extra?: Record<string, any>;
125
+ [key: string]: unknown;
126
+ }
127
+
128
+ /**
129
+ * Derived from @page-agent/page-controller
130
+ * Original: https://github.com/alibaba/page-agent
131
+ * Copyright (c) 2025 Alibaba Group Holding Limited
132
+ * Licensed under MIT License
133
+ */
134
+ declare interface FlatDomTree {
135
+ rootId: string;
136
+ map: Record<string, DomNode>;
137
+ }
138
+
139
+ /**
140
+ * 对应 python 中的 views::clickable_elements_to_string,
141
+ * 将 dom 信息处理成适合 llm 阅读的文本格式
142
+ * @形如
143
+ * ``` text
144
+ * [0]<a aria-label=page-agent.js 首页 />
145
+ * [1]<div >P />
146
+ * [2]<div >page-agent.js
147
+ * UI Agent in your webpage />
148
+ * [3]<a >文档 />
149
+ * [4]<a aria-label=查看源码(在新窗口打开)>源码 />
150
+ * UI Agent in your webpage
151
+ * 用户输入需求,AI 理解页面并自动操作。
152
+ * [5]<a role=button>快速开始 />
153
+ * [6]<a role=button>查看文档 />
154
+ * 无需后端
155
+ * ```
156
+ * 其中可交互元素用序号标出,提示llm可以用序号操作。
157
+ * 缩进代表父子关系。
158
+ * 普通文本则直接列出来。
159
+ *
160
+ * @todo 数据脱敏过滤器
161
+ */
162
+ declare function flatTreeToString(flatTree: FlatDomTree, include_attributes?: string[]): string;
163
+
164
+ declare const getAllTextTillNextClickableElement: (node: TreeNode, maxDepth?: number) => string;
165
+
166
+ declare function getElementTextMap(simplifiedHTML: string): Map<number, string>;
167
+
168
+ declare function getFlatTree(config: DomConfig): FlatDomTree;
169
+
170
+ declare function getSelectorMap(flatTree: FlatDomTree): Map<number, InteractiveElementDomNode>;
171
+
172
+ declare interface InteractiveElementDomNode {
173
+ tagName: string;
174
+ attributes?: Record<string, string>;
175
+ xpath?: string;
176
+ children?: string[];
177
+ isVisible?: boolean;
178
+ isTopElement?: boolean;
179
+ isInViewport?: boolean;
180
+ isInteractive: true;
181
+ highlightIndex: number;
182
+ /**
183
+ * 可交互元素的 dom 引用
184
+ */
185
+ ref: HTMLElement;
186
+ [key: string]: unknown;
187
+ }
188
+
189
+ /**
190
+ * PageController manages DOM state and element interactions.
191
+ * It provides async methods for all DOM operations, keeping state isolated.
192
+ *
193
+ * @lifecycle
194
+ * - beforeUpdate: Emitted before the DOM tree is updated.
195
+ * - afterUpdate: Emitted after the DOM tree is updated.
196
+ */
197
+ export declare class PageController extends EventTarget {
198
+ private config;
199
+ /** Corresponds to eval_page in browser-use */
200
+ private flatTree;
201
+ /**
202
+ * All highlighted index-mapped interactive elements
203
+ * Corresponds to DOMState.selector_map in browser-use
204
+ */
205
+ private selectorMap;
206
+ /** Index -> element text description mapping */
207
+ private elementTextMap;
208
+ /**
209
+ * Simplified HTML for LLM consumption.
210
+ * Corresponds to clickable_elements_to_string in browser-use
211
+ */
212
+ private simplifiedHTML;
213
+ /** last time the tree was updated */
214
+ private lastTimeUpdate;
215
+ /** Whether the tree has been indexed at least once */
216
+ private isIndexed;
217
+ /** Visual mask overlay for blocking user interaction during automation */
218
+ private mask;
219
+ private maskReady;
220
+ constructor(config?: PageControllerConfig);
221
+ /**
222
+ * Initialize mask asynchronously (dynamic import to avoid CSS loading in Node)
223
+ */
224
+ initMask(): void;
225
+ /**
226
+ * Get current page URL
227
+ */
228
+ getCurrentUrl(): Promise<string>;
229
+ /**
230
+ * Get last tree update timestamp
231
+ */
232
+ getLastUpdateTime(): Promise<number>;
233
+ /**
234
+ * Get structured browser state for LLM consumption.
235
+ * Automatically calls updateTree() to refresh the DOM state.
236
+ */
237
+ getBrowserState(): Promise<BrowserState>;
238
+ /**
239
+ * Update DOM tree, returns simplified HTML for LLM.
240
+ * This is the main method to refresh the page state.
241
+ * Automatically bypasses mask during DOM extraction if enabled.
242
+ */
243
+ updateTree(): Promise<string>;
244
+ /**
245
+ * Clean up all element highlights
246
+ */
247
+ cleanUpHighlights(): Promise<void>;
248
+ /**
249
+ * Ensure the tree has been indexed before any index-based operation.
250
+ * Throws if updateTree() hasn't been called yet.
251
+ */
252
+ private assertIndexed;
253
+ /**
254
+ * Click element by index
255
+ */
256
+ clickElement(index: number): Promise<ActionResult>;
257
+ /**
258
+ * Input text into element by index
259
+ */
260
+ inputText(index: number, text: string): Promise<ActionResult>;
261
+ /**
262
+ * Select dropdown option by index and option text
263
+ */
264
+ selectOption(index: number, optionText: string): Promise<ActionResult>;
265
+ /**
266
+ * Scroll vertically
267
+ */
268
+ scroll(options: {
269
+ down: boolean;
270
+ numPages: number;
271
+ pixels?: number;
272
+ index?: number;
273
+ }): Promise<ActionResult>;
274
+ /**
275
+ * Scroll horizontally
276
+ */
277
+ scrollHorizontally(options: {
278
+ right: boolean;
279
+ pixels: number;
280
+ index?: number;
281
+ }): Promise<ActionResult>;
282
+ /**
283
+ * Execute arbitrary JavaScript on the page
284
+ */
285
+ executeJavascript(script: string): Promise<ActionResult>;
286
+ /**
287
+ * Show the visual mask overlay.
288
+ * Only works after mask is setup.
289
+ */
290
+ showMask(): Promise<void>;
291
+ /**
292
+ * Hide the visual mask overlay.
293
+ * Only works after mask is setup.
294
+ */
295
+ hideMask(): Promise<void>;
296
+ /**
297
+ * Dispose and clean up resources
298
+ */
299
+ dispose(): void;
300
+ }
301
+
302
+ /**
303
+ * Configuration for PageController
304
+ */
305
+ declare interface PageControllerConfig extends dom.DomConfig {
306
+ viewportExpansion?: number;
307
+ /** Enable visual mask overlay during operations (default: false) */
308
+ enableMask?: boolean;
309
+ }
310
+
311
+ declare interface TextDomNode {
312
+ type: 'TEXT_NODE';
313
+ text: string;
314
+ isVisible: boolean;
315
+ [key: string]: unknown;
316
+ }
317
+
318
+ declare interface ToolResult {
319
+ status: 'success' | 'error';
320
+ data?: unknown;
321
+ error?: string;
322
+ }
323
+
324
+ /**
325
+ * elementsToString 内部使用的类型
326
+ */
327
+ declare interface TreeNode {
328
+ type: 'text' | 'element';
329
+ parent: TreeNode | null;
330
+ children: TreeNode[];
331
+ isVisible: boolean;
332
+ text?: string;
333
+ tagName?: string;
334
+ attributes?: Record<string, string>;
335
+ isInteractive?: boolean;
336
+ isTopElement?: boolean;
337
+ isNew?: boolean;
338
+ highlightIndex?: number;
339
+ extra?: Record<string, any>;
340
+ }
341
+
342
+ export { }
package/dist/browser.js CHANGED
@@ -1,278 +1,20 @@
1
- import { PageController } from '@page-agent/page-controller';
2
- export { PageController } from '@page-agent/page-controller';
3
-
4
- // src/browser.ts
5
-
6
- // src/browserUse.ts
7
- var injectedPageController = null;
8
- var PageControllerModule = null;
9
- function setPageController(PC) {
10
- injectedPageController = PC;
11
- }
12
- async function getPageController() {
13
- if (injectedPageController) {
14
- return injectedPageController;
15
- }
16
- if (!PageControllerModule) {
17
- try {
18
- PageControllerModule = await import('@page-agent/page-controller');
19
- } catch (error) {
20
- throw new Error(
21
- 'PageController not available. Either import from "@usecrow/client/browser" or install @page-agent/page-controller as a dependency.'
22
- );
23
- }
24
- }
25
- return PageControllerModule.PageController;
26
- }
27
- var CrowBrowserUse = class {
28
- constructor(config) {
29
- this.pageController = null;
30
- this.sessionId = null;
31
- this.maxSteps = 20;
32
- this.config = config;
33
- }
34
- /**
35
- * Initialize PageController with non-blocking pointer
36
- */
37
- async initPageController() {
38
- if (this.pageController) {
39
- return this.pageController;
40
- }
41
- try {
42
- const PageController2 = await getPageController();
43
- this.pageController = new PageController2({
44
- enableMask: true,
45
- viewportExpansion: 500,
46
- highlightLabelOpacity: 0,
47
- // Hide numbered labels from users
48
- highlightOpacity: 0
49
- // Hide highlight boxes from users
50
- });
51
- await this.pageController.showMask();
52
- const mask = this.pageController.mask;
53
- if (mask?.wrapper) {
54
- mask.wrapper.style.pointerEvents = "none";
55
- }
56
- console.log("[CrowBrowserUse] PageController initialized with non-blocking pointer");
57
- return this.pageController;
58
- } catch (error) {
59
- console.error("[CrowBrowserUse] Failed to import @page-agent/page-controller:", error);
60
- throw new Error(
61
- "Failed to initialize browser automation. Make sure @page-agent/page-controller is installed."
62
- );
63
- }
64
- }
65
- /**
66
- * Execute a browser automation task
67
- */
68
- async execute(task) {
69
- console.log("[CrowBrowserUse] Starting task:", task);
70
- try {
71
- const controller = await this.initPageController();
72
- const startResponse = await this.startSession(task);
73
- this.sessionId = startResponse.session_id;
74
- this.maxSteps = startResponse.max_steps;
75
- console.log("[CrowBrowserUse] Session started:", this.sessionId);
76
- let stepCount = 0;
77
- let lastActionResult;
78
- while (stepCount < this.maxSteps) {
79
- stepCount++;
80
- const browserState = await controller.getBrowserState();
81
- const stepResponse = await this.processStep(browserState, lastActionResult);
82
- if (stepResponse.done) {
83
- console.log("[CrowBrowserUse] Task completed:", stepResponse.message);
84
- await this.cleanup();
85
- return {
86
- status: stepResponse.success ? "success" : "error",
87
- data: {
88
- message: stepResponse.message,
89
- steps: stepCount
90
- },
91
- error: stepResponse.success ? void 0 : stepResponse.message
92
- };
93
- }
94
- if (stepResponse.error) {
95
- console.error("[CrowBrowserUse] Error:", stepResponse.error);
96
- await this.cleanup();
97
- return {
98
- status: "error",
99
- error: stepResponse.error
100
- };
101
- }
102
- if (stepResponse.action) {
103
- lastActionResult = await this.executeAction(controller, stepResponse.action);
104
- console.log(`[CrowBrowserUse] Step ${stepCount}:`, lastActionResult);
105
- }
106
- if (stepResponse.reflection) {
107
- console.log("[CrowBrowserUse] Reflection:", stepResponse.reflection.next_goal);
108
- }
109
- }
110
- await this.cleanup();
111
- return {
112
- status: "error",
113
- error: `Task incomplete after ${this.maxSteps} steps`
114
- };
115
- } catch (error) {
116
- console.error("[CrowBrowserUse] Error:", error);
117
- await this.cleanup();
118
- return {
119
- status: "error",
120
- error: error instanceof Error ? error.message : String(error)
121
- };
122
- }
123
- }
124
- /**
125
- * Start a browser-use session on the server
126
- */
127
- async startSession(task) {
128
- const response = await fetch(`${this.config.apiUrl}/api/browser-use/start`, {
129
- method: "POST",
130
- headers: { "Content-Type": "application/json" },
131
- body: JSON.stringify({
132
- product_id: this.config.productId,
133
- task
134
- })
135
- });
136
- if (!response.ok) {
137
- const error = await response.json().catch(() => ({ detail: "Unknown error" }));
138
- throw new Error(error.detail || `Failed to start session: ${response.status}`);
139
- }
140
- return response.json();
141
- }
142
- /**
143
- * Process a step on the server
144
- */
145
- async processStep(browserState, actionResult) {
146
- const response = await fetch(`${this.config.apiUrl}/api/browser-use/step`, {
147
- method: "POST",
148
- headers: { "Content-Type": "application/json" },
149
- body: JSON.stringify({
150
- session_id: this.sessionId,
151
- product_id: this.config.productId,
152
- browser_state: browserState,
153
- action_result: actionResult
154
- })
155
- });
156
- if (!response.ok) {
157
- const error = await response.json().catch(() => ({ detail: "Unknown error" }));
158
- throw new Error(error.detail || `Failed to process step: ${response.status}`);
159
- }
160
- return response.json();
161
- }
162
- /**
163
- * Execute an action using PageController
164
- */
165
- async executeAction(controller, action) {
166
- const actionName = Object.keys(action)[0];
167
- const actionParams = action[actionName];
168
- try {
169
- switch (actionName) {
170
- case "click_element_by_index": {
171
- const result = await controller.clickElement(actionParams.index);
172
- return result.message;
173
- }
174
- case "input_text": {
175
- const result = await controller.inputText(
176
- actionParams.index,
177
- actionParams.text
178
- );
179
- return result.message;
180
- }
181
- case "select_dropdown_option": {
182
- const result = await controller.selectOption(
183
- actionParams.index,
184
- actionParams.text
185
- );
186
- return result.message;
187
- }
188
- case "scroll": {
189
- const result = await controller.scroll({
190
- down: actionParams.down,
191
- numPages: actionParams.num_pages,
192
- pixels: actionParams.pixels,
193
- index: actionParams.index
194
- });
195
- return result.message;
196
- }
197
- case "scroll_horizontally": {
198
- const result = await controller.scrollHorizontally({
199
- right: actionParams.right,
200
- pixels: actionParams.pixels,
201
- index: actionParams.index
202
- });
203
- return result.message;
204
- }
205
- case "wait": {
206
- const seconds = actionParams.seconds || 1;
207
- await new Promise((resolve) => setTimeout(resolve, seconds * 1e3));
208
- return `Waited ${seconds} seconds`;
209
- }
210
- case "done": {
211
- return "Task completed";
212
- }
213
- default:
214
- return `Unknown action: ${actionName}`;
215
- }
216
- } catch (error) {
217
- return `Action failed: ${error instanceof Error ? error.message : String(error)}`;
218
- }
219
- }
220
- /**
221
- * Cleanup resources
222
- */
223
- async cleanup() {
224
- if (this.pageController) {
225
- try {
226
- await this.pageController.hideMask();
227
- await this.pageController.cleanUpHighlights();
228
- this.pageController.dispose();
229
- } catch (error) {
230
- console.warn("[CrowBrowserUse] Cleanup error:", error);
231
- }
232
- this.pageController = null;
233
- }
234
- if (this.sessionId) {
235
- try {
236
- await fetch(`${this.config.apiUrl}/api/browser-use/end`, {
237
- method: "POST",
238
- headers: { "Content-Type": "application/json" },
239
- body: JSON.stringify({
240
- session_id: this.sessionId,
241
- product_id: this.config.productId
242
- })
243
- });
244
- } catch (error) {
245
- }
246
- this.sessionId = null;
247
- }
248
- }
249
- /**
250
- * Stop the current task
251
- */
252
- async stop() {
253
- await this.cleanup();
254
- }
255
- };
256
-
257
- // src/browser.ts
258
- setPageController(PageController);
259
- function createBrowserUseTool(config) {
260
- return async (args) => {
261
- const instruction = args.instruction || args.instruction;
262
- if (!instruction) {
263
- return {
264
- status: "error",
265
- error: "Missing instruction parameter for browser_use tool"
266
- };
267
- }
268
- const browserUse = new CrowBrowserUse({
269
- productId: config.productId,
270
- apiUrl: config.apiUrl
271
- });
272
- return browserUse.execute(instruction);
1
+ import { PageController as t } from "./PageController-KoeqDxMP.js";
2
+ import { C as s, s as n } from "./browserUse-BbPG4pH1.js";
3
+ n(t);
4
+ function a(r) {
5
+ return async (o) => {
6
+ const e = o.instruction || o.instruction;
7
+ return e ? new s({
8
+ productId: r.productId,
9
+ apiUrl: r.apiUrl
10
+ }).execute(e) : {
11
+ status: "error",
12
+ error: "Missing instruction parameter for browser_use tool"
13
+ };
273
14
  };
274
15
  }
275
-
276
- export { CrowBrowserUse, createBrowserUseTool };
277
- //# sourceMappingURL=browser.js.map
278
- //# sourceMappingURL=browser.js.map
16
+ export {
17
+ s as CrowBrowserUse,
18
+ t as PageController,
19
+ a as createBrowserUseTool
20
+ };
@@ -0,0 +1 @@
1
+ "use strict";let c=null,l=null;function p(i){c=i}async function w(){if(c)return c;if(!l)try{l=await Promise.resolve().then(()=>require("./PageController-GcMFZYwU.cjs"))}catch{throw new Error('PageController not available. Either import from "@usecrow/client/browser" or use the bundled version.')}return l.PageController}class u{constructor(t){this.pageController=null,this.sessionId=null,this.maxSteps=20,this.config=t}async initPageController(){if(this.pageController)return this.pageController;try{const t=await w();this.pageController=new t({enableMask:!0,viewportExpansion:500,highlightLabelOpacity:0,highlightOpacity:0}),await this.pageController.showMask();const e=this.pageController.mask;return e!=null&&e.wrapper&&(e.wrapper.style.pointerEvents="none"),console.log("[CrowBrowserUse] PageController initialized with non-blocking pointer"),this.pageController}catch(t){throw console.error("[CrowBrowserUse] Failed to initialize PageController:",t),new Error("Failed to initialize browser automation. Please import from @usecrow/client/browser.")}}async execute(t){console.log("[CrowBrowserUse] Starting task:",t);try{const e=await this.initPageController(),o=await this.startSession(t);this.sessionId=o.session_id,this.maxSteps=o.max_steps,console.log("[CrowBrowserUse] Session started:",this.sessionId);let r=0,s;for(;r<this.maxSteps;){r++;const a=await e.getBrowserState(),n=await this.processStep(a,s);if(n.done)return console.log("[CrowBrowserUse] Task completed:",n.message),await this.cleanup(),{status:n.success?"success":"error",data:{message:n.message,steps:r},error:n.success?void 0:n.message};if(n.error)return console.error("[CrowBrowserUse] Error:",n.error),await this.cleanup(),{status:"error",error:n.error};n.action&&(s=await this.executeAction(e,n.action),console.log(`[CrowBrowserUse] Step ${r}:`,s)),n.reflection&&console.log("[CrowBrowserUse] Reflection:",n.reflection.next_goal)}return await this.cleanup(),{status:"error",error:`Task incomplete after ${this.maxSteps} steps`}}catch(e){return console.error("[CrowBrowserUse] Error:",e),await this.cleanup(),{status:"error",error:e instanceof Error?e.message:String(e)}}}async startSession(t){const e=await fetch(`${this.config.apiUrl}/api/browser-use/start`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({product_id:this.config.productId,task:t})});if(!e.ok){const o=await e.json().catch(()=>({detail:"Unknown error"}));throw new Error(o.detail||`Failed to start session: ${e.status}`)}return e.json()}async processStep(t,e){const o=await fetch(`${this.config.apiUrl}/api/browser-use/step`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({session_id:this.sessionId,product_id:this.config.productId,browser_state:t,action_result:e})});if(!o.ok){const r=await o.json().catch(()=>({detail:"Unknown error"}));throw new Error(r.detail||`Failed to process step: ${o.status}`)}return o.json()}async executeAction(t,e){const o=Object.keys(e)[0],r=e[o];try{switch(o){case"click_element_by_index":return(await t.clickElement(r.index)).message;case"input_text":return(await t.inputText(r.index,r.text)).message;case"select_dropdown_option":return(await t.selectOption(r.index,r.text)).message;case"scroll":return(await t.scroll({down:r.down,numPages:r.num_pages,pixels:r.pixels,index:r.index})).message;case"scroll_horizontally":return(await t.scrollHorizontally({right:r.right,pixels:r.pixels,index:r.index})).message;case"wait":{const s=r.seconds||1;return await new Promise(a=>setTimeout(a,s*1e3)),`Waited ${s} seconds`}case"done":return"Task completed";default:return`Unknown action: ${o}`}}catch(s){return`Action failed: ${s instanceof Error?s.message:String(s)}`}}async cleanup(){if(this.pageController){try{await this.pageController.hideMask(),await this.pageController.cleanUpHighlights(),this.pageController.dispose()}catch(t){console.warn("[CrowBrowserUse] Cleanup error:",t)}this.pageController=null}if(this.sessionId){try{await fetch(`${this.config.apiUrl}/api/browser-use/end`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({session_id:this.sessionId,product_id:this.config.productId})})}catch{}this.sessionId=null}}async stop(){await this.cleanup()}}exports.CrowBrowserUse=u;exports.setPageController=p;