6
6
closeAllSessions ,
7
7
} from "./sessionManager.js" ;
8
8
import type { Tool , ToolContext , ToolResult } from "./tools/tool.js" ;
9
- import type { Config } from "./config.js" ;
9
+ import type { Config } from ".. /config.js" ;
10
10
import {
11
11
Resource ,
12
12
CallToolResult ,
@@ -48,9 +48,8 @@ export type ToolActionResult =
48
48
*/
49
49
export class Context {
50
50
private server : Server ;
51
- private config : Config ;
51
+ public readonly config : Config ;
52
52
public currentSessionId : string = defaultSessionId ;
53
- private screenshots = new Map < string , string > ( ) ;
54
53
private latestSnapshots = new Map < string , PageSnapshot > ( ) ;
55
54
private screenshotResources = new Map <
56
55
string ,
@@ -63,11 +62,6 @@ export class Context {
63
62
this . screenshotResources = new Map ( ) ;
64
63
}
65
64
66
- // --- Public Getter for Config ---
67
- public getConfig ( ) : Config {
68
- return this . config ;
69
- }
70
-
71
65
// --- Snapshot State Handling (Using PageSnapshot) ---
72
66
73
67
/**
@@ -261,7 +255,9 @@ export class Context {
261
255
262
256
// Get the CURRENT latest snapshot - DO NOT capture a new one here.
263
257
const snapshot = this . latestSnapshots . get ( this . currentSessionId ) ;
264
- const initialSnapshotIdentifier = snapshot ?. text ( ) . substring ( 0 , 60 ) . replace ( / \\ n / g, '\\\\n' ) ?? "[No Snapshot]" ;
258
+ const initialSnapshotIdentifier =
259
+ snapshot ?. text ( ) . substring ( 0 , 60 ) . replace ( / \\ n / g, "\\\\n" ) ??
260
+ "[No Snapshot]" ;
265
261
266
262
let locator : Locator | undefined ;
267
263
@@ -270,43 +266,67 @@ export class Context {
270
266
identifier = validatedArgs . selector ;
271
267
identifierType = "selector" ;
272
268
if ( ! identifier ) {
273
- throw new Error ( `Missing required 'selector' argument for tool ${ toolName } .` ) ;
269
+ throw new Error (
270
+ `Missing required 'selector' argument for tool ${ toolName } .`
271
+ ) ;
274
272
}
275
273
try {
276
274
locator = page . locator ( identifier ) ;
277
275
} catch ( locatorError ) {
278
- throw new Error ( `Failed to create locator for selector '${ identifier } ': ${ locatorError instanceof Error ? locatorError . message : String ( locatorError ) } ` ) ;
276
+ throw new Error (
277
+ `Failed to create locator for selector '${ identifier } ': ${
278
+ locatorError instanceof Error
279
+ ? locatorError . message
280
+ : String ( locatorError )
281
+ } `
282
+ ) ;
279
283
}
280
284
} else if ( validatedArgs ?. ref ) {
281
285
identifier = validatedArgs . ref ;
282
286
identifierType = "ref" ;
283
287
if ( ! identifier ) {
284
- throw new Error ( `Missing required 'ref' argument for tool ${ toolName } .` ) ;
288
+ throw new Error (
289
+ `Missing required 'ref' argument for tool ${ toolName } .`
290
+ ) ;
285
291
}
286
292
if ( ! snapshot ) {
287
- throw new Error ( `Cannot resolve ref '${ identifier } ' because no snapshot is available for session ${ this . currentSessionId } . Capture a snapshot or ensure one exists.` ) ;
293
+ throw new Error (
294
+ `Cannot resolve ref '${ identifier } ' because no snapshot is available for session ${ this . currentSessionId } . Capture a snapshot or ensure one exists.`
295
+ ) ;
288
296
}
289
297
try {
290
298
// Resolve using the snapshot we just retrieved
291
299
locator = snapshot . refLocator ( identifier ) ;
292
300
} catch ( locatorError ) {
293
301
// Use the existing snapshot identifier in the error
294
302
throw new Error (
295
- `Failed to resolve ref ${ identifier } using existing snapshot ${ initialSnapshotIdentifier } before action attempt: ${ locatorError instanceof Error ? locatorError . message : String ( locatorError ) } `
303
+ `Failed to resolve ref ${ identifier } using existing snapshot ${ initialSnapshotIdentifier } before action attempt: ${
304
+ locatorError instanceof Error
305
+ ? locatorError . message
306
+ : String ( locatorError )
307
+ } `
296
308
) ;
297
309
}
298
310
} else if ( requiresIdentifier ) {
299
311
// If neither ref nor selector is provided, but one is required
300
- throw new Error ( `Missing required 'ref' or 'selector' argument for tool ${ toolName } .` ) ;
312
+ throw new Error (
313
+ `Missing required 'ref' or 'selector' argument for tool ${ toolName } .`
314
+ ) ;
301
315
} else {
302
- // No identifier needed or provided
303
- identifierType = "none" ; // Explicitly set to none
316
+ // No identifier needed or provided
317
+ identifierType = "none" ; // Explicitly set to none
304
318
}
305
319
306
320
// --- Single Attempt ---
307
321
try {
308
322
// Pass page, the used identifier (selector or ref), args, the resolved locator, and identifierType
309
- const actionFnResult = await actionFn ( page , identifier , validatedArgs , locator , identifierType ) ;
323
+ const actionFnResult = await actionFn (
324
+ page ,
325
+ identifier ,
326
+ validatedArgs ,
327
+ locator ,
328
+ identifierType
329
+ ) ;
310
330
311
331
if ( typeof actionFnResult === "string" ) {
312
332
resultText = actionFnResult ;
@@ -330,7 +350,9 @@ export class Context {
330
350
return { resultText, actionResult } ;
331
351
} catch ( error : any ) {
332
352
throw new Error (
333
- `Action ${ toolName } failed: ${ error instanceof Error ? error . message : String ( error ) } `
353
+ `Action ${ toolName } failed: ${
354
+ error instanceof Error ? error . message : String ( error )
355
+ } `
334
356
) ;
335
357
}
336
358
}
@@ -340,7 +362,8 @@ export class Context {
340
362
let initialPage : Page | null = null ;
341
363
let initialBrowser : BrowserSession [ "browser" ] | null = null ;
342
364
let toolResultFromHandle : ToolResult | null = null ; // Legacy handle result
343
- let finalResult : CallToolResult = { // Initialize finalResult here
365
+ let finalResult : CallToolResult = {
366
+ // Initialize finalResult here
344
367
content : [ { type : "text" , text : `Initialization error for ${ toolName } ` } ] ,
345
368
isError : true ,
346
369
} ;
@@ -406,48 +429,49 @@ export class Context {
406
429
}
407
430
}
408
431
409
- let executionResultText = "" ;
432
+ let toolActionOutput : ToolActionResult | undefined = undefined ; // New variable to store direct tool action output
410
433
let actionSucceeded = false ;
411
434
let shouldCaptureSnapshotAfterAction = false ;
412
435
let postActionSnapshot : PageSnapshot | undefined = undefined ;
413
436
414
437
try {
415
- let actionToRun : ( ( ) => Promise < ToolActionResult > ) | undefined = undefined ;
438
+ let actionToRun : ( ( ) => Promise < ToolActionResult > ) | undefined =
439
+ undefined ;
416
440
let shouldCaptureSnapshot = false ;
417
441
418
442
try {
419
- if ( 'handle' in tool && typeof tool . handle === 'function' ) {
420
- toolResultFromHandle = await tool . handle ( this as any , validatedArgs ) ;
421
- actionToRun = toolResultFromHandle ?. action ;
422
- shouldCaptureSnapshot = toolResultFromHandle ?. captureSnapshot ?? false ;
423
- shouldCaptureSnapshotAfterAction = shouldCaptureSnapshot ;
443
+ if ( "handle" in tool && typeof tool . handle === "function" ) {
444
+ toolResultFromHandle = await tool . handle ( this as any , validatedArgs ) ;
445
+ actionToRun = toolResultFromHandle ?. action ;
446
+ shouldCaptureSnapshot =
447
+ toolResultFromHandle ?. captureSnapshot ?? false ;
448
+ shouldCaptureSnapshotAfterAction = shouldCaptureSnapshot ;
424
449
} else {
425
- throw new Error ( `Tool ${ toolName } could not be handled (no handle method).` ) ;
450
+ throw new Error (
451
+ `Tool ${ toolName } could not be handled (no handle method).`
452
+ ) ;
426
453
}
427
454
428
455
if ( actionToRun ) {
429
- const actionResult = await actionToRun ( ) ;
430
- if ( actionResult ?. content ) {
431
- executionResultText = actionResult . content
432
- . map ( ( c : { type : string ; text ?: string } ) => c . type === "text" ? c . text : `[${ c . type } ]` )
433
- . filter ( Boolean )
434
- . join ( " " ) || `${ toolName } action completed.` ;
435
- } else {
436
- executionResultText = `${ toolName } action completed successfully.` ;
437
- }
438
- actionSucceeded = true ;
456
+ toolActionOutput = await actionToRun ( ) ;
457
+ actionSucceeded = true ;
439
458
} else {
440
- throw new Error ( `Tool ${ toolName } handled without action.` ) ;
459
+ throw new Error ( `Tool ${ toolName } handled without action.` ) ;
441
460
}
442
461
} catch ( error ) {
443
- process . stderr . write ( `${ logPrefix } Error executing tool ${ toolName } : ${ error instanceof Error ? error . message : String ( error ) } \\n` ) ; // Changed and added newline
444
- // --- LOG STACK TRACE ---
462
+ process . stderr . write (
463
+ `${ logPrefix } Error executing tool ${ toolName } : ${
464
+ error instanceof Error ? error . message : String ( error )
465
+ } \\n`
466
+ ) ;
445
467
if ( error instanceof Error && error . stack ) {
446
- process . stderr . write ( `${ logPrefix } Stack Trace: ${ error . stack } \\n` ) ;
468
+ process . stderr . write ( `${ logPrefix } Stack Trace: ${ error . stack } \\n` ) ;
447
469
}
448
470
// -----------------------
449
471
finalResult = this . createErrorResult (
450
- `Execution failed: ${ error instanceof Error ? error . message : String ( error ) } ` ,
472
+ `Execution failed: ${
473
+ error instanceof Error ? error . message : String ( error )
474
+ } `,
451
475
toolName
452
476
) ;
453
477
actionSucceeded = false ;
@@ -465,12 +489,22 @@ export class Context {
465
489
try {
466
490
postActionSnapshot = await this . captureSnapshot ( ) ;
467
491
if ( postActionSnapshot ) {
468
- process . stderr . write ( `[Context.run ${ toolName } ] Added snapshot to final result text.\n` ) ;
492
+ process . stderr . write (
493
+ `[Context.run ${ toolName } ] Added snapshot to final result text.\n`
494
+ ) ;
469
495
} else {
470
- process . stderr . write ( `[Context.run ${ toolName } ] WARN: Snapshot was expected after action but failed to capture.\n` ) ; // Keep warning
496
+ process . stderr . write (
497
+ `[Context.run ${ toolName } ] WARN: Snapshot was expected after action but failed to capture.\n`
498
+ ) ; // Keep warning
471
499
}
472
500
} catch ( postSnapError ) {
473
- process . stderr . write ( `[Context.run ${ toolName } ] WARN: Error capturing post-action snapshot: ${ postSnapError instanceof Error ? postSnapError . message : String ( postSnapError ) } \n` ) ; // Keep warning
501
+ process . stderr . write (
502
+ `[Context.run ${ toolName } ] WARN: Error capturing post-action snapshot: ${
503
+ postSnapError instanceof Error
504
+ ? postSnapError . message
505
+ : String ( postSnapError )
506
+ } \n`
507
+ ) ; // Keep warning
474
508
}
475
509
} else if (
476
510
actionSucceeded &&
@@ -481,49 +515,78 @@ export class Context {
481
515
}
482
516
483
517
if ( actionSucceeded ) {
518
+ const finalContentItems : ( TextContent | ImageContent ) [ ] = [ ] ;
519
+
520
+ // 1. Add content from the tool action itself
521
+ if ( toolActionOutput ?. content && toolActionOutput . content . length > 0 ) {
522
+ finalContentItems . push ( ...toolActionOutput . content ) ;
523
+ } else {
524
+ // If toolActionOutput.content is empty/undefined but action succeeded,
525
+ // provide a generic success message.
526
+ finalContentItems . push ( { type : "text" , text : `${ toolName } action completed successfully.` } ) ;
527
+ }
528
+
529
+ // 2. Prepare and add additional textual information (URL, Title, Snapshot)
530
+ const additionalInfoParts : string [ ] = [ ] ;
484
531
const currentPage = await this . getActivePage ( ) ;
485
- let finalOutputText = executionResultText ; // Start with execution text
486
532
487
533
if ( currentPage ) {
488
534
try {
489
535
const url = currentPage . url ( ) ;
490
536
const title = await currentPage
491
537
. title ( )
492
538
. catch ( ( ) => "[Error retrieving title]" ) ;
493
- finalOutputText += `\n\n- Page URL: ${ url } \n- Page Title: ${ title } ` ;
539
+ additionalInfoParts . push ( `- Page URL: ${ url } ` ) ;
540
+ additionalInfoParts . push ( `- Page Title: ${ title } ` ) ;
494
541
} catch ( pageStateError ) {
495
- finalOutputText +=
496
- "\n\n- [Error retrieving page state after action]" ;
542
+ additionalInfoParts . push (
543
+ "- [Error retrieving page state after action]"
544
+ ) ;
497
545
}
498
546
} else {
499
- finalOutputText += "\n\n - [Page unavailable after action]";
547
+ additionalInfoParts . push ( " - [Page unavailable after action]") ;
500
548
}
501
549
502
550
const snapshotToAdd = postActionSnapshot ;
503
551
if ( snapshotToAdd ) {
504
- finalOutputText += `\n\n- Page Snapshot\n\`\`\`yaml\n${ snapshotToAdd . text ( ) } \n\`\`\`\n` ;
552
+ additionalInfoParts . push (
553
+ `- Page Snapshot\n\`\`\`yaml\n${ snapshotToAdd . text ( ) } \n\`\`\`\n`
554
+ ) ;
505
555
} else {
506
- finalOutputText += `\n\n- [No relevant snapshot available after action]` ;
556
+ additionalInfoParts . push (
557
+ `- [No relevant snapshot available after action]`
558
+ ) ;
559
+ }
560
+
561
+ // 3. Add the additional information as a new TextContent item if it's not empty
562
+ if ( additionalInfoParts . length > 0 ) {
563
+ // Add leading newlines if there's preceding content, to maintain separation
564
+ const additionalInfoText = ( finalContentItems . length > 0 ? "\\n\\n" : "" ) + additionalInfoParts . join ( "\\n" ) ;
565
+ finalContentItems . push ( { type : "text" , text : additionalInfoText } ) ;
507
566
}
508
567
509
568
finalResult = {
510
- content : [ { type : "text" , text : finalOutputText } ] ,
569
+ content : finalContentItems ,
511
570
isError : false ,
512
571
} ;
513
572
} else {
514
573
// Error result is already set in catch block, but ensure it IS set.
515
574
if ( ! finalResult || ! finalResult . isError ) {
516
- finalResult = this . createErrorResult (
517
- `Unknown error occurred during ${ toolName } ` ,
518
- toolName
519
- ) ;
575
+ finalResult = this . createErrorResult (
576
+ `Unknown error occurred during ${ toolName } ` ,
577
+ toolName
578
+ ) ;
520
579
}
521
580
}
522
581
return finalResult ;
523
582
}
524
583
} catch ( error ) {
525
- process . stderr . write ( `${ logPrefix } Error running tool ${ toolName } : ${ error instanceof Error ? error . message : String ( error ) } \n` ) ;
584
+ process . stderr . write (
585
+ `${ logPrefix } Error running tool ${ toolName } : ${
586
+ error instanceof Error ? error . message : String ( error )
587
+ } \n`
588
+ ) ;
526
589
throw error ;
527
590
}
528
591
}
529
- }
592
+ }
0 commit comments