@@ -5,7 +5,7 @@ import { z } from 'zod'
5
5
6
6
describe ( 'createInterpreterTool' , ( ) => {
7
7
test ( 'executes simple code and captures console.log' , async ( ) => {
8
- const tool = createInterpreterTool ( )
8
+ const tool = await createInterpreterTool ( )
9
9
10
10
const startTime = Date . now ( )
11
11
const result = await tool . execute ! ( {
@@ -34,7 +34,7 @@ describe('createInterpreterTool', () => {
34
34
} )
35
35
36
36
test ( 'handles errors gracefully' , async ( ) => {
37
- const tool = createInterpreterTool ( )
37
+ const tool = await createInterpreterTool ( )
38
38
39
39
const result = await tool . execute ! ( {
40
40
title : 'Error test' ,
@@ -51,7 +51,7 @@ describe('createInterpreterTool', () => {
51
51
} )
52
52
53
53
test ( 'handles JSON objects in console.log' , async ( ) => {
54
- const tool = createInterpreterTool ( )
54
+ const tool = await createInterpreterTool ( )
55
55
56
56
const result = await tool . execute ! ( {
57
57
title : 'JSON logging' ,
@@ -79,7 +79,7 @@ describe('createInterpreterTool', () => {
79
79
} )
80
80
81
81
test ( 'enforces timeout' , async ( ) => {
82
- const tool = createInterpreterTool ( )
82
+ const tool = await createInterpreterTool ( )
83
83
84
84
const result = await tool . execute ! ( {
85
85
title : 'Timeout test' ,
@@ -95,7 +95,7 @@ describe('createInterpreterTool', () => {
95
95
} )
96
96
97
97
test ( 'handles async code' , async ( ) => {
98
- const tool = createInterpreterTool ( )
98
+ const tool = await createInterpreterTool ( )
99
99
100
100
const result = await tool . execute ! ( {
101
101
title : 'Async test' ,
@@ -117,7 +117,7 @@ describe('createInterpreterTool', () => {
117
117
} )
118
118
119
119
test ( 'respects custom timeout' , async ( ) => {
120
- const tool = createInterpreterTool ( )
120
+ const tool = await createInterpreterTool ( )
121
121
122
122
const startTime = Date . now ( )
123
123
const result = await tool . execute ! ( {
@@ -138,7 +138,7 @@ describe('createInterpreterTool', () => {
138
138
} )
139
139
140
140
test ( 'returns "no console logs" when no output' , async ( ) => {
141
- const tool = createInterpreterTool ( )
141
+ const tool = await createInterpreterTool ( )
142
142
143
143
const result = await tool . execute ! ( {
144
144
title : 'No output test' ,
@@ -154,7 +154,7 @@ describe('createInterpreterTool', () => {
154
154
} )
155
155
156
156
test ( 'shows stack trace for errors thrown in functions' , async ( ) => {
157
- const tool = createInterpreterTool ( )
157
+ const tool = await createInterpreterTool ( )
158
158
159
159
const result = await tool . execute ! ( {
160
160
title : 'Error with stack trace' ,
@@ -182,10 +182,10 @@ describe('createInterpreterTool', () => {
182
182
Error: Something went wrong in doSomething
183
183
Stack trace:
184
184
Error: Something went wrong in doSomething
185
- at doSomething (<isolated-vm>:33 :27)
186
- at main (<isolated-vm>:38 :21)
187
- at <isolated-vm>:42 :17
188
- at <isolated-vm>:44 :23"
185
+ at doSomething (<isolated-vm>:44 :27)
186
+ at main (<isolated-vm>:49 :21)
187
+ at <isolated-vm>:53 :17
188
+ at <isolated-vm>:55 :23"
189
189
` )
190
190
} )
191
191
@@ -211,7 +211,7 @@ describe('createInterpreterTool', () => {
211
211
}
212
212
} )
213
213
214
- const interpreterTool = createInterpreterTool ( {
214
+ const interpreterTool = await createInterpreterTool ( {
215
215
tools : {
216
216
add : addTool ,
217
217
greet : greetTool ,
@@ -253,7 +253,7 @@ describe('createInterpreterTool', () => {
253
253
execute : async ( { x, y } ) => x * y
254
254
} )
255
255
256
- const interpreterTool = createInterpreterTool ( {
256
+ const interpreterTool = await createInterpreterTool ( {
257
257
tools : {
258
258
multiply : mathTool ,
259
259
}
@@ -274,7 +274,7 @@ describe('createInterpreterTool', () => {
274
274
} )
275
275
276
276
test ( 'supports various console methods' , async ( ) => {
277
- const tool = createInterpreterTool ( )
277
+ const tool = await createInterpreterTool ( )
278
278
279
279
const result = await tool . execute ! ( {
280
280
title : 'Console methods test' ,
@@ -317,7 +317,7 @@ describe('createInterpreterTool', () => {
317
317
} ) ,
318
318
} )
319
319
320
- const interpreterTool = createInterpreterTool ( {
320
+ const interpreterTool = await createInterpreterTool ( {
321
321
tools : {
322
322
schemaOnly : schemaTool ,
323
323
}
@@ -337,6 +337,84 @@ describe('createInterpreterTool', () => {
337
337
` )
338
338
} )
339
339
340
+ test ( 'includes available tools in description with TypeScript types' , async ( ) => {
341
+ const mockFetch = tool ( {
342
+ description : 'Fetch data' ,
343
+ inputSchema : z . object ( { url : z . string ( ) } ) ,
344
+ execute : async ( { url } ) => `Data from ${ url } `
345
+ } )
346
+
347
+ const mockEditor = tool ( {
348
+ description : 'Edit files' ,
349
+ inputSchema : z . object ( {
350
+ path : z . string ( ) ,
351
+ content : z . string ( ) . optional ( )
352
+ } ) ,
353
+ execute : async ( { path, content } ) => `Edited ${ path } `
354
+ } )
355
+
356
+ const schemaOnly = tool ( {
357
+ description : 'Schema only' ,
358
+ inputSchema : z . object ( { value : z . string ( ) } ) ,
359
+ outputSchema : z . object ( { result : z . string ( ) } )
360
+ } )
361
+
362
+ const interpreterTool = await createInterpreterTool ( {
363
+ tools : {
364
+ 'fetch-data' : mockFetch ,
365
+ 'edit_file' : mockEditor ,
366
+ 'schema-only' : schemaOnly
367
+ }
368
+ } )
369
+
370
+ expect ( interpreterTool . description ) . toMatchInlineSnapshot ( `
371
+ "Execute JavaScript code in an isolated sandbox environment with console.log capture
372
+
373
+ Available tools object type:
374
+
375
+ interface Tools {
376
+ fetchData: (args: {
377
+ url: string
378
+ }) => Promise<any>;
379
+ editFile: (args: {
380
+ path: string
381
+ content?: string
382
+ }) => Promise<any>;
383
+ }
384
+ "
385
+ ` )
386
+ } )
387
+
388
+ test ( 'supports URL constructor' , async ( ) => {
389
+ const tool = await createInterpreterTool ( )
390
+
391
+ const result = await tool . execute ! ( {
392
+ title : 'URL test' ,
393
+ code : `
394
+ const url = new URL('https://example.com/path?query=value#hash')
395
+ console.log('URL object:', JSON.stringify(url))
396
+ console.log('Protocol:', url.protocol)
397
+ console.log('Hostname:', url.hostname)
398
+ console.log('Pathname:', url.pathname)
399
+ console.log('Search:', url.search)
400
+ console.log('Hash:', url.hash)
401
+
402
+ const relative = new URL('/api/users', 'https://api.example.com')
403
+ console.log('Full URL:', relative.href)
404
+ `
405
+ } , { } as any ) as string
406
+
407
+ expect ( result ) . toMatchInlineSnapshot ( `
408
+ "URL object: {"href":"https://example.com/path?query=value#hash","protocol":"https:","hostname":"example.com","host":"example.com","port":"","pathname":"/path","search":"?query=value","searchParams":{"query":"value"},"hash":"#hash","origin":"https://example.com","username":"","password":""}
409
+ Protocol: https:
410
+ Hostname: example.com
411
+ Pathname: /path
412
+ Search: ?query=value
413
+ Hash: #hash
414
+ Full URL: https://api.example.com/api/users"
415
+ ` )
416
+ } )
417
+
340
418
test ( 'real-world example with fetch and editor tools' , async ( ) => {
341
419
const files : Record < string , string > = { }
342
420
@@ -395,10 +473,10 @@ describe('createInterpreterTool', () => {
395
473
}
396
474
} )
397
475
398
- const interpreterTool = createInterpreterTool ( {
476
+ const interpreterTool = await createInterpreterTool ( {
399
477
tools : {
400
- fetch : fetchTool ,
401
- editor : strReplaceEditor
478
+ ' fetch-tool' : fetchTool ,
479
+ 'editor_tool' : strReplaceEditor
402
480
}
403
481
} )
404
482
@@ -416,7 +494,7 @@ describe('createInterpreterTool', () => {
416
494
417
495
const results = await Promise.all(
418
496
urls.map(async url => {
419
- const content = await tools.fetch ({ url })
497
+ const content = await tools.fetchTool ({ url })
420
498
const path = url.split('//')[1].split('/').slice(1).join('/')
421
499
return { path, content }
422
500
})
@@ -426,7 +504,7 @@ describe('createInterpreterTool', () => {
426
504
427
505
const writeResults = await Promise.all(
428
506
results.map(({ path, content }) =>
429
- tools.editor ({
507
+ tools.editorTool ({
430
508
command: 'create',
431
509
path: path,
432
510
file_text: content
@@ -436,7 +514,7 @@ describe('createInterpreterTool', () => {
436
514
437
515
console.log('Created', writeResults.length, 'files')
438
516
439
- const userFile = await tools.editor ({
517
+ const userFile = await tools.editorTool ({
440
518
command: 'view',
441
519
path: 'users/1.md'
442
520
})
@@ -445,10 +523,15 @@ describe('createInterpreterTool', () => {
445
523
`
446
524
} , { } as any ) as string
447
525
448
- expect ( result ) . toMatch ( / F e t c h i n g 4 U R L s / )
449
- expect ( result ) . toMatch ( / F e t c h e d a l l d a t a / )
450
- expect ( result ) . toMatch ( / C r e a t e d 4 f i l e s / )
451
- expect ( result ) . toMatch ( / U s e r 1 f i l e : # U s e r 1 / )
526
+ expect ( result ) . toMatchInlineSnapshot ( `
527
+ "Fetching 4 URLs...
528
+ Fetched all data
529
+ Created 4 files
530
+ User 1 file: # User 1
531
+
532
+ - ID: 1
533
+ - ..."
534
+ ` )
452
535
453
536
expect ( files [ 'users/1.md' ] ) . toContain ( '# User 1' )
454
537
expect ( files [ 'users/2.md' ] ) . toContain ( '# User 2' )
0 commit comments