@morphllm/morphsdk 0.2.93 → 0.2.95
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/dist/chunk-2AMEQAO2.js +46 -0
- package/dist/chunk-2AMEQAO2.js.map +1 -0
- package/dist/{chunk-EI4UKP24.js → chunk-2HMEZZKK.js} +2 -2
- package/dist/{chunk-EI4UKP24.js.map → chunk-2HMEZZKK.js.map} +1 -1
- package/dist/chunk-2VERUKO2.js +177 -0
- package/dist/chunk-2VERUKO2.js.map +1 -0
- package/dist/{chunk-VHOWYK66.js → chunk-43LQLGP6.js} +23 -33
- package/dist/chunk-43LQLGP6.js.map +1 -0
- package/dist/{chunk-LMUZ3NGC.js → chunk-73RV6EXR.js} +2 -2
- package/dist/{chunk-PBLPZ6AU.js → chunk-7D6TXC7X.js} +2 -2
- package/dist/{chunk-GU6DACME.js → chunk-O7LDZA52.js} +2 -2
- package/dist/{chunk-5QIWYEHJ.js → chunk-PE4KGDA6.js} +1 -8
- package/dist/chunk-PE4KGDA6.js.map +1 -0
- package/dist/{chunk-SQN4DUQS.js → chunk-Q6Y4R236.js} +26 -2
- package/dist/chunk-Q6Y4R236.js.map +1 -0
- package/dist/{chunk-PUGIOVSP.js → chunk-QAT5UVPX.js} +2 -2
- package/dist/{chunk-MIIJWDOQ.js → chunk-QJP62BXH.js} +166 -71
- package/dist/chunk-QJP62BXH.js.map +1 -0
- package/dist/{chunk-EYGBUH2R.js → chunk-R7IQWNSA.js} +8 -8
- package/dist/chunk-R7IQWNSA.js.map +1 -0
- package/dist/chunk-SI2CKRKJ.js +389 -0
- package/dist/chunk-SI2CKRKJ.js.map +1 -0
- package/dist/{chunk-4WLGDYWQ.js → chunk-TSENDJQI.js} +6 -6
- package/dist/chunk-TSENDJQI.js.map +1 -0
- package/dist/{chunk-IUG2FHNN.js → chunk-XH7P7HVT.js} +1 -8
- package/dist/chunk-XH7P7HVT.js.map +1 -0
- package/dist/{chunk-FNLNDMIX.js → chunk-YZ5NCWO2.js} +6 -6
- package/dist/chunk-YZ5NCWO2.js.map +1 -0
- package/dist/{chunk-IJ54DTJ3.js → chunk-ZYTAKEBW.js} +13 -13
- package/dist/client.cjs +770 -110
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.ts +2 -0
- package/dist/client.js +16 -13
- package/dist/index.cjs +770 -110
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +16 -13
- package/dist/tools/browser/anthropic.cjs +58 -23
- package/dist/tools/browser/anthropic.cjs.map +1 -1
- package/dist/tools/browser/anthropic.js +7 -4
- package/dist/tools/browser/core.cjs +750 -70
- package/dist/tools/browser/core.cjs.map +1 -1
- package/dist/tools/browser/core.d.ts +30 -24
- package/dist/tools/browser/core.js +5 -2
- package/dist/tools/browser/errors.cjs +208 -0
- package/dist/tools/browser/errors.cjs.map +1 -0
- package/dist/tools/browser/errors.d.ts +158 -0
- package/dist/tools/browser/errors.js +22 -0
- package/dist/tools/browser/errors.js.map +1 -0
- package/dist/tools/browser/index.cjs +783 -85
- package/dist/tools/browser/index.cjs.map +1 -1
- package/dist/tools/browser/index.d.ts +5 -2
- package/dist/tools/browser/index.js +32 -9
- package/dist/tools/browser/index.js.map +1 -1
- package/dist/tools/browser/live.cjs +25 -1
- package/dist/tools/browser/live.cjs.map +1 -1
- package/dist/tools/browser/live.js +1 -1
- package/dist/tools/browser/openai.cjs +58 -23
- package/dist/tools/browser/openai.cjs.map +1 -1
- package/dist/tools/browser/openai.js +7 -4
- package/dist/tools/browser/profiles/core.cjs +670 -0
- package/dist/tools/browser/profiles/core.cjs.map +1 -0
- package/dist/tools/browser/profiles/core.d.ts +187 -0
- package/dist/tools/browser/profiles/core.js +29 -0
- package/dist/tools/browser/profiles/core.js.map +1 -0
- package/dist/tools/browser/profiles/index.cjs +670 -0
- package/dist/tools/browser/profiles/index.cjs.map +1 -0
- package/dist/tools/browser/profiles/index.d.ts +4 -0
- package/dist/tools/browser/profiles/index.js +29 -0
- package/dist/tools/browser/profiles/index.js.map +1 -0
- package/dist/tools/browser/profiles/types.cjs +74 -0
- package/dist/tools/browser/profiles/types.cjs.map +1 -0
- package/dist/tools/browser/profiles/types.d.ts +195 -0
- package/dist/tools/browser/profiles/types.js +16 -0
- package/dist/tools/browser/profiles/types.js.map +1 -0
- package/dist/tools/browser/prompts.cjs +1 -1
- package/dist/tools/browser/prompts.cjs.map +1 -1
- package/dist/tools/browser/prompts.d.ts +1 -1
- package/dist/tools/browser/prompts.js +1 -1
- package/dist/tools/browser/types.cjs.map +1 -1
- package/dist/tools/browser/types.d.ts +55 -51
- package/dist/tools/browser/vercel.cjs +60 -25
- package/dist/tools/browser/vercel.cjs.map +1 -1
- package/dist/tools/browser/vercel.d.ts +1 -1
- package/dist/tools/browser/vercel.js +7 -4
- package/dist/tools/fastapply/anthropic.cjs +0 -7
- package/dist/tools/fastapply/anthropic.cjs.map +1 -1
- package/dist/tools/fastapply/anthropic.js +1 -1
- package/dist/tools/fastapply/index.cjs +0 -14
- package/dist/tools/fastapply/index.cjs.map +1 -1
- package/dist/tools/fastapply/index.js +5 -5
- package/dist/tools/fastapply/openai.cjs +0 -7
- package/dist/tools/fastapply/openai.cjs.map +1 -1
- package/dist/tools/fastapply/openai.js +1 -1
- package/dist/tools/index.cjs +0 -14
- package/dist/tools/index.cjs.map +1 -1
- package/dist/tools/index.js +5 -5
- package/dist/tools/warp_grep/agent/runner.cjs +18 -98
- package/dist/tools/warp_grep/agent/runner.cjs.map +1 -1
- package/dist/tools/warp_grep/agent/runner.js +2 -3
- package/dist/tools/warp_grep/anthropic.cjs +18 -98
- package/dist/tools/warp_grep/anthropic.cjs.map +1 -1
- package/dist/tools/warp_grep/anthropic.js +8 -9
- package/dist/tools/warp_grep/client.cjs +18 -98
- package/dist/tools/warp_grep/client.cjs.map +1 -1
- package/dist/tools/warp_grep/client.js +5 -6
- package/dist/tools/warp_grep/gemini.cjs +18 -98
- package/dist/tools/warp_grep/gemini.cjs.map +1 -1
- package/dist/tools/warp_grep/gemini.js +7 -8
- package/dist/tools/warp_grep/gemini.js.map +1 -1
- package/dist/tools/warp_grep/harness.js +10 -10
- package/dist/tools/warp_grep/index.cjs +18 -98
- package/dist/tools/warp_grep/index.cjs.map +1 -1
- package/dist/tools/warp_grep/index.js +8 -9
- package/dist/tools/warp_grep/openai.cjs +18 -98
- package/dist/tools/warp_grep/openai.cjs.map +1 -1
- package/dist/tools/warp_grep/openai.js +8 -9
- package/dist/tools/warp_grep/vercel.cjs +18 -98
- package/dist/tools/warp_grep/vercel.cjs.map +1 -1
- package/dist/tools/warp_grep/vercel.js +8 -9
- package/dist/{vercel-CsnNSdze.d.ts → vercel-CVF27qFK.d.ts} +10 -10
- package/package.json +7 -2
- package/dist/chunk-4WLGDYWQ.js.map +0 -1
- package/dist/chunk-5QIWYEHJ.js.map +0 -1
- package/dist/chunk-EYGBUH2R.js.map +0 -1
- package/dist/chunk-FNLNDMIX.js.map +0 -1
- package/dist/chunk-IUG2FHNN.js.map +0 -1
- package/dist/chunk-MIIJWDOQ.js.map +0 -1
- package/dist/chunk-SQN4DUQS.js.map +0 -1
- package/dist/chunk-VHOWYK66.js.map +0 -1
- /package/dist/{chunk-LMUZ3NGC.js.map → chunk-73RV6EXR.js.map} +0 -0
- /package/dist/{chunk-PBLPZ6AU.js.map → chunk-7D6TXC7X.js.map} +0 -0
- /package/dist/{chunk-GU6DACME.js.map → chunk-O7LDZA52.js.map} +0 -0
- /package/dist/{chunk-PUGIOVSP.js.map → chunk-QAT5UVPX.js.map} +0 -0
- /package/dist/{chunk-IJ54DTJ3.js.map → chunk-ZYTAKEBW.js.map} +0 -0
|
@@ -7,7 +7,7 @@ import { RetryConfig } from '../utils/resilience.js';
|
|
|
7
7
|
/**
|
|
8
8
|
* Available browser automation models
|
|
9
9
|
*/
|
|
10
|
-
type BrowserModel = 'gemini-3-flash-preview' | 'morph-computer-use-v0';
|
|
10
|
+
type BrowserModel = 'gemini-3-flash-preview' | 'morph-computer-use-v0' | 'morph-computer-use-v1';
|
|
11
11
|
/**
|
|
12
12
|
* Configuration for the browser worker service
|
|
13
13
|
*/
|
|
@@ -43,7 +43,7 @@ interface BrowserTaskInput {
|
|
|
43
43
|
/** Starting URL (e.g., https://3000-xyz.e2b.dev) */
|
|
44
44
|
url?: string;
|
|
45
45
|
/** Maximum number of browser actions to take (1-50, default: 10) */
|
|
46
|
-
|
|
46
|
+
maxSteps?: number;
|
|
47
47
|
/** Model to use for task execution (default: morph-computer-use-v0) */
|
|
48
48
|
model?: BrowserModel;
|
|
49
49
|
/** Browserless region: 'sfo' (US West) or 'lon' (Europe) */
|
|
@@ -51,32 +51,36 @@ interface BrowserTaskInput {
|
|
|
51
51
|
/** Enable stealth mode to avoid bot detection (default: true) */
|
|
52
52
|
stealth?: boolean;
|
|
53
53
|
/** Browser viewport width (default: 1280) */
|
|
54
|
-
|
|
54
|
+
viewportWidth?: number;
|
|
55
55
|
/** Browser viewport height (default: 720) */
|
|
56
|
-
|
|
56
|
+
viewportHeight?: number;
|
|
57
57
|
/** User-defined reference/tracking ID (e.g., "PR-1234", "jira-PROJ-567") */
|
|
58
|
-
|
|
59
|
-
/** Optional repository ID to associate with this session */
|
|
60
|
-
|
|
58
|
+
externalId?: string;
|
|
59
|
+
/** Optional repository database ID (UUID) to associate with this session - for internal use */
|
|
60
|
+
repoId?: string;
|
|
61
|
+
/** Optional repository full name (e.g., "owner/repo") - for external SDK users */
|
|
62
|
+
repoFullName?: string;
|
|
61
63
|
/** Optional commit UUID to associate with this session */
|
|
62
|
-
|
|
64
|
+
commitId?: string;
|
|
63
65
|
/** Record session video to S3 (default: false) */
|
|
64
|
-
|
|
66
|
+
recordVideo?: boolean;
|
|
65
67
|
/** Video width (default: 1280) */
|
|
66
|
-
|
|
68
|
+
videoWidth?: number;
|
|
67
69
|
/** Video height (default: 720) */
|
|
68
|
-
|
|
70
|
+
videoHeight?: number;
|
|
69
71
|
/** Enable window resizing for responsive/mobile testing. Disables stealth mode. (default: false) */
|
|
70
|
-
|
|
72
|
+
allowResizing?: boolean;
|
|
71
73
|
/** Serialized structured output schema (internal use) */
|
|
72
|
-
|
|
74
|
+
structuredOutput?: string;
|
|
73
75
|
/** Site authentication - global credentials or per-domain dict (follows browser-use pattern) */
|
|
74
76
|
auth?: AuthCredentials | Record<string, AuthCredentials>;
|
|
77
|
+
/** Profile ID - restore cookies/localStorage from a saved browser profile */
|
|
78
|
+
profileId?: string;
|
|
75
79
|
}
|
|
76
80
|
/**
|
|
77
81
|
* Input with Zod schema for structured output
|
|
78
82
|
*/
|
|
79
|
-
interface BrowserTaskInputWithSchema<T> extends Omit<BrowserTaskInput, '
|
|
83
|
+
interface BrowserTaskInputWithSchema<T> extends Omit<BrowserTaskInput, 'structuredOutput'> {
|
|
80
84
|
/** Zod schema for structured output */
|
|
81
85
|
schema: any;
|
|
82
86
|
}
|
|
@@ -91,27 +95,27 @@ interface BrowserTaskResult {
|
|
|
91
95
|
/** Error message if task failed */
|
|
92
96
|
error?: string;
|
|
93
97
|
/** Number of browser actions taken */
|
|
94
|
-
|
|
98
|
+
stepsTaken?: number;
|
|
95
99
|
/** Total execution time in milliseconds */
|
|
96
|
-
|
|
100
|
+
executionTimeMs?: number;
|
|
97
101
|
/** All URLs visited during execution */
|
|
98
102
|
urls?: (string | null)[];
|
|
99
103
|
/** Names of all actions executed */
|
|
100
|
-
|
|
104
|
+
actionNames?: string[];
|
|
101
105
|
/** Per-step errors (null for steps without errors) */
|
|
102
106
|
errors?: (string | null)[];
|
|
103
107
|
/** All model actions with parameters */
|
|
104
|
-
|
|
108
|
+
modelActions?: any[];
|
|
105
109
|
/** Whether agent marked task as done */
|
|
106
|
-
|
|
110
|
+
isDone?: boolean;
|
|
107
111
|
/** Truncated action history with essential fields */
|
|
108
|
-
|
|
112
|
+
actionHistory?: any[][];
|
|
109
113
|
/** All action results */
|
|
110
|
-
|
|
114
|
+
actionResults?: any[];
|
|
111
115
|
/** Whether any errors occurred */
|
|
112
|
-
|
|
116
|
+
hasErrors?: boolean;
|
|
113
117
|
/** Total number of steps executed */
|
|
114
|
-
|
|
118
|
+
numberOfSteps?: number;
|
|
115
119
|
/** Judge validation result if available */
|
|
116
120
|
judgement?: {
|
|
117
121
|
reasoning?: string;
|
|
@@ -121,17 +125,17 @@ interface BrowserTaskResult {
|
|
|
121
125
|
reached_captcha?: boolean;
|
|
122
126
|
};
|
|
123
127
|
/** Whether judge validated the execution */
|
|
124
|
-
|
|
128
|
+
isValidated?: boolean;
|
|
125
129
|
/** UUID of saved replay record (if session replay enabled) */
|
|
126
|
-
|
|
130
|
+
replayId?: string;
|
|
127
131
|
/** Browserless replay URL (if session replay enabled) */
|
|
128
|
-
|
|
129
|
-
/** Recording ID (if
|
|
130
|
-
|
|
132
|
+
replayUrl?: string;
|
|
133
|
+
/** Recording ID (if recordVideo=true) */
|
|
134
|
+
recordingId?: string;
|
|
131
135
|
/** Recording status: PENDING, PROCESSING, COMPLETED, ERROR */
|
|
132
|
-
|
|
136
|
+
recordingStatus?: string;
|
|
133
137
|
/** Task ID for async task tracking */
|
|
134
|
-
|
|
138
|
+
taskId?: string;
|
|
135
139
|
/** Task status: pending, running, completed, failed */
|
|
136
140
|
status?: string;
|
|
137
141
|
/** Structured output (JSON string) */
|
|
@@ -171,7 +175,7 @@ interface IframeOptions extends LiveSessionOptions {
|
|
|
171
175
|
* Task result with convenience methods for async execution
|
|
172
176
|
*/
|
|
173
177
|
interface BrowserTaskWithPromise extends BrowserTaskResult {
|
|
174
|
-
|
|
178
|
+
taskId: string;
|
|
175
179
|
/** Live URL to watch task execution in real-time */
|
|
176
180
|
liveUrl: string;
|
|
177
181
|
/** Wait for task completion */
|
|
@@ -190,7 +194,7 @@ interface BrowserTaskWithPromise extends BrowserTaskResult {
|
|
|
190
194
|
* Task result with schema validation
|
|
191
195
|
*/
|
|
192
196
|
interface BrowserTaskWithPromiseAndSchema<T> extends BrowserTaskResult {
|
|
193
|
-
|
|
197
|
+
taskId: string;
|
|
194
198
|
/** Live URL to watch task execution in real-time */
|
|
195
199
|
liveUrl: string;
|
|
196
200
|
/** Parsed and validated output */
|
|
@@ -218,23 +222,23 @@ interface RecordingStatus {
|
|
|
218
222
|
/** Current status */
|
|
219
223
|
status: 'PENDING' | 'PROCESSING' | 'COMPLETED' | 'ERROR';
|
|
220
224
|
/** Presigned S3 URL for rrweb replay JSON (interactive DOM replay) */
|
|
221
|
-
|
|
225
|
+
replayUrl?: string;
|
|
222
226
|
/** Presigned S3 URL for network logs (NDJSON format) */
|
|
223
|
-
|
|
227
|
+
networkUrl?: string;
|
|
224
228
|
/** Presigned S3 URL for console logs (NDJSON format) */
|
|
225
|
-
|
|
229
|
+
consoleUrl?: string;
|
|
226
230
|
/** Presigned S3 URL for native browser video (WebM or MP4 format, real-time recording) */
|
|
227
|
-
|
|
231
|
+
videoUrl?: string;
|
|
228
232
|
/** Total rrweb events captured */
|
|
229
|
-
|
|
233
|
+
totalEvents?: number;
|
|
230
234
|
/** Total bytes of all files */
|
|
231
|
-
|
|
235
|
+
fileSize?: number;
|
|
232
236
|
/** Duration in milliseconds */
|
|
233
237
|
duration?: number;
|
|
234
238
|
/** Error message if status=ERROR */
|
|
235
239
|
error?: string;
|
|
236
240
|
/** When recording was created */
|
|
237
|
-
|
|
241
|
+
createdAt: string;
|
|
238
242
|
}
|
|
239
243
|
/**
|
|
240
244
|
* Browser error with screenshot captured at error time
|
|
@@ -249,9 +253,9 @@ interface BrowserError {
|
|
|
249
253
|
/** CDP timestamp in seconds since browser start */
|
|
250
254
|
timestamp: number;
|
|
251
255
|
/** Presigned S3 URL to screenshot JPEG (captured 500ms after error) */
|
|
252
|
-
|
|
256
|
+
screenshotUrl?: string;
|
|
253
257
|
/** When screenshot was captured (Unix timestamp) */
|
|
254
|
-
|
|
258
|
+
capturedAt?: number;
|
|
255
259
|
/** HTTP status code (for network errors) */
|
|
256
260
|
status?: number;
|
|
257
261
|
}
|
|
@@ -260,9 +264,9 @@ interface BrowserError {
|
|
|
260
264
|
*/
|
|
261
265
|
interface ErrorsResponse {
|
|
262
266
|
/** Recording ID */
|
|
263
|
-
|
|
267
|
+
recordingId: string;
|
|
264
268
|
/** Total number of errors */
|
|
265
|
-
|
|
269
|
+
totalErrors: number;
|
|
266
270
|
/** Errors with real-time screenshots */
|
|
267
271
|
errors: BrowserError[];
|
|
268
272
|
}
|
|
@@ -271,7 +275,7 @@ interface ErrorsResponse {
|
|
|
271
275
|
*/
|
|
272
276
|
interface WebpOptions {
|
|
273
277
|
/** Maximum duration in seconds (1-120, default: 60) */
|
|
274
|
-
|
|
278
|
+
maxDuration?: number;
|
|
275
279
|
/** Frame rate (5-30, default: 15) */
|
|
276
280
|
fps?: number;
|
|
277
281
|
/** Output width in pixels (320-1920, default: 780) */
|
|
@@ -281,14 +285,14 @@ interface WebpOptions {
|
|
|
281
285
|
/** Enable auto-zoom that follows click/input actions (default: false) */
|
|
282
286
|
autoZoom?: boolean;
|
|
283
287
|
/** Maximum file size in MB (0.5-50). Uses iterative reduction to guarantee budget. */
|
|
284
|
-
|
|
288
|
+
maxSizeMb?: number;
|
|
285
289
|
}
|
|
286
290
|
/**
|
|
287
291
|
* Response from getWebp()
|
|
288
292
|
*/
|
|
289
293
|
interface WebpResponse {
|
|
290
294
|
/** Presigned S3 URL for the WebP file */
|
|
291
|
-
|
|
295
|
+
webpUrl: string;
|
|
292
296
|
/** Whether the WebP was served from cache */
|
|
293
297
|
cached: boolean;
|
|
294
298
|
/** Width of the WebP (may differ from requested if budget-constrained) */
|
|
@@ -296,15 +300,15 @@ interface WebpResponse {
|
|
|
296
300
|
/** Frame rate of the WebP (may differ from requested if budget-constrained) */
|
|
297
301
|
fps: number;
|
|
298
302
|
/** Max duration used (may differ from requested if budget-constrained) */
|
|
299
|
-
|
|
303
|
+
maxDuration: number;
|
|
300
304
|
/** File size in bytes */
|
|
301
|
-
|
|
305
|
+
fileSize?: number;
|
|
302
306
|
/** Max size budget in MB (if specified) */
|
|
303
|
-
|
|
307
|
+
maxSizeMb?: number;
|
|
304
308
|
/** Whether the file fits within the budget */
|
|
305
|
-
|
|
309
|
+
budgetMet?: boolean;
|
|
306
310
|
/** Quality setting used (may differ from requested if budget-constrained) */
|
|
307
|
-
|
|
311
|
+
qualityUsed?: number;
|
|
308
312
|
/** Number of encoding attempts needed to meet budget */
|
|
309
313
|
attempts?: number;
|
|
310
314
|
}
|
|
@@ -101,6 +101,9 @@ function sleep(ms) {
|
|
|
101
101
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
// tools/browser/profiles/core.ts
|
|
105
|
+
var DEFAULT_API_URL = process.env.MORPH_ENVIRONMENT === "DEV" ? "http://localhost:8000" : "https://browser.morphllm.com";
|
|
106
|
+
|
|
104
107
|
// tools/browser/core.ts
|
|
105
108
|
var DEFAULT_CONFIG = {
|
|
106
109
|
apiUrl: process.env.MORPH_ENVIRONMENT === "DEV" ? "http://localhost:8000" : "https://browser.morphllm.com",
|
|
@@ -118,15 +121,15 @@ async function executeBrowserTask(input, config = {}) {
|
|
|
118
121
|
error: 'Task description is required. Example: "Go to example.com and click the login button"'
|
|
119
122
|
};
|
|
120
123
|
}
|
|
121
|
-
if (input.
|
|
124
|
+
if (input.maxSteps !== void 0 && (input.maxSteps < 1 || input.maxSteps > 50)) {
|
|
122
125
|
return {
|
|
123
126
|
success: false,
|
|
124
|
-
error: "
|
|
127
|
+
error: "maxSteps must be between 1 and 50. Use more steps for complex multi-page flows."
|
|
125
128
|
};
|
|
126
129
|
}
|
|
127
130
|
if (debug) {
|
|
128
|
-
console.log(`[Browser] Task: "${input.task.slice(0, 60)}..." url=${input.url || "none"} maxSteps=${input.
|
|
129
|
-
console.log(`[Browser] Recording: ${input.
|
|
131
|
+
console.log(`[Browser] Task: "${input.task.slice(0, 60)}..." url=${input.url || "none"} maxSteps=${input.maxSteps ?? 10}`);
|
|
132
|
+
console.log(`[Browser] Recording: ${input.recordVideo ? "yes" : "no"} | Calling ${apiUrl}/browser-task`);
|
|
130
133
|
}
|
|
131
134
|
const startTime = Date.now();
|
|
132
135
|
try {
|
|
@@ -140,19 +143,20 @@ async function executeBrowserTask(input, config = {}) {
|
|
|
140
143
|
body: JSON.stringify({
|
|
141
144
|
task: input.task,
|
|
142
145
|
url: input.url,
|
|
143
|
-
max_steps: input.
|
|
146
|
+
max_steps: input.maxSteps ?? 10,
|
|
144
147
|
model: input.model ?? "morph-computer-use-v0",
|
|
145
|
-
viewport_width: input.
|
|
146
|
-
viewport_height: input.
|
|
147
|
-
external_id: input.
|
|
148
|
-
repo_id: input.
|
|
149
|
-
commit_id: input.
|
|
150
|
-
record_video: input.
|
|
151
|
-
video_width: input.
|
|
152
|
-
video_height: input.
|
|
153
|
-
allow_resizing: input.
|
|
154
|
-
structured_output: input.
|
|
155
|
-
auth: input.auth
|
|
148
|
+
viewport_width: input.viewportWidth ?? 1280,
|
|
149
|
+
viewport_height: input.viewportHeight ?? 720,
|
|
150
|
+
external_id: input.externalId,
|
|
151
|
+
repo_id: input.repoId,
|
|
152
|
+
commit_id: input.commitId,
|
|
153
|
+
record_video: input.recordVideo ?? false,
|
|
154
|
+
video_width: input.videoWidth ?? input.viewportWidth ?? 1280,
|
|
155
|
+
video_height: input.videoHeight ?? input.viewportHeight ?? 720,
|
|
156
|
+
allow_resizing: input.allowResizing ?? false,
|
|
157
|
+
structured_output: input.structuredOutput,
|
|
158
|
+
auth: input.auth,
|
|
159
|
+
profile_id: input.profileId
|
|
156
160
|
})
|
|
157
161
|
},
|
|
158
162
|
config.retryConfig
|
|
@@ -160,17 +164,17 @@ async function executeBrowserTask(input, config = {}) {
|
|
|
160
164
|
const response = await withTimeout(
|
|
161
165
|
fetchPromise,
|
|
162
166
|
timeout,
|
|
163
|
-
`Browser task timed out after ${timeout}ms. Consider increasing timeout or reducing
|
|
167
|
+
`Browser task timed out after ${timeout}ms. Consider increasing timeout or reducing maxSteps.`
|
|
164
168
|
);
|
|
165
169
|
if (!response.ok) {
|
|
166
170
|
const errorText = await response.text().catch(() => response.statusText);
|
|
167
171
|
if (debug) console.error(`[Browser] Error: ${response.status} - ${errorText}`);
|
|
168
172
|
throw new Error(`HTTP ${response.status}: ${errorText}`);
|
|
169
173
|
}
|
|
170
|
-
const result = await response.json();
|
|
174
|
+
const result = mapTaskResult(await response.json());
|
|
171
175
|
const elapsed = Date.now() - startTime;
|
|
172
176
|
if (debug) {
|
|
173
|
-
console.log(`[Browser] \u2705 ${result.success ? "Success" : "Failed"} in ${elapsed}ms | steps=${result.
|
|
177
|
+
console.log(`[Browser] \u2705 ${result.success ? "Success" : "Failed"} in ${elapsed}ms | steps=${result.stepsTaken ?? 0} recordingId=${result.recordingId ?? "none"}`);
|
|
174
178
|
}
|
|
175
179
|
return result;
|
|
176
180
|
} catch (error) {
|
|
@@ -192,6 +196,37 @@ async function executeBrowserTask(input, config = {}) {
|
|
|
192
196
|
};
|
|
193
197
|
}
|
|
194
198
|
}
|
|
199
|
+
function mapTaskResult(api) {
|
|
200
|
+
if (!api || typeof api !== "object") {
|
|
201
|
+
return api;
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
success: api.success,
|
|
205
|
+
result: api.result,
|
|
206
|
+
error: api.error,
|
|
207
|
+
stepsTaken: api.steps_taken,
|
|
208
|
+
executionTimeMs: api.execution_time_ms,
|
|
209
|
+
urls: api.urls,
|
|
210
|
+
actionNames: api.action_names,
|
|
211
|
+
errors: api.errors,
|
|
212
|
+
modelActions: api.model_actions,
|
|
213
|
+
isDone: api.is_done,
|
|
214
|
+
actionHistory: api.action_history,
|
|
215
|
+
actionResults: api.action_results,
|
|
216
|
+
hasErrors: api.has_errors,
|
|
217
|
+
numberOfSteps: api.number_of_steps,
|
|
218
|
+
judgement: api.judgement,
|
|
219
|
+
isValidated: api.is_validated,
|
|
220
|
+
replayId: api.replay_id,
|
|
221
|
+
replayUrl: api.replay_url,
|
|
222
|
+
recordingId: api.recording_id,
|
|
223
|
+
recordingStatus: api.recording_status,
|
|
224
|
+
taskId: api.task_id,
|
|
225
|
+
status: api.status,
|
|
226
|
+
output: api.output,
|
|
227
|
+
debugUrl: api.debug_url
|
|
228
|
+
};
|
|
229
|
+
}
|
|
195
230
|
|
|
196
231
|
// tools/browser/prompts.ts
|
|
197
232
|
var BROWSER_TOOL_DESCRIPTION = `Test and verify your implemented code in a live browser. This tool executes natural language test instructions and returns a video recording plus detailed logs to help you debug issues.
|
|
@@ -229,31 +264,31 @@ Include verification steps:
|
|
|
229
264
|
## Requirements
|
|
230
265
|
- **URL**: Must be publicly accessible (use tunnels like ngrok, Cloudflare, or deploy to staging)
|
|
231
266
|
- **Timing**: Use this after implementation, not during coding
|
|
232
|
-
- **Complexity**: Set
|
|
267
|
+
- **Complexity**: Set maxSteps higher (20-30) for multi-step user workflows`;
|
|
233
268
|
|
|
234
269
|
// tools/browser/vercel.ts
|
|
235
270
|
function createBrowserTool(config) {
|
|
236
271
|
const schema = import_zod.z.object({
|
|
237
272
|
task: import_zod.z.string().describe('Natural language description of what to do (e.g., "Test checkout flow for buying a pineapple")'),
|
|
238
273
|
url: import_zod.z.string().optional().describe("Starting URL (e.g., https://3000-xyz.e2b.dev)"),
|
|
239
|
-
|
|
274
|
+
maxSteps: import_zod.z.number().min(1).max(50).default(10).describe("Maximum number of browser actions to take"),
|
|
240
275
|
region: import_zod.z.enum(["sfo", "lon"]).default("sfo").describe("Browserless region: sfo (US West) or lon (Europe)")
|
|
241
276
|
});
|
|
242
277
|
return (0, import_ai.tool)({
|
|
243
278
|
description: BROWSER_TOOL_DESCRIPTION,
|
|
244
279
|
inputSchema: schema,
|
|
245
280
|
execute: async (params) => {
|
|
246
|
-
const { task, url,
|
|
281
|
+
const { task, url, maxSteps, region } = params;
|
|
247
282
|
const result = await executeBrowserTask(
|
|
248
|
-
{ task, url,
|
|
283
|
+
{ task, url, maxSteps, region },
|
|
249
284
|
config
|
|
250
285
|
);
|
|
251
286
|
if (result.success) {
|
|
252
287
|
return {
|
|
253
288
|
success: true,
|
|
254
289
|
result: result.result,
|
|
255
|
-
|
|
256
|
-
|
|
290
|
+
stepsTaken: result.stepsTaken,
|
|
291
|
+
executionTimeMs: result.executionTimeMs
|
|
257
292
|
};
|
|
258
293
|
}
|
|
259
294
|
return {
|