@browserbasehq/convex-stagehand 0.0.3 → 0.1.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.
@@ -2,9 +2,33 @@
2
2
  * Stagehand REST API Client
3
3
  *
4
4
  * Wraps the Stagehand API at https://api.stagehand.browserbase.com
5
+ * Wire format matches the OpenAPI spec defined in stagehand/packages/core/lib/v3/types/public/api.ts
5
6
  */
6
7
 
7
- const API_BASE = "https://api.stagehand.browserbase.com/v1";
8
+ export type BrowserbaseRegion =
9
+ | "us-west-2"
10
+ | "us-east-1"
11
+ | "eu-central-1"
12
+ | "ap-southeast-1";
13
+
14
+ export interface BrowserbaseSessionCreateParams {
15
+ region?: BrowserbaseRegion;
16
+ }
17
+
18
+ /** Multi-region API URL mapping (matches official SDK) */
19
+ const REGION_API_URLS: Record<BrowserbaseRegion, string> = {
20
+ "us-west-2": "https://api.stagehand.browserbase.com",
21
+ "us-east-1": "https://api.use1.stagehand.browserbase.com",
22
+ "eu-central-1": "https://api.euc1.stagehand.browserbase.com",
23
+ "ap-southeast-1": "https://api.apse1.stagehand.browserbase.com",
24
+ };
25
+
26
+ export function getApiBase(region?: BrowserbaseRegion): string {
27
+ const baseUrl =
28
+ (region && REGION_API_URLS[region]) ||
29
+ REGION_API_URLS["us-west-2"];
30
+ return `${baseUrl}/v1`;
31
+ }
8
32
 
9
33
  export interface ApiConfig {
10
34
  browserbaseApiKey: string;
@@ -13,19 +37,22 @@ export interface ApiConfig {
13
37
  modelName?: string;
14
38
  }
15
39
 
40
+ /** Matches SessionStartResult from the OpenAPI spec */
16
41
  export interface SessionData {
17
42
  sessionId: string;
18
- browserbaseSessionId?: string;
19
- cdpUrl?: string;
43
+ cdpUrl?: string | null;
20
44
  available: boolean;
21
45
  }
22
46
 
23
47
  export interface StartSessionOptions {
24
- browserbaseSessionId?: string;
25
- browserbaseSessionCreateParams?: Record<string, unknown>;
48
+ browserbaseSessionID?: string;
49
+ browserbaseSessionCreateParams?: BrowserbaseSessionCreateParams;
50
+ model?: unknown;
26
51
  domSettleTimeoutMs?: number;
27
52
  selfHeal?: boolean;
28
53
  systemPrompt?: string;
54
+ verbose?: 0 | 1 | 2;
55
+ experimental?: boolean;
29
56
  }
30
57
 
31
58
  export interface ApiResponse<T> {
@@ -56,86 +83,135 @@ async function handleResponse<T>(response: Response): Promise<T> {
56
83
  return json.data;
57
84
  }
58
85
 
86
+ /** POST /v1/sessions/start — matches SessionStartRequest schema */
59
87
  export async function startSession(
60
88
  config: ApiConfig,
61
89
  options?: StartSessionOptions,
62
90
  ): Promise<SessionData> {
63
- const response = await fetch(`${API_BASE}/sessions/start`, {
64
- method: "POST",
65
- headers: getHeaders(config),
66
- body: JSON.stringify({
67
- modelName: config.modelName || "openai/gpt-4o",
68
- browserbaseSessionId: options?.browserbaseSessionId,
69
- browserbaseSessionCreateParams: options?.browserbaseSessionCreateParams,
70
- domSettleTimeoutMs: options?.domSettleTimeoutMs,
71
- selfHeal: options?.selfHeal,
72
- systemPrompt: options?.systemPrompt,
73
- }),
74
- });
91
+ const region = options?.browserbaseSessionCreateParams?.region;
92
+ const response = await fetch(
93
+ `${getApiBase(region)}/sessions/start`,
94
+ {
95
+ method: "POST",
96
+ headers: getHeaders(config),
97
+ body: JSON.stringify({
98
+ modelName: config.modelName || "openai/gpt-4o",
99
+ model: options?.model,
100
+ browserbaseSessionID: options?.browserbaseSessionID,
101
+ browserbaseSessionCreateParams:
102
+ options?.browserbaseSessionCreateParams,
103
+ domSettleTimeoutMs: options?.domSettleTimeoutMs,
104
+ selfHeal: options?.selfHeal,
105
+ systemPrompt: options?.systemPrompt,
106
+ verbose: options?.verbose,
107
+ experimental: options?.experimental,
108
+ }),
109
+ },
110
+ );
75
111
  return handleResponse<SessionData>(response);
76
112
  }
77
113
 
114
+ /** POST /v1/sessions/{id}/end */
78
115
  export async function endSession(
79
116
  sessionId: string,
80
117
  config: ApiConfig,
118
+ region?: BrowserbaseRegion,
81
119
  ): Promise<void> {
82
- try {
83
- await fetch(`${API_BASE}/sessions/${sessionId}/end`, {
84
- method: "POST",
85
- headers: getHeaders(config),
86
- });
87
- } catch {
88
- // Ignore errors when ending session - best effort cleanup
120
+ const response = await fetch(`${getApiBase(region)}/sessions/${sessionId}/end`, {
121
+ method: "POST",
122
+ headers: getHeaders(config),
123
+ });
124
+ if (!response.ok) {
125
+ const errorText = await response.text();
126
+ throw new Error(`Stagehand API error (${response.status}): ${errorText}`);
127
+ }
128
+ const text = await response.text();
129
+ if (text) {
130
+ const json = JSON.parse(text) as { success?: boolean };
131
+ if (json.success === false) {
132
+ throw new Error("Stagehand API returned success: false");
133
+ }
89
134
  }
90
135
  }
91
136
 
137
+ /** Matches NavigateOptions from the OpenAPI spec */
92
138
  export interface NavigateOptions {
93
139
  waitUntil?: "load" | "domcontentloaded" | "networkidle";
94
140
  timeout?: number;
141
+ referer?: string;
95
142
  }
96
143
 
144
+ /** POST /v1/sessions/{id}/navigate — matches NavigateRequest schema */
97
145
  export async function navigate(
98
146
  sessionId: string,
99
147
  url: string,
100
148
  config: ApiConfig,
101
149
  options?: NavigateOptions,
150
+ region?: BrowserbaseRegion,
102
151
  ): Promise<void> {
103
- const response = await fetch(`${API_BASE}/sessions/${sessionId}/navigate`, {
104
- method: "POST",
105
- headers: getHeaders(config),
106
- body: JSON.stringify({
107
- url,
108
- options: {
109
- waitUntil: options?.waitUntil || "networkidle",
110
- timeout: options?.timeout,
111
- },
112
- }),
113
- });
152
+ const response = await fetch(
153
+ `${getApiBase(region)}/sessions/${sessionId}/navigate`,
154
+ {
155
+ method: "POST",
156
+ headers: getHeaders(config),
157
+ body: JSON.stringify({
158
+ url,
159
+ options: {
160
+ waitUntil: options?.waitUntil || "networkidle",
161
+ timeout: options?.timeout,
162
+ referer: options?.referer,
163
+ },
164
+ }),
165
+ },
166
+ );
114
167
  await handleResponse(response);
115
168
  }
116
169
 
117
- export interface ExtractResult<T = any> {
170
+ export interface ExtractResult<T = unknown> {
118
171
  result: T;
119
- actionId: string;
172
+ actionId?: string;
173
+ }
174
+
175
+ /** Matches ExtractOptions from the OpenAPI spec */
176
+ export interface ExtractOperationOptions {
177
+ model?: unknown;
178
+ timeout?: number;
179
+ selector?: string;
120
180
  }
121
181
 
182
+ /** POST /v1/sessions/{id}/extract — matches ExtractRequest schema */
122
183
  export async function extract(
123
184
  sessionId: string,
124
185
  instruction: string,
125
- schema: any,
186
+ schema: unknown,
126
187
  config: ApiConfig,
188
+ operationOptions?: ExtractOperationOptions,
189
+ region?: BrowserbaseRegion,
127
190
  ): Promise<ExtractResult> {
128
- const response = await fetch(`${API_BASE}/sessions/${sessionId}/extract`, {
129
- method: "POST",
130
- headers: getHeaders(config),
131
- body: JSON.stringify({
132
- instruction,
133
- schema,
134
- }),
135
- });
191
+ const body: Record<string, unknown> = { instruction, schema };
192
+ if (
193
+ operationOptions?.model != null ||
194
+ operationOptions?.timeout != null ||
195
+ operationOptions?.selector != null
196
+ ) {
197
+ body.options = {
198
+ model: operationOptions?.model,
199
+ timeout: operationOptions?.timeout,
200
+ selector: operationOptions?.selector,
201
+ };
202
+ }
203
+ const response = await fetch(
204
+ `${getApiBase(region)}/sessions/${sessionId}/extract`,
205
+ {
206
+ method: "POST",
207
+ headers: getHeaders(config),
208
+ body: JSON.stringify(body),
209
+ },
210
+ );
136
211
  return handleResponse<ExtractResult>(response);
137
212
  }
138
213
 
214
+ /** Matches ActResultData from the OpenAPI spec */
139
215
  export interface ActResult {
140
216
  result: {
141
217
  actionDescription: string;
@@ -143,101 +219,182 @@ export interface ActResult {
143
219
  description: string;
144
220
  selector: string;
145
221
  arguments?: string[];
146
- method: string;
222
+ method?: string;
223
+ backendNodeId?: number;
147
224
  }>;
148
225
  message: string;
149
226
  success: boolean;
150
227
  };
151
- actionId: string;
228
+ actionId?: string;
152
229
  }
153
230
 
231
+ /** Matches ActOptions from the OpenAPI spec */
232
+ export interface ActOperationOptions {
233
+ model?: unknown;
234
+ variables?: Record<string, string>;
235
+ timeout?: number;
236
+ }
237
+
238
+ /** POST /v1/sessions/{id}/act — matches ActRequest schema */
154
239
  export async function act(
155
240
  sessionId: string,
156
241
  action: string,
157
242
  config: ApiConfig,
243
+ operationOptions?: ActOperationOptions,
244
+ region?: BrowserbaseRegion,
158
245
  ): Promise<ActResult> {
159
- const response = await fetch(`${API_BASE}/sessions/${sessionId}/act`, {
160
- method: "POST",
161
- headers: getHeaders(config),
162
- body: JSON.stringify({
163
- input: action,
164
- }),
165
- });
246
+ const body: Record<string, unknown> = { input: action };
247
+ if (
248
+ operationOptions?.model != null ||
249
+ operationOptions?.variables != null ||
250
+ operationOptions?.timeout != null
251
+ ) {
252
+ body.options = {
253
+ model: operationOptions?.model,
254
+ variables: operationOptions?.variables,
255
+ timeout: operationOptions?.timeout,
256
+ };
257
+ }
258
+ const response = await fetch(
259
+ `${getApiBase(region)}/sessions/${sessionId}/act`,
260
+ {
261
+ method: "POST",
262
+ headers: getHeaders(config),
263
+ body: JSON.stringify(body),
264
+ },
265
+ );
166
266
  return handleResponse<ActResult>(response);
167
267
  }
168
268
 
269
+ /** Matches ObserveResult from the OpenAPI spec (Action schema) */
169
270
  export interface ObserveResult {
170
271
  result: Array<{
171
272
  description: string;
172
273
  selector: string;
173
274
  arguments?: string[];
174
275
  backendNodeId?: number;
175
- method: string;
276
+ method?: string;
176
277
  }>;
177
- actionId: string;
278
+ actionId?: string;
279
+ }
280
+
281
+ /** Matches ObserveOptions from the OpenAPI spec */
282
+ export interface ObserveOperationOptions {
283
+ model?: unknown;
284
+ timeout?: number;
285
+ selector?: string;
178
286
  }
179
287
 
288
+ /** POST /v1/sessions/{id}/observe — matches ObserveRequest schema */
180
289
  export async function observe(
181
290
  sessionId: string,
182
291
  instruction: string,
183
292
  config: ApiConfig,
293
+ operationOptions?: ObserveOperationOptions,
294
+ region?: BrowserbaseRegion,
184
295
  ): Promise<ObserveResult> {
185
- const response = await fetch(`${API_BASE}/sessions/${sessionId}/observe`, {
186
- method: "POST",
187
- headers: getHeaders(config),
188
- body: JSON.stringify({
189
- instruction,
190
- }),
191
- });
296
+ const body: Record<string, unknown> = { instruction };
297
+ if (
298
+ operationOptions?.model != null ||
299
+ operationOptions?.timeout != null ||
300
+ operationOptions?.selector != null
301
+ ) {
302
+ body.options = {
303
+ model: operationOptions?.model,
304
+ timeout: operationOptions?.timeout,
305
+ selector: operationOptions?.selector,
306
+ };
307
+ }
308
+ const response = await fetch(
309
+ `${getApiBase(region)}/sessions/${sessionId}/observe`,
310
+ {
311
+ method: "POST",
312
+ headers: getHeaders(config),
313
+ body: JSON.stringify(body),
314
+ },
315
+ );
192
316
  return handleResponse<ObserveResult>(response);
193
317
  }
194
318
 
319
+ /** Matches AgentConfig from the OpenAPI spec */
195
320
  export interface AgentConfig {
196
321
  cua?: boolean;
197
- model?: string;
322
+ mode?: "dom" | "hybrid" | "cua";
323
+ model?: unknown;
198
324
  systemPrompt?: string;
325
+ executionModel?: unknown;
326
+ provider?: "openai" | "anthropic" | "google" | "microsoft";
199
327
  }
200
328
 
329
+ /** Matches AgentExecuteOptions from the OpenAPI spec */
201
330
  export interface AgentExecuteOptions {
202
331
  instruction: string;
203
332
  maxSteps?: number;
333
+ highlightCursor?: boolean;
204
334
  }
205
335
 
336
+ /** Matches AgentAction from the OpenAPI spec */
206
337
  export interface AgentAction {
207
338
  type: string;
208
339
  action?: string;
209
340
  reasoning?: string;
210
341
  timeMs?: number;
342
+ taskCompleted?: boolean;
343
+ pageText?: string;
344
+ pageUrl?: string;
345
+ instruction?: string;
346
+ }
347
+
348
+ /** Matches AgentUsage from the OpenAPI spec */
349
+ export interface AgentUsage {
350
+ input_tokens: number;
351
+ output_tokens: number;
352
+ reasoning_tokens?: number;
353
+ cached_input_tokens?: number;
354
+ inference_time_ms: number;
211
355
  }
212
356
 
357
+ /** Matches AgentExecuteResult from the OpenAPI spec */
213
358
  export interface AgentExecuteResult {
214
359
  result: {
215
360
  actions: AgentAction[];
216
361
  completed: boolean;
217
362
  message: string;
218
363
  success: boolean;
364
+ metadata?: Record<string, unknown>;
365
+ usage?: AgentUsage;
219
366
  };
220
367
  }
221
368
 
369
+ /** POST /v1/sessions/{id}/agentExecute — matches AgentExecuteRequest schema */
222
370
  export async function agentExecute(
223
371
  sessionId: string,
224
372
  agentConfig: AgentConfig,
225
373
  executeOptions: AgentExecuteOptions,
226
374
  config: ApiConfig,
375
+ shouldCache?: boolean,
376
+ region?: BrowserbaseRegion,
227
377
  ): Promise<AgentExecuteResult> {
228
378
  const response = await fetch(
229
- `${API_BASE}/sessions/${sessionId}/agentExecute`,
379
+ `${getApiBase(region)}/sessions/${sessionId}/agentExecute`,
230
380
  {
231
381
  method: "POST",
232
382
  headers: getHeaders(config),
233
383
  body: JSON.stringify({
234
384
  agentConfig: {
235
385
  cua: agentConfig.cua,
386
+ mode: agentConfig.mode,
236
387
  model: agentConfig.model,
237
388
  systemPrompt: agentConfig.systemPrompt,
389
+ executionModel: agentConfig.executionModel,
390
+ provider: agentConfig.provider,
391
+ },
392
+ executeOptions: {
393
+ instruction: executeOptions.instruction,
394
+ maxSteps: executeOptions.maxSteps,
395
+ highlightCursor: executeOptions.highlightCursor,
238
396
  },
239
- instruction: executeOptions.instruction,
240
- maxSteps: executeOptions.maxSteps,
397
+ shouldCache,
241
398
  }),
242
399
  },
243
400
  );