@@ -19,11 +19,39 @@ export class BrowserSession {
1919 private browser ?: Browser
2020 private page ?: Page
2121 private currentMousePosition ?: string
22+ private sessionTimeout ?: NodeJS . Timeout
23+ private readonly SESSION_TIMEOUT = 30 * 60 * 1000 // 30 minutes
2224
2325 constructor ( context : vscode . ExtensionContext ) {
2426 this . context = context
2527 }
2628
29+ private async getKeepBrowserOpen ( ) : Promise < boolean > {
30+ return this . context . globalState . get < boolean > ( "keepBrowserOpen" ) ?? false
31+ }
32+
33+ private async resetSessionTimeout ( ) {
34+ if ( this . sessionTimeout ) {
35+ clearTimeout ( this . sessionTimeout )
36+ }
37+
38+ const keepBrowserOpen = await this . getKeepBrowserOpen ( )
39+ if ( keepBrowserOpen ) {
40+ this . sessionTimeout = setTimeout ( ( ) => {
41+ console . log ( "Browser session timed out after inactivity" )
42+ this . browser ?. close ( ) . catch ( ( ) => { } )
43+ this . browser = undefined
44+ this . page = undefined
45+ this . currentMousePosition = undefined
46+ } , this . SESSION_TIMEOUT )
47+ } else {
48+ this . sessionTimeout = setTimeout ( ( ) => {
49+ console . log ( "Browser session timed out after inactivity" )
50+ this . closeBrowser ( )
51+ } , this . SESSION_TIMEOUT )
52+ }
53+ }
54+
2755 private async ensureChromiumExists ( ) : Promise < PCRStats > {
2856 const globalStoragePath = this . context ?. globalStorageUri ?. fsPath
2957 if ( ! globalStoragePath ) {
@@ -47,46 +75,58 @@ export class BrowserSession {
4775
4876 async launchBrowser ( ) : Promise < void > {
4977 console . log ( "launch browser called" )
50- if ( this . browser ) {
51- // throw new Error("Browser already launched")
78+ if ( this . browser || this . page ) {
5279 await this . closeBrowser ( ) // this may happen when the model launches a browser again after having used it already before
5380 }
5481
5582 const stats = await this . ensureChromiumExists ( )
56- this . browser = await stats . puppeteer . launch ( {
57- args : [
58- "--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36" ,
59- ] ,
60- executablePath : stats . executablePath ,
61- defaultViewport : ( ( ) => {
62- const size = ( this . context . globalState . get ( "browserViewportSize" ) as string | undefined ) || "900x600"
63- const [ width , height ] = size . split ( "x" ) . map ( Number )
64- return { width, height }
65- } ) ( ) ,
66- // headless: false,
67- } )
68- // (latest version of puppeteer does not add headless to user agent)
69- this . page = await this . browser ?. newPage ( )
83+ if ( ! this . browser || ! this . page ) {
84+ this . browser = await stats . puppeteer . launch ( {
85+ args : [
86+ "--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36" ,
87+ ] ,
88+ executablePath : stats . executablePath ,
89+ defaultViewport : ( ( ) => {
90+ const size =
91+ ( this . context . globalState . get ( "browserViewportSize" ) as string | undefined ) || "900x600"
92+ const [ width , height ] = size . split ( "x" ) . map ( Number )
93+ return { width, height }
94+ } ) ( ) ,
95+ // headless: false,
96+ } )
97+ // (latest version of puppeteer does not add headless to user agent)
98+ this . page = await this . browser ?. newPage ( )
99+ }
70100 }
71101
72102 async closeBrowser ( ) : Promise < BrowserActionResult > {
73103 if ( this . browser || this . page ) {
74- console . log ( "closing browser..." )
75- await this . browser ?. close ( ) . catch ( ( ) => { } )
76- this . browser = undefined
77- this . page = undefined
78- this . currentMousePosition = undefined
104+ const keepBrowserOpen = await this . getKeepBrowserOpen ( )
105+ if ( ! keepBrowserOpen ) {
106+ console . log ( "closing browser..." )
107+ await this . browser ?. close ( ) . catch ( ( ) => { } )
108+ this . browser = undefined
109+ this . page = undefined
110+ this . currentMousePosition = undefined
111+ } else {
112+ console . log ( "keeping browser open..." )
113+ }
79114 }
80115 return { }
81116 }
82117
83118 async doAction ( action : ( page : Page ) => Promise < void > ) : Promise < BrowserActionResult > {
84- if ( ! this . page ) {
85- throw new Error (
86- "Browser is not launched. This may occur if the browser was automatically closed by a non-`browser_action` tool." ,
87- )
119+ if ( ! this . page || ! this . browser ) {
120+ console . log ( "No browser/page found, launching new one" )
121+ await this . launchBrowser ( )
122+ if ( ! this . page ) {
123+ throw new Error ( "Failed to launch browser" )
124+ }
88125 }
89126
127+ // Reset timeout on each action
128+ await this . resetSessionTimeout ( )
129+
90130 const logs : string [ ] = [ ]
91131 let lastLogTs = Date . now ( )
92132
0 commit comments