1
+ import { Browserbase } from "@browserbasehq/sdk" ;
1
2
import type {
2
- Page as PlaywrightPage ,
3
- BrowserContext as PlaywrightContext ,
4
3
CDPSession ,
4
+ BrowserContext as PlaywrightContext ,
5
+ Page as PlaywrightPage ,
5
6
} from "@playwright/test" ;
6
- import { LLMClient } from "./llm/LLMClient" ;
7
- import { ActOptions , ActResult , GotoOptions , Stagehand } from "./index" ;
8
- import { StagehandActHandler } from "./handlers/actHandler" ;
9
- import { StagehandContext } from "./StagehandContext" ;
7
+ import { chromium } from "@playwright/test" ;
8
+ import { z } from "zod" ;
10
9
import { Page , defaultExtractSchema } from "../types/page" ;
11
10
import {
12
11
ExtractOptions ,
13
12
ExtractResult ,
14
13
ObserveOptions ,
15
14
ObserveResult ,
16
15
} from "../types/stagehand" ;
17
- import { z } from "zod" ;
16
+ import { StagehandAPI } from "./api" ;
17
+ import { StagehandActHandler } from "./handlers/actHandler" ;
18
18
import { StagehandExtractHandler } from "./handlers/extractHandler" ;
19
19
import { StagehandObserveHandler } from "./handlers/observeHandler" ;
20
+ import { ActOptions , ActResult , GotoOptions , Stagehand } from "./index" ;
21
+ import { LLMClient } from "./llm/LLMClient" ;
22
+ import { StagehandContext } from "./StagehandContext" ;
20
23
import { clearOverlays } from "./utils" ;
21
24
25
+ const BROWSERBASE_REGION_DOMAIN = {
26
+ "us-west-2" : "wss://connect.usw2.browserbase.com" ,
27
+ "us-east-1" : "wss://connect.use1.browserbase.com" ,
28
+ "eu-central-1" : "wss://connect.euc1.browserbase.com" ,
29
+ "ap-southeast-1" : "wss://connect.apse1.browserbase.com" ,
30
+ } ;
31
+
22
32
export class StagehandPage {
23
33
private stagehand : Stagehand ;
24
34
private intPage : Page ;
@@ -28,13 +38,16 @@ export class StagehandPage {
28
38
private observeHandler : StagehandObserveHandler ;
29
39
private llmClient : LLMClient ;
30
40
private cdpClient : CDPSession | null = null ;
41
+ private api : StagehandAPI ;
42
+ private userProvidedInstructions ?: string ;
31
43
32
44
constructor (
33
45
page : PlaywrightPage ,
34
46
stagehand : Stagehand ,
35
47
context : StagehandContext ,
36
48
llmClient : LLMClient ,
37
49
userProvidedInstructions ?: string ,
50
+ api ?: StagehandAPI ,
38
51
) {
39
52
this . intPage = Object . assign ( page , {
40
53
act : ( ) => {
@@ -61,6 +74,8 @@ export class StagehandPage {
61
74
this . stagehand = stagehand ;
62
75
this . intContext = context ;
63
76
this . llmClient = llmClient ;
77
+ this . api = api ;
78
+ this . userProvidedInstructions = userProvidedInstructions ;
64
79
if ( this . llmClient ) {
65
80
this . actHandler = new StagehandActHandler ( {
66
81
verbose : this . stagehand . verbose ,
@@ -88,23 +103,72 @@ export class StagehandPage {
88
103
}
89
104
}
90
105
106
+ private async _refreshPageFromAPI ( ) {
107
+ if ( ! this . api ) return ;
108
+
109
+ const sessionId = this . stagehand . browserbaseSessionID ;
110
+ if ( ! sessionId ) {
111
+ throw new Error ( "No Browserbase session ID found" ) ;
112
+ }
113
+
114
+ const browserbase = new Browserbase ( {
115
+ apiKey : process . env . BROWSERBASE_API_KEY ,
116
+ } ) ;
117
+
118
+ const sessionStatus = await browserbase . sessions . retrieve ( sessionId ) ;
119
+ const browserbaseDomain =
120
+ BROWSERBASE_REGION_DOMAIN [ sessionStatus . region ] ||
121
+ "wss://connect.browserbase.com" ;
122
+ const connectUrl = `${ browserbaseDomain } ?apiKey=${ process . env . BROWSERBASE_API_KEY } &sessionId=${ sessionId } ` ;
123
+
124
+ const browser = await chromium . connectOverCDP ( connectUrl ) ;
125
+ const context = browser . contexts ( ) [ 0 ] ;
126
+ const newPage = context . pages ( ) [ 0 ] ;
127
+
128
+ const newStagehandPage = await new StagehandPage (
129
+ newPage ,
130
+ this . stagehand ,
131
+ this . intContext ,
132
+ this . llmClient ,
133
+ this . userProvidedInstructions ,
134
+ this . api ,
135
+ ) . init ( ) ;
136
+
137
+ this . intPage = newStagehandPage . page ;
138
+
139
+ if ( this . stagehand . debugDom ) {
140
+ await this . intPage . evaluate (
141
+ ( debugDom ) => ( window . showChunks = debugDom ) ,
142
+ this . stagehand . debugDom ,
143
+ ) ;
144
+ }
145
+ await this . intPage . waitForLoadState ( "domcontentloaded" ) ;
146
+ await this . _waitForSettledDom ( ) ;
147
+ }
148
+
91
149
async init ( ) : Promise < StagehandPage > {
92
150
const page = this . intPage ;
93
151
const stagehand = this . stagehand ;
94
152
this . intPage = new Proxy ( page , {
95
153
get : ( target , prop ) => {
96
- // Override the goto method to add debugDom and waitForSettledDom
97
154
if ( prop === "goto" )
98
155
return async ( url : string , options : GotoOptions ) => {
99
- const result = await page . goto ( url , options ) ;
100
- if ( stagehand . debugDom ) {
101
- await page . evaluate (
102
- ( debugDom ) => ( window . showChunks = debugDom ) ,
103
- stagehand . debugDom ,
104
- ) ;
156
+ const result = this . api
157
+ ? await this . api . goto ( url , options )
158
+ : await page . goto ( url , options ) ;
159
+
160
+ if ( this . api ) {
161
+ await this . _refreshPageFromAPI ( ) ;
162
+ } else {
163
+ if ( stagehand . debugDom ) {
164
+ await page . evaluate (
165
+ ( debugDom ) => ( window . showChunks = debugDom ) ,
166
+ stagehand . debugDom ,
167
+ ) ;
168
+ }
169
+ await this . intPage . waitForLoadState ( "domcontentloaded" ) ;
170
+ await this . _waitForSettledDom ( ) ;
105
171
}
106
- await this . intPage . waitForLoadState ( "domcontentloaded" ) ;
107
- await this . _waitForSettledDom ( ) ;
108
172
return result ;
109
173
} ;
110
174
@@ -343,6 +407,12 @@ export class StagehandPage {
343
407
} ) ;
344
408
}
345
409
410
+ if ( this . api ) {
411
+ const result = await this . api . act ( actionOrOptions ) ;
412
+ await this . _refreshPageFromAPI ( ) ;
413
+ return result ;
414
+ }
415
+
346
416
const requestId = Math . random ( ) . toString ( 36 ) . substring ( 2 ) ;
347
417
const llmClient : LLMClient = modelName
348
418
? this . stagehand . llmProvider . getClient ( modelName , modelClientOptions )
@@ -431,6 +501,10 @@ export class StagehandPage {
431
501
useTextExtract,
432
502
} = options ;
433
503
504
+ if ( this . api ) {
505
+ return this . api . extract < T > ( options ) ;
506
+ }
507
+
434
508
const requestId = Math . random ( ) . toString ( 36 ) . substring ( 2 ) ;
435
509
const llmClient = modelName
436
510
? this . stagehand . llmProvider . getClient ( modelName , modelClientOptions )
@@ -540,6 +614,10 @@ export class StagehandPage {
540
614
} ) ;
541
615
}
542
616
617
+ if ( this . api ) {
618
+ return this . api . observe ( options ) ;
619
+ }
620
+
543
621
const requestId = Math . random ( ) . toString ( 36 ) . substring ( 2 ) ;
544
622
const llmClient = modelName
545
623
? this . stagehand . llmProvider . getClient ( modelName , modelClientOptions )
0 commit comments