1
+ import { z } from "zod" ;
2
+ import type { Tool , ToolSchema , ToolContext , ToolResult } from "./tool.js" ;
3
+ import { createSuccessResult , createErrorResult } from "./toolUtils.js" ;
4
+ import type { Context } from "../context.js" ;
5
+ import type { ToolActionResult } from "../context.js" ;
6
+ import { Browserbase } from "@browserbasehq/sdk" ;
7
+
8
+ // Store contexts in memory
9
+ // In a production app, these should be persisted to a database
10
+ const contexts = new Map < string , string > ( ) ;
11
+
12
+ // --- Tool: Create Context ---
13
+ const CreateContextInputSchema = z . object ( {
14
+ name : z
15
+ . string ( )
16
+ . optional ( )
17
+ . describe ( "Optional friendly name to reference this context later (otherwise, you'll need to use the returned ID)" ) ,
18
+ } ) ;
19
+ type CreateContextInput = z . infer < typeof CreateContextInputSchema > ;
20
+
21
+ const createContextSchema : ToolSchema < typeof CreateContextInputSchema > = {
22
+ name : "browserbase_context_create" ,
23
+ description : "Create a new Browserbase context for reusing cookies, authentication, and cached data across browser sessions" ,
24
+ inputSchema : CreateContextInputSchema ,
25
+ } ;
26
+
27
+ async function handleCreateContext (
28
+ context : Context ,
29
+ params : CreateContextInput
30
+ ) : Promise < ToolResult > {
31
+ try {
32
+ const config = context . getConfig ( ) ;
33
+
34
+ if ( ! config . browserbaseApiKey || ! config . browserbaseProjectId ) {
35
+ throw new Error ( "Browserbase API Key or Project ID is missing in the configuration" ) ;
36
+ }
37
+
38
+ const bb = new Browserbase ( {
39
+ apiKey : config . browserbaseApiKey ,
40
+ } ) ;
41
+
42
+ console . error ( "Creating new Browserbase context" ) ;
43
+ const bbContext = await bb . contexts . create ( {
44
+ projectId : config . browserbaseProjectId ,
45
+ } ) ;
46
+
47
+ console . error ( `Successfully created context: ${ bbContext . id } ` ) ;
48
+
49
+ // Store context ID with optional name if provided
50
+ const contextName = params . name || bbContext . id ;
51
+ contexts . set ( contextName , bbContext . id ) ;
52
+
53
+ const result : ToolActionResult = {
54
+ content : [
55
+ {
56
+ type : "text" ,
57
+ text : `Created new Browserbase context with ID: ${ bbContext . id } ${ params . name ? ` and name: ${ params . name } ` : '' } ` ,
58
+ } ,
59
+ ] ,
60
+ } ;
61
+
62
+ return {
63
+ resultOverride : result ,
64
+ code : [ ] ,
65
+ captureSnapshot : false ,
66
+ waitForNetwork : false ,
67
+ } ;
68
+ } catch ( error : any ) {
69
+ console . error ( `CreateContext handle failed: ${ error . message || error } ` ) ;
70
+ throw new Error ( `Failed to create Browserbase context: ${ error . message || error } ` ) ;
71
+ }
72
+ }
73
+
74
+ // --- Tool: Delete Context ---
75
+ const DeleteContextInputSchema = z . object ( {
76
+ contextId : z
77
+ . string ( )
78
+ . optional ( )
79
+ . describe ( "The context ID to delete (required if name not provided)" ) ,
80
+ name : z
81
+ . string ( )
82
+ . optional ( )
83
+ . describe ( "The friendly name of the context to delete (required if contextId not provided)" ) ,
84
+ } ) ;
85
+ type DeleteContextInput = z . infer < typeof DeleteContextInputSchema > ;
86
+
87
+ const deleteContextSchema : ToolSchema < typeof DeleteContextInputSchema > = {
88
+ name : "browserbase_context_delete" ,
89
+ description : "Delete a Browserbase context when you no longer need it" ,
90
+ inputSchema : DeleteContextInputSchema ,
91
+ } ;
92
+
93
+ async function handleDeleteContext (
94
+ context : Context ,
95
+ params : DeleteContextInput
96
+ ) : Promise < ToolResult > {
97
+ try {
98
+ const config = context . getConfig ( ) ;
99
+
100
+ if ( ! config . browserbaseApiKey ) {
101
+ throw new Error ( "Browserbase API Key is missing in the configuration" ) ;
102
+ }
103
+
104
+ if ( ! params . contextId && ! params . name ) {
105
+ throw new Error ( "Missing required argument: either contextId or name must be provided" ) ;
106
+ }
107
+
108
+ // Resolve context ID either directly or by name
109
+ let contextId = params . contextId ;
110
+ if ( ! contextId && params . name ) {
111
+ contextId = contexts . get ( params . name ) ;
112
+ if ( ! contextId ) {
113
+ throw new Error ( `Context with name "${ params . name } " not found` ) ;
114
+ }
115
+ }
116
+
117
+ console . error ( `Deleting Browserbase context: ${ contextId } ` ) ;
118
+
119
+ // Delete from Browserbase API
120
+ // The SDK may not have a delete method directly, so we use the REST API
121
+ const response = await fetch ( `https://api.browserbase.com/v1/contexts/${ contextId } ` , {
122
+ method : 'DELETE' ,
123
+ headers : {
124
+ 'X-BB-API-Key' : config . browserbaseApiKey ,
125
+ } ,
126
+ } ) ;
127
+
128
+ if ( response . status !== 204 ) {
129
+ const errorText = await response . text ( ) ;
130
+ throw new Error ( `Failed to delete context with status ${ response . status } : ${ errorText } ` ) ;
131
+ }
132
+
133
+ // Remove from local store
134
+ if ( params . name ) {
135
+ contexts . delete ( params . name ) ;
136
+ }
137
+
138
+ // Delete by ID too (in case it was stored multiple ways)
139
+ for ( const [ name , id ] of contexts . entries ( ) ) {
140
+ if ( id === contextId ) {
141
+ contexts . delete ( name ) ;
142
+ }
143
+ }
144
+
145
+ console . error ( `Successfully deleted context: ${ contextId } ` ) ;
146
+
147
+ const result : ToolActionResult = {
148
+ content : [
149
+ {
150
+ type : "text" ,
151
+ text : `Deleted Browserbase context with ID: ${ contextId } ` ,
152
+ } ,
153
+ ] ,
154
+ } ;
155
+
156
+ return {
157
+ resultOverride : result ,
158
+ code : [ ] ,
159
+ captureSnapshot : false ,
160
+ waitForNetwork : false ,
161
+ } ;
162
+ } catch ( error : any ) {
163
+ console . error ( `DeleteContext handle failed: ${ error . message || error } ` ) ;
164
+ throw new Error ( `Failed to delete Browserbase context: ${ error . message || error } ` ) ;
165
+ }
166
+ }
167
+
168
+ // Helper function to get a context ID from name or direct ID (exported for use by session.ts)
169
+ export function getContextId ( nameOrId : string ) : string | undefined {
170
+ // First check if it's a direct context ID
171
+ if ( nameOrId . length > 20 ) { // Assumption: context IDs are long strings
172
+ return nameOrId ;
173
+ }
174
+
175
+ // Otherwise, look it up by name
176
+ return contexts . get ( nameOrId ) ;
177
+ }
178
+
179
+ // Define tools
180
+ const createContextTool : Tool < typeof CreateContextInputSchema > = {
181
+ capability : "core" ,
182
+ schema : createContextSchema ,
183
+ handle : handleCreateContext ,
184
+ } ;
185
+
186
+ const deleteContextTool : Tool < typeof DeleteContextInputSchema > = {
187
+ capability : "core" ,
188
+ schema : deleteContextSchema ,
189
+ handle : handleDeleteContext ,
190
+ } ;
191
+
192
+ // Export as an array of tools
193
+ export default [ createContextTool , deleteContextTool ] ;
0 commit comments