@@ -110,6 +110,7 @@ const createToolCall = async (
110110 targetFn : IAgentTool ,
111111 reason : string ,
112112 mode : ExecutionMode ,
113+ outputEpoch : number ,
113114 self : ClientAgent
114115) => {
115116 self . _runningToolCalls += 1 ;
@@ -192,7 +193,7 @@ const createToolCall = async (
192193 tool . function . name
193194 } error=${ getErrorMessage ( error ) } `
194195 ) ;
195- await self . _emitOutput ( mode , result ) ;
196+ await self . _emitOutput ( mode , result , outputEpoch ) ;
196197 }
197198 } finally {
198199 self . _runningToolCalls -= 1 ;
@@ -359,6 +360,7 @@ const EXECUTE_FN = async (
359360 incoming ,
360361 mode
361362 ) ;
363+ const outputEpoch = self . _outputEpoch ;
362364 await self . params . history . push ( {
363365 role : "user" ,
364366 mode,
@@ -431,7 +433,7 @@ const EXECUTE_FN = async (
431433 self . params . logger . debug (
432434 `ClientAgent agentName=${ self . params . agentName } clientId=${ self . params . clientId } execute end result=${ result } `
433435 ) ;
434- await self . _emitOutput ( mode , result ) ;
436+ await self . _emitOutput ( mode , result , outputEpoch ) ;
435437 run ( false ) ;
436438 return ;
437439 }
@@ -485,7 +487,7 @@ const EXECUTE_FN = async (
485487 self . params . logger . debug (
486488 `ClientAgent agentName=${ self . params . agentName } clientId=${ self . params . clientId } execute end result=${ result } `
487489 ) ;
488- await self . _emitOutput ( mode , result ) ;
490+ await self . _emitOutput ( mode , result , outputEpoch ) ;
489491 run ( false ) ;
490492 return ;
491493 }
@@ -556,6 +558,7 @@ const EXECUTE_FN = async (
556558 targetFn ,
557559 message . content || "" ,
558560 mode ,
561+ outputEpoch ,
559562 self
560563 ) ;
561564 const status = await statusAwaiter ;
@@ -626,7 +629,7 @@ const EXECUTE_FN = async (
626629 self . params . logger . debug (
627630 `ClientAgent agentName=${ self . params . agentName } clientId=${ self . params . clientId } execute end result=${ result } `
628631 ) ;
629- await self . _emitOutput ( mode , result ) ;
632+ await self . _emitOutput ( mode , result , outputEpoch ) ;
630633 }
631634 return status ;
632635 } ) ;
@@ -669,14 +672,14 @@ const EXECUTE_FN = async (
669672 mode ,
670673 `Invalid model output: ${ result } `
671674 ) ;
672- await self . _emitOutput ( mode , result1 ) ;
675+ await self . _emitOutput ( mode , result1 , outputEpoch ) ;
673676 return ;
674677 }
675678 GLOBAL_CONFIG . CC_LOGGER_ENABLE_DEBUG &&
676679 self . params . logger . debug (
677680 `ClientAgent agentName=${ self . params . agentName } clientId=${ self . params . clientId } execute end result=${ result } `
678681 ) ;
679- await self . _emitOutput ( mode , result ) ;
682+ await self . _emitOutput ( mode , result , outputEpoch ) ;
680683} ;
681684
682685/**
@@ -710,6 +713,15 @@ export class ClientAgent implements IAgent {
710713 */
711714 _activeToolChains = 0 ;
712715
716+ /**
717+ * Generation counter for output emissions. Bumped by commitCancelOutput and by
718+ * swarm-level output substitution (emit). Executions capture the epoch at start
719+ * and _emitOutput drops their result when the epoch moved on — otherwise the
720+ * stale output of a cancelled/substituted execution would resolve the waiter
721+ * of the NEXT message, poisoning that exchange.
722+ */
723+ _outputEpoch = 0 ;
724+
713725 /**
714726 * Subject for signaling agent changes, halting subsequent tool executions via commitAgentChange.
715727 * @readonly
@@ -915,7 +927,19 @@ export class ClientAgent implements IAgent {
915927 * Supports SwarmConnectionService by broadcasting agent outputs within the swarm.
916928 * @throws {Error } If validation fails after model resurrection, indicating an unrecoverable state.
917929 **/
918- async _emitOutput ( mode : ExecutionMode , rawResult : string ) : Promise < void > {
930+ async _emitOutput (
931+ mode : ExecutionMode ,
932+ rawResult : string ,
933+ outputEpoch = this . _outputEpoch
934+ ) : Promise < void > {
935+ if ( outputEpoch !== this . _outputEpoch ) {
936+ GLOBAL_CONFIG . CC_LOGGER_ENABLE_DEBUG &&
937+ this . params . logger . debug (
938+ `ClientAgent agentName=${ this . params . agentName } clientId=${ this . params . clientId } _emitOutput skipped for stale execution (cancelled or substituted)` ,
939+ { mode, rawResult }
940+ ) ;
941+ return ;
942+ }
919943 const result = await this . params . transform (
920944 rawResult ,
921945 this . params . clientId ,
@@ -939,6 +963,9 @@ export class ClientAgent implements IAgent {
939963 `agent-swarm-kit ClientAgent agentName=${ this . params . agentName } clientId=${ this . params . clientId } model resurrect failed: ${ validation } `
940964 ) ;
941965 }
966+ if ( outputEpoch !== this . _outputEpoch ) {
967+ return ;
968+ }
942969 this . params . onOutput &&
943970 this . params . onOutput (
944971 this . params . clientId ,
@@ -969,6 +996,9 @@ export class ClientAgent implements IAgent {
969996 } ) ;
970997 return ;
971998 }
999+ if ( outputEpoch !== this . _outputEpoch ) {
1000+ return ;
1001+ }
9721002 this . params . onOutput &&
9731003 this . params . onOutput ( this . params . clientId , this . params . agentName , result ) ;
9741004 await this . _outputSubject . next ( result ) ;
@@ -1094,6 +1124,19 @@ export class ClientAgent implements IAgent {
10941124 return placeholder ;
10951125 }
10961126
1127+ /**
1128+ * Marks in-flight executions as substituted: the swarm emitted a replacement
1129+ * output (ClientSwarm.emit), so results of executions started earlier must not
1130+ * reach _outputSubject — they would pair with the next waiter otherwise.
1131+ */
1132+ commitOutputSubstituted ( ) : void {
1133+ GLOBAL_CONFIG . CC_LOGGER_ENABLE_DEBUG &&
1134+ this . params . logger . debug (
1135+ `ClientAgent agentName=${ this . params . agentName } clientId=${ this . params . clientId } commitOutputSubstituted`
1136+ ) ;
1137+ this . _outputEpoch += 1 ;
1138+ }
1139+
10971140 /**
10981141 * Waits for the next output to be emitted via _outputSubject, typically after execute or run.
10991142 * Useful for external consumers (e.g., SwarmConnectionService) awaiting agent responses.
@@ -1366,6 +1409,7 @@ export class ClientAgent implements IAgent {
13661409 this . params . logger . debug (
13671410 `ClientAgent agentName=${ this . params . agentName } clientId=${ this . params . clientId } commitCancelOutput`
13681411 ) ;
1412+ this . _outputEpoch += 1 ;
13691413 this . _toolAbortController . abort ( ) ;
13701414 await this . _cancelOutputSubject . next ( CANCEL_OUTPUT_SYMBOL ) ;
13711415 await this . params . bus . emit < IBusEvent > ( this . params . clientId , {
0 commit comments