88from pydantic import BaseModel
99from .task import Task
1010from .agent import Agent
11-
11+ from . utils . logging_config import logger
1212
1313class TaskInstruction (BaseModel ):
1414 task_id : str
@@ -30,15 +30,15 @@ def create_conduct_tool(agents: List[Any], tool_summaries: bool) -> Callable:
3030 }
3131
3232 # Format available agents string with their tools
33- available_agents = "\n " .join (
33+ available_agents = "No agents have been installed yet. Notify the user to install or add some agents first." if not agents else " \n " .join (
3434 f"- { agent_id } \n ({ agent_id } 's tools: { ', ' .join (agent_tools [agent_id ] or ['No tools' ])} )"
3535 for agent_id in sorted (agent_map .keys ())
3636 )
3737
3838 async def conduct_tool (
3939 tasks : List , event_queue : Optional [Queue ] = None , ** kwargs
4040 ) -> Any :
41- print (f"[DELEGATION] Starting conduct delegation with { len (tasks )} tasks" )
41+ logger . debug (f"Starting conduct delegation with { len (tasks )} tasks" )
4242
4343 # Add max iteration limits
4444 MAX_AGENT_ITERATIONS = 3 # Maximum times an agent can attempt to complete a task
@@ -77,22 +77,26 @@ async def conduct_tool(
7777 # Convert dict to TaskInstruction model
7878 task = TaskInstruction .model_validate (instruction_item )
7979
80+ # Add progress logging
81+ current_task_index = tasks .index (instruction_item ) + 1
82+ logger .info (f"Processing task { current_task_index } of { len (tasks )} : '{ task .task_id } ' with agent '{ task .agent_id } '" )
83+
8084 target_agent = agent_map .get (task .agent_id )
81- print (
82- f"[DELEGATION] Processing task '{ task .task_id } ' with agent '{ task .agent_id } '"
85+ logger . debug (
86+ f"Processing task '{ task .task_id } ' with agent '{ task .agent_id } '"
8387 )
8488
8589 if not target_agent :
86- print (
87- f"[DELEGATION] Warning: Agent { task .agent_id } not found. Available agents: { list (agent_map .keys ())} "
90+ logger . warning (
91+ f"Warning: Agent { task .agent_id } not found. Available agents: { list (agent_map .keys ())} "
8892 )
8993 continue
9094
9195 # Track agent iterations
9296 agent_call_counts [task .agent_id ] = agent_call_counts .get (task .agent_id , 0 ) + 1
9397 if agent_call_counts [task .agent_id ] > MAX_AGENT_ITERATIONS :
94- print (
95- f"[DELEGATION] Warning: Agent { task .agent_id } exceeded maximum iterations"
98+ logger . warning (
99+ f"Warning: Agent { task .agent_id } exceeded maximum iterations"
96100 )
97101 continue
98102
@@ -108,7 +112,7 @@ async def conduct_tool(
108112 }
109113 ]
110114
111- print (f"\n [DELEGATION] Starting task for agent: { task .agent_id } " )
115+ logger . debug (f"\n Starting task for agent: { task .agent_id } " )
112116 instruction_text = task .instruction + (
113117 "\n \n Use the following information from previous tasks:\n \n "
114118 + "\n \n " .join (
@@ -121,20 +125,19 @@ async def conduct_tool(
121125 )
122126
123127 async def nested_callback (result ):
124- if isinstance (result , dict ) and result .get ("tool" ):
128+ if isinstance (result , dict ) and ( result .get ("tool" ) or result . get ( "type" ) == "delegation_result " ):
125129 current_time = datetime .now ().isoformat ()
126130
127131 # Ensure any existing timestamp is serializable
128132 if "timestamp" in result and isinstance (result ["timestamp" ], datetime ):
129133 result ["timestamp" ] = result ["timestamp" ].isoformat ()
130134
131135 # Standardize message format for all delegation-related events
132- if result .get ("type" ) in [ "delegation_result" , "final_response" ] :
136+ if result .get ("type" ) == "delegation_result" :
133137 message = {
134138 "type" : "delegation_result" ,
135- "role" : "delegation" ,
136- "name" : target_agent .agent_id ,
137139 "content" : result .get ("content" , "" ),
140+ "agent_id" : target_agent .agent_id ,
138141 "conducted_task_id" : task .task_id ,
139142 "timestamp" : current_time ,
140143 }
@@ -177,13 +180,12 @@ async def nested_callback(result):
177180 msg_signature += (
178181 f":{ result .get ('tool' )} :{ json .dumps (result .get ('params' , {}))} "
179182 )
180- # print(f"[DELEGATION DEBUG] Tool call: {result.get('tool')}")
183+
181184 elif result .get ("type" ) == "tool_result" :
182185 msg_signature += f":{ result .get ('tool' )} "
183- # print(f"[DELEGATION DEBUG] Tool result received")
186+
184187 elif result .get ("type" ) == "delegation_result" :
185188 msg_signature += f":delegation:{ result .get ('conducted_task_id' )} "
186- # print(f"[DELEGATION DEBUG] Conductor result received for task: {result.get('conducted_task_id')}")
187189
188190 # Send to event queue if available
189191 if event_queue :
@@ -199,6 +201,15 @@ async def nested_callback(result):
199201 tool_summaries = tool_summaries ,
200202 )
201203
204+ # Generate a delegation result event after task completion
205+ delegation_result = {
206+ "type" : "delegation_result" ,
207+ "content" : task_result ,
208+ "agent_id" : target_agent .agent_id ,
209+ "conducted_task_id" : task .task_id
210+ }
211+ await nested_callback (delegation_result )
212+
202213 # Include context in the result
203214 context = "\n \n " .join (
204215 f"Results from task '{ dep_id } ':\n { all_results [dep_id ]} "
@@ -209,13 +220,16 @@ async def nested_callback(result):
209220 f"{ context } \n \n { task_result } " if context else task_result
210221 )
211222
212- # Return the final combined results
213- return "\n \n " .join (
214- f"Task '{ task_id } ':\n "
215- f"Instruction: { next ((item ['instruction' ] for item in tasks if item ['task_id' ] == task_id ), '' )} \n "
216- f"Result: { result } "
223+ # Return results as JSON structure
224+ return json .dumps ([
225+ {
226+ "task_id" : task_id ,
227+ "agent" : next ((item ['agent_id' ] for item in tasks if item ['task_id' ] == task_id ), '' ),
228+ "instruction" : next ((item ['instruction' ] for item in tasks if item ['task_id' ] == task_id ), '' ),
229+ "result" : result
230+ }
217231 for task_id , result in all_results .items ()
218- )
232+ ] )
219233
220234 conduct_tool .__name__ = "conduct_tool"
221235 conduct_tool .__doc__ = f"""Tool function to orchestrate multiple agents in a single, coordinated multi-agent flow. Tasks should be submitted in a single list, and they will be executed in the order they are submitted. Do not make separate calls to the tool.
@@ -275,7 +289,6 @@ def create_composition_tool(agents: List[Agent]) -> Callable:
275289 async def composition_tool (
276290 goal : str , event_queue : Optional [Queue ] = None , ** kwargs
277291 ) -> Any :
278- # KEEP: Create composer agent instance with all these fields
279292 composer_agent = Agent (
280293 agent_id = "composer" ,
281294 role = "Composer" ,
@@ -287,7 +300,7 @@ async def composition_tool(
287300 llm = next (iter (agents )).llm ,
288301 )
289302
290- # KEEP: Initialize messages array with BOTH system and user messages
303+ # Initialize messages array with both system and user messages
291304 messages = [
292305 {
293306 "role" : "system" ,
@@ -312,7 +325,6 @@ async def composition_tool(
312325 ]
313326
314327 try :
315- # KEEP: All these parameters to Task.create()
316328 task_result = await Task .create (
317329 agent = composer_agent ,
318330 instruction = f"Create a detailed plan for achieving this goal: { goal } " ,
@@ -322,7 +334,7 @@ async def composition_tool(
322334 )
323335 return task_result
324336 except Exception as e :
325- print (f"[COMPOSITION ERROR] Failed to create task: { str (e )} " )
337+ logger . error (f"[COMPOSITION ERROR] Failed to create task: { str (e )} " )
326338 raise
327339
328340 composition_tool .__name__ = "composition_flow"
0 commit comments