@intuned/browser-use-dev 0.0.0-stage → 0.1.2-dev.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.
- package/LICENSE +43 -0
- package/README.md +39 -2
- package/dist/browser-use/errors.js +15 -0
- package/dist/browser-use/eventCollector.js +96 -0
- package/dist/browser-use/executeTask.js +242 -0
- package/dist/browser-use/export.d.ts +228 -0
- package/dist/browser-use/index.d.ts +228 -0
- package/dist/browser-use/index.js +19 -0
- package/dist/browser-use/messages.js +71 -0
- package/dist/browser-use/playwrightComputer.js +442 -0
- package/dist/browser-use/prompts.js +11 -0
- package/dist/browser-use/tools.js +338 -0
- package/dist/common/Logger/index.js +60 -0
- package/dist/common/Logger/types.js +5 -0
- package/dist/common/aiGateway.js +76 -0
- package/dist/common/networkSettled.js +31 -0
- package/dist/common/parseCostInCents.js +13 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +16 -0
- package/dist/types/intuned-runtime.d.ts +6 -0
- package/package.json +82 -3
|
@@ -0,0 +1,442 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.PlaywrightComputer = void 0;
|
|
7
|
+
var _networkSettled = require("../common/networkSettled");
|
|
8
|
+
var _Logger = require("../common/Logger");
|
|
9
|
+
var _eventCollector = require("./eventCollector");
|
|
10
|
+
const NETWORK_SETTLE_TIMEOUT_MS = 15_000;
|
|
11
|
+
const PRE_CLICK_DELAY_MS = 500;
|
|
12
|
+
const TYPE_DELAY_MS = 12;
|
|
13
|
+
const SCROLL_STEP_DELAY_MS = 200;
|
|
14
|
+
const CONSECUTIVE_SCROLL_WARNING_THRESHOLD = 5;
|
|
15
|
+
const HOME_END_SCROLL_AMOUNT = 100;
|
|
16
|
+
const HOME_END_SCROLL_PIXELS_PER_UNIT = 100;
|
|
17
|
+
const HOME_END_SCROLL_STEP_DELAY_MS = 50;
|
|
18
|
+
const MAX_WAIT_MS = 100_000;
|
|
19
|
+
const MAX_ECHOED_VALUE = 120;
|
|
20
|
+
const KEY_MAP = {
|
|
21
|
+
"/": "/",
|
|
22
|
+
"\\": "\\",
|
|
23
|
+
alt: "Alt",
|
|
24
|
+
arrowdown: "ArrowDown",
|
|
25
|
+
arrowleft: "ArrowLeft",
|
|
26
|
+
arrowright: "ArrowRight",
|
|
27
|
+
arrowup: "ArrowUp",
|
|
28
|
+
backspace: "Backspace",
|
|
29
|
+
capslock: "CapsLock",
|
|
30
|
+
cmd: "ControlOrMeta",
|
|
31
|
+
command: "ControlOrMeta",
|
|
32
|
+
control: "Control",
|
|
33
|
+
ctrl: "Control",
|
|
34
|
+
delete: "Delete",
|
|
35
|
+
down: "ArrowDown",
|
|
36
|
+
end: "End",
|
|
37
|
+
enter: "Enter",
|
|
38
|
+
esc: "Escape",
|
|
39
|
+
escape: "Escape",
|
|
40
|
+
home: "Home",
|
|
41
|
+
insert: "Insert",
|
|
42
|
+
left: "ArrowLeft",
|
|
43
|
+
meta: "Meta",
|
|
44
|
+
option: "Alt",
|
|
45
|
+
page_down: "PageDown",
|
|
46
|
+
page_up: "PageUp",
|
|
47
|
+
pagedown: "PageDown",
|
|
48
|
+
pageup: "PageUp",
|
|
49
|
+
return: "Enter",
|
|
50
|
+
right: "ArrowRight",
|
|
51
|
+
shift: "Shift",
|
|
52
|
+
space: " ",
|
|
53
|
+
super: "Meta",
|
|
54
|
+
tab: "Tab",
|
|
55
|
+
up: "ArrowUp",
|
|
56
|
+
win: "Meta"
|
|
57
|
+
};
|
|
58
|
+
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
|
|
59
|
+
const truncate = text => text.length > MAX_ECHOED_VALUE ? `${text.slice(0, MAX_ECHOED_VALUE)}…` : text;
|
|
60
|
+
class PlaywrightComputer {
|
|
61
|
+
_mouseX = 0;
|
|
62
|
+
_mouseY = 0;
|
|
63
|
+
_consecutiveScrollCount = 0;
|
|
64
|
+
_lastScrollDirection = null;
|
|
65
|
+
_viewportWidth = 1280;
|
|
66
|
+
_viewportHeight = 720;
|
|
67
|
+
constructor(page) {
|
|
68
|
+
this._page = page;
|
|
69
|
+
}
|
|
70
|
+
syncViewport = async () => {
|
|
71
|
+
try {
|
|
72
|
+
const {
|
|
73
|
+
width,
|
|
74
|
+
height
|
|
75
|
+
} = await this._page.evaluate(() => ({
|
|
76
|
+
width: window.innerWidth,
|
|
77
|
+
height: window.innerHeight
|
|
78
|
+
}));
|
|
79
|
+
if (width > 0 && height > 0) {
|
|
80
|
+
await this._page.setViewportSize({
|
|
81
|
+
width,
|
|
82
|
+
height
|
|
83
|
+
});
|
|
84
|
+
this._viewportWidth = width;
|
|
85
|
+
this._viewportHeight = height;
|
|
86
|
+
}
|
|
87
|
+
} catch (e) {
|
|
88
|
+
_Logger.logger.warn(`[browser-use] failed to sync viewport: ${e}`);
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
runAction = async (fn, {
|
|
92
|
+
collectEvents = true
|
|
93
|
+
} = {}) => {
|
|
94
|
+
await this.syncViewport();
|
|
95
|
+
if (!collectEvents) {
|
|
96
|
+
const result = await fn();
|
|
97
|
+
let url = "unknown";
|
|
98
|
+
try {
|
|
99
|
+
url = this._page.url();
|
|
100
|
+
} catch {}
|
|
101
|
+
return `CURRENT URL: ${url}\nResult: ${result}`;
|
|
102
|
+
}
|
|
103
|
+
const collector = new _eventCollector.EventCollector(this._page);
|
|
104
|
+
collector.start();
|
|
105
|
+
try {
|
|
106
|
+
const result = await fn();
|
|
107
|
+
await collector.stop();
|
|
108
|
+
for (const event of collector.getEvents()) {
|
|
109
|
+
_Logger.logger.info(`[browser-use] event: ${event}`);
|
|
110
|
+
}
|
|
111
|
+
return collector.formatResponse(result);
|
|
112
|
+
} catch (e) {
|
|
113
|
+
await collector.stop().catch(() => undefined);
|
|
114
|
+
throw e;
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
settled = fn => (0, _networkSettled.withNetworkSettled)(fn, {
|
|
118
|
+
page: this._page,
|
|
119
|
+
timeoutInMs: NETWORK_SETTLE_TIMEOUT_MS
|
|
120
|
+
});
|
|
121
|
+
resetScrollStreak = () => {
|
|
122
|
+
this._consecutiveScrollCount = 0;
|
|
123
|
+
this._lastScrollDirection = null;
|
|
124
|
+
};
|
|
125
|
+
validateCoordinates = (x, y) => {
|
|
126
|
+
if (!Number.isFinite(x) || !Number.isFinite(y) || x < 0 || y < 0) {
|
|
127
|
+
throw new Error(`Coordinates (${x}, ${y}) must be non-negative numbers`);
|
|
128
|
+
}
|
|
129
|
+
if (x > this._viewportWidth || y > this._viewportHeight) {
|
|
130
|
+
throw new Error(`Coordinates (${x}, ${y}) are out of bounds — the viewport is ` + `${this._viewportWidth}x${this._viewportHeight} pixels`);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
url = () => {
|
|
134
|
+
try {
|
|
135
|
+
return this._page.url();
|
|
136
|
+
} catch {
|
|
137
|
+
return "unknown";
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
screenshot = async () => {
|
|
141
|
+
await this.syncViewport();
|
|
142
|
+
await this._page.bringToFront();
|
|
143
|
+
const buf = await this._page.screenshot({
|
|
144
|
+
fullPage: false,
|
|
145
|
+
scale: "css",
|
|
146
|
+
timeout: 30_000
|
|
147
|
+
});
|
|
148
|
+
return buf.toString("base64");
|
|
149
|
+
};
|
|
150
|
+
click = ({
|
|
151
|
+
x,
|
|
152
|
+
y,
|
|
153
|
+
button = "left",
|
|
154
|
+
click_count = 1
|
|
155
|
+
}) => this.runAction(async () => {
|
|
156
|
+
this.resetScrollStreak();
|
|
157
|
+
switch (button) {
|
|
158
|
+
case "back":
|
|
159
|
+
return this.goBack();
|
|
160
|
+
case "forward":
|
|
161
|
+
return this.goForward();
|
|
162
|
+
case "wheel":
|
|
163
|
+
_Logger.logger.info(`[browser-use] scroll wheel by (${x}, ${y})`);
|
|
164
|
+
await this._page.mouse.wheel(x, y);
|
|
165
|
+
return `Scrolled wheel by (${x}, ${y})`;
|
|
166
|
+
default:
|
|
167
|
+
{
|
|
168
|
+
if (button !== "left" && click_count !== 1) {
|
|
169
|
+
throw new Error(`click_count is only supported for left clicks, not ${button}`);
|
|
170
|
+
}
|
|
171
|
+
if (![1, 2, 3].includes(click_count)) {
|
|
172
|
+
throw new Error(`click_count must be 1, 2, or 3, got ${click_count}`);
|
|
173
|
+
}
|
|
174
|
+
this.validateCoordinates(x, y);
|
|
175
|
+
this._mouseX = x;
|
|
176
|
+
this._mouseY = y;
|
|
177
|
+
const clickDesc = click_count === 1 ? `${button} click` : `${click_count}x ${button} click`;
|
|
178
|
+
_Logger.logger.info(`[browser-use] ${clickDesc} at (${x}, ${y})`);
|
|
179
|
+
await sleep(PRE_CLICK_DELAY_MS);
|
|
180
|
+
await this.settled(async p => {
|
|
181
|
+
if (button === "left" && click_count === 2) {
|
|
182
|
+
await p.mouse.dblclick(x, y);
|
|
183
|
+
} else {
|
|
184
|
+
await p.mouse.click(x, y, {
|
|
185
|
+
button,
|
|
186
|
+
clickCount: click_count
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
return `Clicked ${clickDesc} at (${x}, ${y})`;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
double_click = ({
|
|
195
|
+
x,
|
|
196
|
+
y
|
|
197
|
+
}) => this.click({
|
|
198
|
+
x,
|
|
199
|
+
y,
|
|
200
|
+
button: "left",
|
|
201
|
+
click_count: 2
|
|
202
|
+
});
|
|
203
|
+
scrollSteps = async (amount, direction, pixelsPerUnit, delayBetweenStepsMs = SCROLL_STEP_DELAY_MS) => {
|
|
204
|
+
let deltaX = 0;
|
|
205
|
+
let deltaY = 0;
|
|
206
|
+
if (direction === "up") deltaY = -pixelsPerUnit;else if (direction === "down") deltaY = pixelsPerUnit;else if (direction === "left") deltaX = -pixelsPerUnit;else deltaX = pixelsPerUnit;
|
|
207
|
+
for (let i = 0; i < amount; i++) {
|
|
208
|
+
await sleep(delayBetweenStepsMs);
|
|
209
|
+
await this._page.mouse.wheel(deltaX, deltaY);
|
|
210
|
+
}
|
|
211
|
+
return `Scrolled ${direction} by ${amount}`;
|
|
212
|
+
};
|
|
213
|
+
scroll = ({
|
|
214
|
+
x,
|
|
215
|
+
y,
|
|
216
|
+
scroll_direction,
|
|
217
|
+
scroll_amount
|
|
218
|
+
}) => this.runAction(async () => {
|
|
219
|
+
if (!Number.isFinite(scroll_amount) || scroll_amount <= 0) {
|
|
220
|
+
throw new Error(`scroll_amount must be a positive number`);
|
|
221
|
+
}
|
|
222
|
+
if (x !== undefined && y !== undefined) {
|
|
223
|
+
this.validateCoordinates(x, y);
|
|
224
|
+
await this._page.mouse.move(x, y);
|
|
225
|
+
this._mouseX = x;
|
|
226
|
+
this._mouseY = y;
|
|
227
|
+
}
|
|
228
|
+
_Logger.logger.info(`[browser-use] scroll ${scroll_direction} by ${scroll_amount} at ` + `(${this._mouseX}, ${this._mouseY})`);
|
|
229
|
+
const pixelsPerUnit = Math.max(1, Math.floor(this._viewportHeight / 8));
|
|
230
|
+
let result = await this.scrollSteps(scroll_amount, scroll_direction, pixelsPerUnit);
|
|
231
|
+
if (scroll_direction !== this._lastScrollDirection) {
|
|
232
|
+
this._consecutiveScrollCount = 0;
|
|
233
|
+
}
|
|
234
|
+
this._lastScrollDirection = scroll_direction;
|
|
235
|
+
this._consecutiveScrollCount += 1;
|
|
236
|
+
if (this._consecutiveScrollCount >= CONSECUTIVE_SCROLL_WARNING_THRESHOLD) {
|
|
237
|
+
const warning = `⚠️ WARNING: You have performed ${this._consecutiveScrollCount} consecutive scroll operations.\n` + `- If skipping through the content is not an issue, consider using a bigger scroll_amount\n` + `- If content is essential to the task, keep scrolling\n`;
|
|
238
|
+
_Logger.logger.warn(`[browser-use] ${warning}`);
|
|
239
|
+
result = `${warning}\n${result}`;
|
|
240
|
+
}
|
|
241
|
+
return result;
|
|
242
|
+
}, {
|
|
243
|
+
collectEvents: false
|
|
244
|
+
});
|
|
245
|
+
type = ({
|
|
246
|
+
text
|
|
247
|
+
}) => this.runAction(async () => {
|
|
248
|
+
this.resetScrollStreak();
|
|
249
|
+
_Logger.logger.info(`[browser-use] type "${text}"`);
|
|
250
|
+
await this.settled(p => p.keyboard.type(text, {
|
|
251
|
+
delay: TYPE_DELAY_MS
|
|
252
|
+
}));
|
|
253
|
+
return `Typed ${text}`;
|
|
254
|
+
});
|
|
255
|
+
focusedValue = () => this._page.evaluate(() => {
|
|
256
|
+
const el = document.activeElement;
|
|
257
|
+
if (!el) return null;
|
|
258
|
+
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) return el.value;
|
|
259
|
+
if (el.isContentEditable) return el.textContent ?? "";
|
|
260
|
+
return null;
|
|
261
|
+
});
|
|
262
|
+
clearFocused = async () => {
|
|
263
|
+
const p = this._page;
|
|
264
|
+
await p.keyboard.press("ControlOrMeta+a");
|
|
265
|
+
await p.keyboard.press("Delete");
|
|
266
|
+
let value = await this.focusedValue();
|
|
267
|
+
if (value) {
|
|
268
|
+
await p.evaluate(() => {
|
|
269
|
+
const el = document.activeElement;
|
|
270
|
+
try {
|
|
271
|
+
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) el.select();else if (el !== null && el !== void 0 && el.isContentEditable) document.execCommand("selectAll");
|
|
272
|
+
} catch {}
|
|
273
|
+
});
|
|
274
|
+
await p.keyboard.press("Delete");
|
|
275
|
+
value = await this.focusedValue();
|
|
276
|
+
}
|
|
277
|
+
return value;
|
|
278
|
+
};
|
|
279
|
+
clear_field = ({
|
|
280
|
+
x,
|
|
281
|
+
y
|
|
282
|
+
}) => this.runAction(async () => {
|
|
283
|
+
this.resetScrollStreak();
|
|
284
|
+
this.validateCoordinates(x, y);
|
|
285
|
+
_Logger.logger.info(`[browser-use] clear the field at (${x}, ${y})`);
|
|
286
|
+
const left = await this.settled(async p => {
|
|
287
|
+
await p.mouse.click(x, y);
|
|
288
|
+
return this.clearFocused();
|
|
289
|
+
});
|
|
290
|
+
if (left === null) return `Clicked (${x}, ${y}) and sent select-all + delete, but no text field has focus there — check the screenshot`;
|
|
291
|
+
if (left) return `Tried to clear the field at (${x}, ${y}) but it still holds "${truncate(left)}"`;
|
|
292
|
+
return `Cleared the field at (${x}, ${y})`;
|
|
293
|
+
});
|
|
294
|
+
fill_field = ({
|
|
295
|
+
x,
|
|
296
|
+
y,
|
|
297
|
+
text
|
|
298
|
+
}) => this.runAction(async () => {
|
|
299
|
+
this.resetScrollStreak();
|
|
300
|
+
this.validateCoordinates(x, y);
|
|
301
|
+
_Logger.logger.info(`[browser-use] fill the field at (${x}, ${y}) with "${text}"`);
|
|
302
|
+
const value = await this.settled(async p => {
|
|
303
|
+
await p.mouse.click(x, y);
|
|
304
|
+
await this.clearFocused();
|
|
305
|
+
await p.keyboard.type(text, {
|
|
306
|
+
delay: TYPE_DELAY_MS
|
|
307
|
+
});
|
|
308
|
+
return this.focusedValue();
|
|
309
|
+
});
|
|
310
|
+
if (value === null) return `Clicked (${x}, ${y}) and typed "${text}", but no text field has focus there — check the screenshot`;
|
|
311
|
+
if (value === text) return `Set the field at (${x}, ${y}) to "${text}"`;
|
|
312
|
+
return `Typed "${text}" into the field at (${x}, ${y}); it now holds "${truncate(value)}"`;
|
|
313
|
+
});
|
|
314
|
+
keypress = ({
|
|
315
|
+
keys
|
|
316
|
+
}) => this.runAction(async () => {
|
|
317
|
+
this.resetScrollStreak();
|
|
318
|
+
if (!Array.isArray(keys) || keys.length === 0) {
|
|
319
|
+
throw new Error("keys must be a non-empty array");
|
|
320
|
+
}
|
|
321
|
+
if (keys.length === 1) {
|
|
322
|
+
const single = keys[0].toLowerCase();
|
|
323
|
+
if (single === "home" || single === "end") {
|
|
324
|
+
_Logger.logger.info(`[browser-use] press ${keys[0]} (slow scroll)`);
|
|
325
|
+
const direction = single === "home" ? "up" : "down";
|
|
326
|
+
await this.scrollSteps(HOME_END_SCROLL_AMOUNT, direction, HOME_END_SCROLL_PIXELS_PER_UNIT, HOME_END_SCROLL_STEP_DELAY_MS);
|
|
327
|
+
return `Pressed key ${keys[0]} (scrolled to ${direction === "up" ? "top" : "bottom"} with scroll amount of ${HOME_END_SCROLL_AMOUNT})`;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
_Logger.logger.info(`[browser-use] press ${keys.join("+")}`);
|
|
331
|
+
const mapped = keys.map(k => KEY_MAP[k.toLowerCase()] ?? k);
|
|
332
|
+
await this.settled(async p => {
|
|
333
|
+
const modifiers = mapped.slice(0, -1);
|
|
334
|
+
const mainKey = mapped[mapped.length - 1];
|
|
335
|
+
for (const mod of modifiers) await p.keyboard.down(mod);
|
|
336
|
+
try {
|
|
337
|
+
await p.keyboard.press(mainKey);
|
|
338
|
+
} finally {
|
|
339
|
+
for (const mod of [...modifiers].reverse()) await p.keyboard.up(mod);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
return `Pressed key ${keys.join("+")}`;
|
|
343
|
+
});
|
|
344
|
+
wait = ({
|
|
345
|
+
ms = 1000
|
|
346
|
+
} = {}) => this.runAction(async () => {
|
|
347
|
+
this.resetScrollStreak();
|
|
348
|
+
if (!Number.isFinite(ms) || ms < 0) {
|
|
349
|
+
throw new Error(`wait ms must be a non-negative number, got ${ms}`);
|
|
350
|
+
}
|
|
351
|
+
const capped = Math.min(ms, MAX_WAIT_MS);
|
|
352
|
+
_Logger.logger.info(`[browser-use] wait ${capped}ms`);
|
|
353
|
+
await sleep(capped);
|
|
354
|
+
return `Waited for ${capped}ms`;
|
|
355
|
+
}, {
|
|
356
|
+
collectEvents: false
|
|
357
|
+
});
|
|
358
|
+
move = ({
|
|
359
|
+
x,
|
|
360
|
+
y
|
|
361
|
+
}) => this.runAction(async () => {
|
|
362
|
+
this.resetScrollStreak();
|
|
363
|
+
this.validateCoordinates(x, y);
|
|
364
|
+
_Logger.logger.info(`[browser-use] move mouse to (${x}, ${y})`);
|
|
365
|
+
await this._page.mouse.move(x, y);
|
|
366
|
+
this._mouseX = x;
|
|
367
|
+
this._mouseY = y;
|
|
368
|
+
return `Moved mouse to (${x}, ${y})`;
|
|
369
|
+
}, {
|
|
370
|
+
collectEvents: false
|
|
371
|
+
});
|
|
372
|
+
drag = ({
|
|
373
|
+
path
|
|
374
|
+
}) => this.runAction(async () => {
|
|
375
|
+
this.resetScrollStreak();
|
|
376
|
+
const first = path[0];
|
|
377
|
+
if (!first) return "Nothing to drag — empty path";
|
|
378
|
+
const last = path[path.length - 1];
|
|
379
|
+
_Logger.logger.info(`[browser-use] drag from (${first.x}, ${first.y}) to (${last.x}, ${last.y})`);
|
|
380
|
+
await this.settled(async p => {
|
|
381
|
+
await p.mouse.move(first.x, first.y);
|
|
382
|
+
await p.mouse.down();
|
|
383
|
+
for (const pt of path.slice(1)) await p.mouse.move(pt.x, pt.y);
|
|
384
|
+
await p.mouse.up();
|
|
385
|
+
});
|
|
386
|
+
this._mouseX = last.x;
|
|
387
|
+
this._mouseY = last.y;
|
|
388
|
+
return `Dragged from (${first.x}, ${first.y}) to (${last.x}, ${last.y})`;
|
|
389
|
+
});
|
|
390
|
+
list_tabs = async () => {
|
|
391
|
+
const pages = this._page.context().pages();
|
|
392
|
+
const tabs = await Promise.all(pages.map(async (p, index) => ({
|
|
393
|
+
index,
|
|
394
|
+
url: p.url(),
|
|
395
|
+
title: await p.title().catch(() => ""),
|
|
396
|
+
is_current: p === this._page
|
|
397
|
+
})));
|
|
398
|
+
const current = tabs.find(t => t.is_current);
|
|
399
|
+
_Logger.logger.info(`[browser-use] list tabs: ${tabs.length} open, current: ${(current === null || current === void 0 ? void 0 : current.url) ?? "unknown"}`);
|
|
400
|
+
return {
|
|
401
|
+
tabs
|
|
402
|
+
};
|
|
403
|
+
};
|
|
404
|
+
executeJavascript = async code => {
|
|
405
|
+
this.resetScrollStreak();
|
|
406
|
+
_Logger.logger.info(`[browser-use] execute javascript: ${code.slice(0, 200)}${code.length > 200 ? "…" : ""}`);
|
|
407
|
+
const collector = new _eventCollector.EventCollector(this._page);
|
|
408
|
+
collector.start();
|
|
409
|
+
try {
|
|
410
|
+
const value = await this._page.evaluate(src => new Function(`return (async () => { ${src} })()`)(), code);
|
|
411
|
+
await collector.stop();
|
|
412
|
+
return {
|
|
413
|
+
value,
|
|
414
|
+
events: collector.getEvents()
|
|
415
|
+
};
|
|
416
|
+
} catch (e) {
|
|
417
|
+
await collector.stop().catch(() => undefined);
|
|
418
|
+
throw e;
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
goBack = async () => {
|
|
422
|
+
_Logger.logger.info("[browser-use] go back");
|
|
423
|
+
try {
|
|
424
|
+
await this._page.goBack();
|
|
425
|
+
return "Navigated back";
|
|
426
|
+
} catch {
|
|
427
|
+
_Logger.logger.info("[browser-use] cannot go back — no previous page in history");
|
|
428
|
+
return "Cannot go back — no previous page in history";
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
goForward = async () => {
|
|
432
|
+
_Logger.logger.info("[browser-use] go forward");
|
|
433
|
+
try {
|
|
434
|
+
await this._page.goForward();
|
|
435
|
+
return "Navigated forward";
|
|
436
|
+
} catch {
|
|
437
|
+
_Logger.logger.info("[browser-use] cannot go forward — no next page in history");
|
|
438
|
+
return "Cannot go forward — no next page in history";
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
exports.PlaywrightComputer = PlaywrightComputer;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.composeDefaultSystemPrompt = composeDefaultSystemPrompt;
|
|
7
|
+
function composeDefaultSystemPrompt() {
|
|
8
|
+
const capability = ["<SYSTEM_CAPABILITY>", "- You are controlling a web browser already open on the current page, through screenshots and mouse/keyboard actions.", "- Every action waits for the page to settle (network requests to finish) before it returns, so you never need a wait after a click, a navigation or a form submit. Use wait only for animations and timers.", "- Actions return text, not a screenshot. Call the screenshot tool to see the page. scroll and wait already return a screenshot of the settled page, so don't add one after them.", "- Tool results report the current URL and any browser events the action triggered (file downloads, popup tabs opening or closing).", "</SYSTEM_CAPABILITY>"].join("\n");
|
|
9
|
+
const instructions = ["<IMPORTANT_INSTRUCTIONS>", "- You are a fully autonomous agent. Never ask the user for permission or confirmation.", "- Complete the task immediately and fully, then report what you did.", "- Act only on what you can actually see on screen — never invent values.", "- Always use parallel tool calls (several tool calls in one response) for actions that don't depend on each other's result, e.g. fill_field for every field of a form, click Submit, then screenshot. They run one after another in the order you list them and stop at the first failure.", "- When an action navigates or changes the page, call it together with screenshot in the same response: the screenshot will show the new state.", "- Use separate responses only when you need to see the screen between steps.", "</IMPORTANT_INSTRUCTIONS>"].join("\n");
|
|
10
|
+
return `${capability}\n\n${instructions}`;
|
|
11
|
+
}
|