@intuned/browser-use-dev 0.0.0-stage → 0.1.2-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +43 -0
- package/README.md +39 -2
- package/dist/browser-use/errors.js +15 -0
- package/dist/browser-use/eventCollector.js +96 -0
- package/dist/browser-use/executeTask.js +242 -0
- package/dist/browser-use/export.d.ts +228 -0
- package/dist/browser-use/index.d.ts +228 -0
- package/dist/browser-use/index.js +19 -0
- package/dist/browser-use/messages.js +71 -0
- package/dist/browser-use/playwrightComputer.js +442 -0
- package/dist/browser-use/prompts.js +11 -0
- package/dist/browser-use/tools.js +338 -0
- package/dist/common/Logger/index.js +60 -0
- package/dist/common/Logger/types.js +5 -0
- package/dist/common/aiGateway.js +76 -0
- package/dist/common/networkSettled.js +31 -0
- package/dist/common/parseCostInCents.js +13 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +16 -0
- package/dist/types/intuned-runtime.d.ts +6 -0
- package/package.json +82 -3
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { Page } from "playwright";
|
|
2
|
+
import { ModelMessage } from "ai";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A caller-supplied function tool the browser-use model can invoke during a
|
|
6
|
+
* run, alongside the built-in `computer`, `list_tabs`, `clear_field` and `fill_field`
|
|
7
|
+
* tools. The handler's return value is serialized and fed back to the model
|
|
8
|
+
* as the tool output ("success" when it returns nothing); a thrown error is
|
|
9
|
+
* fed back as an `error: ...` output the model can react to.
|
|
10
|
+
*
|
|
11
|
+
* @interface BrowserUseFunctionTool
|
|
12
|
+
*/
|
|
13
|
+
export interface BrowserUseFunctionTool {
|
|
14
|
+
/** Tool name the model calls it by. Must not collide with built-in tools. */
|
|
15
|
+
name: string;
|
|
16
|
+
/** What the tool does and when the model should use it. */
|
|
17
|
+
description: string;
|
|
18
|
+
/** JSON schema object describing the tool's arguments. */
|
|
19
|
+
parameters: Record<string, unknown>;
|
|
20
|
+
/** Executes the tool call with the model-provided arguments. */
|
|
21
|
+
handler: (args: Record<string, unknown>) => unknown | Promise<unknown>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A debug frame captured immediately BEFORE a mouse action executes, with the
|
|
26
|
+
* action's target point(s) so a recording shows exactly where each action
|
|
27
|
+
* landed on the state the model acted on.
|
|
28
|
+
*
|
|
29
|
+
* @interface BrowserUseFrame
|
|
30
|
+
*/
|
|
31
|
+
export interface BrowserUseFrame {
|
|
32
|
+
/** PNG screenshot, one pixel per CSS pixel. */
|
|
33
|
+
image: Buffer;
|
|
34
|
+
/** Screenshot width in CSS pixels. */
|
|
35
|
+
width: number;
|
|
36
|
+
/** Screenshot height in CSS pixels. */
|
|
37
|
+
height: number;
|
|
38
|
+
/** The action about to run (e.g. "click", "drag", "clear_field"). */
|
|
39
|
+
action: string;
|
|
40
|
+
/** The action's target coordinate(s) in CSS pixels. */
|
|
41
|
+
markers: { x: number; y: number }[];
|
|
42
|
+
/** Extra action context (e.g. mouse button, scroll deltas). */
|
|
43
|
+
label: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Options for {@link executeTask}.
|
|
48
|
+
*
|
|
49
|
+
* @interface ExecuteTaskOptions
|
|
50
|
+
*/
|
|
51
|
+
export interface ExecuteTaskOptions {
|
|
52
|
+
/** The Playwright page the agent acts on. The agent stays pinned to this
|
|
53
|
+
* exact page for screenshots and actions (it never switches tabs). */
|
|
54
|
+
page: Page;
|
|
55
|
+
/** Model id to drive the run. Any vision-capable model id supported by the
|
|
56
|
+
* SDK's AI gateway (Anthropic, OpenAI, Google) — the provider is detected
|
|
57
|
+
* from the id. Defaults to "gpt-5.6-luna". */
|
|
58
|
+
model?: string;
|
|
59
|
+
/** Explicit API key for the detected provider. When omitted, the
|
|
60
|
+
* provider's env var (`ANTHROPIC_API_KEY` / `OPENAI_API_KEY` /
|
|
61
|
+
* `GOOGLE_API_KEY`) is used; when that is also absent, the Intuned AI
|
|
62
|
+
* gateway (via `@intuned/runtime`) provides credentials. */
|
|
63
|
+
apiKey?: string;
|
|
64
|
+
/** Extra function tools the model may call during the run. */
|
|
65
|
+
tools?: BrowserUseFunctionTool[];
|
|
66
|
+
/** Log each model message, tool call, and request cost. Defaults to true. */
|
|
67
|
+
logSteps?: boolean;
|
|
68
|
+
/** Expose the built-in `execute_javascript` tool, letting the model run
|
|
69
|
+
* arbitrary JavaScript in the page and get its result back — an escape
|
|
70
|
+
* hatch for cases the standard actions can't reach. Disabled by default. */
|
|
71
|
+
enableJavaScriptTool?: boolean;
|
|
72
|
+
/** The task for the agent, in plain English. Scope it tightly — say exactly
|
|
73
|
+
* what to act on and what outcome is expected. */
|
|
74
|
+
task: string;
|
|
75
|
+
/** Appended (after a blank line) to the built-in system prompt — the place
|
|
76
|
+
* for caller-specific rules the agent must follow at system priority. The
|
|
77
|
+
* built-in prompt (browser capability + viewport size + full-autonomy
|
|
78
|
+
* framing) is always present and never replaced, so callers only supply
|
|
79
|
+
* what's specific to them. */
|
|
80
|
+
systemPrompt?: string;
|
|
81
|
+
/** JSON schema for a structured result of the run. When provided, the
|
|
82
|
+
* model gets a reserved `submit_result` tool with these parameters and is
|
|
83
|
+
* instructed to call it once when the task is done; the submission is
|
|
84
|
+
* validated against the schema (an invalid one is sent back for the model
|
|
85
|
+
* to correct), and the validated object is returned as the result's
|
|
86
|
+
* `output`. If the model finishes without submitting, it is nudged once;
|
|
87
|
+
* `output` is null when it still doesn't submit. Reserves the tool name
|
|
88
|
+
* "submit_result". */
|
|
89
|
+
outputSchema?: Record<string, unknown>;
|
|
90
|
+
/** Model-call cap; the run throws when exceeded (runaway guard).
|
|
91
|
+
* Defaults to 100. */
|
|
92
|
+
maxTurns?: number;
|
|
93
|
+
/** Overall wall-clock cap for the run. On expiry the loop is aborted (no
|
|
94
|
+
* further page actions) and the returned promise rejects. */
|
|
95
|
+
timeoutInMs?: number;
|
|
96
|
+
/** External abort signal; aborting stops the loop between model calls and
|
|
97
|
+
* before each page action. */
|
|
98
|
+
signal?: AbortSignal;
|
|
99
|
+
/** Keep raw screenshots in the returned `messages` instead of replacing
|
|
100
|
+
* them with "[omitted]". Defaults to false. */
|
|
101
|
+
showImages?: boolean;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Result of a completed {@link executeTask} run.
|
|
106
|
+
*
|
|
107
|
+
* @interface BrowserUseTurnResult
|
|
108
|
+
*/
|
|
109
|
+
export interface BrowserUseTurnResult<TOutput = unknown> {
|
|
110
|
+
/** The final text of the model's last assistant message ("" when none). */
|
|
111
|
+
finalText: string;
|
|
112
|
+
/** The full run transcript (screenshots omitted unless `showImages`). */
|
|
113
|
+
messages: ModelMessage[];
|
|
114
|
+
/** The schema-validated structured result the model submitted via the
|
|
115
|
+
* `submit_result` tool (see `outputSchema`). Null when no `outputSchema`
|
|
116
|
+
* was given or the model never submitted a valid result. */
|
|
117
|
+
output: TOutput | null;
|
|
118
|
+
/** Summed per-request cost of the run in cents, read from the Intuned AI
|
|
119
|
+
* gateway's `x-ai-cost-in-cents` response header (0 when unavailable,
|
|
120
|
+
* e.g. when calling a provider directly). */
|
|
121
|
+
totalCostInCents: number;
|
|
122
|
+
/** Number of model calls the run made. */
|
|
123
|
+
turns: number;
|
|
124
|
+
/** Token usage summed over the run's model calls (input, output, and total tokens). */
|
|
125
|
+
usage: { inputTokens: number; outputTokens: number; totalTokens: number };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Run a browser-use agent (BETA) that drives a Playwright page: screenshots
|
|
130
|
+
* in, click/type/scroll actions out, executed on the exact page you pass in.
|
|
131
|
+
* Built on the AI SDK, so any vision-capable model the SDK's AI gateway
|
|
132
|
+
* supports (Anthropic, OpenAI, Google) can drive the browser — not just
|
|
133
|
+
* models with a provider-specific "computer use" tool.
|
|
134
|
+
*
|
|
135
|
+
* ## Features and limitations
|
|
136
|
+
* - Composes the system and user messages for you — pass a plain-English
|
|
137
|
+
* `task` (and optionally extra system-priority rules via `systemPrompt`).
|
|
138
|
+
* - Structured results: pass an `outputSchema` (JSON schema) and the run
|
|
139
|
+
* returns a schema-validated `output` object the model submits via a
|
|
140
|
+
* reserved `submit_result` tool when the task is done.
|
|
141
|
+
* - Built-in function tools beyond the standard actions (click, double_click,
|
|
142
|
+
* scroll, type, keypress, wait, move, drag): `screenshot` (see the page),
|
|
143
|
+
* `list_tabs` (check whether a popup tab opened), `clear_field`
|
|
144
|
+
* (deterministically empty an input) and `fill_field` (click, clear and
|
|
145
|
+
* type into a field in one action). Add your own via `tools`.
|
|
146
|
+
* - Every action reports the browser events it triggered — file downloads,
|
|
147
|
+
* popup tabs opening or closing — plus the current URL back to the model,
|
|
148
|
+
* so out-of-viewport side effects aren't invisible.
|
|
149
|
+
* - Actions return text and run one at a time in the order the model issued
|
|
150
|
+
* them; the agent calls `screenshot` to see the page (`scroll` and `wait`
|
|
151
|
+
* return one). Screenshots are one pixel per CSS pixel, viewport-synced, so
|
|
152
|
+
* model coordinates and mouse coordinates share one space — safe on HiDPI
|
|
153
|
+
* headful browsers.
|
|
154
|
+
* - Actions wait for the network they trigger to settle, and scrolling is
|
|
155
|
+
* slow and stepped so lazy-loaded content renders instead of being skipped.
|
|
156
|
+
* - Credentials resolve like the rest of the SDK: explicit `apiKey`, else
|
|
157
|
+
* the provider's env var, else the Intuned AI gateway. Per-request gateway
|
|
158
|
+
* cost is summed into the result's `totalCostInCents`.
|
|
159
|
+
* - BETA: the API surface may change between minor versions.
|
|
160
|
+
*
|
|
161
|
+
* @param {ExecuteTaskOptions} options - Task and agent configuration.
|
|
162
|
+
* @returns {Promise<BrowserUseTurnResult>} The completed run's result.
|
|
163
|
+
* @example
|
|
164
|
+
* ```typescript Run a task on the current page
|
|
165
|
+
* import { executeTask } from "@intuned/browser-use";
|
|
166
|
+
* import { BrowserContext, Page } from "playwright";
|
|
167
|
+
*
|
|
168
|
+
* interface Params {}
|
|
169
|
+
*
|
|
170
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext) {
|
|
171
|
+
* await page.goto("https://sandbox.intuned.dev/infinite-scroll");
|
|
172
|
+
* const result = await executeTask({
|
|
173
|
+
* page,
|
|
174
|
+
* task: "Scroll down until the year 2021 is visible and report the first 2021 entry's title.",
|
|
175
|
+
* maxTurns: 20,
|
|
176
|
+
* timeoutInMs: 120_000,
|
|
177
|
+
* });
|
|
178
|
+
* return { answer: result.finalText, costInCents: result.totalCostInCents };
|
|
179
|
+
* }
|
|
180
|
+
* ```
|
|
181
|
+
* @example
|
|
182
|
+
* ```typescript Custom tool and system prompt
|
|
183
|
+
* import { executeTask } from "@intuned/browser-use";
|
|
184
|
+
* import { BrowserContext, Page } from "playwright";
|
|
185
|
+
*
|
|
186
|
+
* interface Params {}
|
|
187
|
+
*
|
|
188
|
+
* export default async function handler(params: Params, page: Page, context: BrowserContext) {
|
|
189
|
+
* const result = await executeTask({
|
|
190
|
+
* page,
|
|
191
|
+
* task: "Use the get_reference_code tool, type the code into the Lookup field, and click Search.",
|
|
192
|
+
* systemPrompt:
|
|
193
|
+
* "- Act ONLY on the current screen of the active tab. Never navigate to another URL.",
|
|
194
|
+
* tools: [
|
|
195
|
+
* {
|
|
196
|
+
* name: "get_reference_code",
|
|
197
|
+
* description: "Get the reference code to type into the lookup field.",
|
|
198
|
+
* parameters: { type: "object", properties: {}, additionalProperties: false, required: [] },
|
|
199
|
+
* handler: () => ({ code: "REF-1234" }),
|
|
200
|
+
* },
|
|
201
|
+
* ],
|
|
202
|
+
* });
|
|
203
|
+
* return { answer: result.finalText };
|
|
204
|
+
* }
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
export declare function executeTask<TOutput = unknown>(
|
|
208
|
+
options: ExecuteTaskOptions
|
|
209
|
+
): Promise<BrowserUseTurnResult<TOutput>>;
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Thrown when a run doesn't finish cleanly (timeout or maxTurns exceeded).
|
|
213
|
+
* Carries spend/progress up to the point of failure — the ONLY way to read
|
|
214
|
+
* it in these cases, since there is no persistent agent object to poll and
|
|
215
|
+
* no successful {@link BrowserUseTurnResult} to return.
|
|
216
|
+
*
|
|
217
|
+
* @class BrowserUseError
|
|
218
|
+
*/
|
|
219
|
+
export declare class BrowserUseError extends Error {
|
|
220
|
+
/** Accumulated cost (in cents) up to the point of failure. */
|
|
221
|
+
readonly totalCostInCents: number;
|
|
222
|
+
/** Model calls completed before the failure. */
|
|
223
|
+
readonly turns: number;
|
|
224
|
+
constructor(
|
|
225
|
+
message: string,
|
|
226
|
+
info: { totalCostInCents: number; turns: number }
|
|
227
|
+
);
|
|
228
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "BrowserUseError", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _errors.BrowserUseError;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "executeTask", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () {
|
|
15
|
+
return _executeTask.executeTask;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
var _executeTask = require("./executeTask");
|
|
19
|
+
var _errors = require("./errors");
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.SCREENSHOT_OMITTED_TEXT = void 0;
|
|
7
|
+
exports.pruneImages = pruneImages;
|
|
8
|
+
const SCREENSHOT_OMITTED_TEXT = exports.SCREENSHOT_OMITTED_TEXT = "[screenshot omitted to save context]";
|
|
9
|
+
const isImageMedia = item => item.type === "media" && item.mediaType.startsWith("image/");
|
|
10
|
+
function pruneImages(messages, keep) {
|
|
11
|
+
if (keep <= 0) return messages;
|
|
12
|
+
let total = 0;
|
|
13
|
+
for (const message of messages) {
|
|
14
|
+
if (message.role === "user" && Array.isArray(message.content)) {
|
|
15
|
+
total += message.content.filter(part => part.type === "image").length;
|
|
16
|
+
} else if (message.role === "tool") {
|
|
17
|
+
for (const part of message.content) {
|
|
18
|
+
if (part.output.type === "content") total += part.output.value.filter(isImageMedia).length;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
let toRemove = total - keep;
|
|
23
|
+
toRemove -= toRemove % keep;
|
|
24
|
+
if (toRemove <= 0) return messages;
|
|
25
|
+
return messages.map(message => {
|
|
26
|
+
if (toRemove <= 0) return message;
|
|
27
|
+
if (message.role === "user" && Array.isArray(message.content)) {
|
|
28
|
+
const content = message.content.map(part => {
|
|
29
|
+
if (part.type === "image" && toRemove > 0) {
|
|
30
|
+
toRemove -= 1;
|
|
31
|
+
return {
|
|
32
|
+
type: "text",
|
|
33
|
+
text: SCREENSHOT_OMITTED_TEXT
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return part;
|
|
37
|
+
});
|
|
38
|
+
return {
|
|
39
|
+
...message,
|
|
40
|
+
content
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (message.role === "tool") {
|
|
44
|
+
const content = message.content.map(part => {
|
|
45
|
+
if (part.output.type !== "content") return part;
|
|
46
|
+
const value = part.output.value.map(item => {
|
|
47
|
+
if (isImageMedia(item) && toRemove > 0) {
|
|
48
|
+
toRemove -= 1;
|
|
49
|
+
return {
|
|
50
|
+
type: "text",
|
|
51
|
+
text: SCREENSHOT_OMITTED_TEXT
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
return item;
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
...part,
|
|
58
|
+
output: {
|
|
59
|
+
type: "content",
|
|
60
|
+
value
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
return {
|
|
65
|
+
...message,
|
|
66
|
+
content
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return message;
|
|
70
|
+
});
|
|
71
|
+
}
|