browser-use 0.3.0 → 0.5.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/README.md +12 -12
- package/dist/actor/page.d.ts +1 -1
- package/dist/agent/service.d.ts +4 -0
- package/dist/agent/service.js +73 -3
- package/dist/browser/profile.d.ts +2 -2
- package/dist/browser/profile.js +24 -8
- package/dist/browser/session.d.ts +11 -4
- package/dist/browser/session.js +431 -159
- package/dist/browser/types.d.ts +153 -154
- package/dist/cli.js +0 -0
- package/dist/config.d.ts +2 -0
- package/dist/config.js +40 -4
- package/dist/controller/service.js +29 -22
- package/dist/dom/dom_tree/index.js +24 -11
- package/dist/llm/schema.js +28 -3
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +8 -2
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +2 -1
- package/package.json +32 -26
package/README.md
CHANGED
|
@@ -95,13 +95,13 @@ npx browser-use --mcp
|
|
|
95
95
|
|
|
96
96
|
```
|
|
97
97
|
┌─────────────────────────────────────────────────────┐
|
|
98
|
-
│ Browser-Use
|
|
98
|
+
│ Browser-Use │
|
|
99
99
|
├─────────────────────────────────────────────────────┤
|
|
100
|
-
│ Agent ← MessageManager ← LLM Providers
|
|
101
|
-
│ ↓
|
|
100
|
+
│ Agent ← MessageManager ← LLM Providers │
|
|
101
|
+
│ ↓ │
|
|
102
102
|
│ Controller → Action Registry → BrowserSession │
|
|
103
|
-
│ ↓
|
|
104
|
-
│ DomService
|
|
103
|
+
│ ↓ │
|
|
104
|
+
│ DomService │
|
|
105
105
|
└─────────────────────────────────────────────────────┘
|
|
106
106
|
```
|
|
107
107
|
|
|
@@ -396,23 +396,23 @@ const agent = new Agent({
|
|
|
396
396
|
|
|
397
397
|
```bash
|
|
398
398
|
# Install dependencies
|
|
399
|
-
|
|
399
|
+
pnpm install
|
|
400
400
|
|
|
401
401
|
# Build
|
|
402
|
-
|
|
402
|
+
pnpm build
|
|
403
403
|
|
|
404
404
|
# Run tests
|
|
405
|
-
|
|
405
|
+
pnpm test
|
|
406
406
|
|
|
407
407
|
# Lint & format
|
|
408
|
-
|
|
409
|
-
|
|
408
|
+
pnpm lint
|
|
409
|
+
pnpm prettier
|
|
410
410
|
|
|
411
411
|
# Type checking
|
|
412
|
-
|
|
412
|
+
pnpm typecheck
|
|
413
413
|
|
|
414
414
|
# Run an example
|
|
415
|
-
|
|
415
|
+
pnpm exec tsx examples/simple-search.ts
|
|
416
416
|
```
|
|
417
417
|
|
|
418
418
|
## Requirements
|
package/dist/actor/page.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ export declare class Page {
|
|
|
7
7
|
private _mouse;
|
|
8
8
|
constructor(browser_session: BrowserSession);
|
|
9
9
|
get mouse(): Mouse;
|
|
10
|
-
_currentPage(): Promise<import("playwright
|
|
10
|
+
_currentPage(): Promise<import("playwright").Page>;
|
|
11
11
|
get_url(): Promise<string>;
|
|
12
12
|
get_title(): Promise<string>;
|
|
13
13
|
goto(url: string, options?: {
|
package/dist/agent/service.d.ts
CHANGED
|
@@ -332,6 +332,10 @@ export declare class Agent<Context = ControllerContext, AgentStructuredOutput =
|
|
|
332
332
|
private _replace_shortened_urls_in_value;
|
|
333
333
|
private _parseCompletionPayload;
|
|
334
334
|
private _isModelActionMissing;
|
|
335
|
+
private _getOutputActionNames;
|
|
336
|
+
private _toStrictActionParamSchema;
|
|
337
|
+
private _buildActionOutputSchema;
|
|
338
|
+
private _buildLlmOutputFormat;
|
|
335
339
|
private _get_model_output_with_retry;
|
|
336
340
|
private _try_switch_to_fallback_llm;
|
|
337
341
|
private _log_fallback_switch;
|
package/dist/agent/service.js
CHANGED
|
@@ -3633,13 +3633,83 @@ export class Agent {
|
|
|
3633
3633
|
return Object.keys(candidate).length === 0;
|
|
3634
3634
|
});
|
|
3635
3635
|
}
|
|
3636
|
+
_getOutputActionNames(doneOnly) {
|
|
3637
|
+
const registryActions = this.controller.registry.get_all_actions();
|
|
3638
|
+
const modelForStep = doneOnly
|
|
3639
|
+
? this.DoneActionModel
|
|
3640
|
+
: this.ActionModel;
|
|
3641
|
+
const modelAvailableNames = modelForStep?.available_actions;
|
|
3642
|
+
if (Array.isArray(modelAvailableNames) && modelAvailableNames.length > 0) {
|
|
3643
|
+
const deduped = Array.from(new Set(modelAvailableNames.filter((name) => typeof name === 'string' &&
|
|
3644
|
+
name.trim().length > 0 &&
|
|
3645
|
+
registryActions.has(name))));
|
|
3646
|
+
if (deduped.length > 0) {
|
|
3647
|
+
return deduped;
|
|
3648
|
+
}
|
|
3649
|
+
}
|
|
3650
|
+
if (doneOnly && registryActions.has('done')) {
|
|
3651
|
+
return ['done'];
|
|
3652
|
+
}
|
|
3653
|
+
return Array.from(registryActions.keys());
|
|
3654
|
+
}
|
|
3655
|
+
_toStrictActionParamSchema(schema) {
|
|
3656
|
+
if (schema instanceof z.ZodObject) {
|
|
3657
|
+
return schema.strict();
|
|
3658
|
+
}
|
|
3659
|
+
return schema;
|
|
3660
|
+
}
|
|
3661
|
+
_buildActionOutputSchema(doneOnly) {
|
|
3662
|
+
const registryActions = this.controller.registry.get_all_actions();
|
|
3663
|
+
const actionSchemas = this._getOutputActionNames(doneOnly)
|
|
3664
|
+
.map((actionName) => {
|
|
3665
|
+
const actionInfo = registryActions.get(actionName);
|
|
3666
|
+
if (!actionInfo) {
|
|
3667
|
+
return null;
|
|
3668
|
+
}
|
|
3669
|
+
const paramSchema = this._toStrictActionParamSchema(actionInfo.paramSchema);
|
|
3670
|
+
return z.object({ [actionName]: paramSchema }).strict();
|
|
3671
|
+
})
|
|
3672
|
+
.filter((schema) => schema != null);
|
|
3673
|
+
if (actionSchemas.length === 0) {
|
|
3674
|
+
const doneAction = registryActions.get('done');
|
|
3675
|
+
if (doneAction) {
|
|
3676
|
+
const doneParams = this._toStrictActionParamSchema(doneAction.paramSchema);
|
|
3677
|
+
return z.object({ done: doneParams }).strict();
|
|
3678
|
+
}
|
|
3679
|
+
return z.object({ done: z.object({}).strict() }).strict();
|
|
3680
|
+
}
|
|
3681
|
+
if (actionSchemas.length === 1) {
|
|
3682
|
+
return actionSchemas[0];
|
|
3683
|
+
}
|
|
3684
|
+
const [firstActionSchema, secondActionSchema, ...remainingActionSchemas] = actionSchemas;
|
|
3685
|
+
return z.union([
|
|
3686
|
+
firstActionSchema,
|
|
3687
|
+
secondActionSchema,
|
|
3688
|
+
...remainingActionSchemas,
|
|
3689
|
+
]);
|
|
3690
|
+
}
|
|
3691
|
+
_buildLlmOutputFormat(doneOnly) {
|
|
3692
|
+
const schema = z.object({
|
|
3693
|
+
thinking: z.string().optional().nullable(),
|
|
3694
|
+
evaluation_previous_goal: z.string().optional().nullable(),
|
|
3695
|
+
memory: z.string().optional().nullable(),
|
|
3696
|
+
next_goal: z.string().optional().nullable(),
|
|
3697
|
+
current_plan_item: z.number().int().optional().nullable(),
|
|
3698
|
+
plan_update: z.array(z.string()).optional().nullable(),
|
|
3699
|
+
action: z
|
|
3700
|
+
.array(this._buildActionOutputSchema(doneOnly))
|
|
3701
|
+
.optional()
|
|
3702
|
+
.nullable(),
|
|
3703
|
+
});
|
|
3704
|
+
const outputFormat = schema;
|
|
3705
|
+
outputFormat.schema = schema;
|
|
3706
|
+
return outputFormat;
|
|
3707
|
+
}
|
|
3636
3708
|
async _get_model_output_with_retry(messages, signal = null) {
|
|
3637
3709
|
const urlReplacements = this._process_messages_and_replace_long_urls_shorter_ones(messages);
|
|
3638
3710
|
const invokeAndParse = async (inputMessages) => {
|
|
3639
3711
|
this._throwIfAborted(signal);
|
|
3640
|
-
const outputFormat = this._enforceDoneOnlyForCurrentStep
|
|
3641
|
-
? DoneOnlyLLMOutputFormat
|
|
3642
|
-
: AgentLLMOutputFormat;
|
|
3712
|
+
const outputFormat = this._buildLlmOutputFormat(this._enforceDoneOnlyForCurrentStep);
|
|
3643
3713
|
const completion = await this.llm.ainvoke(inputMessages, outputFormat, {
|
|
3644
3714
|
signal: signal ?? undefined,
|
|
3645
3715
|
session_id: this.session_id,
|
|
@@ -173,9 +173,9 @@ export declare class BrowserProfile {
|
|
|
173
173
|
get traces_dir(): Nullable<string>;
|
|
174
174
|
get user_data_dir(): Nullable<string>;
|
|
175
175
|
get viewport_expansion(): number;
|
|
176
|
-
get viewport(): Nullable<import("playwright
|
|
176
|
+
get viewport(): Nullable<import("playwright").ViewportSize>;
|
|
177
177
|
get wait_for_network_idle_page_load_time(): number;
|
|
178
|
-
get window_size(): Nullable<import("playwright
|
|
178
|
+
get window_size(): Nullable<import("playwright").ViewportSize>;
|
|
179
179
|
private applyLegacyWindowSize;
|
|
180
180
|
private warnStorageStateUserDataDirConflict;
|
|
181
181
|
private warnUserDataDirNonDefault;
|
package/dist/browser/profile.js
CHANGED
|
@@ -360,10 +360,17 @@ const DEFAULT_BROWSER_PROFILE_OPTIONS = {
|
|
|
360
360
|
profile_directory: 'Default',
|
|
361
361
|
cookies_file: null,
|
|
362
362
|
};
|
|
363
|
+
const splitArgOnce = (arg) => {
|
|
364
|
+
const separatorIndex = arg.indexOf('=');
|
|
365
|
+
if (separatorIndex === -1) {
|
|
366
|
+
return [arg, ''];
|
|
367
|
+
}
|
|
368
|
+
return [arg.slice(0, separatorIndex), arg.slice(separatorIndex + 1)];
|
|
369
|
+
};
|
|
363
370
|
const argsAsDict = (args) => {
|
|
364
371
|
const result = {};
|
|
365
372
|
for (const arg of args) {
|
|
366
|
-
const [keyPart, valuePart = ''] = arg
|
|
373
|
+
const [keyPart, valuePart = ''] = splitArgOnce(arg);
|
|
367
374
|
const key = keyPart.trim().replace(/^-+/, '');
|
|
368
375
|
result[key] = valuePart.trim();
|
|
369
376
|
}
|
|
@@ -376,9 +383,22 @@ const cloneDefaultOptions = () => JSON.parse(JSON.stringify(DEFAULT_BROWSER_PROF
|
|
|
376
383
|
const normalizeDomainEntry = (entry) => String(entry ?? '')
|
|
377
384
|
.trim()
|
|
378
385
|
.toLowerCase();
|
|
386
|
+
const isExactHostDomainEntry = (entry) => {
|
|
387
|
+
if (!entry) {
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
if (entry.includes('*') || entry.includes('://') || entry.includes('/')) {
|
|
391
|
+
return false;
|
|
392
|
+
}
|
|
393
|
+
// Keep set optimization for plain hostnames only. Entries with ports/pattern-like
|
|
394
|
+
// delimiters must stay as arrays to preserve wildcard/scheme matching semantics.
|
|
395
|
+
return !entry.includes(':');
|
|
396
|
+
};
|
|
379
397
|
const optimizeDomainList = (value) => {
|
|
380
398
|
const cleaned = value.map(normalizeDomainEntry).filter(Boolean);
|
|
381
|
-
|
|
399
|
+
const canOptimizeToSet = cleaned.length >= DOMAIN_OPTIMIZATION_THRESHOLD &&
|
|
400
|
+
cleaned.every(isExactHostDomainEntry);
|
|
401
|
+
if (canOptimizeToSet) {
|
|
382
402
|
logger.warning(`Optimizing domain list with ${cleaned.length} entries to a Set for O(1) matching`);
|
|
383
403
|
return new Set(cleaned);
|
|
384
404
|
}
|
|
@@ -407,16 +427,12 @@ export class BrowserProfile {
|
|
|
407
427
|
allowed_domains: Array.isArray(init.allowed_domains)
|
|
408
428
|
? optimizeDomainList(init.allowed_domains)
|
|
409
429
|
: init.allowed_domains instanceof Set
|
|
410
|
-
?
|
|
411
|
-
.map(normalizeDomainEntry)
|
|
412
|
-
.filter(Boolean))
|
|
430
|
+
? optimizeDomainList(Array.from(init.allowed_domains))
|
|
413
431
|
: defaults.allowed_domains,
|
|
414
432
|
prohibited_domains: Array.isArray(init.prohibited_domains)
|
|
415
433
|
? optimizeDomainList(init.prohibited_domains)
|
|
416
434
|
: init.prohibited_domains instanceof Set
|
|
417
|
-
?
|
|
418
|
-
.map(normalizeDomainEntry)
|
|
419
|
-
.filter(Boolean))
|
|
435
|
+
? optimizeDomainList(Array.from(init.prohibited_domains))
|
|
420
436
|
: defaults.prohibited_domains,
|
|
421
437
|
window_position: init.window_position ?? defaults.window_position,
|
|
422
438
|
};
|
|
@@ -96,6 +96,8 @@ export declare class BrowserSession {
|
|
|
96
96
|
get_or_create_cdp_session(page?: Page | null): Promise<any>;
|
|
97
97
|
private _waitForStableNetwork;
|
|
98
98
|
private _setActivePage;
|
|
99
|
+
private _syncCurrentTabFromPage;
|
|
100
|
+
private _syncTabsWithBrowserPages;
|
|
99
101
|
private _captureClosedPopupMessage;
|
|
100
102
|
private _getClosedPopupMessagesSnapshot;
|
|
101
103
|
private _recordRecentEvent;
|
|
@@ -145,13 +147,13 @@ export declare class BrowserSession {
|
|
|
145
147
|
private _shutdown_browser_session;
|
|
146
148
|
close(): Promise<void>;
|
|
147
149
|
get_browser_state_with_recovery(options?: BrowserStateOptions): Promise<BrowserStateSummary>;
|
|
148
|
-
get_current_page(): Promise<import("playwright
|
|
150
|
+
get_current_page(): Promise<import("playwright").Page | null>;
|
|
149
151
|
update_current_page(page: Page | null, title?: string | null, url?: string | null): void;
|
|
150
152
|
private _buildTabs;
|
|
151
|
-
navigate_to(url: string, options?: BrowserNavigationOptions): Promise<import("playwright
|
|
152
|
-
create_new_tab(url: string, options?: BrowserNavigationOptions): Promise<import("playwright
|
|
153
|
+
navigate_to(url: string, options?: BrowserNavigationOptions): Promise<import("playwright").Page | null>;
|
|
154
|
+
create_new_tab(url: string, options?: BrowserNavigationOptions): Promise<import("playwright").Page | null>;
|
|
153
155
|
private _resolveTabIndex;
|
|
154
|
-
switch_to_tab(identifier: number | string, options?: BrowserActionOptions): Promise<import("playwright
|
|
156
|
+
switch_to_tab(identifier: number | string, options?: BrowserActionOptions): Promise<import("playwright").Page | null>;
|
|
155
157
|
close_tab(identifier: number | string): Promise<void>;
|
|
156
158
|
wait(seconds: number, options?: BrowserActionOptions): Promise<void>;
|
|
157
159
|
send_keys(keys: string, options?: BrowserActionOptions): Promise<void>;
|
|
@@ -327,6 +329,7 @@ export declare class BrowserSession {
|
|
|
327
329
|
private _is_new_tab_page;
|
|
328
330
|
private _is_ip_address_host;
|
|
329
331
|
private _get_domain_variants;
|
|
332
|
+
private _setEntryMatchesUrl;
|
|
330
333
|
/**
|
|
331
334
|
* Check if page is displaying a PDF
|
|
332
335
|
*/
|
|
@@ -530,6 +533,10 @@ export declare class BrowserSession {
|
|
|
530
533
|
* Updates human_current_page to reflect which tab the user is viewing
|
|
531
534
|
*/
|
|
532
535
|
private _onTabVisibilityChange;
|
|
536
|
+
/**
|
|
537
|
+
* Normalize pid values before issuing process operations.
|
|
538
|
+
*/
|
|
539
|
+
private _normalizePid;
|
|
533
540
|
/**
|
|
534
541
|
* Kill all child processes spawned by this browser session
|
|
535
542
|
*/
|