3838from ..tools .decorator import tool
3939from ..types ._events import (
4040 MultiAgentHandoffEvent ,
41+ MultiAgentNodeCancelEvent ,
4142 MultiAgentNodeStartEvent ,
4243 MultiAgentNodeStopEvent ,
4344 MultiAgentNodeStreamEvent ,
@@ -679,11 +680,23 @@ async def _execute_swarm(self, invocation_state: dict[str, Any]) -> AsyncIterato
679680 len (self .state .node_history ) + 1 ,
680681 )
681682
683+ before_event , _ = await self .hooks .invoke_callbacks_async (
684+ BeforeNodeCallEvent (self , current_node .node_id , invocation_state )
685+ )
686+
682687 # TODO: Implement cancellation token to stop _execute_node from continuing
683688 try :
684- await self .hooks .invoke_callbacks_async (
685- BeforeNodeCallEvent (self , current_node .node_id , invocation_state )
686- )
689+ if before_event .cancel_node :
690+ cancel_message = (
691+ before_event .cancel_node
692+ if isinstance (before_event .cancel_node , str )
693+ else "node cancelled by user"
694+ )
695+ logger .debug ("reason=<%s> | cancelling execution" , cancel_message )
696+ yield MultiAgentNodeCancelEvent (current_node .node_id , cancel_message )
697+ self .state .completion_status = Status .FAILED
698+ break
699+
687700 node_stream = self ._stream_with_timeout (
688701 self ._execute_node (current_node , self .state .task , invocation_state ),
689702 self .node_timeout ,
@@ -693,40 +706,42 @@ async def _execute_swarm(self, invocation_state: dict[str, Any]) -> AsyncIterato
693706 yield event
694707
695708 self .state .node_history .append (current_node )
709+
710+ except Exception :
711+ logger .exception ("node=<%s> | node execution failed" , current_node .node_id )
712+ self .state .completion_status = Status .FAILED
713+ break
714+
715+ finally :
696716 await self .hooks .invoke_callbacks_async (
697717 AfterNodeCallEvent (self , current_node .node_id , invocation_state )
698718 )
699719
700- logger .debug ("node=<%s> | node execution completed" , current_node .node_id )
701-
702- # Check if handoff requested during execution
703- if self .state .handoff_node :
704- previous_node = current_node
705- current_node = self .state .handoff_node
720+ logger .debug ("node=<%s> | node execution completed" , current_node .node_id )
706721
707- self .state .handoff_node = None
708- self .state .current_node = current_node
722+ # Check if handoff requested during execution
723+ if self .state .handoff_node :
724+ previous_node = current_node
725+ current_node = self .state .handoff_node
709726
710- handoff_event = MultiAgentHandoffEvent (
711- from_node_ids = [previous_node .node_id ],
712- to_node_ids = [current_node .node_id ],
713- message = self .state .handoff_message or "Agent handoff occurred" ,
714- )
715- yield handoff_event
716- logger .debug (
717- "from_node=<%s>, to_node=<%s> | handoff detected" ,
718- previous_node .node_id ,
719- current_node .node_id ,
720- )
727+ self .state .handoff_node = None
728+ self .state .current_node = current_node
721729
722- else :
723- logger .debug ("node=<%s> | no handoff occurred, marking swarm as complete" , current_node .node_id )
724- self .state .completion_status = Status .COMPLETED
725- break
730+ handoff_event = MultiAgentHandoffEvent (
731+ from_node_ids = [previous_node .node_id ],
732+ to_node_ids = [current_node .node_id ],
733+ message = self .state .handoff_message or "Agent handoff occurred" ,
734+ )
735+ yield handoff_event
736+ logger .debug (
737+ "from_node=<%s>, to_node=<%s> | handoff detected" ,
738+ previous_node .node_id ,
739+ current_node .node_id ,
740+ )
726741
727- except Exception :
728- logger .exception ("node=<%s> | node execution failed " , current_node .node_id )
729- self .state .completion_status = Status .FAILED
742+ else :
743+ logger .debug ("node=<%s> | no handoff occurred, marking swarm as complete " , current_node .node_id )
744+ self .state .completion_status = Status .COMPLETED
730745 break
731746
732747 except Exception :
0 commit comments