77from flo_ai .tool .base_tool import Tool
88from flo_ai .arium .models import StartNode , EndNode
99from flo_ai .arium .events import AriumEventType , AriumEvent
10+ from flo_ai .arium .nodes import AriumNode , ForEachNode
1011from flo_ai .utils .logger import logger
1112from flo_ai .utils .variable_extractor import (
1213 extract_variables_from_inputs ,
@@ -73,14 +74,16 @@ async def run(
7374
7475 # Execute the workflow with event support
7576 result = await self ._execute_graph (
76- resolved_inputs , event_callback , events_filter
77+ resolved_inputs , event_callback , events_filter , variables
7778 )
7879
7980 # Emit workflow completed event
8081 self ._emit_event (
8182 AriumEventType .WORKFLOW_COMPLETED , event_callback , events_filter
8283 )
8384
85+ self .memory = MessageMemory () # cleanup the graph (if used as AriumNode multiple times in graph, then the same instance is used for now hence we need to cleanup memory)
86+
8487 return result
8588
8689 except Exception as e :
@@ -118,6 +121,7 @@ async def _execute_graph(
118121 inputs : List [str | ImageMessage | DocumentMessage ],
119122 event_callback : Optional [Callable [[AriumEvent ], None ]] = None ,
120123 events_filter : Optional [List [AriumEventType ]] = None ,
124+ variables : Optional [Dict [str , Any ]] = None ,
121125 ):
122126 [self .memory .add (msg ) for msg in inputs ]
123127
@@ -162,11 +166,16 @@ async def _execute_graph(
162166 )
163167 # execute current node
164168 result = await self ._execute_node (
165- current_node , event_callback , events_filter
169+ current_node , event_callback , events_filter , variables
166170 )
167171
168- # update results to memory
169- self ._add_to_memory (result )
172+ if isinstance (result , List ): # for each node will give results array
173+ for item in result :
174+ # update each item in result to memory
175+ self ._add_to_memory (item )
176+ else :
177+ # update results to memory
178+ self ._add_to_memory (result )
170179
171180 # find next node post current node
172181 # Prepare execution context for router functions
@@ -301,6 +310,7 @@ async def _execute_node(
301310 node : Agent | Tool | StartNode | EndNode ,
302311 event_callback : Optional [Callable [[AriumEvent ], None ]] = None ,
303312 events_filter : Optional [List [AriumEventType ]] = None ,
313+ variables : Optional [Dict [str , Any ]] = None ,
304314 ):
305315 """
306316 Execute a single node with optional event emission.
@@ -318,6 +328,10 @@ async def _execute_node(
318328 node_type = 'agent'
319329 elif isinstance (node , Tool ):
320330 node_type = 'tool'
331+ elif isinstance (node , ForEachNode ):
332+ node_type = 'foreach'
333+ elif isinstance (node , AriumNode ):
334+ node_type = 'arium'
321335 elif isinstance (node , StartNode ):
322336 node_type = 'start'
323337 elif isinstance (node , EndNode ):
@@ -342,7 +356,16 @@ async def _execute_node(
342356 # Variables are already resolved, pass empty dict to avoid re-processing
343357 result = await node .run (self .memory .get (), variables = {})
344358 elif isinstance (node , Tool ):
345- result = await node .execute ()
359+ # result = await node.execute() # as Tool is also an ExecutableNode now
360+ result = await node .run (inputs = [], variables = None )
361+ elif isinstance (node , ForEachNode ):
362+ result = await node .run (
363+ inputs = self .memory .get (),
364+ variables = variables ,
365+ )
366+ elif isinstance (node , AriumNode ):
367+ # AriumNode execution
368+ result = await node .run (inputs = self .memory .get (), variables = variables )
346369 elif isinstance (node , StartNode ):
347370 result = None
348371 elif isinstance (node , EndNode ):
0 commit comments