browser-use 0.2.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 +295 -686
- 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 -41
- package/dist/agent/service.js +2266 -472
- package/dist/agent/variable-detector.d.ts +12 -0
- package/dist/agent/variable-detector.js +211 -0
- package/dist/agent/views.d.ts +237 -18
- package/dist/agent/views.js +446 -33
- 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 +1097 -58
- 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 +7 -2
- package/dist/cli.js +182 -25
- 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 +1807 -268
- 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/exceptions.d.ts +0 -3
- package/dist/exceptions.js +0 -7
- package/dist/filesystem/file-system.d.ts +18 -0
- package/dist/filesystem/file-system.js +503 -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 +4 -4
- 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 +126 -26
- 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 -54
- 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 +267 -64
- 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/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 +14 -9
- 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 +255 -52
- 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 +27 -8
- 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 +87 -26
- 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
|
@@ -10,7 +10,12 @@ export interface SensitiveDataMap {
|
|
|
10
10
|
export interface ExecuteActionContext<Context> {
|
|
11
11
|
context?: Context;
|
|
12
12
|
browser_session?: BrowserSession | null;
|
|
13
|
+
browser?: BrowserSession | null;
|
|
14
|
+
browser_context?: BrowserSession | null;
|
|
15
|
+
page_url?: string | null;
|
|
16
|
+
cdp_client?: unknown;
|
|
13
17
|
page_extraction_llm?: BaseChatModel | null;
|
|
18
|
+
extraction_schema?: Record<string, unknown> | null;
|
|
14
19
|
file_system?: FileSystem | null;
|
|
15
20
|
available_file_paths?: string[] | null;
|
|
16
21
|
sensitive_data?: SensitiveDataMap | null;
|
|
@@ -22,16 +27,20 @@ export type RegistryActionHandler<Params = any, Context = unknown> = (params: Pa
|
|
|
22
27
|
}) => Promise<unknown> | unknown;
|
|
23
28
|
export interface ActionOptions {
|
|
24
29
|
param_model?: ZodTypeAny;
|
|
30
|
+
action_name?: string;
|
|
25
31
|
domains?: string[] | null;
|
|
26
32
|
allowed_domains?: string[] | null;
|
|
27
33
|
page_filter?: ((page: Page) => boolean) | null;
|
|
34
|
+
terminates_sequence?: boolean;
|
|
28
35
|
}
|
|
29
36
|
export declare class Registry<Context = unknown> {
|
|
30
37
|
private registry;
|
|
31
38
|
private excludeActions;
|
|
32
39
|
constructor(exclude_actions?: string[] | null);
|
|
33
|
-
action(description: string, options?: ActionOptions): <Params = any>(handler: RegistryActionHandler<Params, Context>) =>
|
|
40
|
+
action(description: string, options?: ActionOptions): <Params = any>(handler: RegistryActionHandler<Params, Context>) => any;
|
|
34
41
|
get_action(action_name: string): RegisteredAction | null;
|
|
42
|
+
exclude_action(action_name: string): void;
|
|
43
|
+
remove_action(action_name: string): void;
|
|
35
44
|
get_all_actions(): Map<string, RegisteredAction>;
|
|
36
45
|
execute_action: (...args: any[]) => any;
|
|
37
46
|
private replace_sensitive_data;
|
|
@@ -1,10 +1,145 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
+
import { createHmac } from 'node:crypto';
|
|
2
3
|
import { createLogger } from '../../logging-config.js';
|
|
3
4
|
import { observe_debug } from '../../observability.js';
|
|
4
5
|
import { time_execution_async } from '../../utils.js';
|
|
5
6
|
import { is_new_tab_page, match_url_with_domain_pattern } from '../../utils.js';
|
|
7
|
+
import { BrowserError } from '../../browser/views.js';
|
|
6
8
|
import { ActionModel, ActionRegistry, RegisteredAction } from './views.js';
|
|
7
9
|
const logger = createLogger('browser_use.controller.registry');
|
|
10
|
+
const SPECIAL_PARAM_NAMES = new Set([
|
|
11
|
+
'context',
|
|
12
|
+
'browser_session',
|
|
13
|
+
'browser',
|
|
14
|
+
'browser_context',
|
|
15
|
+
'page',
|
|
16
|
+
'page_url',
|
|
17
|
+
'cdp_client',
|
|
18
|
+
'page_extraction_llm',
|
|
19
|
+
'available_file_paths',
|
|
20
|
+
'has_sensitive_data',
|
|
21
|
+
'file_system',
|
|
22
|
+
'extraction_schema',
|
|
23
|
+
'sensitive_data',
|
|
24
|
+
'signal',
|
|
25
|
+
]);
|
|
26
|
+
const splitTopLevelParameters = (paramsSource) => {
|
|
27
|
+
const segments = [];
|
|
28
|
+
let current = '';
|
|
29
|
+
let depthParen = 0;
|
|
30
|
+
let depthBrace = 0;
|
|
31
|
+
let depthBracket = 0;
|
|
32
|
+
let quote = null;
|
|
33
|
+
let escaped = false;
|
|
34
|
+
const flush = () => {
|
|
35
|
+
const trimmed = current.trim();
|
|
36
|
+
if (trimmed) {
|
|
37
|
+
segments.push(trimmed);
|
|
38
|
+
}
|
|
39
|
+
current = '';
|
|
40
|
+
};
|
|
41
|
+
for (const char of paramsSource) {
|
|
42
|
+
if (escaped) {
|
|
43
|
+
current += char;
|
|
44
|
+
escaped = false;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
if (char === '\\') {
|
|
48
|
+
current += char;
|
|
49
|
+
escaped = true;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (quote) {
|
|
53
|
+
current += char;
|
|
54
|
+
if (char === quote) {
|
|
55
|
+
quote = null;
|
|
56
|
+
}
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (char === "'" || char === '"' || char === '`') {
|
|
60
|
+
current += char;
|
|
61
|
+
quote = char;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (char === '(')
|
|
65
|
+
depthParen += 1;
|
|
66
|
+
else if (char === ')')
|
|
67
|
+
depthParen -= 1;
|
|
68
|
+
else if (char === '{')
|
|
69
|
+
depthBrace += 1;
|
|
70
|
+
else if (char === '}')
|
|
71
|
+
depthBrace -= 1;
|
|
72
|
+
else if (char === '[')
|
|
73
|
+
depthBracket += 1;
|
|
74
|
+
else if (char === ']')
|
|
75
|
+
depthBracket -= 1;
|
|
76
|
+
if (char === ',' &&
|
|
77
|
+
depthParen === 0 &&
|
|
78
|
+
depthBrace === 0 &&
|
|
79
|
+
depthBracket === 0) {
|
|
80
|
+
flush();
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
current += char;
|
|
84
|
+
}
|
|
85
|
+
flush();
|
|
86
|
+
return segments;
|
|
87
|
+
};
|
|
88
|
+
const extractFunctionParameters = (fn) => {
|
|
89
|
+
const source = fn.toString().trim();
|
|
90
|
+
if (!source) {
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
let paramsSource;
|
|
94
|
+
const arrowIndex = source.indexOf('=>');
|
|
95
|
+
if (arrowIndex !== -1) {
|
|
96
|
+
let lhs = source.slice(0, arrowIndex).trim();
|
|
97
|
+
if (lhs.startsWith('async ')) {
|
|
98
|
+
lhs = lhs.slice('async '.length).trim();
|
|
99
|
+
}
|
|
100
|
+
if (lhs.startsWith('(') && lhs.endsWith(')')) {
|
|
101
|
+
paramsSource = lhs.slice(1, -1);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
paramsSource = lhs;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
const openIndex = source.indexOf('(');
|
|
109
|
+
const closeIndex = source.indexOf(')', openIndex + 1);
|
|
110
|
+
if (openIndex === -1 || closeIndex === -1) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
paramsSource = source.slice(openIndex + 1, closeIndex);
|
|
114
|
+
}
|
|
115
|
+
const tokens = splitTopLevelParameters(paramsSource);
|
|
116
|
+
if (!tokens.length) {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
const parsed = [];
|
|
120
|
+
for (const token of tokens) {
|
|
121
|
+
if (token.startsWith('...')) {
|
|
122
|
+
const fnName = fn.name || '<anonymous>';
|
|
123
|
+
throw new Error(`Action '${fnName}' has ${token} which is not allowed. Actions must have explicit positional parameters only.`);
|
|
124
|
+
}
|
|
125
|
+
if (token.includes('{') ||
|
|
126
|
+
token.includes('}') ||
|
|
127
|
+
token.includes('[') ||
|
|
128
|
+
token.includes(']')) {
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
const eqIndex = token.indexOf('=');
|
|
132
|
+
const name = (eqIndex === -1 ? token : token.slice(0, eqIndex)).trim();
|
|
133
|
+
if (!name) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
parsed.push({
|
|
137
|
+
name,
|
|
138
|
+
hasDefault: eqIndex !== -1,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return parsed;
|
|
142
|
+
};
|
|
8
143
|
const isAbortError = (error) => error instanceof Error && error.name === 'AbortError';
|
|
9
144
|
const createAbortError = (reason) => {
|
|
10
145
|
if (isAbortError(reason)) {
|
|
@@ -19,6 +154,9 @@ const createAbortError = (reason) => {
|
|
|
19
154
|
return error;
|
|
20
155
|
};
|
|
21
156
|
const wrapActionExecutionError = (actionName, error) => {
|
|
157
|
+
if (error instanceof BrowserError) {
|
|
158
|
+
return error;
|
|
159
|
+
}
|
|
22
160
|
const message = error instanceof Error ? error.message : String(error);
|
|
23
161
|
const wrapped = new Error(`Error executing action ${actionName}: ${message}`);
|
|
24
162
|
if (error !== undefined) {
|
|
@@ -26,6 +164,61 @@ const wrapActionExecutionError = (actionName, error) => {
|
|
|
26
164
|
}
|
|
27
165
|
return wrapped;
|
|
28
166
|
};
|
|
167
|
+
const isSpecialContextMissingError = (error) => {
|
|
168
|
+
if (!(error instanceof Error)) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
return (error.message.includes('requires browser_session but none provided') ||
|
|
172
|
+
error.message.includes('requires page_extraction_llm but none provided'));
|
|
173
|
+
};
|
|
174
|
+
const safeJsonStringify = (value) => {
|
|
175
|
+
try {
|
|
176
|
+
return JSON.stringify(value);
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return String(value);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
const isTimeoutError = (error) => error instanceof Error && error.name === 'TimeoutError';
|
|
183
|
+
const BASE32_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
|
|
184
|
+
const decodeBase32Secret = (secret) => {
|
|
185
|
+
const sanitized = secret.toUpperCase().replace(/[^A-Z2-7]/g, '');
|
|
186
|
+
if (!sanitized.length) {
|
|
187
|
+
throw new Error('Invalid TOTP secret: empty base32 payload');
|
|
188
|
+
}
|
|
189
|
+
let bits = 0;
|
|
190
|
+
let bitBuffer = 0;
|
|
191
|
+
const bytes = [];
|
|
192
|
+
for (const char of sanitized) {
|
|
193
|
+
const value = BASE32_ALPHABET.indexOf(char);
|
|
194
|
+
if (value < 0) {
|
|
195
|
+
throw new Error(`Invalid base32 character in TOTP secret: ${char}`);
|
|
196
|
+
}
|
|
197
|
+
bitBuffer = (bitBuffer << 5) | value;
|
|
198
|
+
bits += 5;
|
|
199
|
+
while (bits >= 8) {
|
|
200
|
+
bytes.push((bitBuffer >>> (bits - 8)) & 0xff);
|
|
201
|
+
bits -= 8;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (!bytes.length) {
|
|
205
|
+
throw new Error('Invalid TOTP secret: failed to decode base32 payload');
|
|
206
|
+
}
|
|
207
|
+
return Buffer.from(bytes);
|
|
208
|
+
};
|
|
209
|
+
const generateTotpCode = (secret) => {
|
|
210
|
+
const key = decodeBase32Secret(secret);
|
|
211
|
+
const counter = Math.floor(Date.now() / 1000 / 30);
|
|
212
|
+
const counterBuffer = Buffer.alloc(8);
|
|
213
|
+
counterBuffer.writeBigUInt64BE(BigInt(counter));
|
|
214
|
+
const hmac = createHmac('sha1', key).update(counterBuffer).digest();
|
|
215
|
+
const offset = hmac[hmac.length - 1] & 0x0f;
|
|
216
|
+
const binaryCode = ((hmac[offset] & 0x7f) << 24) |
|
|
217
|
+
((hmac[offset + 1] & 0xff) << 16) |
|
|
218
|
+
((hmac[offset + 2] & 0xff) << 8) |
|
|
219
|
+
(hmac[offset + 3] & 0xff);
|
|
220
|
+
return String(binaryCode % 1_000_000).padStart(6, '0');
|
|
221
|
+
};
|
|
29
222
|
export class Registry {
|
|
30
223
|
registry = new ActionRegistry();
|
|
31
224
|
excludeActions;
|
|
@@ -33,21 +226,68 @@ export class Registry {
|
|
|
33
226
|
this.excludeActions = new Set(exclude_actions ?? []);
|
|
34
227
|
}
|
|
35
228
|
action(description, options = {}) {
|
|
36
|
-
|
|
229
|
+
if (options.allowed_domains && options.domains) {
|
|
230
|
+
throw new Error("Cannot specify both 'domains' and 'allowed_domains' - they are aliases for the same parameter");
|
|
231
|
+
}
|
|
232
|
+
let schema = options.param_model ?? z.object({}).strict();
|
|
233
|
+
const actionNameOverride = options.action_name ?? null;
|
|
37
234
|
const domains = options.allowed_domains ?? options.domains ?? null;
|
|
38
235
|
const pageFilter = options.page_filter ?? null;
|
|
236
|
+
const terminatesSequence = options.terminates_sequence ?? false;
|
|
39
237
|
return (handler) => {
|
|
40
|
-
|
|
238
|
+
const actionName = actionNameOverride ?? handler.name;
|
|
239
|
+
if (this.excludeActions.has(actionName)) {
|
|
41
240
|
return handler;
|
|
42
241
|
}
|
|
43
|
-
const
|
|
242
|
+
const parsedHandlerParams = extractFunctionParameters(handler);
|
|
243
|
+
let normalizedHandler = handler;
|
|
244
|
+
if (!options.param_model) {
|
|
245
|
+
const supportsCompatSignature = Boolean(parsedHandlerParams &&
|
|
246
|
+
parsedHandlerParams.length > 0 &&
|
|
247
|
+
!(parsedHandlerParams.length <= 2 &&
|
|
248
|
+
parsedHandlerParams[0]?.name === 'params'));
|
|
249
|
+
if (supportsCompatSignature && parsedHandlerParams) {
|
|
250
|
+
const actionParams = parsedHandlerParams.filter((entry) => !SPECIAL_PARAM_NAMES.has(entry.name));
|
|
251
|
+
const shape = Object.fromEntries(actionParams.map((entry) => [
|
|
252
|
+
entry.name,
|
|
253
|
+
entry.hasDefault ? z.any().optional() : z.any(),
|
|
254
|
+
]));
|
|
255
|
+
schema = z.object(shape).strict();
|
|
256
|
+
normalizedHandler = ((params, ctx) => {
|
|
257
|
+
const args = parsedHandlerParams.map((entry) => {
|
|
258
|
+
if (SPECIAL_PARAM_NAMES.has(entry.name)) {
|
|
259
|
+
const value = ctx[entry.name];
|
|
260
|
+
if ((value === null || value === undefined) &&
|
|
261
|
+
!entry.hasDefault) {
|
|
262
|
+
throw new Error(`Action ${actionName} requires ${entry.name} but none provided.`);
|
|
263
|
+
}
|
|
264
|
+
return value;
|
|
265
|
+
}
|
|
266
|
+
const value = params[entry.name];
|
|
267
|
+
if (value === undefined && !entry.hasDefault) {
|
|
268
|
+
throw new Error(`${actionName}() missing required parameter '${entry.name}'`);
|
|
269
|
+
}
|
|
270
|
+
return value;
|
|
271
|
+
});
|
|
272
|
+
return handler(...args);
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
const action = new RegisteredAction(actionName, description, normalizedHandler, schema, domains, pageFilter, terminatesSequence);
|
|
44
277
|
this.registry.register(action);
|
|
45
|
-
return
|
|
278
|
+
return normalizedHandler;
|
|
46
279
|
};
|
|
47
280
|
}
|
|
48
281
|
get_action(action_name) {
|
|
49
282
|
return this.registry.get(action_name);
|
|
50
283
|
}
|
|
284
|
+
exclude_action(action_name) {
|
|
285
|
+
this.excludeActions.add(action_name);
|
|
286
|
+
this.registry.remove(action_name);
|
|
287
|
+
}
|
|
288
|
+
remove_action(action_name) {
|
|
289
|
+
this.registry.remove(action_name);
|
|
290
|
+
}
|
|
51
291
|
get_all_actions() {
|
|
52
292
|
return this.registry.actionsMap;
|
|
53
293
|
}
|
|
@@ -55,14 +295,14 @@ export class Registry {
|
|
|
55
295
|
name: 'execute_action',
|
|
56
296
|
ignore_input: true,
|
|
57
297
|
ignore_output: true,
|
|
58
|
-
})(time_execution_async('--execute_action')(async (action_name, params, { browser_session = null, page_extraction_llm = null, file_system = null, sensitive_data = null, available_file_paths = null, signal = null, context = null, } = {}) => {
|
|
298
|
+
})(time_execution_async('--execute_action')(async (action_name, params, { browser_session = null, page_extraction_llm = null, extraction_schema = null, file_system = null, sensitive_data = null, available_file_paths = null, signal = null, context = null, } = {}) => {
|
|
59
299
|
const action = this.registry.get(action_name);
|
|
60
300
|
if (!action) {
|
|
61
301
|
throw new Error(`Action ${action_name} not found`);
|
|
62
302
|
}
|
|
63
303
|
const parsed = action.paramSchema.safeParse(params);
|
|
64
304
|
if (!parsed.success) {
|
|
65
|
-
throw new Error(`Invalid parameters for action ${action_name}: ${parsed.error.message}`);
|
|
305
|
+
throw new Error(`Invalid parameters ${safeJsonStringify(params)} for action ${action_name}: ${parsed.error.message}`);
|
|
66
306
|
}
|
|
67
307
|
let validatedParams = parsed.data;
|
|
68
308
|
let currentUrl = null;
|
|
@@ -86,11 +326,16 @@ export class Registry {
|
|
|
86
326
|
browser: browser_session,
|
|
87
327
|
browser_context: browser_session,
|
|
88
328
|
page,
|
|
329
|
+
page_url: currentUrl,
|
|
330
|
+
cdp_client: browser_session?.cdp_client ?? null,
|
|
89
331
|
page_extraction_llm,
|
|
332
|
+
extraction_schema,
|
|
90
333
|
file_system,
|
|
91
334
|
available_file_paths,
|
|
335
|
+
sensitive_data,
|
|
92
336
|
signal,
|
|
93
|
-
has_sensitive_data: action_name === 'input_text'
|
|
337
|
+
has_sensitive_data: (action_name === 'input_text' || action_name === 'input') &&
|
|
338
|
+
Boolean(sensitive_data),
|
|
94
339
|
};
|
|
95
340
|
if (signal?.aborted) {
|
|
96
341
|
throw createAbortError(signal.reason);
|
|
@@ -102,6 +347,12 @@ export class Registry {
|
|
|
102
347
|
if (signal?.aborted || isAbortError(error)) {
|
|
103
348
|
throw createAbortError(signal?.reason ?? error);
|
|
104
349
|
}
|
|
350
|
+
if (isTimeoutError(error)) {
|
|
351
|
+
throw new Error(`Error executing action ${action_name} due to timeout.`, { cause: error });
|
|
352
|
+
}
|
|
353
|
+
if (isSpecialContextMissingError(error)) {
|
|
354
|
+
throw error;
|
|
355
|
+
}
|
|
105
356
|
throw wrapActionExecutionError(action_name, error);
|
|
106
357
|
}
|
|
107
358
|
}));
|
|
@@ -134,10 +385,15 @@ export class Registry {
|
|
|
134
385
|
const missing = new Set();
|
|
135
386
|
const traverse = (value) => {
|
|
136
387
|
if (typeof value === 'string') {
|
|
137
|
-
return value.replace(secretPattern, (_,
|
|
388
|
+
return value.replace(secretPattern, (_, placeholderValue) => {
|
|
389
|
+
const placeholder = String(placeholderValue);
|
|
138
390
|
if (placeholder in applicableSecrets) {
|
|
139
391
|
replaced.add(placeholder);
|
|
140
|
-
|
|
392
|
+
const replacement = applicableSecrets[placeholder];
|
|
393
|
+
if (placeholder.endsWith('bu_2fa_code')) {
|
|
394
|
+
return generateTotpCode(replacement);
|
|
395
|
+
}
|
|
396
|
+
return replacement;
|
|
141
397
|
}
|
|
142
398
|
missing.add(placeholder);
|
|
143
399
|
return `<secret>${placeholder}</secret>`;
|
|
@@ -165,7 +421,7 @@ export class Registry {
|
|
|
165
421
|
return;
|
|
166
422
|
}
|
|
167
423
|
const urlInfo = currentUrl && !is_new_tab_page(currentUrl) ? ` on ${currentUrl}` : '';
|
|
168
|
-
logger.info(`🔒 Using sensitive data placeholders: ${Array.from(placeholders).join(', ')}${urlInfo}`);
|
|
424
|
+
logger.info(`🔒 Using sensitive data placeholders: ${Array.from(placeholders).sort().join(', ')}${urlInfo}`);
|
|
169
425
|
}
|
|
170
426
|
create_action_model(options = {}) {
|
|
171
427
|
const { include_actions = null, page = null } = options;
|
|
@@ -11,7 +11,8 @@ export declare class RegisteredAction {
|
|
|
11
11
|
readonly paramSchema: ZodTypeAny;
|
|
12
12
|
readonly domains: string[] | null;
|
|
13
13
|
readonly pageFilter: ((page: Page) => boolean) | null;
|
|
14
|
-
|
|
14
|
+
readonly terminates_sequence: boolean;
|
|
15
|
+
constructor(name: string, description: string, handler: ActionHandler, paramSchema: ZodTypeAny, domains?: string[] | null, pageFilter?: ((page: Page) => boolean) | null, terminates_sequence?: boolean);
|
|
15
16
|
promptDescription(): string;
|
|
16
17
|
}
|
|
17
18
|
export declare class ActionModel {
|
|
@@ -30,6 +31,7 @@ export declare class ActionModel {
|
|
|
30
31
|
export declare class ActionRegistry {
|
|
31
32
|
private actions;
|
|
32
33
|
register(action: RegisteredAction): void;
|
|
34
|
+
remove(name: string): void;
|
|
33
35
|
get(name: string): RegisteredAction | null;
|
|
34
36
|
getAll(): RegisteredAction[];
|
|
35
37
|
get actionsMap(): Map<string, RegisteredAction>;
|
|
@@ -46,6 +48,7 @@ export declare class SpecialActionParameters {
|
|
|
46
48
|
browser_context: BrowserSession | null;
|
|
47
49
|
page: Page | null;
|
|
48
50
|
page_extraction_llm: BaseChatModel | null;
|
|
51
|
+
extraction_schema: Record<string, unknown> | null;
|
|
49
52
|
file_system: FileSystem | null;
|
|
50
53
|
available_file_paths: string[] | null;
|
|
51
54
|
signal: AbortSignal | null;
|
|
@@ -22,13 +22,15 @@ export class RegisteredAction {
|
|
|
22
22
|
paramSchema;
|
|
23
23
|
domains;
|
|
24
24
|
pageFilter;
|
|
25
|
-
|
|
25
|
+
terminates_sequence;
|
|
26
|
+
constructor(name, description, handler, paramSchema, domains = null, pageFilter = null, terminates_sequence = false) {
|
|
26
27
|
this.name = name;
|
|
27
28
|
this.description = description;
|
|
28
29
|
this.handler = handler;
|
|
29
30
|
this.paramSchema = paramSchema;
|
|
30
31
|
this.domains = domains;
|
|
31
32
|
this.pageFilter = pageFilter;
|
|
33
|
+
this.terminates_sequence = terminates_sequence;
|
|
32
34
|
}
|
|
33
35
|
promptDescription() {
|
|
34
36
|
const skipKeys = new Set(['title']);
|
|
@@ -36,8 +38,25 @@ export class RegisteredAction {
|
|
|
36
38
|
description += `{${this.name}: `;
|
|
37
39
|
const schemaShape = (this.paramSchema instanceof z.ZodObject && this.paramSchema.shape) ||
|
|
38
40
|
('shape' in this.paramSchema ? this.paramSchema.shape : null);
|
|
41
|
+
const hideStructuredDoneSuccess = Boolean(this.name === 'done' &&
|
|
42
|
+
schemaShape &&
|
|
43
|
+
typeof schemaShape === 'object' &&
|
|
44
|
+
Object.prototype.hasOwnProperty.call(schemaShape, 'data') &&
|
|
45
|
+
Object.prototype.hasOwnProperty.call(schemaShape, 'success'));
|
|
46
|
+
if (hideStructuredDoneSuccess) {
|
|
47
|
+
skipKeys.add('success');
|
|
48
|
+
}
|
|
49
|
+
const hideExtractOutputSchema = Boolean(this.name === 'extract_structured_data' &&
|
|
50
|
+
schemaShape &&
|
|
51
|
+
typeof schemaShape === 'object' &&
|
|
52
|
+
Object.prototype.hasOwnProperty.call(schemaShape, 'output_schema'));
|
|
53
|
+
if (hideExtractOutputSchema) {
|
|
54
|
+
skipKeys.add('output_schema');
|
|
55
|
+
}
|
|
39
56
|
if (schemaShape) {
|
|
40
|
-
const props = Object.fromEntries(Object.entries(schemaShape)
|
|
57
|
+
const props = Object.fromEntries(Object.entries(schemaShape)
|
|
58
|
+
.filter(([key]) => !skipKeys.has(key))
|
|
59
|
+
.map(([key, value]) => {
|
|
41
60
|
const entries = value instanceof z.ZodType ? value._def : value;
|
|
42
61
|
const cleanEntries = Object.fromEntries(Object.entries(entries).filter(([propKey]) => !skipKeys.has(propKey)));
|
|
43
62
|
return [key, cleanEntries];
|
|
@@ -97,6 +116,9 @@ export class ActionRegistry {
|
|
|
97
116
|
register(action) {
|
|
98
117
|
this.actions.set(action.name, action);
|
|
99
118
|
}
|
|
119
|
+
remove(name) {
|
|
120
|
+
this.actions.delete(name);
|
|
121
|
+
}
|
|
100
122
|
get(name) {
|
|
101
123
|
return this.actions.get(name) ?? null;
|
|
102
124
|
}
|
|
@@ -164,6 +186,7 @@ export class SpecialActionParameters {
|
|
|
164
186
|
browser_context = null;
|
|
165
187
|
page = null;
|
|
166
188
|
page_extraction_llm = null;
|
|
189
|
+
extraction_schema = null;
|
|
167
190
|
file_system = null;
|
|
168
191
|
available_file_paths = null;
|
|
169
192
|
signal = null;
|
|
@@ -28,22 +28,31 @@ export interface ActParams<Context = unknown> {
|
|
|
28
28
|
export declare class Controller<Context = unknown> {
|
|
29
29
|
registry: Registry<Context>;
|
|
30
30
|
private displayFilesInDoneText;
|
|
31
|
+
private outputModel;
|
|
32
|
+
private coordinateClickingEnabled;
|
|
33
|
+
private clickActionHandler;
|
|
31
34
|
private logger;
|
|
32
35
|
constructor(options?: ControllerOptions<Context>);
|
|
33
36
|
private registerDefaultActions;
|
|
34
37
|
private registerNavigationActions;
|
|
35
38
|
private registerElementActions;
|
|
39
|
+
private registerClickActions;
|
|
36
40
|
private registerTabActions;
|
|
37
41
|
private registerContentActions;
|
|
42
|
+
private registerExplorationActions;
|
|
38
43
|
private registerScrollActions;
|
|
39
44
|
private registerFileSystemActions;
|
|
45
|
+
private registerUtilityActions;
|
|
40
46
|
private registerKeyboardActions;
|
|
41
47
|
private registerDropdownActions;
|
|
42
48
|
private registerSheetsActions;
|
|
43
49
|
private gotoSheetsRange;
|
|
44
50
|
private registerDoneAction;
|
|
45
51
|
use_structured_output_action(outputModel: z.ZodTypeAny): void;
|
|
46
|
-
|
|
52
|
+
get_output_model(): z.ZodTypeAny | null;
|
|
53
|
+
exclude_action(actionName: string): void;
|
|
54
|
+
set_coordinate_clicking(enabled: boolean): void;
|
|
55
|
+
action(description: string, options?: {}): <Params = any>(handler: import("./index.js").RegistryActionHandler<Params, Context>) => any;
|
|
47
56
|
act(action: Record<string, unknown>, { browser_session, page_extraction_llm, sensitive_data, available_file_paths, file_system, context, signal, }: ActParams<Context>): Promise<ActionResult>;
|
|
48
57
|
}
|
|
49
58
|
export {};
|