browser-use 0.1.0 → 0.3.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 +301 -636
- package/dist/actor/element.d.ts +19 -0
- package/dist/actor/element.js +46 -0
- package/dist/actor/index.d.ts +4 -0
- package/dist/actor/index.js +4 -0
- package/dist/actor/mouse.d.ts +19 -0
- package/dist/actor/mouse.js +39 -0
- package/dist/actor/page.d.ts +29 -0
- package/dist/actor/page.js +88 -0
- package/dist/actor/utils.d.ts +4 -0
- package/dist/actor/utils.js +35 -0
- package/dist/agent/cloud-events.d.ts +18 -0
- package/dist/agent/cloud-events.js +65 -2
- package/dist/agent/gif.d.ts +1 -0
- package/dist/agent/gif.js +24 -2
- package/dist/agent/judge.d.ts +17 -0
- package/dist/agent/judge.js +197 -0
- package/dist/agent/message-manager/service.d.ts +12 -4
- package/dist/agent/message-manager/service.js +205 -39
- package/dist/agent/message-manager/utils.js +0 -1
- package/dist/agent/message-manager/views.d.ts +4 -0
- package/dist/agent/message-manager/views.js +11 -7
- package/dist/agent/prompts.d.ts +24 -3
- package/dist/agent/prompts.js +274 -59
- package/dist/agent/service.d.ts +99 -40
- package/dist/agent/service.js +2282 -474
- package/dist/agent/variable-detector.d.ts +12 -0
- package/dist/agent/variable-detector.js +211 -0
- package/dist/agent/views.d.ts +237 -17
- package/dist/agent/views.js +446 -32
- package/dist/browser/cloud/cloud.d.ts +20 -0
- package/dist/browser/cloud/cloud.js +129 -0
- package/dist/browser/cloud/index.d.ts +2 -0
- package/dist/browser/cloud/index.js +2 -0
- package/dist/browser/cloud/views.d.ts +41 -0
- package/dist/browser/cloud/views.js +35 -0
- package/dist/browser/events.d.ts +345 -0
- package/dist/browser/events.js +566 -0
- package/dist/browser/extensions.js +17 -17
- package/dist/browser/index.d.ts +4 -0
- package/dist/browser/index.js +4 -0
- package/dist/browser/profile.d.ts +8 -2
- package/dist/browser/profile.js +79 -12
- package/dist/browser/session-manager.d.ts +85 -0
- package/dist/browser/session-manager.js +208 -0
- package/dist/browser/session.d.ts +100 -8
- package/dist/browser/session.js +1102 -63
- package/dist/browser/types.d.ts +0 -2
- package/dist/browser/views.d.ts +39 -0
- package/dist/browser/views.js +32 -0
- package/dist/browser/watchdogs/aboutblank-watchdog.d.ts +12 -0
- package/dist/browser/watchdogs/aboutblank-watchdog.js +131 -0
- package/dist/browser/watchdogs/base.d.ts +21 -0
- package/dist/browser/watchdogs/base.js +81 -0
- package/dist/browser/watchdogs/cdp-session-watchdog.d.ts +14 -0
- package/dist/browser/watchdogs/cdp-session-watchdog.js +177 -0
- package/dist/browser/watchdogs/crash-watchdog.d.ts +38 -0
- package/dist/browser/watchdogs/crash-watchdog.js +296 -0
- package/dist/browser/watchdogs/default-action-watchdog.d.ts +49 -0
- package/dist/browser/watchdogs/default-action-watchdog.js +212 -0
- package/dist/browser/watchdogs/dom-watchdog.d.ts +8 -0
- package/dist/browser/watchdogs/dom-watchdog.js +31 -0
- package/dist/browser/watchdogs/downloads-watchdog.d.ts +77 -0
- package/dist/browser/watchdogs/downloads-watchdog.js +409 -0
- package/dist/browser/watchdogs/har-recording-watchdog.d.ts +19 -0
- package/dist/browser/watchdogs/har-recording-watchdog.js +317 -0
- package/dist/browser/watchdogs/index.d.ts +15 -0
- package/dist/browser/watchdogs/index.js +15 -0
- package/dist/browser/watchdogs/local-browser-watchdog.d.ts +10 -0
- package/dist/browser/watchdogs/local-browser-watchdog.js +32 -0
- package/dist/browser/watchdogs/permissions-watchdog.d.ts +8 -0
- package/dist/browser/watchdogs/permissions-watchdog.js +73 -0
- package/dist/browser/watchdogs/popups-watchdog.d.ts +13 -0
- package/dist/browser/watchdogs/popups-watchdog.js +77 -0
- package/dist/browser/watchdogs/recording-watchdog.d.ts +27 -0
- package/dist/browser/watchdogs/recording-watchdog.js +249 -0
- package/dist/browser/watchdogs/screenshot-watchdog.d.ts +6 -0
- package/dist/browser/watchdogs/screenshot-watchdog.js +13 -0
- package/dist/browser/watchdogs/security-watchdog.d.ts +10 -0
- package/dist/browser/watchdogs/security-watchdog.js +84 -0
- package/dist/browser/watchdogs/storage-state-watchdog.d.ts +24 -0
- package/dist/browser/watchdogs/storage-state-watchdog.js +288 -0
- package/dist/cli.d.ts +41 -0
- package/dist/cli.js +820 -10
- package/dist/code-use/formatting.d.ts +3 -0
- package/dist/code-use/formatting.js +18 -0
- package/dist/code-use/index.d.ts +6 -0
- package/dist/code-use/index.js +6 -0
- package/dist/code-use/namespace.d.ts +5 -0
- package/dist/code-use/namespace.js +81 -0
- package/dist/code-use/notebook-export.d.ts +3 -0
- package/dist/code-use/notebook-export.js +56 -0
- package/dist/code-use/service.d.ts +24 -0
- package/dist/code-use/service.js +104 -0
- package/dist/code-use/utils.d.ts +4 -0
- package/dist/code-use/utils.js +98 -0
- package/dist/code-use/views.d.ts +108 -0
- package/dist/code-use/views.js +165 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.js +69 -3
- package/dist/controller/registry/service.d.ts +10 -1
- package/dist/controller/registry/service.js +266 -10
- package/dist/controller/registry/views.d.ts +4 -1
- package/dist/controller/registry/views.js +25 -2
- package/dist/controller/service.d.ts +10 -1
- package/dist/controller/service.js +1849 -288
- package/dist/controller/views.d.ts +78 -155
- package/dist/controller/views.js +61 -12
- package/dist/dom/history-tree-processor/service.d.ts +5 -0
- package/dist/dom/history-tree-processor/service.js +169 -14
- package/dist/dom/history-tree-processor/view.d.ts +7 -1
- package/dist/dom/history-tree-processor/view.js +10 -1
- package/dist/dom/markdown-extractor.d.ts +37 -0
- package/dist/dom/markdown-extractor.js +345 -0
- package/dist/dom/service.d.ts +3 -1
- package/dist/dom/service.js +76 -0
- package/dist/dom/views.d.ts +1 -0
- package/dist/dom/views.js +45 -0
- package/dist/event-bus.d.ts +107 -7
- package/dist/event-bus.js +313 -10
- package/dist/filesystem/file-system.d.ts +18 -0
- package/dist/filesystem/file-system.js +530 -42
- package/dist/index.d.ts +7 -0
- package/dist/index.js +6 -0
- package/dist/integrations/gmail/actions.d.ts +3 -3
- package/dist/integrations/gmail/actions.js +5 -5
- package/dist/llm/anthropic/chat.d.ts +18 -1
- package/dist/llm/anthropic/chat.js +123 -55
- package/dist/llm/anthropic/serializer.d.ts +2 -0
- package/dist/llm/anthropic/serializer.js +81 -9
- package/dist/llm/aws/chat-anthropic.d.ts +17 -0
- package/dist/llm/aws/chat-anthropic.js +129 -40
- package/dist/llm/aws/chat-bedrock.d.ts +28 -1
- package/dist/llm/aws/chat-bedrock.js +161 -34
- package/dist/llm/aws/serializer.d.ts +13 -1
- package/dist/llm/aws/serializer.js +56 -17
- package/dist/llm/azure/chat.d.ts +53 -2
- package/dist/llm/azure/chat.js +366 -53
- package/dist/llm/base.d.ts +2 -0
- package/dist/llm/browser-use/chat.d.ts +40 -0
- package/dist/llm/browser-use/chat.js +305 -0
- package/dist/llm/browser-use/index.d.ts +1 -0
- package/dist/llm/browser-use/index.js +1 -0
- package/dist/llm/cerebras/chat.d.ts +39 -0
- package/dist/llm/cerebras/chat.js +178 -0
- package/dist/llm/cerebras/index.d.ts +2 -0
- package/dist/llm/cerebras/index.js +2 -0
- package/dist/llm/cerebras/serializer.d.ts +7 -0
- package/dist/llm/cerebras/serializer.js +82 -0
- package/dist/llm/deepseek/chat.d.ts +19 -2
- package/dist/llm/deepseek/chat.js +138 -25
- package/dist/llm/google/chat.d.ts +46 -2
- package/dist/llm/google/chat.js +268 -63
- package/dist/llm/google/serializer.d.ts +9 -1
- package/dist/llm/google/serializer.js +141 -34
- package/dist/llm/groq/chat.d.ts +21 -2
- package/dist/llm/groq/chat.js +125 -26
- package/dist/llm/groq/parser.js +3 -1
- package/dist/llm/messages.d.ts +4 -4
- package/dist/llm/mistral/chat.d.ts +43 -0
- package/dist/llm/mistral/chat.js +154 -0
- package/dist/llm/mistral/index.d.ts +2 -0
- package/dist/llm/mistral/index.js +2 -0
- package/dist/llm/mistral/schema.d.ts +8 -0
- package/dist/llm/mistral/schema.js +27 -0
- package/dist/llm/models.d.ts +2 -0
- package/dist/llm/models.js +317 -0
- package/dist/llm/ollama/chat.d.ts +13 -1
- package/dist/llm/ollama/chat.js +110 -19
- package/dist/llm/ollama/serializer.d.ts +1 -0
- package/dist/llm/ollama/serializer.js +34 -12
- package/dist/llm/openai/chat.d.ts +16 -0
- package/dist/llm/openai/chat.js +94 -44
- package/dist/llm/openai/like.d.ts +5 -3
- package/dist/llm/openai/like.js +7 -3
- package/dist/llm/openai/responses-serializer.d.ts +18 -0
- package/dist/llm/openai/responses-serializer.js +72 -0
- package/dist/llm/openrouter/chat.d.ts +28 -2
- package/dist/llm/openrouter/chat.js +115 -29
- package/dist/llm/schema.d.ts +11 -1
- package/dist/llm/schema.js +81 -1
- package/dist/llm/vercel/chat.d.ts +50 -0
- package/dist/llm/vercel/chat.js +276 -0
- package/dist/llm/vercel/index.d.ts +1 -0
- package/dist/llm/vercel/index.js +1 -0
- package/dist/llm/vercel/serializer.d.ts +5 -0
- package/dist/llm/vercel/serializer.js +7 -0
- package/dist/llm/views.d.ts +2 -1
- package/dist/llm/views.js +3 -1
- package/dist/logging-config.d.ts +2 -0
- package/dist/logging-config.js +82 -29
- package/dist/mcp/client.d.ts +10 -5
- package/dist/mcp/client.js +21 -15
- package/dist/mcp/controller.d.ts +42 -3
- package/dist/mcp/controller.js +56 -31
- package/dist/mcp/server.d.ts +14 -0
- package/dist/mcp/server.js +257 -51
- package/dist/observability.js +10 -4
- package/dist/sandbox/index.d.ts +2 -0
- package/dist/sandbox/index.js +2 -0
- package/dist/sandbox/sandbox.d.ts +19 -0
- package/dist/sandbox/sandbox.js +140 -0
- package/dist/sandbox/views.d.ts +67 -0
- package/dist/sandbox/views.js +121 -0
- package/dist/skill-cli/index.d.ts +3 -0
- package/dist/skill-cli/index.js +3 -0
- package/dist/skill-cli/protocol.d.ts +30 -0
- package/dist/skill-cli/protocol.js +48 -0
- package/dist/skill-cli/server.d.ts +11 -0
- package/dist/skill-cli/server.js +85 -0
- package/dist/skill-cli/sessions.d.ts +24 -0
- package/dist/skill-cli/sessions.js +47 -0
- package/dist/skills/index.d.ts +3 -0
- package/dist/skills/index.js +3 -0
- package/dist/skills/service.d.ts +27 -0
- package/dist/skills/service.js +266 -0
- package/dist/skills/utils.d.ts +6 -0
- package/dist/skills/utils.js +53 -0
- package/dist/skills/views.d.ts +40 -0
- package/dist/skills/views.js +10 -0
- package/dist/sync/auth.js +8 -3
- package/dist/sync/service.d.ts +6 -6
- package/dist/sync/service.js +54 -89
- package/dist/telemetry/views.d.ts +20 -6
- package/dist/telemetry/views.js +23 -5
- package/dist/tokens/custom-pricing.d.ts +2 -0
- package/dist/tokens/custom-pricing.js +22 -0
- package/dist/tokens/index.d.ts +2 -0
- package/dist/tokens/index.js +2 -0
- package/dist/tokens/mappings.d.ts +1 -0
- package/dist/tokens/mappings.js +3 -0
- package/dist/tokens/service.js +30 -12
- package/dist/tools/extraction/index.d.ts +2 -0
- package/dist/tools/extraction/index.js +2 -0
- package/dist/tools/extraction/schema-utils.d.ts +6 -0
- package/dist/tools/extraction/schema-utils.js +237 -0
- package/dist/tools/extraction/views.d.ts +7 -0
- package/dist/tools/index.d.ts +5 -0
- package/dist/tools/index.js +5 -0
- package/dist/tools/registry/index.d.ts +2 -0
- package/dist/tools/registry/index.js +2 -0
- package/dist/tools/registry/service.d.ts +1 -0
- package/dist/tools/registry/service.js +1 -0
- package/dist/tools/registry/views.d.ts +1 -0
- package/dist/tools/registry/views.js +1 -0
- package/dist/tools/service.d.ts +2 -0
- package/dist/tools/service.js +1 -0
- package/dist/tools/utils.d.ts +2 -0
- package/dist/tools/utils.js +57 -0
- package/dist/tools/views.d.ts +1 -0
- package/dist/tools/views.js +1 -0
- package/dist/utils.d.ts +10 -1
- package/dist/utils.js +70 -3
- package/package.json +265 -28
- package/dist/dom/playground/process-dom.js +0 -5
- package/dist/dom/playground/test-accessibility.d.ts +0 -44
- package/dist/dom/playground/test-accessibility.js +0 -111
- /package/dist/{dom/playground/process-dom.d.ts → tools/extraction/views.js} +0 -0
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,770 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { stdin, stdout } from 'node:process';
|
|
6
|
+
import { createInterface } from 'node:readline/promises';
|
|
2
7
|
import { Agent } from './agent/service.js';
|
|
8
|
+
import { BrowserProfile, } from './browser/profile.js';
|
|
9
|
+
import { BrowserSession } from './browser/session.js';
|
|
10
|
+
import { CONFIG } from './config.js';
|
|
3
11
|
import { ChatOpenAI } from './llm/openai/chat.js';
|
|
12
|
+
import { ChatAnthropic } from './llm/anthropic/chat.js';
|
|
13
|
+
import { ChatGoogle } from './llm/google/chat.js';
|
|
14
|
+
import { ChatDeepSeek } from './llm/deepseek/chat.js';
|
|
15
|
+
import { ChatGroq } from './llm/groq/chat.js';
|
|
16
|
+
import { ChatOpenRouter } from './llm/openrouter/chat.js';
|
|
17
|
+
import { ChatAzure } from './llm/azure/chat.js';
|
|
18
|
+
import { ChatOllama } from './llm/ollama/chat.js';
|
|
19
|
+
import { ChatMistral } from './llm/mistral/chat.js';
|
|
20
|
+
import { ChatCerebras } from './llm/cerebras/chat.js';
|
|
21
|
+
import { ChatVercel } from './llm/vercel/chat.js';
|
|
22
|
+
import { ChatAnthropicBedrock } from './llm/aws/chat-anthropic.js';
|
|
23
|
+
import { ChatBedrockConverse } from './llm/aws/chat-bedrock.js';
|
|
24
|
+
import { ChatBrowserUse } from './llm/browser-use/chat.js';
|
|
4
25
|
import { MCPServer } from './mcp/server.js';
|
|
5
26
|
import { get_browser_use_version } from './utils.js';
|
|
27
|
+
import { setupLogging } from './logging-config.js';
|
|
6
28
|
import dotenv from 'dotenv';
|
|
7
29
|
dotenv.config();
|
|
30
|
+
const CLI_PROVIDER_ALIASES = {
|
|
31
|
+
openai: 'openai',
|
|
32
|
+
anthropic: 'anthropic',
|
|
33
|
+
google: 'google',
|
|
34
|
+
gemini: 'google',
|
|
35
|
+
deepseek: 'deepseek',
|
|
36
|
+
groq: 'groq',
|
|
37
|
+
openrouter: 'openrouter',
|
|
38
|
+
azure: 'azure',
|
|
39
|
+
mistral: 'mistral',
|
|
40
|
+
cerebras: 'cerebras',
|
|
41
|
+
vercel: 'vercel',
|
|
42
|
+
oci: 'oci',
|
|
43
|
+
ollama: 'ollama',
|
|
44
|
+
'browser-use': 'browser-use',
|
|
45
|
+
browseruse: 'browser-use',
|
|
46
|
+
bu: 'browser-use',
|
|
47
|
+
bedrock: 'aws',
|
|
48
|
+
aws: 'aws',
|
|
49
|
+
'aws-anthropic': 'aws-anthropic',
|
|
50
|
+
'bedrock-anthropic': 'aws-anthropic',
|
|
51
|
+
};
|
|
52
|
+
export const CLI_HISTORY_LIMIT = 100;
|
|
53
|
+
const INTERACTIVE_EXIT_COMMANDS = new Set(['exit', 'quit', ':q', '/q', '.q']);
|
|
54
|
+
const INTERACTIVE_HELP_COMMANDS = new Set(['help', '?', ':help']);
|
|
55
|
+
const parseAllowedDomains = (value) => {
|
|
56
|
+
const domains = value
|
|
57
|
+
.split(',')
|
|
58
|
+
.map((entry) => entry.trim())
|
|
59
|
+
.filter((entry) => entry.length > 0);
|
|
60
|
+
if (domains.length === 0) {
|
|
61
|
+
throw new Error('--allowed-domains must include at least one domain pattern');
|
|
62
|
+
}
|
|
63
|
+
return domains;
|
|
64
|
+
};
|
|
65
|
+
const parsePositiveInt = (name, value) => {
|
|
66
|
+
const parsed = Number.parseInt(value, 10);
|
|
67
|
+
if (!Number.isFinite(parsed) || Number.isNaN(parsed) || parsed <= 0) {
|
|
68
|
+
throw new Error(`${name} must be a positive integer, got "${value}"`);
|
|
69
|
+
}
|
|
70
|
+
return parsed;
|
|
71
|
+
};
|
|
72
|
+
const parseProvider = (value) => {
|
|
73
|
+
const normalized = value.trim().toLowerCase();
|
|
74
|
+
const provider = CLI_PROVIDER_ALIASES[normalized];
|
|
75
|
+
if (!provider) {
|
|
76
|
+
throw new Error(`Unsupported provider "${value}". Supported values: openai, anthropic, google, deepseek, groq, openrouter, azure, mistral, cerebras, vercel, oci, ollama, browser-use, aws, aws-anthropic.`);
|
|
77
|
+
}
|
|
78
|
+
return provider;
|
|
79
|
+
};
|
|
80
|
+
const takeOptionValue = (arg, currentIndex, argv) => {
|
|
81
|
+
const eqIndex = arg.indexOf('=');
|
|
82
|
+
if (eqIndex >= 0) {
|
|
83
|
+
const inlineValue = arg.slice(eqIndex + 1).trim();
|
|
84
|
+
if (!inlineValue) {
|
|
85
|
+
throw new Error(`Missing value for option: ${arg.slice(0, eqIndex)}`);
|
|
86
|
+
}
|
|
87
|
+
return { value: inlineValue, nextIndex: currentIndex };
|
|
88
|
+
}
|
|
89
|
+
const next = argv[currentIndex + 1];
|
|
90
|
+
if (!next || next.startsWith('-')) {
|
|
91
|
+
throw new Error(`Missing value for option: ${arg}`);
|
|
92
|
+
}
|
|
93
|
+
return { value: next, nextIndex: currentIndex + 1 };
|
|
94
|
+
};
|
|
95
|
+
const expandHome = (value) => {
|
|
96
|
+
if (!value.startsWith('~')) {
|
|
97
|
+
return value;
|
|
98
|
+
}
|
|
99
|
+
const home = process.env.HOME || process.env.USERPROFILE || '';
|
|
100
|
+
if (!home) {
|
|
101
|
+
return value;
|
|
102
|
+
}
|
|
103
|
+
if (value === '~') {
|
|
104
|
+
return home;
|
|
105
|
+
}
|
|
106
|
+
if (value.startsWith('~/') || value.startsWith('~\\')) {
|
|
107
|
+
return path.join(home, value.slice(2));
|
|
108
|
+
}
|
|
109
|
+
return value;
|
|
110
|
+
};
|
|
111
|
+
export const parseCliArgs = (argv) => {
|
|
112
|
+
const parsed = {
|
|
113
|
+
help: false,
|
|
114
|
+
version: false,
|
|
115
|
+
debug: false,
|
|
116
|
+
headless: null,
|
|
117
|
+
window_width: null,
|
|
118
|
+
window_height: null,
|
|
119
|
+
user_data_dir: null,
|
|
120
|
+
profile_directory: null,
|
|
121
|
+
allowed_domains: null,
|
|
122
|
+
proxy_url: null,
|
|
123
|
+
no_proxy: null,
|
|
124
|
+
proxy_username: null,
|
|
125
|
+
proxy_password: null,
|
|
126
|
+
cdp_url: null,
|
|
127
|
+
model: null,
|
|
128
|
+
provider: null,
|
|
129
|
+
prompt: null,
|
|
130
|
+
mcp: false,
|
|
131
|
+
positional: [],
|
|
132
|
+
};
|
|
133
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
134
|
+
const arg = argv[i];
|
|
135
|
+
if (arg === '--') {
|
|
136
|
+
parsed.positional.push(...argv.slice(i + 1));
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
if (arg === '-h' || arg === '--help') {
|
|
140
|
+
parsed.help = true;
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
if (arg === '--version') {
|
|
144
|
+
parsed.version = true;
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (arg === '--debug') {
|
|
148
|
+
parsed.debug = true;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
if (arg === '--headless') {
|
|
152
|
+
parsed.headless = true;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (arg === '--mcp') {
|
|
156
|
+
parsed.mcp = true;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (arg === '-p' || arg === '--prompt' || arg.startsWith('--prompt=')) {
|
|
160
|
+
const { value, nextIndex } = takeOptionValue(arg, i, argv);
|
|
161
|
+
parsed.prompt = value;
|
|
162
|
+
i = nextIndex;
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
if (arg === '--model' || arg.startsWith('--model=')) {
|
|
166
|
+
const { value, nextIndex } = takeOptionValue(arg, i, argv);
|
|
167
|
+
parsed.model = value;
|
|
168
|
+
i = nextIndex;
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
if (arg === '--provider' || arg.startsWith('--provider=')) {
|
|
172
|
+
const { value, nextIndex } = takeOptionValue(arg, i, argv);
|
|
173
|
+
parsed.provider = parseProvider(value);
|
|
174
|
+
i = nextIndex;
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
if (arg === '--window-width' || arg.startsWith('--window-width=')) {
|
|
178
|
+
const { value, nextIndex } = takeOptionValue(arg, i, argv);
|
|
179
|
+
parsed.window_width = parsePositiveInt('--window-width', value);
|
|
180
|
+
i = nextIndex;
|
|
181
|
+
continue;
|
|
182
|
+
}
|
|
183
|
+
if (arg === '--window-height' || arg.startsWith('--window-height=')) {
|
|
184
|
+
const { value, nextIndex } = takeOptionValue(arg, i, argv);
|
|
185
|
+
parsed.window_height = parsePositiveInt('--window-height', value);
|
|
186
|
+
i = nextIndex;
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
if (arg === '--user-data-dir' || arg.startsWith('--user-data-dir=')) {
|
|
190
|
+
const { value, nextIndex } = takeOptionValue(arg, i, argv);
|
|
191
|
+
parsed.user_data_dir = path.resolve(expandHome(value));
|
|
192
|
+
i = nextIndex;
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (arg === '--profile-directory' ||
|
|
196
|
+
arg.startsWith('--profile-directory=')) {
|
|
197
|
+
const { value, nextIndex } = takeOptionValue(arg, i, argv);
|
|
198
|
+
parsed.profile_directory = value;
|
|
199
|
+
i = nextIndex;
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
if (arg === '--allowed-domains' || arg.startsWith('--allowed-domains=')) {
|
|
203
|
+
const { value, nextIndex } = takeOptionValue(arg, i, argv);
|
|
204
|
+
const domains = parseAllowedDomains(value);
|
|
205
|
+
parsed.allowed_domains = [...(parsed.allowed_domains ?? []), ...domains];
|
|
206
|
+
i = nextIndex;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (arg === '--proxy-url' || arg.startsWith('--proxy-url=')) {
|
|
210
|
+
const { value, nextIndex } = takeOptionValue(arg, i, argv);
|
|
211
|
+
parsed.proxy_url = value.trim();
|
|
212
|
+
i = nextIndex;
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
if (arg === '--no-proxy' || arg.startsWith('--no-proxy=')) {
|
|
216
|
+
const { value, nextIndex } = takeOptionValue(arg, i, argv);
|
|
217
|
+
parsed.no_proxy = value;
|
|
218
|
+
i = nextIndex;
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (arg === '--proxy-username' || arg.startsWith('--proxy-username=')) {
|
|
222
|
+
const { value, nextIndex } = takeOptionValue(arg, i, argv);
|
|
223
|
+
parsed.proxy_username = value;
|
|
224
|
+
i = nextIndex;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
if (arg === '--proxy-password' || arg.startsWith('--proxy-password=')) {
|
|
228
|
+
const { value, nextIndex } = takeOptionValue(arg, i, argv);
|
|
229
|
+
parsed.proxy_password = value;
|
|
230
|
+
i = nextIndex;
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
if (arg === '--cdp-url' || arg.startsWith('--cdp-url=')) {
|
|
234
|
+
const { value, nextIndex } = takeOptionValue(arg, i, argv);
|
|
235
|
+
parsed.cdp_url = value;
|
|
236
|
+
i = nextIndex;
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
if (arg.startsWith('-')) {
|
|
240
|
+
throw new Error(`Unknown option: ${arg}`);
|
|
241
|
+
}
|
|
242
|
+
parsed.positional.push(arg);
|
|
243
|
+
}
|
|
244
|
+
if (parsed.prompt && parsed.positional.length > 0) {
|
|
245
|
+
throw new Error('Use either positional task text or --prompt, not both.');
|
|
246
|
+
}
|
|
247
|
+
return parsed;
|
|
248
|
+
};
|
|
249
|
+
const resolveTask = (args) => {
|
|
250
|
+
if (args.prompt) {
|
|
251
|
+
return args.prompt.trim();
|
|
252
|
+
}
|
|
253
|
+
if (args.positional.length > 0) {
|
|
254
|
+
return args.positional.join(' ').trim();
|
|
255
|
+
}
|
|
256
|
+
return null;
|
|
257
|
+
};
|
|
258
|
+
export const isInteractiveExitCommand = (value) => INTERACTIVE_EXIT_COMMANDS.has(value.trim().toLowerCase());
|
|
259
|
+
export const isInteractiveHelpCommand = (value) => INTERACTIVE_HELP_COMMANDS.has(value.trim().toLowerCase());
|
|
260
|
+
export const normalizeCliHistory = (history, maxLength = CLI_HISTORY_LIMIT) => {
|
|
261
|
+
const normalized = history
|
|
262
|
+
.map((entry) => (typeof entry === 'string' ? entry.trim() : ''))
|
|
263
|
+
.filter((entry) => entry.length > 0);
|
|
264
|
+
return normalized.slice(-maxLength);
|
|
265
|
+
};
|
|
266
|
+
export const getCliHistoryPath = (configDir) => {
|
|
267
|
+
const baseDir = configDir ??
|
|
268
|
+
CONFIG.BROWSER_USE_CONFIG_DIR ??
|
|
269
|
+
path.join(os.homedir(), '.config', 'browseruse');
|
|
270
|
+
return path.join(baseDir, 'command_history.json');
|
|
271
|
+
};
|
|
272
|
+
export const loadCliHistory = async (historyPath = getCliHistoryPath()) => {
|
|
273
|
+
try {
|
|
274
|
+
const raw = await fs.readFile(historyPath, 'utf-8');
|
|
275
|
+
const parsed = JSON.parse(raw);
|
|
276
|
+
if (!Array.isArray(parsed)) {
|
|
277
|
+
return [];
|
|
278
|
+
}
|
|
279
|
+
return normalizeCliHistory(parsed);
|
|
280
|
+
}
|
|
281
|
+
catch (error) {
|
|
282
|
+
const nodeError = error;
|
|
283
|
+
if (nodeError.code === 'ENOENT') {
|
|
284
|
+
return [];
|
|
285
|
+
}
|
|
286
|
+
return [];
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
export const saveCliHistory = async (history, historyPath = getCliHistoryPath()) => {
|
|
290
|
+
const normalized = normalizeCliHistory(history);
|
|
291
|
+
await fs.mkdir(path.dirname(historyPath), { recursive: true });
|
|
292
|
+
await fs.writeFile(historyPath, JSON.stringify(normalized, null, 2), 'utf-8');
|
|
293
|
+
};
|
|
294
|
+
export const shouldStartInteractiveMode = (task, options = {}) => {
|
|
295
|
+
const forceInteractive = options.forceInteractive ??
|
|
296
|
+
process.env.BROWSER_USE_CLI_FORCE_INTERACTIVE === '1';
|
|
297
|
+
const inputIsTTY = options.inputIsTTY ?? Boolean(stdin.isTTY);
|
|
298
|
+
const outputIsTTY = options.outputIsTTY ?? Boolean(stdout.isTTY);
|
|
299
|
+
return !task && (forceInteractive || (inputIsTTY && outputIsTTY));
|
|
300
|
+
};
|
|
301
|
+
const requireEnv = (name) => {
|
|
302
|
+
const value = process.env[name];
|
|
303
|
+
if (!value) {
|
|
304
|
+
throw new Error(`Missing environment variable: ${name}`);
|
|
305
|
+
}
|
|
306
|
+
return value;
|
|
307
|
+
};
|
|
308
|
+
const inferProviderFromModel = (model) => {
|
|
309
|
+
const lower = model.toLowerCase();
|
|
310
|
+
if (lower.startsWith('gpt') ||
|
|
311
|
+
lower.startsWith('o1') ||
|
|
312
|
+
lower.startsWith('o3') ||
|
|
313
|
+
lower.startsWith('o4') ||
|
|
314
|
+
lower.startsWith('gpt-5')) {
|
|
315
|
+
return 'openai';
|
|
316
|
+
}
|
|
317
|
+
if (lower.startsWith('claude')) {
|
|
318
|
+
return 'anthropic';
|
|
319
|
+
}
|
|
320
|
+
if (lower.startsWith('gemini')) {
|
|
321
|
+
return 'google';
|
|
322
|
+
}
|
|
323
|
+
if (lower.startsWith('deepseek')) {
|
|
324
|
+
return 'deepseek';
|
|
325
|
+
}
|
|
326
|
+
if (lower.startsWith('groq:')) {
|
|
327
|
+
return 'groq';
|
|
328
|
+
}
|
|
329
|
+
if (lower.startsWith('openrouter:')) {
|
|
330
|
+
return 'openrouter';
|
|
331
|
+
}
|
|
332
|
+
if (lower.startsWith('azure:')) {
|
|
333
|
+
return 'azure';
|
|
334
|
+
}
|
|
335
|
+
if (lower.startsWith('mistral:')) {
|
|
336
|
+
return 'mistral';
|
|
337
|
+
}
|
|
338
|
+
if (lower.startsWith('cerebras:')) {
|
|
339
|
+
return 'cerebras';
|
|
340
|
+
}
|
|
341
|
+
if (lower.startsWith('vercel:')) {
|
|
342
|
+
return 'vercel';
|
|
343
|
+
}
|
|
344
|
+
if (lower.startsWith('oci:')) {
|
|
345
|
+
return 'oci';
|
|
346
|
+
}
|
|
347
|
+
if (lower.startsWith('mistral-') ||
|
|
348
|
+
lower.startsWith('codestral') ||
|
|
349
|
+
lower.startsWith('pixtral')) {
|
|
350
|
+
return 'mistral';
|
|
351
|
+
}
|
|
352
|
+
if (lower.startsWith('llama3.') ||
|
|
353
|
+
lower.startsWith('llama-4-') ||
|
|
354
|
+
lower.startsWith('gpt-oss-') ||
|
|
355
|
+
lower.startsWith('qwen-3-')) {
|
|
356
|
+
return 'cerebras';
|
|
357
|
+
}
|
|
358
|
+
if (lower.startsWith('ollama:')) {
|
|
359
|
+
return 'ollama';
|
|
360
|
+
}
|
|
361
|
+
if (lower.startsWith('browser-use:') ||
|
|
362
|
+
lower.startsWith('bu-') ||
|
|
363
|
+
lower.startsWith('browser-use/')) {
|
|
364
|
+
return 'browser-use';
|
|
365
|
+
}
|
|
366
|
+
if (lower.startsWith('bedrock:anthropic.')) {
|
|
367
|
+
return 'aws-anthropic';
|
|
368
|
+
}
|
|
369
|
+
if (lower.startsWith('bedrock:')) {
|
|
370
|
+
return 'aws';
|
|
371
|
+
}
|
|
372
|
+
if (lower.startsWith('anthropic.')) {
|
|
373
|
+
return 'aws-anthropic';
|
|
374
|
+
}
|
|
375
|
+
if (lower.includes('/') &&
|
|
376
|
+
!lower.startsWith('http://') &&
|
|
377
|
+
!lower.startsWith('https://')) {
|
|
378
|
+
return 'openrouter';
|
|
379
|
+
}
|
|
380
|
+
return null;
|
|
381
|
+
};
|
|
382
|
+
const normalizeModelValue = (model, provider) => {
|
|
383
|
+
const lower = model.toLowerCase();
|
|
384
|
+
if (provider === 'groq' && lower.startsWith('groq:')) {
|
|
385
|
+
return model.slice('groq:'.length);
|
|
386
|
+
}
|
|
387
|
+
if (provider === 'openrouter' && lower.startsWith('openrouter:')) {
|
|
388
|
+
return model.slice('openrouter:'.length);
|
|
389
|
+
}
|
|
390
|
+
if (provider === 'azure' && lower.startsWith('azure:')) {
|
|
391
|
+
return model.slice('azure:'.length);
|
|
392
|
+
}
|
|
393
|
+
if (provider === 'mistral' && lower.startsWith('mistral:')) {
|
|
394
|
+
return model.slice('mistral:'.length);
|
|
395
|
+
}
|
|
396
|
+
if (provider === 'cerebras' && lower.startsWith('cerebras:')) {
|
|
397
|
+
return model.slice('cerebras:'.length);
|
|
398
|
+
}
|
|
399
|
+
if (provider === 'vercel' && lower.startsWith('vercel:')) {
|
|
400
|
+
return model.slice('vercel:'.length);
|
|
401
|
+
}
|
|
402
|
+
if (provider === 'oci' && lower.startsWith('oci:')) {
|
|
403
|
+
return model.slice('oci:'.length);
|
|
404
|
+
}
|
|
405
|
+
if (provider === 'ollama' && lower.startsWith('ollama:')) {
|
|
406
|
+
return model.slice('ollama:'.length);
|
|
407
|
+
}
|
|
408
|
+
if (provider === 'browser-use' && lower.startsWith('browser-use:')) {
|
|
409
|
+
return model.slice('browser-use:'.length);
|
|
410
|
+
}
|
|
411
|
+
if (provider === 'browser-use' && lower.startsWith('bu_')) {
|
|
412
|
+
return model.replace(/_/g, '-');
|
|
413
|
+
}
|
|
414
|
+
if (provider === 'aws-anthropic' && lower.startsWith('bedrock:')) {
|
|
415
|
+
return model.slice('bedrock:'.length);
|
|
416
|
+
}
|
|
417
|
+
if (provider === 'aws' && lower.startsWith('bedrock:')) {
|
|
418
|
+
return model.slice('bedrock:'.length);
|
|
419
|
+
}
|
|
420
|
+
return model;
|
|
421
|
+
};
|
|
422
|
+
const providersAreCompatible = (explicitProvider, inferredProvider) => {
|
|
423
|
+
if (explicitProvider === inferredProvider) {
|
|
424
|
+
return true;
|
|
425
|
+
}
|
|
426
|
+
if ((explicitProvider === 'aws' && inferredProvider === 'aws-anthropic') ||
|
|
427
|
+
(explicitProvider === 'aws-anthropic' && inferredProvider === 'aws')) {
|
|
428
|
+
return true;
|
|
429
|
+
}
|
|
430
|
+
return false;
|
|
431
|
+
};
|
|
432
|
+
const getDefaultModelForProvider = (provider) => {
|
|
433
|
+
switch (provider) {
|
|
434
|
+
case 'openai':
|
|
435
|
+
return 'gpt-5-mini';
|
|
436
|
+
case 'anthropic':
|
|
437
|
+
return 'claude-4-sonnet';
|
|
438
|
+
case 'google':
|
|
439
|
+
return 'gemini-2.5-pro';
|
|
440
|
+
case 'deepseek':
|
|
441
|
+
return 'deepseek-chat';
|
|
442
|
+
case 'groq':
|
|
443
|
+
return 'llama-3.1-70b-versatile';
|
|
444
|
+
case 'openrouter':
|
|
445
|
+
return 'openai/gpt-5-mini';
|
|
446
|
+
case 'azure':
|
|
447
|
+
return 'gpt-4o';
|
|
448
|
+
case 'mistral':
|
|
449
|
+
return 'mistral-large-latest';
|
|
450
|
+
case 'cerebras':
|
|
451
|
+
return 'llama3.1-8b';
|
|
452
|
+
case 'vercel':
|
|
453
|
+
return 'openai/gpt-5-mini';
|
|
454
|
+
case 'oci':
|
|
455
|
+
return null;
|
|
456
|
+
case 'aws-anthropic':
|
|
457
|
+
return 'anthropic.claude-3-5-sonnet-20241022-v2:0';
|
|
458
|
+
case 'ollama':
|
|
459
|
+
return process.env.OLLAMA_MODEL || 'qwen2.5:latest';
|
|
460
|
+
case 'browser-use':
|
|
461
|
+
return 'bu-latest';
|
|
462
|
+
case 'aws':
|
|
463
|
+
return null;
|
|
464
|
+
default:
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
const createLlmForProvider = (provider, model) => {
|
|
469
|
+
switch (provider) {
|
|
470
|
+
case 'openai':
|
|
471
|
+
return new ChatOpenAI({
|
|
472
|
+
model,
|
|
473
|
+
apiKey: requireEnv('OPENAI_API_KEY'),
|
|
474
|
+
});
|
|
475
|
+
case 'anthropic':
|
|
476
|
+
return new ChatAnthropic({
|
|
477
|
+
model,
|
|
478
|
+
apiKey: requireEnv('ANTHROPIC_API_KEY'),
|
|
479
|
+
});
|
|
480
|
+
case 'google':
|
|
481
|
+
requireEnv('GOOGLE_API_KEY');
|
|
482
|
+
return new ChatGoogle(model);
|
|
483
|
+
case 'deepseek':
|
|
484
|
+
requireEnv('DEEPSEEK_API_KEY');
|
|
485
|
+
return new ChatDeepSeek(model);
|
|
486
|
+
case 'groq':
|
|
487
|
+
requireEnv('GROQ_API_KEY');
|
|
488
|
+
return new ChatGroq(model);
|
|
489
|
+
case 'openrouter':
|
|
490
|
+
requireEnv('OPENROUTER_API_KEY');
|
|
491
|
+
return new ChatOpenRouter(model);
|
|
492
|
+
case 'azure':
|
|
493
|
+
requireEnv('AZURE_OPENAI_API_KEY');
|
|
494
|
+
requireEnv('AZURE_OPENAI_ENDPOINT');
|
|
495
|
+
return new ChatAzure(model);
|
|
496
|
+
case 'mistral':
|
|
497
|
+
return new ChatMistral({
|
|
498
|
+
model,
|
|
499
|
+
apiKey: requireEnv('MISTRAL_API_KEY'),
|
|
500
|
+
baseURL: process.env.MISTRAL_BASE_URL,
|
|
501
|
+
});
|
|
502
|
+
case 'cerebras':
|
|
503
|
+
return new ChatCerebras({
|
|
504
|
+
model,
|
|
505
|
+
apiKey: requireEnv('CEREBRAS_API_KEY'),
|
|
506
|
+
baseURL: process.env.CEREBRAS_BASE_URL,
|
|
507
|
+
});
|
|
508
|
+
case 'vercel':
|
|
509
|
+
return new ChatVercel({
|
|
510
|
+
model,
|
|
511
|
+
apiKey: requireEnv('VERCEL_API_KEY'),
|
|
512
|
+
baseURL: process.env.VERCEL_BASE_URL,
|
|
513
|
+
});
|
|
514
|
+
case 'oci':
|
|
515
|
+
throw new Error('OCI models require manual configuration in TypeScript runtime. Use a custom BaseChatModel integration for OCI credentials and endpoint setup.');
|
|
516
|
+
case 'ollama': {
|
|
517
|
+
const host = process.env.OLLAMA_HOST || 'http://localhost:11434';
|
|
518
|
+
return new ChatOllama(model, host);
|
|
519
|
+
}
|
|
520
|
+
case 'browser-use':
|
|
521
|
+
return new ChatBrowserUse({
|
|
522
|
+
model,
|
|
523
|
+
apiKey: requireEnv('BROWSER_USE_API_KEY'),
|
|
524
|
+
});
|
|
525
|
+
case 'aws-anthropic':
|
|
526
|
+
return new ChatAnthropicBedrock({
|
|
527
|
+
model,
|
|
528
|
+
region: process.env.AWS_REGION || 'us-east-1',
|
|
529
|
+
});
|
|
530
|
+
case 'aws':
|
|
531
|
+
return new ChatBedrockConverse(model, process.env.AWS_REGION || 'us-east-1');
|
|
532
|
+
default:
|
|
533
|
+
throw new Error(`Unsupported provider "${provider}"`);
|
|
534
|
+
}
|
|
535
|
+
};
|
|
536
|
+
export const getLlmFromCliArgs = (args) => {
|
|
537
|
+
if (args.model) {
|
|
538
|
+
const inferredProvider = inferProviderFromModel(args.model);
|
|
539
|
+
if (args.provider &&
|
|
540
|
+
inferredProvider &&
|
|
541
|
+
!providersAreCompatible(args.provider, inferredProvider)) {
|
|
542
|
+
throw new Error(`Provider mismatch: --provider ${args.provider} conflicts with model "${args.model}" (inferred: ${inferredProvider}).`);
|
|
543
|
+
}
|
|
544
|
+
const provider = args.provider ?? inferredProvider;
|
|
545
|
+
if (!provider) {
|
|
546
|
+
throw new Error(`Cannot infer provider from model "${args.model}". Provide --provider or use a supported model prefix: gpt*/o*, claude*, gemini*, deepseek*, groq:, openrouter:, azure:, mistral:, cerebras:, vercel:, oci:, ollama:, browser-use:, bu-*, bedrock:.`);
|
|
547
|
+
}
|
|
548
|
+
const normalizedModel = normalizeModelValue(args.model, provider);
|
|
549
|
+
return createLlmForProvider(provider, normalizedModel);
|
|
550
|
+
}
|
|
551
|
+
if (args.provider) {
|
|
552
|
+
const defaultModel = getDefaultModelForProvider(args.provider);
|
|
553
|
+
if (!defaultModel) {
|
|
554
|
+
throw new Error(`Provider "${args.provider}" requires --model. Example: --provider aws --model bedrock:us.amazon.nova-lite-v1:0`);
|
|
555
|
+
}
|
|
556
|
+
return createLlmForProvider(args.provider, defaultModel);
|
|
557
|
+
}
|
|
558
|
+
if (process.env.OPENAI_API_KEY) {
|
|
559
|
+
return new ChatOpenAI({
|
|
560
|
+
model: 'gpt-5-mini',
|
|
561
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
562
|
+
});
|
|
563
|
+
}
|
|
564
|
+
if (process.env.ANTHROPIC_API_KEY) {
|
|
565
|
+
return new ChatAnthropic({
|
|
566
|
+
model: 'claude-4-sonnet',
|
|
567
|
+
apiKey: process.env.ANTHROPIC_API_KEY,
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
if (process.env.GOOGLE_API_KEY) {
|
|
571
|
+
return new ChatGoogle('gemini-2.5-pro');
|
|
572
|
+
}
|
|
573
|
+
if (process.env.DEEPSEEK_API_KEY) {
|
|
574
|
+
return new ChatDeepSeek('deepseek-chat');
|
|
575
|
+
}
|
|
576
|
+
if (process.env.GROQ_API_KEY) {
|
|
577
|
+
return new ChatGroq('llama-3.1-70b-versatile');
|
|
578
|
+
}
|
|
579
|
+
if (process.env.OPENROUTER_API_KEY) {
|
|
580
|
+
return new ChatOpenRouter('openai/gpt-5-mini');
|
|
581
|
+
}
|
|
582
|
+
if (process.env.AZURE_OPENAI_API_KEY && process.env.AZURE_OPENAI_ENDPOINT) {
|
|
583
|
+
return new ChatAzure('gpt-4o');
|
|
584
|
+
}
|
|
585
|
+
if (process.env.MISTRAL_API_KEY) {
|
|
586
|
+
return new ChatMistral({
|
|
587
|
+
model: 'mistral-large-latest',
|
|
588
|
+
apiKey: process.env.MISTRAL_API_KEY,
|
|
589
|
+
baseURL: process.env.MISTRAL_BASE_URL,
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
if (process.env.CEREBRAS_API_KEY) {
|
|
593
|
+
return new ChatCerebras({
|
|
594
|
+
model: 'llama3.1-8b',
|
|
595
|
+
apiKey: process.env.CEREBRAS_API_KEY,
|
|
596
|
+
baseURL: process.env.CEREBRAS_BASE_URL,
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
if (process.env.VERCEL_API_KEY) {
|
|
600
|
+
return new ChatVercel({
|
|
601
|
+
model: 'openai/gpt-5-mini',
|
|
602
|
+
apiKey: process.env.VERCEL_API_KEY,
|
|
603
|
+
baseURL: process.env.VERCEL_BASE_URL,
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
if (process.env.AWS_ACCESS_KEY_ID || process.env.AWS_PROFILE) {
|
|
607
|
+
return new ChatAnthropicBedrock({
|
|
608
|
+
model: 'anthropic.claude-3-5-sonnet-20241022-v2:0',
|
|
609
|
+
region: process.env.AWS_REGION || 'us-east-1',
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
return new ChatOllama(process.env.OLLAMA_MODEL || 'qwen2.5:latest', process.env.OLLAMA_HOST || 'http://localhost:11434');
|
|
613
|
+
};
|
|
614
|
+
const parseCommaSeparatedList = (value) => value
|
|
615
|
+
.split(',')
|
|
616
|
+
.map((entry) => entry.trim())
|
|
617
|
+
.filter((entry) => entry.length > 0);
|
|
618
|
+
export const buildBrowserProfileFromCliArgs = (args) => {
|
|
619
|
+
const profile = {};
|
|
620
|
+
if (args.headless !== null) {
|
|
621
|
+
profile.headless = args.headless;
|
|
622
|
+
}
|
|
623
|
+
if (args.window_width !== null) {
|
|
624
|
+
profile.window_width = args.window_width;
|
|
625
|
+
}
|
|
626
|
+
if (args.window_height !== null) {
|
|
627
|
+
profile.window_height = args.window_height;
|
|
628
|
+
}
|
|
629
|
+
if (args.user_data_dir) {
|
|
630
|
+
profile.user_data_dir = args.user_data_dir;
|
|
631
|
+
}
|
|
632
|
+
if (args.profile_directory) {
|
|
633
|
+
profile.profile_directory = args.profile_directory;
|
|
634
|
+
}
|
|
635
|
+
if (args.allowed_domains && args.allowed_domains.length > 0) {
|
|
636
|
+
profile.allowed_domains = args.allowed_domains;
|
|
637
|
+
}
|
|
638
|
+
if (args.proxy_url ||
|
|
639
|
+
args.no_proxy ||
|
|
640
|
+
args.proxy_username ||
|
|
641
|
+
args.proxy_password) {
|
|
642
|
+
const proxy = {};
|
|
643
|
+
if (args.proxy_url) {
|
|
644
|
+
proxy.server = args.proxy_url;
|
|
645
|
+
}
|
|
646
|
+
if (args.no_proxy) {
|
|
647
|
+
proxy.bypass = parseCommaSeparatedList(args.no_proxy).join(',');
|
|
648
|
+
}
|
|
649
|
+
if (args.proxy_username) {
|
|
650
|
+
proxy.username = args.proxy_username;
|
|
651
|
+
}
|
|
652
|
+
if (args.proxy_password) {
|
|
653
|
+
proxy.password = args.proxy_password;
|
|
654
|
+
}
|
|
655
|
+
profile.proxy = proxy;
|
|
656
|
+
}
|
|
657
|
+
if (Object.keys(profile).length === 0) {
|
|
658
|
+
return null;
|
|
659
|
+
}
|
|
660
|
+
return new BrowserProfile(profile);
|
|
661
|
+
};
|
|
662
|
+
const runAgentTask = async ({ task, llm, browserProfile, browserSession, sessionAttachmentMode, }) => {
|
|
663
|
+
const agent = new Agent({
|
|
664
|
+
task,
|
|
665
|
+
llm,
|
|
666
|
+
...(browserProfile ? { browser_profile: browserProfile } : {}),
|
|
667
|
+
...(browserSession ? { browser_session: browserSession } : {}),
|
|
668
|
+
...(sessionAttachmentMode
|
|
669
|
+
? { session_attachment_mode: sessionAttachmentMode }
|
|
670
|
+
: {}),
|
|
671
|
+
source: 'cli',
|
|
672
|
+
});
|
|
673
|
+
await agent.run();
|
|
674
|
+
};
|
|
675
|
+
const runInteractiveMode = async (args, llm) => {
|
|
676
|
+
const historyPath = getCliHistoryPath();
|
|
677
|
+
const history = await loadCliHistory(historyPath);
|
|
678
|
+
const browserProfile = buildBrowserProfileFromCliArgs(args) ?? new BrowserProfile();
|
|
679
|
+
browserProfile.keep_alive = true;
|
|
680
|
+
const browserSession = new BrowserSession({
|
|
681
|
+
browser_profile: browserProfile,
|
|
682
|
+
...(args.cdp_url ? { cdp_url: args.cdp_url } : {}),
|
|
683
|
+
});
|
|
684
|
+
const rl = createInterface({
|
|
685
|
+
input: stdin,
|
|
686
|
+
output: stdout,
|
|
687
|
+
terminal: true,
|
|
688
|
+
historySize: CLI_HISTORY_LIMIT,
|
|
689
|
+
});
|
|
690
|
+
if (Array.isArray(rl.history) && history.length > 0) {
|
|
691
|
+
rl.history = [...history].reverse();
|
|
692
|
+
}
|
|
693
|
+
console.log('Interactive mode started. Type a task and press Enter.');
|
|
694
|
+
console.log('Commands: help, exit');
|
|
695
|
+
try {
|
|
696
|
+
while (true) {
|
|
697
|
+
const line = await rl.question('browser-use> ');
|
|
698
|
+
const task = line.trim();
|
|
699
|
+
if (!task) {
|
|
700
|
+
continue;
|
|
701
|
+
}
|
|
702
|
+
if (isInteractiveExitCommand(task)) {
|
|
703
|
+
break;
|
|
704
|
+
}
|
|
705
|
+
if (isInteractiveHelpCommand(task)) {
|
|
706
|
+
console.log('Type any task to run it. Use "exit" to quit.');
|
|
707
|
+
continue;
|
|
708
|
+
}
|
|
709
|
+
history.push(task);
|
|
710
|
+
await saveCliHistory(history, historyPath);
|
|
711
|
+
console.log(`Starting task: ${task}`);
|
|
712
|
+
try {
|
|
713
|
+
await runAgentTask({
|
|
714
|
+
task,
|
|
715
|
+
llm,
|
|
716
|
+
browserProfile,
|
|
717
|
+
browserSession,
|
|
718
|
+
sessionAttachmentMode: 'strict',
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
catch (error) {
|
|
722
|
+
console.error('Error running agent:', error);
|
|
723
|
+
}
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
finally {
|
|
727
|
+
rl.close();
|
|
728
|
+
await saveCliHistory(history, historyPath);
|
|
729
|
+
try {
|
|
730
|
+
if (browserSession._owns_browser_resources) {
|
|
731
|
+
await browserSession.kill();
|
|
732
|
+
}
|
|
733
|
+
else {
|
|
734
|
+
await browserSession.stop();
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
catch (error) {
|
|
738
|
+
console.error(`Warning: failed to close interactive browser session: ${error.message}`);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
export const getCliUsage = () => `Usage:
|
|
743
|
+
browser-use # interactive mode (TTY)
|
|
744
|
+
browser-use <task>
|
|
745
|
+
browser-use -p "<task>"
|
|
746
|
+
browser-use [options] <task>
|
|
747
|
+
browser-use --mcp
|
|
748
|
+
|
|
749
|
+
Options:
|
|
750
|
+
-h, --help Show this help message
|
|
751
|
+
--version Print version and exit
|
|
752
|
+
--mcp Run as MCP server
|
|
753
|
+
--provider <name> Force provider (openai|anthropic|google|deepseek|groq|openrouter|azure|mistral|cerebras|vercel|oci|ollama|browser-use|aws|aws-anthropic)
|
|
754
|
+
--model <model> Set model (e.g., gpt-5-mini, claude-4-sonnet, gemini-2.5-pro)
|
|
755
|
+
-p, --prompt <task> Run a single task
|
|
756
|
+
--headless Run browser in headless mode
|
|
757
|
+
--allowed-domains <items> Comma-separated allowlist (e.g., example.com,*.example.org)
|
|
758
|
+
--window-width <px> Browser window width
|
|
759
|
+
--window-height <px> Browser window height
|
|
760
|
+
--user-data-dir <path> Chrome user data directory
|
|
761
|
+
--profile-directory <name> Chrome profile directory (Default, Profile 1, ...)
|
|
762
|
+
--proxy-url <url> Proxy server URL (e.g., http://proxy.example.com:8080)
|
|
763
|
+
--no-proxy <items> Comma-separated proxy bypass list
|
|
764
|
+
--proxy-username <value> Proxy username
|
|
765
|
+
--proxy-password <value> Proxy password
|
|
766
|
+
--cdp-url <url> Connect to an existing Chromium instance via CDP
|
|
767
|
+
--debug Enable debug logging`;
|
|
8
768
|
async function runMcpServer() {
|
|
9
769
|
const server = new MCPServer('browser-use', get_browser_use_version());
|
|
10
770
|
await server.start();
|
|
@@ -16,23 +776,73 @@ async function runMcpServer() {
|
|
|
16
776
|
process.once('SIGTERM', () => void shutdown());
|
|
17
777
|
await new Promise(() => { });
|
|
18
778
|
}
|
|
19
|
-
async function main() {
|
|
20
|
-
|
|
21
|
-
|
|
779
|
+
export async function main(argv = process.argv.slice(2)) {
|
|
780
|
+
let args;
|
|
781
|
+
try {
|
|
782
|
+
args = parseCliArgs(argv);
|
|
783
|
+
}
|
|
784
|
+
catch (error) {
|
|
785
|
+
console.error(error.message);
|
|
786
|
+
console.error(getCliUsage());
|
|
787
|
+
process.exit(1);
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
if (args.help) {
|
|
791
|
+
console.log(getCliUsage());
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
if (args.version) {
|
|
795
|
+
console.log(get_browser_use_version());
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
if (args.debug) {
|
|
799
|
+
process.env.BROWSER_USE_LOGGING_LEVEL = 'debug';
|
|
800
|
+
setupLogging({ logLevel: 'debug', forceSetup: true });
|
|
801
|
+
}
|
|
802
|
+
if (args.mcp) {
|
|
22
803
|
await runMcpServer();
|
|
23
804
|
return;
|
|
24
805
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
806
|
+
const task = resolveTask(args);
|
|
807
|
+
const shouldStartInteractive = shouldStartInteractiveMode(task);
|
|
808
|
+
if (!task && !shouldStartInteractive) {
|
|
809
|
+
console.error(getCliUsage());
|
|
28
810
|
process.exit(1);
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
let llm;
|
|
814
|
+
try {
|
|
815
|
+
llm = getLlmFromCliArgs(args);
|
|
816
|
+
}
|
|
817
|
+
catch (error) {
|
|
818
|
+
console.error(`Error selecting LLM: ${error.message}`);
|
|
819
|
+
process.exit(1);
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
if (shouldStartInteractive) {
|
|
823
|
+
await runInteractiveMode(args, llm);
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
826
|
+
if (!task) {
|
|
827
|
+
console.error(getCliUsage());
|
|
828
|
+
process.exit(1);
|
|
829
|
+
return;
|
|
29
830
|
}
|
|
30
|
-
const task = args.join(' ');
|
|
31
831
|
console.log(`Starting task: ${task}`);
|
|
32
|
-
const
|
|
33
|
-
const
|
|
832
|
+
const browserProfile = buildBrowserProfileFromCliArgs(args);
|
|
833
|
+
const browserSession = args.cdp_url
|
|
834
|
+
? new BrowserSession({
|
|
835
|
+
browser_profile: browserProfile ?? undefined,
|
|
836
|
+
cdp_url: args.cdp_url,
|
|
837
|
+
})
|
|
838
|
+
: null;
|
|
34
839
|
try {
|
|
35
|
-
await
|
|
840
|
+
await runAgentTask({
|
|
841
|
+
task,
|
|
842
|
+
llm,
|
|
843
|
+
browserProfile,
|
|
844
|
+
browserSession,
|
|
845
|
+
});
|
|
36
846
|
}
|
|
37
847
|
catch (error) {
|
|
38
848
|
console.error('Error running agent:', error);
|