@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.
@@ -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
+ }