browser-use 0.0.2 β 0.2.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 +64 -8
- package/dist/agent/service.d.ts +1 -0
- package/dist/agent/service.js +23 -9
- package/dist/agent/views.d.ts +1 -0
- package/dist/agent/views.js +1 -0
- package/dist/browser/session.js +5 -5
- package/dist/cli.d.ts +36 -0
- package/dist/cli.js +663 -10
- package/dist/controller/service.js +43 -21
- package/dist/exceptions.d.ts +3 -0
- package/dist/exceptions.js +7 -0
- package/dist/filesystem/file-system.js +31 -4
- package/dist/integrations/gmail/actions.js +2 -2
- package/dist/llm/aws/chat-anthropic.js +5 -16
- package/dist/llm/azure/chat.js +2 -1
- package/dist/llm/google/chat.js +4 -2
- package/dist/llm/messages.d.ts +4 -4
- package/dist/mcp/client.js +7 -6
- package/dist/mcp/server.js +5 -2
- package/dist/tokens/service.js +4 -5
- package/dist/utils.js +1 -1
- package/package.json +184 -8
package/README.md
CHANGED
|
@@ -47,6 +47,15 @@ We are committed to:
|
|
|
47
47
|
|
|
48
48
|
This is **not** a fork or competing projectβit's a respectful port to serve a different programming language community.
|
|
49
49
|
|
|
50
|
+
### Upstream Parity Status
|
|
51
|
+
|
|
52
|
+
This Node.js/TypeScript implementation is currently **strictly aligned** with the Python `browser-use` release
|
|
53
|
+
[`v0.5.11`](https://github.com/browser-use/browser-use/releases/tag/0.5.11), published on **August 10, 2025**.
|
|
54
|
+
|
|
55
|
+
- π¦ Core features and behavior are aligned against that upstream tag baseline.
|
|
56
|
+
- β
Our test strategy is maintained to be as equivalent as practical to the Python coverage and behavior checks.
|
|
57
|
+
- π We expect to move this parity baseline forward to the Python **January 2026** release line very soon.
|
|
58
|
+
|
|
50
59
|
## Features
|
|
51
60
|
|
|
52
61
|
- π€ **AI-Powered**: Built specifically for LLM-driven web automation with structured output support
|
|
@@ -74,6 +83,9 @@ pnpm add browser-use
|
|
|
74
83
|
|
|
75
84
|
Playwright browsers will be installed automatically via postinstall hook.
|
|
76
85
|
|
|
86
|
+
Use only documented public entrypoints such as `browser-use` and
|
|
87
|
+
`browser-use/llm/openai`. Avoid deep imports like `browser-use/dist/...`.
|
|
88
|
+
|
|
77
89
|
### Basic Usage with Agent
|
|
78
90
|
|
|
79
91
|
```typescript
|
|
@@ -145,6 +157,47 @@ const history = await agent.run(10);
|
|
|
145
157
|
console.log(history.final_result());
|
|
146
158
|
```
|
|
147
159
|
|
|
160
|
+
### CLI Usage
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# Interactive mode (when running in a TTY)
|
|
164
|
+
npx browser-use
|
|
165
|
+
|
|
166
|
+
# One-shot task
|
|
167
|
+
npx browser-use -p "Go to example.com and extract the page title"
|
|
168
|
+
|
|
169
|
+
# Positional task mode
|
|
170
|
+
npx browser-use "Search for TypeScript browser automation"
|
|
171
|
+
|
|
172
|
+
# Pick model/provider by model name
|
|
173
|
+
npx browser-use --model claude-sonnet-4-20250514 -p "Summarize latest AI news"
|
|
174
|
+
|
|
175
|
+
# Pick provider explicitly (uses provider default model)
|
|
176
|
+
npx browser-use --provider anthropic -p "Summarize latest AI news"
|
|
177
|
+
|
|
178
|
+
# Headless + custom browser profile settings
|
|
179
|
+
npx browser-use --headless --window-width 1440 --window-height 900 -p "Check dashboard status"
|
|
180
|
+
|
|
181
|
+
# Restrict navigation to trusted domains (recommended with secrets)
|
|
182
|
+
npx browser-use --allowed-domains "example.com,*.example.org" -p "Log in and fetch account info"
|
|
183
|
+
|
|
184
|
+
# Connect to existing Chromium via CDP
|
|
185
|
+
npx browser-use --cdp-url http://localhost:9222 -p "Inspect the active tab"
|
|
186
|
+
|
|
187
|
+
# MCP server mode
|
|
188
|
+
npx browser-use --mcp
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Interactive mode commands:
|
|
192
|
+
|
|
193
|
+
- `help`: show interactive usage
|
|
194
|
+
- `exit`: quit interactive mode
|
|
195
|
+
|
|
196
|
+
Security notes:
|
|
197
|
+
|
|
198
|
+
- Prefer `--allowed-domains` whenever tasks involve credentials or sensitive data.
|
|
199
|
+
- `--allow-insecure` disables domain-lockdown enforcement for sensitive data and is unsafe for production.
|
|
200
|
+
|
|
148
201
|
## Advanced Usage
|
|
149
202
|
|
|
150
203
|
### Vision/Multimodal Support
|
|
@@ -565,6 +618,9 @@ yarn test test/integration-advanced.test.ts
|
|
|
565
618
|
|
|
566
619
|
# Watch mode
|
|
567
620
|
yarn test:watch
|
|
621
|
+
|
|
622
|
+
# Validate published package exports
|
|
623
|
+
yarn test:pack
|
|
568
624
|
```
|
|
569
625
|
|
|
570
626
|
### Code Quality
|
|
@@ -577,7 +633,7 @@ yarn lint
|
|
|
577
633
|
yarn prettier
|
|
578
634
|
|
|
579
635
|
# Type check
|
|
580
|
-
yarn
|
|
636
|
+
yarn typecheck
|
|
581
637
|
```
|
|
582
638
|
|
|
583
639
|
## Architecture
|
|
@@ -585,28 +641,28 @@ yarn build
|
|
|
585
641
|
The library follows a modular, layered architecture:
|
|
586
642
|
|
|
587
643
|
```
|
|
588
|
-
|
|
644
|
+
ββββββββββββββββββββββββββββββββββββββββββββ
|
|
589
645
|
β Agent (Orchestrator) β
|
|
590
646
|
β - Task execution & planning β
|
|
591
647
|
β - LLM message management β
|
|
592
648
|
β - Step execution loop β
|
|
593
|
-
|
|
649
|
+
βββββββββββ¬βββββββββββββββββββββββββββββββββ
|
|
594
650
|
β
|
|
595
|
-
|
|
651
|
+
βββββββββββΌβββββββββββββββββββββββββββββββββ
|
|
596
652
|
β Controller (Actions) β
|
|
597
653
|
β - Action registry & execution β
|
|
598
654
|
β - Built-in actions (30+) β
|
|
599
655
|
β - Custom action support β
|
|
600
|
-
|
|
656
|
+
βββββββββββ¬βββββββββββββββββββββββββββββββββ
|
|
601
657
|
β
|
|
602
|
-
|
|
658
|
+
βββββββββββΌβββββββββββββββββββββββββββββββββ
|
|
603
659
|
β BrowserSession (Browser) β
|
|
604
660
|
β - Playwright integration β
|
|
605
661
|
β - Tab & page management β
|
|
606
662
|
β - Navigation & interaction β
|
|
607
|
-
|
|
663
|
+
βββββββββββ¬βββββββββββββββββββββββββββββββββ
|
|
608
664
|
β
|
|
609
|
-
|
|
665
|
+
βββββββββββΌβββββββββββββββββββββββββββββββββ
|
|
610
666
|
β DOMService (DOM Analysis) β
|
|
611
667
|
β - Element extraction β
|
|
612
668
|
β - Clickable element detection β
|
package/dist/agent/service.d.ts
CHANGED
|
@@ -69,6 +69,7 @@ interface AgentConstructorParams<Context, AgentStructuredOutput> {
|
|
|
69
69
|
include_tool_call_examples?: boolean;
|
|
70
70
|
vision_detail_level?: AgentSettings['vision_detail_level'];
|
|
71
71
|
session_attachment_mode?: AgentSettings['session_attachment_mode'];
|
|
72
|
+
allow_insecure_sensitive_data?: boolean;
|
|
72
73
|
llm_timeout?: number;
|
|
73
74
|
step_timeout?: number;
|
|
74
75
|
}
|
package/dist/agent/service.js
CHANGED
|
@@ -7,14 +7,15 @@ import { z } from 'zod';
|
|
|
7
7
|
import { createLogger } from '../logging-config.js';
|
|
8
8
|
import { CONFIG } from '../config.js';
|
|
9
9
|
import { EventBus } from '../event-bus.js';
|
|
10
|
-
import { uuid7str, SignalHandler, get_browser_use_version
|
|
10
|
+
import { uuid7str, SignalHandler, get_browser_use_version } from '../utils.js';
|
|
11
11
|
import { Controller as DefaultController } from '../controller/service.js';
|
|
12
12
|
import { FileSystem as AgentFileSystem, DEFAULT_FILE_SYSTEM_PATH, } from '../filesystem/file-system.js';
|
|
13
13
|
import { SystemPrompt } from './prompts.js';
|
|
14
14
|
import { MessageManager } from './message-manager/service.js';
|
|
15
15
|
import { BrowserStateHistory } from '../browser/views.js';
|
|
16
16
|
import { BrowserSession } from '../browser/session.js';
|
|
17
|
-
import { BrowserProfile, DEFAULT_BROWSER_PROFILE
|
|
17
|
+
import { BrowserProfile, DEFAULT_BROWSER_PROFILE } from '../browser/profile.js';
|
|
18
|
+
import { InsecureSensitiveDataError } from '../exceptions.js';
|
|
18
19
|
import { HistoryTreeProcessor } from '../dom/history-tree-processor/service.js';
|
|
19
20
|
import { DOMHistoryElement } from '../dom/history-tree-processor/view.js';
|
|
20
21
|
import { UserMessage } from '../llm/messages.js';
|
|
@@ -128,6 +129,7 @@ const defaultAgentOptions = () => ({
|
|
|
128
129
|
display_files_in_done_text: true,
|
|
129
130
|
include_tool_call_examples: false,
|
|
130
131
|
session_attachment_mode: 'copy',
|
|
132
|
+
allow_insecure_sensitive_data: false,
|
|
131
133
|
vision_detail_level: 'auto',
|
|
132
134
|
llm_timeout: 60,
|
|
133
135
|
step_timeout: 180,
|
|
@@ -137,7 +139,11 @@ const AgentLLMOutputSchema = z.object({
|
|
|
137
139
|
evaluation_previous_goal: z.string().optional().nullable(),
|
|
138
140
|
memory: z.string().optional().nullable(),
|
|
139
141
|
next_goal: z.string().optional().nullable(),
|
|
140
|
-
action: z
|
|
142
|
+
action: z
|
|
143
|
+
.array(z.record(z.string(), z.any()))
|
|
144
|
+
.optional()
|
|
145
|
+
.nullable()
|
|
146
|
+
.default([]),
|
|
141
147
|
});
|
|
142
148
|
const AgentLLMOutputFormat = AgentLLMOutputSchema;
|
|
143
149
|
AgentLLMOutputFormat.schema = AgentLLMOutputSchema;
|
|
@@ -198,7 +204,7 @@ export class Agent {
|
|
|
198
204
|
DoneActionModel = ActionModel;
|
|
199
205
|
DoneAgentOutput = AgentOutput;
|
|
200
206
|
constructor(params) {
|
|
201
|
-
const { task, llm, page = null, browser = null, browser_context = null, browser_profile = null, browser_session = null, controller = null, sensitive_data = null, initial_actions = null, register_new_step_callback = null, register_done_callback = null, register_external_agent_status_raise_error_callback = null, output_model_schema = null, use_vision = true, save_conversation_path = null, save_conversation_path_encoding = 'utf-8', max_failures = 3, retry_delay = 10, override_system_message = null, extend_system_message = null, validate_output = false, generate_gif = false, available_file_paths = [], include_attributes, max_actions_per_step = 10, use_thinking = true, flash_mode = false, max_history_items = null, page_extraction_llm = null, context = null, source = null, file_system_path = null, task_id = null, cloud_sync = null, calculate_cost = false, display_files_in_done_text = true, include_tool_call_examples = false, vision_detail_level = 'auto', session_attachment_mode = 'copy', llm_timeout = 60, step_timeout = 180, } = { ...defaultAgentOptions(), ...params };
|
|
207
|
+
const { task, llm, page = null, browser = null, browser_context = null, browser_profile = null, browser_session = null, controller = null, sensitive_data = null, initial_actions = null, register_new_step_callback = null, register_done_callback = null, register_external_agent_status_raise_error_callback = null, output_model_schema = null, use_vision = true, save_conversation_path = null, save_conversation_path_encoding = 'utf-8', max_failures = 3, retry_delay = 10, override_system_message = null, extend_system_message = null, validate_output = false, generate_gif = false, available_file_paths = [], include_attributes, max_actions_per_step = 10, use_thinking = true, flash_mode = false, max_history_items = null, page_extraction_llm = null, context = null, source = null, file_system_path = null, task_id = null, cloud_sync = null, calculate_cost = false, display_files_in_done_text = true, include_tool_call_examples = false, vision_detail_level = 'auto', session_attachment_mode = 'copy', allow_insecure_sensitive_data = false, llm_timeout = 60, step_timeout = 180, } = { ...defaultAgentOptions(), ...params };
|
|
202
208
|
if (!llm) {
|
|
203
209
|
throw new Error('Invalid llm, must be provided');
|
|
204
210
|
}
|
|
@@ -249,6 +255,7 @@ export class Agent {
|
|
|
249
255
|
calculate_cost,
|
|
250
256
|
include_tool_call_examples,
|
|
251
257
|
session_attachment_mode,
|
|
258
|
+
allow_insecure_sensitive_data,
|
|
252
259
|
llm_timeout,
|
|
253
260
|
step_timeout,
|
|
254
261
|
};
|
|
@@ -489,7 +496,7 @@ export class Agent {
|
|
|
489
496
|
Agent._sharedSessionStepLocks.delete(browser_session.id);
|
|
490
497
|
}
|
|
491
498
|
_init_browser_session(init) {
|
|
492
|
-
let { page, browser, browser_context, browser_profile, browser_session
|
|
499
|
+
let { page, browser, browser_context, browser_profile, browser_session } = init;
|
|
493
500
|
if (browser instanceof BrowserSession) {
|
|
494
501
|
browser_session = browser_session ?? browser;
|
|
495
502
|
browser = null;
|
|
@@ -617,6 +624,9 @@ export class Agent {
|
|
|
617
624
|
: Boolean(allowedDomainsConfig);
|
|
618
625
|
// If no allowed_domains are configured, show a security warning
|
|
619
626
|
if (!hasAllowedDomains) {
|
|
627
|
+
if (!this.settings.allow_insecure_sensitive_data) {
|
|
628
|
+
throw new InsecureSensitiveDataError();
|
|
629
|
+
}
|
|
620
630
|
this.logger.error('β οΈβ οΈβ οΈ Agent(sensitive_data=β’β’β’β’β’β’β’β’) was provided but BrowserSession(allowed_domains=[...]) is not locked down! β οΈβ οΈβ οΈ\n' +
|
|
621
631
|
' β οΈ If the agent visits a malicious website and encounters a prompt-injection attack, your sensitive_data may be exposed!\n\n' +
|
|
622
632
|
' https://docs.browser-use.com/customize/browser-settings#restrict-urls\n' +
|
|
@@ -627,7 +637,7 @@ export class Agent {
|
|
|
627
637
|
// User can still abort process with Ctrl+C.
|
|
628
638
|
this._sleep_blocking(10_000);
|
|
629
639
|
}
|
|
630
|
-
this.logger.warning('βΌοΈ Continuing with insecure settings
|
|
640
|
+
this.logger.warning('βΌοΈ Continuing with insecure settings because allow_insecure_sensitive_data=true is enabled.');
|
|
631
641
|
}
|
|
632
642
|
// If we're using domain-specific credentials, validate domain patterns
|
|
633
643
|
else if (hasDomainSpecificCredentials) {
|
|
@@ -1701,7 +1711,7 @@ export class Agent {
|
|
|
1701
1711
|
throw new Error('Agent paused');
|
|
1702
1712
|
}
|
|
1703
1713
|
}
|
|
1704
|
-
async _handle_post_llm_processing(browser_state_summary, input_messages,
|
|
1714
|
+
async _handle_post_llm_processing(browser_state_summary, input_messages, _actions = []) {
|
|
1705
1715
|
if (this.register_new_step_callback && this.state.last_model_output) {
|
|
1706
1716
|
await this.register_new_step_callback(browser_state_summary, this.state.last_model_output, this.state.n_steps);
|
|
1707
1717
|
}
|
|
@@ -1939,7 +1949,9 @@ export class Agent {
|
|
|
1939
1949
|
typeof entry.model_dump === 'function'
|
|
1940
1950
|
? entry.model_dump()
|
|
1941
1951
|
: entry;
|
|
1942
|
-
if (!candidate ||
|
|
1952
|
+
if (!candidate ||
|
|
1953
|
+
typeof candidate !== 'object' ||
|
|
1954
|
+
Array.isArray(candidate)) {
|
|
1943
1955
|
return false;
|
|
1944
1956
|
}
|
|
1945
1957
|
return Object.keys(candidate).length === 0;
|
|
@@ -2018,7 +2030,9 @@ export class Agent {
|
|
|
2018
2030
|
typeof entry.model_dump === 'function'
|
|
2019
2031
|
? entry.model_dump()
|
|
2020
2032
|
: entry;
|
|
2021
|
-
if (!candidate ||
|
|
2033
|
+
if (!candidate ||
|
|
2034
|
+
typeof candidate !== 'object' ||
|
|
2035
|
+
Array.isArray(candidate)) {
|
|
2022
2036
|
throw new Error(`Invalid action at index ${i}: expected an object with exactly one action key`);
|
|
2023
2037
|
}
|
|
2024
2038
|
const actionObject = candidate;
|
package/dist/agent/views.d.ts
CHANGED
|
@@ -55,6 +55,7 @@ export declare class ActionResult {
|
|
|
55
55
|
}
|
|
56
56
|
export interface AgentSettings {
|
|
57
57
|
session_attachment_mode: 'copy' | 'strict' | 'shared';
|
|
58
|
+
allow_insecure_sensitive_data: boolean;
|
|
58
59
|
use_vision: boolean;
|
|
59
60
|
vision_detail_level: 'auto' | 'low' | 'high';
|
|
60
61
|
use_vision_for_planner: boolean;
|
package/dist/agent/views.js
CHANGED
package/dist/browser/session.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
import { exec } from 'node:child_process';
|
|
4
5
|
import { promisify } from 'node:util';
|
|
@@ -52,7 +53,7 @@ export class BrowserSession {
|
|
|
52
53
|
? typeof structuredClone === 'function'
|
|
53
54
|
? structuredClone(init.browser_profile.config)
|
|
54
55
|
: JSON.parse(JSON.stringify(init.browser_profile.config))
|
|
55
|
-
: init.profile ?? {};
|
|
56
|
+
: (init.profile ?? {});
|
|
56
57
|
this.browser_profile = new BrowserProfile(sourceProfileConfig);
|
|
57
58
|
this.id = init.id ?? uuid7str();
|
|
58
59
|
this.browser = init.browser ?? null;
|
|
@@ -493,8 +494,7 @@ export class BrowserSession {
|
|
|
493
494
|
}
|
|
494
495
|
catch (error) {
|
|
495
496
|
const sandboxEnabled = this.browser_profile.config.chromium_sandbox;
|
|
496
|
-
if (!sandboxEnabled ||
|
|
497
|
-
!this._isSandboxLaunchError(error)) {
|
|
497
|
+
if (!sandboxEnabled || !this._isSandboxLaunchError(error)) {
|
|
498
498
|
throw error;
|
|
499
499
|
}
|
|
500
500
|
this.logger.warning('Chromium sandbox is unavailable in this environment. Retrying launch with chromium_sandbox=false (--no-sandbox).');
|
|
@@ -3094,7 +3094,7 @@ export class BrowserSession {
|
|
|
3094
3094
|
*/
|
|
3095
3095
|
_escapeSelector(selector) {
|
|
3096
3096
|
// Escape special CSS characters
|
|
3097
|
-
return selector.replace(/[!"#$%&'()
|
|
3097
|
+
return selector.replace(/[!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g, '\\$&');
|
|
3098
3098
|
}
|
|
3099
3099
|
// endregion
|
|
3100
3100
|
// region - User Data Directory Management
|
|
@@ -3181,7 +3181,7 @@ export class BrowserSession {
|
|
|
3181
3181
|
* Create a temporary user data directory
|
|
3182
3182
|
*/
|
|
3183
3183
|
async _createTempUserDataDir() {
|
|
3184
|
-
const osTempDir =
|
|
3184
|
+
const osTempDir = os.tmpdir();
|
|
3185
3185
|
const tempDir = path.join(osTempDir, `browser-use-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
3186
3186
|
fs.mkdirSync(tempDir, { recursive: true });
|
|
3187
3187
|
return tempDir;
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,2 +1,38 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import type { BaseChatModel } from './llm/base.js';
|
|
3
|
+
type CliModelProvider = 'openai' | 'anthropic' | 'google' | 'deepseek' | 'groq' | 'openrouter' | 'azure' | 'aws-anthropic' | 'aws' | 'ollama';
|
|
4
|
+
export interface ParsedCliArgs {
|
|
5
|
+
help: boolean;
|
|
6
|
+
version: boolean;
|
|
7
|
+
debug: boolean;
|
|
8
|
+
allow_insecure: boolean;
|
|
9
|
+
headless: boolean | null;
|
|
10
|
+
window_width: number | null;
|
|
11
|
+
window_height: number | null;
|
|
12
|
+
user_data_dir: string | null;
|
|
13
|
+
profile_directory: string | null;
|
|
14
|
+
allowed_domains: string[] | null;
|
|
15
|
+
cdp_url: string | null;
|
|
16
|
+
model: string | null;
|
|
17
|
+
provider: CliModelProvider | null;
|
|
18
|
+
prompt: string | null;
|
|
19
|
+
mcp: boolean;
|
|
20
|
+
positional: string[];
|
|
21
|
+
}
|
|
22
|
+
export declare const CLI_HISTORY_LIMIT = 100;
|
|
23
|
+
export declare const parseCliArgs: (argv: string[]) => ParsedCliArgs;
|
|
24
|
+
export declare const isInteractiveExitCommand: (value: string) => boolean;
|
|
25
|
+
export declare const isInteractiveHelpCommand: (value: string) => boolean;
|
|
26
|
+
export declare const normalizeCliHistory: (history: unknown[], maxLength?: number) => string[];
|
|
27
|
+
export declare const getCliHistoryPath: (configDir?: string | null) => string;
|
|
28
|
+
export declare const loadCliHistory: (historyPath?: string) => Promise<string[]>;
|
|
29
|
+
export declare const saveCliHistory: (history: string[], historyPath?: string) => Promise<void>;
|
|
30
|
+
export declare const shouldStartInteractiveMode: (task: string | null, options?: {
|
|
31
|
+
forceInteractive?: boolean;
|
|
32
|
+
inputIsTTY?: boolean;
|
|
33
|
+
outputIsTTY?: boolean;
|
|
34
|
+
}) => boolean;
|
|
35
|
+
export declare const getLlmFromCliArgs: (args: ParsedCliArgs) => BaseChatModel;
|
|
36
|
+
export declare const getCliUsage: () => string;
|
|
37
|
+
export declare function main(argv?: string[]): Promise<void>;
|
|
2
38
|
export {};
|