@@ -236,7 +236,7 @@ export class AgentToolExecutorService implements IAgentToolExecutorService {
236236 candidates . push (
237237 nextTimed . then (
238238 ( result ) : ToolExecutionStreamEvent => ( { type : 'timed' , result } ) ,
239- ( reason ) : ToolExecutionStreamEvent => ( { type : 'timedRejected' , reason } ) ,
239+ ( error ) : ToolExecutionStreamEvent => ( { type : 'timedRejected' , error } ) ,
240240 ) ,
241241 ) ;
242242 }
@@ -266,7 +266,7 @@ export class AgentToolExecutorService implements IAgentToolExecutorService {
266266 options ,
267267 ) . then (
268268 ( value ) : SettledToolExecutionResult => ( { status : 'fulfilled' , value } ) ,
269- ( reason ) : SettledToolExecutionResult => ( { status : 'rejected' , reason } ) ,
269+ ( error ) : SettledToolExecutionResult => ( { status : 'rejected' , error } ) ,
270270 ) ;
271271 finalizations . add ( finalization ) ;
272272 nextTimed = timedResults . next ( ) ;
@@ -302,7 +302,7 @@ export class AgentToolExecutorService implements IAgentToolExecutorService {
302302 ) ;
303303
304304 this . dispatchToolResult ( call , finalized , options ) ;
305- this . trackToolCall ( call , finalized , timedResult . durationMs , options ) ;
305+ this . trackToolCall ( call , finalized , timedResult . durationMs , timedResult . outcome , options ) ;
306306
307307 return {
308308 toolCallId : call . toolCall . id ,
@@ -315,9 +315,10 @@ export class AgentToolExecutorService implements IAgentToolExecutorService {
315315 call : PreflightedToolCall ,
316316 result : ToolResult ,
317317 durationMs : number ,
318+ executionOutcome : ToolExecutionOutcome ,
318319 options : ToolExecutorExecuteOptions ,
319320 ) : void {
320- const outcome = toolTelemetryOutcome ( result ) ;
321+ const outcome = toolTelemetryOutcome ( result , executionOutcome ) ;
321322 const toolCallId = call . toolCall . id ;
322323 const dupType = this . toolCallDupTypes . get ( toolCallId ) ?? 'normal' ;
323324 this . toolCallDupTypes . delete ( toolCallId ) ;
@@ -468,13 +469,21 @@ export class AgentToolExecutorService implements IAgentToolExecutorService {
468469 accesses : task . accesses ,
469470 start : async ( ) => {
470471 const startedAt = Date . now ( ) ;
472+ const execution = task . execute ( signal ) ;
471473 return {
472- result : task . execute ( signal ) . then ( ( { result, outcome } ) => ( {
474+ result : execution . then ( ( { result, outcome } ) => ( {
473475 index,
474476 result,
475477 outcome,
476478 durationMs : Math . max ( 0 , Date . now ( ) - startedAt ) ,
477479 } ) ) ,
480+ effectsSettled : ( async ( ) => {
481+ try {
482+ const run = await execution ;
483+ if ( run . effectsSettled !== undefined ) await run . effectsSettled ;
484+ } catch {
485+ }
486+ } ) ( ) ,
478487 } ;
479488 } ,
480489 } ) ;
@@ -483,7 +492,7 @@ export class AgentToolExecutorService implements IAgentToolExecutorService {
483492 index ,
484493 pendingResult . then (
485494 ( value ) : SettledTimedToolResult => ( { status : 'fulfilled' , value } ) ,
486- ( reason ) : SettledTimedToolResult => ( { status : 'rejected' , index, reason } ) ,
495+ ( error ) : SettledTimedToolResult => ( { status : 'rejected' , index, error } ) ,
487496 ) ,
488497 ) ;
489498 }
@@ -534,21 +543,25 @@ export class AgentToolExecutorService implements IAgentToolExecutorService {
534543 } ,
535544 } ) ;
536545 rawResult = await raceWithAbortGrace ( executePromise , signal , call . toolName ) ;
546+ const abortedByGrace =
547+ signal . aborted &&
548+ typeof rawResult === 'object' &&
549+ rawResult !== null &&
550+ ( rawResult as { isError ?: boolean } ) . isError === true ;
551+ return {
552+ result : this . normalizeAndMergeResult ( rawResult , call . toolName , execution ) ,
553+ outcome : abortedByGrace ? 'aborted' : 'executed' ,
554+ } ;
537555 } catch ( error ) {
538556 const aborted = isAbortError ( error ) || signal . aborted ;
539557 const output = aborted
540558 ? abortedToolOutput ( call . toolName , signal . reason )
541559 : `Tool "${ call . toolName } " failed: ${ errorMessage ( error ) } ` ;
542560 return {
543561 result : makeErrorToolResult ( call , call . args , output ) . result ,
544- outcome : 'executed' ,
562+ outcome : aborted ? 'aborted' : 'executed' ,
545563 } ;
546564 }
547-
548- return {
549- result : this . normalizeAndMergeResult ( rawResult , call . toolName , execution ) ,
550- outcome : 'executed' ,
551- } ;
552565 }
553566
554567 private normalizeAndMergeResult (
@@ -908,28 +921,20 @@ function normalizeToolResult(result: ExecutableToolResult): ToolResult {
908921 return base ;
909922}
910923
911- function toolTelemetryOutcome ( result : ToolResult ) : 'success' | 'error' | 'cancelled' {
924+ function toolTelemetryOutcome (
925+ result : ToolResult ,
926+ executionOutcome : ToolExecutionOutcome ,
927+ ) : 'success' | 'error' | 'cancelled' {
928+ if ( executionOutcome === 'aborted' || executionOutcome === 'cancelled' ) return 'cancelled' ;
912929 if ( result . isError !== true ) return 'success' ;
913- const text = toolOutputText ( result . output ) . toLowerCase ( ) ;
914- return text . includes ( 'aborted' ) ||
915- text . includes ( 'cancelled' ) ||
916- text . includes ( 'manually interrupted' )
917- ? 'cancelled'
918- : 'error' ;
930+ return 'error' ;
919931}
920932
921933function toolTelemetryErrorType ( outcome : 'success' | 'error' | 'cancelled' ) : 'cancelled' | 'error' {
922934 if ( outcome === 'cancelled' ) return 'cancelled' ;
923935 return 'error' ;
924936}
925937
926- function toolOutputText ( output : ToolResult [ 'output' ] ) : string {
927- if ( typeof output === 'string' ) return output ;
928- return output
929- . filter ( ( part ) : part is Extract < ContentPart , { type : 'text' } > => part . type === 'text' )
930- . map ( ( part ) => part . text )
931- . join ( '' ) ;
932- }
933938
934939function isMediaContentPart ( part : ContentPart ) : boolean {
935940 return part . type === 'image_url' || part . type === 'audio_url' || part . type === 'video_url' ;
0 commit comments