Added: Team Agent Tool Edit: Prompts for Team Agent support Code Exe tool, input tool, and instructions to support individual terminal reset and better terminal management for complex coding tasks.
Added: Team Agent Tool Edit: Prompts for Team Agent support Code Exe tool, input tool, and instructions to support individual terminal reset and better terminal management for complex coding tasks.
deci committed
May 10, 2025 at 16:43 UTC
66bb2f720d687bd61576f2871371bf8deb59f3af
7 files changed
+1694
-89
prompts/default/agent.system.tool.code_exe.md
+98
-45
@@ -1,76 +1,129 @@
1
### code_execution_tool
2
3
-execute terminal commands python nodejs code for computation or software tasks
4
-place code in "code" arg; escape carefully and indent properly
5
-select "runtime" arg: "terminal" "python" "nodejs" "output" "reset"
6
-select "session" number, 0 default, others for multitasking
7
-if code runs long, use "output" to wait, "reset" to kill process
8
-use "pip" "npm" "apt-get" in "terminal" to install packages
9
-to output, use print() or console.log()
10
-if tool outputs error, adjust code before retrying; knowledge_tool can help
11
-important: check code for placeholders or demo data; replace with real variables; don't reuse snippets
12
-don't use with other tools except thoughts; wait for response before using others
13
-check dependencies before running code
14
-usage:
3
+Execute commands and code for computation, data analysis, and file operations.
4
16
-1 execute python code
5
+**PARAMETERS:**
6
+- **runtime:** "terminal" (shell), "python", "nodejs", "output" (wait), "reset" (kill)
7
+- **session:** 0 for file operations, 1-10 for running programs (keep separate)
8
+- **code:** Your command or code to execute (use print/console.log for output)
9
18
-~~~json
10
+## CORE PATTERNS:
11
+
12
+### BASIC FILE OPERATIONS
13
+```json
14
{
20
- "thoughts": [
21
- "Need to do...",
22
- "I can use...",
23
- "Then I can...",
24
- ],
25
- "tool_name": "code_execution_tool",
15
+ "thoughts": ["Creating a project structure and files"],
16
+ "tool_name": "code_execution_tool",
17
"tool_args": {
18
"runtime": "python",
19
"session": 0,
29
- "code": "import os\nprint(os.getcwd())",
20
+ "code": "import os\n\n# Create project structure\nos.makedirs('myproject/src', exist_ok=True)\n\n# Create main file\nfile_path = 'myproject/src/main.py'\nwith open(file_path, 'w') as f:\n f.write('def main():\\n print(\"Program running\")\\n\\nif __name__ == \"__main__\":\\n main()')\n\n# Verify file creation\nif os.path.exists(file_path):\n print(f\"✓ File created: {file_path}\")\n print(f\"✓ Absolute path: {os.path.abspath(file_path)}\")\nelse:\n print(f\"✗ Failed to create file: {file_path}\")"
21
}
22
}
32
-~~~
23
+```
24
34
-2 execute terminal command
35
-~~~json
25
+### RUNNING CODE (USE SEPARATE SESSIONS)
26
+```json
27
+{
28
+ "thoughts": ["Reset session before running"],
29
+ "tool_name": "code_execution_tool",
30
+ "tool_args": {
31
+ "runtime": "reset",
32
+ "session": 1
33
+ }
34
+}
35
+```
36
+```json
37
{
37
- "thoughts": [
38
- "Need to do...",
39
- "Need to install...",
40
- ],
38
+ "thoughts": ["Running created file in session 1"],
39
"tool_name": "code_execution_tool",
40
"tool_args": {
41
"runtime": "terminal",
44
- "session": 0,
45
- "code": "apt-get install zip",
42
+ "session": 1,
43
+ "code": "python myproject/src/main.py"
44
}
45
}
48
-~~~
46
+```
47
50
-2.1 wait for output with long-running scripts
51
-~~~json
48
+### PACKAGE INSTALLATION
49
+```json
50
{
53
- "thoughts": [
54
- "Waiting for program to finish...",
55
- ],
51
+ "thoughts": ["Installing required packages"],
52
"tool_name": "code_execution_tool",
53
"tool_args": {
58
- "runtime": "output",
54
+ "runtime": "terminal",
55
"session": 0,
56
+ "code": "pip install pandas matplotlib"
57
}
58
}
62
-~~~
59
+```
60
64
-2.2 reset terminal
65
-~~~json
61
+### INTERACTIVE PROGRAMS WITH INPUT
62
+```json
63
+{
64
+ "thoughts": ["Creating interactive program"],
65
+ "tool_name": "code_execution_tool",
66
+ "tool_args": {
67
+ "runtime": "python",
68
+ "session": 0,
69
+ "code": "file_path = 'interactive.py'\nwith open(file_path, 'w') as f:\n f.write('name = input(\"Enter your name: \")\\nprint(f\"Hello, {name}!\")')\nprint(f\"✓ File created: {file_path}\")"
70
+ }
71
+}
72
+```
73
+```json
74
{
67
- "thoughts": [
68
- "code_execution_tool not responding...",
69
- ],
75
+ "thoughts": ["Running interactive program"],
76
"tool_name": "code_execution_tool",
77
"tool_args": {
78
"runtime": "reset",
73
- "session": 0,
79
+ "session": 1
80
+ }
81
+}
82
+```
83
+```json
84
+{
85
+ "thoughts": ["Starting interactive program"],
86
+ "tool_name": "code_execution_tool",
87
+ "tool_args": {
88
+ "runtime": "terminal",
89
+ "session": 1,
90
+ "code": "python interactive.py"
91
+ }
92
+}
93
+```
94
+```json
95
+{
96
+ "thoughts": ["Providing input to program"],
97
+ "tool_name": "input",
98
+ "tool_args": {
99
+ "keyboard": "John Doe",
100
+ "session": 1
101
}
102
}
76
-~~~
\ No newline at end of file
103
+```
104
+
105
+## BEST PRACTICES:
106
+
107
+### FILE OPERATIONS
108
+- Always create files with clear paths in session 0
109
+- Verify file creation before attempting to run files
110
+- Use Python's file operations for complex files
111
+- Organize projects with standard directory structure
112
+
113
+### SESSION MANAGEMENT
114
+- Keep session 0 for file creation/editing only
115
+- Use sessions 1+ for running programs
116
+- Reset sessions before running new programs
117
+- Never run commands in sessions waiting for input
118
+
119
+### ERROR HANDLING
120
+- If file operations fail, verify the current directory and file paths
121
+- For import errors, check dependencies and installation
122
+- Reset sessions after errors before trying again
123
+- Use try/except in Python code to handle potential errors
124
+
125
+### DEBUGGING
126
+- Print absolute paths when verifying file creation
127
+- List directory contents to check available files
128
+- Create debugging scripts to test environment setup
129
+- Use explicit path variables for consistency
\ No newline at end of file
prompts/default/agent.system.tool.input.md
+2
@@ -2,6 +2,7 @@
2
use keyboard arg for terminal program input
3
answer dialogues enter passwords etc
4
not for browser
5
+specify session number to match the terminal session where program is running
6
usage:
7
~~~json
8
{
@@ -11,6 +12,7 @@ usage:
12
"tool_name": "input",
13
"tool_args": {
14
"keyboard": "Y",
15
+ "session": 1
16
}
17
}
18
~~~
\ No newline at end of file
prompts/default/agent.system.tool.team_agent.md
new
+181
@@ -0,0 +1,181 @@
1
+### team_agent:
2
+
3
+create and manage specialized teams of agents that collaborate on complex tasks
4
+enables coordinated work through different roles and dependencies
5
+use for multistep problems requiring different expertise
6
+
7
+usage:
8
+
9
+```json
10
+{
11
+ "thoughts": [
12
+ "I need to create a research team to investigate this complex problem"
13
+ ],
14
+ "tool_name": "team_agent",
15
+ "tool_args": {
16
+ "action": "create",
17
+ "name": "Research Team",
18
+ "goal": "Research quantum computing algorithms"
19
+ }
20
+}
21
+```
22
+
23
+```json
24
+{
25
+ "thoughts": [
26
+ "I need to add a researcher who can find information"
27
+ ],
28
+ "tool_name": "team_agent",
29
+ "tool_args": {
30
+ "action": "add_agent",
31
+ "team_id": "team_abcd1234",
32
+ "role": "researcher",
33
+ "skills": ["information gathering", "analysis"]
34
+ }
35
+}
36
+```
37
+
38
+```json
39
+{
40
+ "thoughts": [
41
+ "I'll assign a task to the researcher agent"
42
+ ],
43
+ "tool_name": "team_agent",
44
+ "tool_args": {
45
+ "action": "assign_task",
46
+ "team_id": "team_abcd1234",
47
+ "agent_id": "agent_xyz789",
48
+ "task": "Find the 3 most recent papers on quantum computing algorithms",
49
+ "context": "Focus on papers from the last 2 years"
50
+ }
51
+}
52
+```
53
+
54
+```json
55
+{
56
+ "thoughts": [
57
+ "Time to execute the task I assigned"
58
+ ],
59
+ "tool_name": "team_agent",
60
+ "tool_args": {
61
+ "action": "execute_task",
62
+ "team_id": "team_abcd1234",
63
+ "task_id": "task_def456"
64
+ }
65
+}
66
+```
67
+
68
+```json
69
+{
70
+ "thoughts": [
71
+ "I should share information between agents"
72
+ ],
73
+ "tool_name": "team_agent",
74
+ "tool_args": {
75
+ "action": "message",
76
+ "team_id": "team_abcd1234",
77
+ "from": "agent_xyz789",
78
+ "to": "agent_abc123",
79
+ "content": "I found 3 relevant papers on quantum algorithms"
80
+ }
81
+}
82
+```
83
+
84
+```json
85
+{
86
+ "thoughts": [
87
+ "Let's get all the results from the team"
88
+ ],
89
+ "tool_name": "team_agent",
90
+ "tool_args": {
91
+ "action": "get_results",
92
+ "team_id": "team_abcd1234"
93
+ }
94
+}
95
+```
96
+
97
+```json
98
+{
99
+ "thoughts": [
100
+ "I need to check the team's progress"
101
+ ],
102
+ "tool_name": "team_agent",
103
+ "tool_args": {
104
+ "action": "team_status",
105
+ "team_id": "team_abcd1234"
106
+ }
107
+}
108
+```
109
+
110
+```json
111
+{
112
+ "thoughts": [
113
+ "I need to retrieve a specific task result to reference in my current work"
114
+ ],
115
+ "tool_name": "team_agent",
116
+ "tool_args": {
117
+ "action": "get_task_result",
118
+ "team_id": "team_abcd1234",
119
+ "task_id": "task_def456"
120
+ }
121
+}
122
+```
123
+
124
+```json
125
+{
126
+ "thoughts": [
127
+ "Now that I have all the results, I need to integrate them into a cohesive final product"
128
+ ],
129
+ "tool_name": "team_agent",
130
+ "tool_args": {
131
+ "action": "integrate_results",
132
+ "team_id": "team_abcd1234"
133
+ }
134
+}
135
+```
136
+
137
+workflow sequence:
138
+1. create a team
139
+2. add specialized agents with clear roles
140
+3. assign specific tasks to agents
141
+4. execute tasks one at a time
142
+5. share results between agents as needed
143
+6. get all results with get_results
144
+7. integrate results into a final product
145
+8. respond to the user with the final integrated work
146
+
147
+IMPORTANT: Follow this precise workflow for optimal results:
148
+
149
+STEP 1: CREATE TEAM & ALL AGENTS
150
+- First create the team with the 'create' action
151
+- Then add ALL needed specialized agents with 'add_agent' before assigning any tasks
152
+- Only proceed to task assignment after ALL required agents are created
153
+
154
+STEP 2: ASSIGN ALL TASKS
155
+- Assign tasks to EACH agent with the 'assign_task' action
156
+- Make sure to specify the correct agent_id for each task
157
+- Define dependencies between tasks if needed
158
+- Only proceed to execution after ALL tasks are assigned
159
+
160
+STEP 3: EXECUTE ALL TASKS
161
+- Execute each task using 'execute_task' in dependency order
162
+- Complete ALL tasks before proceeding to results integration
163
+- Tasks with dependencies will automatically receive results from prerequisite tasks
164
+- Use 'get_task_result' if you need to access specific task outputs during execution
165
+
166
+STEP 4: COMPILE & SYNTHESIZE
167
+- First gather all task results with 'get_results'
168
+- Then synthesize into a complete product with 'integrate_results'
169
+- Ensure the integrated result directly addresses the original goal
170
+
171
+STEP 5: DELIVER FINAL PRODUCT
172
+- Present the integrated results to the user in a comprehensive manner
173
+- Use the response tool to provide the complete answer to the original request
174
+
175
+When team agents execute tasks, they automatically respond in the proper format using the "response" tool. Team management handles all communication between agents for you - you only need to use the actions shown above.
176
+
177
+COMMON ERRORS TO AVOID:
178
+- Don't assign tasks without specifying which agent should perform them
179
+- Don't execute tasks before all necessary agents are created
180
+- Don't try to integrate results before all tasks are completed
181
+- Don't mix task assignment with task execution - complete each phase fully
\ No newline at end of file
prompts/default/agent.system.tools.md
+2
@@ -4,6 +4,8 @@
4
5
{{ include './agent.system.tool.call_sub.md' }}
6
7
+{{ include './agent.system.tool.team_agent.md' }}
8
+
9
{{ include './agent.system.tool.behaviour.md' }}
10
11
{{ include './agent.system.tool.knowledge.md' }}
python/tools/code_execution_tool.py
+73
-43
@@ -43,7 +43,7 @@ class CodeExecution(Tool):
43
)
44
elif runtime == "output":
45
response = await self.get_terminal_output(
46
- session=session, wait_with_output=5, wait_without_output=60
46
+ session=session, first_output_timeout=60, between_output_timeout=5
47
)
48
elif runtime == "reset":
49
response = await self.reset_terminal(session=session)
@@ -89,12 +89,12 @@ class CodeExecution(Tool):
89
async def after_execution(self, response, **kwargs):
90
self.agent.hist_add_tool_result(self.name, response.message)
91
92
- async def prepare_state(self, reset=False):
92
+ async def prepare_state(self, reset=False, session=None):
93
self.state = self.agent.get_data("_cot_state")
94
if not self.state or reset:
95
96
# initialize docker container if execution in docker is configured
97
- if self.agent.config.code_exec_docker_enabled:
97
+ if not self.state and self.agent.config.code_exec_docker_enabled:
98
docker = DockerContainerManager(
99
logger=self.agent.context.log,
100
name=self.agent.config.code_exec_docker_name,
@@ -104,27 +104,43 @@ class CodeExecution(Tool):
104
)
105
docker.start_container()
106
else:
107
- docker = None
108
-
109
- # initialize local or remote interactive shell insterface
110
- if self.agent.config.code_exec_ssh_enabled:
111
- pswd = (
112
- self.agent.config.code_exec_ssh_pass
113
- if self.agent.config.code_exec_ssh_pass
114
- else await rfc_exchange.get_root_password()
115
- )
116
- shell = SSHInteractiveSession(
117
- self.agent.context.log,
118
- self.agent.config.code_exec_ssh_addr,
119
- self.agent.config.code_exec_ssh_port,
120
- self.agent.config.code_exec_ssh_user,
121
- pswd,
122
- )
123
- else:
124
- shell = LocalInteractiveSession()
107
+ docker = self.state.docker if self.state else None
108
+
109
+ # initialize shells dictionary if not exists
110
+ shells = {} if not self.state else self.state.shells.copy()
111
+
112
+ # Only reset the specified session if provided
113
+ if session is not None and session in shells:
114
+ shells[session].close()
115
+ del shells[session]
116
+ elif reset and not session:
117
+ # Close all sessions if full reset requested
118
+ for s in list(shells.keys()):
119
+ shells[s].close()
120
+ shells = {}
121
+
122
+ # initialize local or remote interactive shell interface for session 0 if needed
123
+ if 0 not in shells:
124
+ if self.agent.config.code_exec_ssh_enabled:
125
+ pswd = (
126
+ self.agent.config.code_exec_ssh_pass
127
+ if self.agent.config.code_exec_ssh_pass
128
+ else await rfc_exchange.get_root_password()
129
+ )
130
+ shell = SSHInteractiveSession(
131
+ self.agent.context.log,
132
+ self.agent.config.code_exec_ssh_addr,
133
+ self.agent.config.code_exec_ssh_port,
134
+ self.agent.config.code_exec_ssh_user,
135
+ pswd,
136
+ )
137
+ else:
138
+ shell = LocalInteractiveSession()
139
126
- self.state = State(shells={0: shell}, docker=docker)
127
- await shell.connect()
140
+ shells[0] = shell
141
+ await shell.connect()
142
+
143
+ self.state = State(shells=shells, docker=docker)
144
self.agent.set_data("_cot_state", self.state)
145
146
async def execute_python_code(self, session: int, code: str, reset: bool = False):
@@ -191,41 +207,55 @@ class CodeExecution(Tool):
207
self,
208
session=0,
209
reset_full_output=True,
194
- wait_with_output=3,
195
- wait_without_output=10,
196
- max_exec_time=60,
210
+ first_output_timeout=30, # Wait up to 60s for first output
211
+ between_output_timeout=10, # Wait up to 10s between outputs
212
+ sleep_time=0.1,
213
):
198
- idle = 0
199
- SLEEP_TIME = 0.1
214
+ """
215
+ Waits for terminal output with a sliding window idle timeout:
216
+ - Waits up to first_output_timeout (default 60s) for the first output.
217
+ - After any output, waits up to between_output_timeout (default 10s) for more output.
218
+ - Each new output resets the between_output_timeout timer.
219
+ - No hard cap on total runtime.
220
+ - If no output for between_output_timeout after last output, or no output at all for first_output_timeout, returns.
221
+ """
222
start_time = time.time()
223
+ last_output_time = start_time
224
full_output = ""
225
+ got_output = False
226
203
- while max_exec_time <= 0 or time.time() - start_time < max_exec_time:
204
- await asyncio.sleep(SLEEP_TIME) # Wait for some output to be generated
227
+ while True:
228
+ await asyncio.sleep(sleep_time)
229
full_output, partial_output = await self.state.shells[session].read_output(
206
- timeout=max_exec_time, reset_full_output=reset_full_output
230
+ timeout=between_output_timeout, reset_full_output=reset_full_output
231
)
208
- reset_full_output = False # only reset once
232
+ reset_full_output = False
233
210
- await self.agent.handle_intervention() # wait for intervention and handle it, if paused
234
+ await self.agent.handle_intervention()
235
236
+ now = time.time()
237
if partial_output:
238
PrintStyle(font_color="#85C1E9").stream(partial_output)
239
self.log.update(content=full_output)
215
- idle = 0
240
+ last_output_time = now
241
+ got_output = True
242
+
243
+ if not got_output:
244
+ # Waiting for first output
245
+ if now - start_time > first_output_timeout:
246
+ PrintStyle.error(f"No output for {first_output_timeout}s after start, returning.")
247
+ break
248
else:
217
- idle += 1
218
- if (full_output and idle > wait_with_output / SLEEP_TIME) or (
219
- not full_output and idle > wait_without_output / SLEEP_TIME
220
- ):
249
+ # Waiting for more output after first output
250
+ if now - last_output_time > between_output_timeout:
251
+ PrintStyle.error(f"No output for {between_output_timeout}s after last output, returning.")
252
break
253
+
254
return full_output
255
256
async def reset_terminal(self, session=0):
225
- if session in self.state.shells:
226
- self.state.shells[session].close()
227
- del self.state.shells[session]
228
- await self.prepare_state(reset=True)
257
+ # Only reset the specified session while preserving others
258
+ await self.prepare_state(reset=True, session=session)
259
response = self.agent.read_prompt("fw.code_reset.md")
260
self.log.update(content=response)
231
- return response
261
+ return response
\ No newline at end of file
python/tools/input.py
+1
-1
@@ -5,7 +5,7 @@ from python.tools.code_execution_tool import CodeExecution
5
6
class Input(Tool):
7
8
- async def execute(self, keyboard="", **kwargs):
8
+ async def execute(self, keyboard="", session=0, **kwargs):
9
# normalize keyboard input
10
keyboard = keyboard.rstrip()
11
keyboard += "\n"
python/tools/team_agent.py
new
+1337
@@ -0,0 +1,1337 @@
1
+from agent import Agent, UserMessage
2
+from python.helpers.tool import Tool, Response
3
+import uuid
4
+import json
5
+import time
6
+
7
+class TeamAgent(Tool):
8
+ """
9
+ TeamAgent tool that integrates with the agent zero framework to manage
10
+ collaborative agent teams.
11
+ """
12
+
13
+ async def execute(self, action="", team_id="", **kwargs):
14
+ """
15
+ Execute the TeamAgent tool with better integration with agent.py.
16
+
17
+ Args:
18
+ action: Action to perform (create, add_agent, assign_task, message, get_results)
19
+ team_id: ID of the team (except for 'create' action)
20
+ **kwargs: Additional arguments based on the action
21
+ """
22
+ # Parameter validation and normalization
23
+ if not action and "action" in kwargs:
24
+ action = kwargs.pop("action")
25
+ self.log.update(progress=f"Normalized action parameter from kwargs: {action}")
26
+
27
+ # Initialize teams data structure if not present
28
+ if not self.agent.get_data("teams"):
29
+ self.agent.set_data("teams", {})
30
+
31
+ # Use active team if not explicitly provided
32
+ if not team_id and action != "create" and self.agent.get_data("active_team_id"):
33
+ team_id = self.agent.get_data("active_team_id")
34
+ self.log.update(progress=f"Using active team ID: {team_id}")
35
+
36
+ # Handle different actions
37
+ if action == "create":
38
+ return await self._create_team(**kwargs)
39
+ # Handle actions with better logging
40
+ try:
41
+ if action == "create":
42
+ return await self._create_team(**kwargs)
43
+ elif action == "add_agent":
44
+ self.log.update(progress=f"Adding agent to team {team_id}...")
45
+ return await self._add_agent(team_id, **kwargs)
46
+ elif action == "assign_task":
47
+ self.log.update(progress=f"Assigning task to agent in team {team_id}...")
48
+ return await self._assign_task(team_id, **kwargs)
49
+ elif action == "execute_task":
50
+ self.log.update(progress=f"Executing task in team {team_id}...")
51
+ return await self._execute_task(team_id, **kwargs)
52
+ elif action == "message":
53
+ self.log.update(progress=f"Sending message in team {team_id}...")
54
+ return await self._send_message(team_id, **kwargs)
55
+ elif action == "get_results":
56
+ self.log.update(progress=f"Getting results from team {team_id}...")
57
+ return await self._get_results(team_id, **kwargs)
58
+ elif action == "team_status":
59
+ self.log.update(progress=f"Getting status for team {team_id}...")
60
+ return await self._team_status(team_id, **kwargs)
61
+ elif action == "integrate_results":
62
+ self.log.update(progress=f"Integrating results from team {team_id}...")
63
+ return await self._integrate_results(team_id, **kwargs)
64
+ elif action == "get_task_result":
65
+ self.log.update(progress=f"Getting specific task result from team {team_id}...")
66
+ return await self._get_task_result(team_id, **kwargs)
67
+ else:
68
+ self.log.update(error=f"Unknown action: {action}")
69
+ return Response(
70
+ message=self._format_response({
71
+ "error": f"Unknown action: {action}",
72
+ "available_actions": [
73
+ "create", "add_agent", "assign_task",
74
+ "execute_task", "message", "get_results",
75
+ "team_status", "integrate_results", "get_task_result"
76
+ ]
77
+ }),
78
+ break_loop=False
79
+ )
80
+ except Exception as e:
81
+ # Log the error and return a formatted response
82
+ error_message = f"Error executing {action}: {str(e)}"
83
+ self.log.update(error=error_message)
84
+
85
+ return Response(
86
+ message=self._format_response({
87
+ "error": error_message,
88
+ "action_attempted": action,
89
+ "next_step": "Check parameters and try again"
90
+ }),
91
+ break_loop=False
92
+ )
93
+ else:
94
+ return Response(
95
+ message=self._format_response({
96
+ "error": f"Unknown action: {action}",
97
+ "available_actions": [
98
+ "create", "add_agent", "assign_task",
99
+ "execute_task", "message", "get_results",
100
+ "team_status", "integrate_results", "get_task_result"
101
+ ]
102
+ }),
103
+ break_loop=False
104
+ )
105
+
106
+ async def _create_team(self, name="Team", goal="Collaborate on a task", **kwargs):
107
+ """Create a new team with a team leader agent"""
108
+ team_id = f"team_{str(uuid.uuid4())[:8]}"
109
+
110
+ # Create team leader agent - use the same number as the current agent
111
+ # to avoid numbering issues when creating subordinates
112
+ team_leader = Agent(self.agent.number, self.agent.config, self.agent.context)
113
+ team_leader.set_data("role", "team_leader")
114
+ team_leader.set_data("team_id", team_id)
115
+ team_leader.set_data("team_name", name)
116
+ team_leader.set_data("team_goal", goal)
117
+ team_leader.set_data("team_members", {})
118
+ team_leader.set_data("tasks", {})
119
+ team_leader.set_data("created_at", time.time())
120
+
121
+ # Store team in agent's data
122
+ teams = self.agent.get_data("teams")
123
+ teams[team_id] = {
124
+ "id": team_id,
125
+ "name": name,
126
+ "goal": goal,
127
+ "leader_agent": team_leader,
128
+ "created_at": time.time()
129
+ }
130
+ self.agent.set_data("teams", teams)
131
+
132
+ # Set as the active team
133
+ self.agent.set_data("active_team_id", team_id)
134
+
135
+ return Response(
136
+ message=self._format_response({
137
+ "team_id": team_id,
138
+ "name": name,
139
+ "goal": goal,
140
+ "status": "created",
141
+ "next_step": "Step 1: CREATE ALL TEAM AGENTS FIRST by using add_agent multiple times to create each specialized agent needed for the task. Only proceed to assigning tasks after all agents are created."
142
+ }),
143
+ break_loop=False
144
+ )
145
+
146
+ async def _add_agent(self, team_id, role="member", skills=None, **kwargs):
147
+ """Add a specialized agent to the team"""
148
+ if skills is None:
149
+ skills = []
150
+
151
+ # Get team data
152
+ teams = self.agent.get_data("teams")
153
+ if not team_id or team_id not in teams:
154
+ return Response(
155
+ message=self._format_response({
156
+ "error": f"Team {team_id} not found",
157
+ "available_teams": list(teams.keys()) if teams else []
158
+ }),
159
+ break_loop=False
160
+ )
161
+
162
+ team_data = teams[team_id]
163
+ team_leader = team_data["leader_agent"]
164
+
165
+ agent_id = f"agent_{str(uuid.uuid4())[:6]}"
166
+
167
+ # Create a new agent instance - ensure we're using the next sequential number
168
+ # Correcting the agent numbering to avoid skips
169
+ new_agent = Agent(self.agent.number + 1, self.agent.config, self.agent.context)
170
+
171
+ # Set agent properties
172
+ new_agent.set_data("role", role)
173
+ new_agent.set_data("skills", skills)
174
+ new_agent.set_data("team_id", team_id)
175
+ new_agent.set_data("agent_id", agent_id)
176
+ new_agent.set_data("created_at", time.time())
177
+
178
+ # Establish superior-subordinate relationship
179
+ new_agent.set_data(Agent.DATA_NAME_SUPERIOR, team_leader)
180
+
181
+ # Update team members registry
182
+ team_members = team_leader.get_data("team_members") or {}
183
+ team_members[agent_id] = {
184
+ "role": role,
185
+ "skills": skills,
186
+ "agent": new_agent
187
+ }
188
+ team_leader.set_data("team_members", team_members)
189
+
190
+ # Count existing team members
191
+ member_count = len(team_members)
192
+
193
+ next_step = f"Step 1 CONTINUE: ADD MORE AGENTS if needed to complete the team composition. You have {member_count} agent(s) so far. Once ALL needed agents are created, proceed to Step 2: ASSIGN TASKS to each agent using the assign_task action."
194
+
195
+ return Response(
196
+ message=self._format_response({
197
+ "team_id": team_id,
198
+ "agent_id": agent_id,
199
+ "role": role,
200
+ "status": "added",
201
+ "next_step": next_step
202
+ }),
203
+ break_loop=False
204
+ )
205
+
206
+ async def _assign_task(self, team_id, agent_id="", task="", context="", depends_on=None, **kwargs):
207
+ """Assign a task to a team member"""
208
+ if depends_on is None:
209
+ depends_on = []
210
+
211
+ # Get team data
212
+ teams = self.agent.get_data("teams")
213
+ if not team_id or team_id not in teams:
214
+ return Response(
215
+ message=self._format_response({
216
+ "error": f"Team {team_id} not found",
217
+ "available_teams": list(teams.keys()) if teams else []
218
+ }),
219
+ break_loop=False
220
+ )
221
+
222
+ team_data = teams[team_id]
223
+ team_leader = team_data["leader_agent"]
224
+
225
+ # Get team members
226
+ team_members = team_leader.get_data("team_members") or {}
227
+ if not agent_id or agent_id not in team_members:
228
+ return Response(
229
+ message=self._format_response({
230
+ "error": f"Agent {agent_id} not found in team {team_id}",
231
+ "available_agents": list(team_members.keys()) if team_members else []
232
+ }),
233
+ break_loop=False
234
+ )
235
+
236
+ if not task:
237
+ return Response(
238
+ message=self._format_response({
239
+ "error": "Task description is required"
240
+ }),
241
+ break_loop=False
242
+ )
243
+
244
+ # Get existing tasks to determine sequence number and auto-dependencies
245
+ tasks = team_leader.get_data("tasks") or {}
246
+ sequence_num = len(tasks) + 1 # Start from 1
247
+
248
+ # If no dependencies were explicitly provided, automatically set the most recent task as a dependency
249
+ if not depends_on and tasks:
250
+ # Find the most recent assigned or completed task by highest sequence number
251
+ most_recent_task = None
252
+ highest_seq = 0
253
+
254
+ for task_id, task_data in tasks.items():
255
+ task_seq = task_data.get("sequence_num", 0)
256
+ if task_seq > highest_seq:
257
+ most_recent_task = task_id
258
+ highest_seq = task_seq
259
+
260
+ if most_recent_task:
261
+ depends_on = [most_recent_task]
262
+ self.log.update(progress=f"Automatically set task dependency on prior task: {most_recent_task}")
263
+
264
+ # Create task ID
265
+ task_id = f"task_{str(uuid.uuid4())[:6]}"
266
+
267
+ # Create task
268
+ task_data = {
269
+ "id": task_id,
270
+ "agent_id": agent_id,
271
+ "description": task,
272
+ "context": context,
273
+ "depends_on": depends_on,
274
+ "status": "assigned",
275
+ "created_at": time.time(),
276
+ "sequence_num": sequence_num, # Add explicit sequence number
277
+ "completed_at": None,
278
+ "result": None,
279
+ "auto_dependency": True if not kwargs.get("depends_on") and depends_on else False
280
+ }
281
+
282
+ # Store task in team leader's data
283
+ tasks[task_id] = task_data
284
+ team_leader.set_data("tasks", tasks)
285
+
286
+ # Get the agent's role for better context
287
+ agent_role = team_members[agent_id]["role"] if agent_id in team_members else "unknown"
288
+
289
+ # Create a task keywords summary
290
+ task_keywords = " ".join(task.split()[:7]) + "..." if len(task.split()) > 7 else task
291
+
292
+ # Prepare dependency info if any
293
+ dependency_info = ""
294
+ if depends_on:
295
+ dependency_names = []
296
+ for dep_id in depends_on:
297
+ if dep_id in tasks:
298
+ dep_agent_id = tasks[dep_id].get("agent_id", "unknown")
299
+ dep_role = "unknown"
300
+ if dep_agent_id in team_members:
301
+ dep_role = team_members[dep_agent_id].get("role", "unknown")
302
+ dependency_names.append(f"{dep_id} ({dep_role})")
303
+
304
+ if dependency_names:
305
+ dependency_info = f", depends on: {', '.join(dependency_names)}"
306
+
307
+ # Count remaining agents without tasks
308
+ agents_without_tasks = []
309
+ for aid, adata in team_members.items():
310
+ if not any(t["agent_id"] == aid for t in tasks.values()):
311
+ agents_without_tasks.append(f"{adata['role']} ({aid})")
312
+
313
+ if agents_without_tasks:
314
+ next_step = f"Step 2 CONTINUE: ASSIGN TASKS to remaining agents ({', '.join(agents_without_tasks)}). Only after ALL agents have assigned tasks, proceed to Step 3: EXECUTE TASKS using the execute_task action."
315
+ else:
316
+ next_step = "Step 3: EXECUTE ALL TASKS by using execute_task for each task in sequence. Start with tasks that have no dependencies."
317
+
318
+ return Response(
319
+ message=self._format_response({
320
+ "team_id": team_id,
321
+ "agent_id": agent_id,
322
+ "task_id": task_id,
323
+ "status": "assigned",
324
+ "agent_role": agent_role,
325
+ "task_description": task_keywords,
326
+ "dependencies": depends_on if depends_on else [],
327
+ "sequence_num": sequence_num, # Include sequence number in response
328
+ "has_context": bool(context),
329
+ "auto_dependency": True if not kwargs.get("depends_on") and depends_on else False,
330
+ "next_step": next_step
331
+ }),
332
+ break_loop=False
333
+ )
334
+
335
+ async def _execute_task(self, team_id, task_id="", **kwargs):
336
+ """Execute a task with a specified team member"""
337
+ self.log.update(progress="Executing task in team...")
338
+
339
+ # Get team data
340
+ teams = self.agent.get_data("teams")
341
+ if not team_id or team_id not in teams:
342
+ return Response(
343
+ message=self._format_response({
344
+ "error": f"Team {team_id} not found",
345
+ "available_teams": list(teams.keys()) if teams else []
346
+ }),
347
+ break_loop=False
348
+ )
349
+
350
+ team_data = teams[team_id]
351
+ team_leader = team_data["leader_agent"]
352
+
353
+ # Get tasks
354
+ tasks = team_leader.get_data("tasks") or {}
355
+ if not task_id or task_id not in tasks:
356
+ return Response(
357
+ message=self._format_response({
358
+ "error": f"Task {task_id} not found in team {team_id}",
359
+ "available_tasks": list(tasks.keys()) if tasks else []
360
+ }),
361
+ break_loop=False
362
+ )
363
+
364
+ task = tasks[task_id]
365
+ agent_id = task["agent_id"]
366
+
367
+ # Get team members
368
+ team_members = team_leader.get_data("team_members") or {}
369
+ if agent_id not in team_members:
370
+ return Response(
371
+ message=self._format_response({
372
+ "error": f"Agent {agent_id} not found in team {team_id}"
373
+ }),
374
+ break_loop=False
375
+ )
376
+
377
+ agent_instance = team_members[agent_id]["agent"]
378
+ agent_role = team_members[agent_id]["role"]
379
+ agent_skills = team_members[agent_id]["skills"]
380
+
381
+ # Check for dependency status
382
+ if task.get("depends_on") and not task.get("dependencies_met", False):
383
+ # Check if dependencies are satisfied
384
+ dependencies_met = True
385
+ pending_deps = []
386
+
387
+ for dep_id in task.get("depends_on", []):
388
+ if dep_id not in tasks or tasks.get(dep_id, {}).get("status") != "completed":
389
+ dependencies_met = False
390
+ pending_deps.append(dep_id)
391
+
392
+ if not dependencies_met:
393
+ return Response(
394
+ message=self._format_response({
395
+ "error": "Task dependencies not met",
396
+ "pending_dependencies": pending_deps
397
+ }),
398
+ break_loop=False
399
+ )
400
+
401
+ # Collect dependency results for context
402
+ dependency_context = ""
403
+ for dep_id in task.get("depends_on", []):
404
+ dep_task = tasks.get(dep_id, {})
405
+ if dep_task.get("status") == "completed" and dep_task.get("result"):
406
+ dep_agent_id = dep_task.get("agent_id", "")
407
+ dep_agent_role = "unknown"
408
+
409
+ if dep_agent_id in team_members:
410
+ dep_agent_role = team_members[dep_agent_id].get("role", "")
411
+
412
+ dependency_context += f"\n--- DEPENDENCY RESULT FROM {dep_agent_role.upper()} (TASK {dep_id}) ---\n"
413
+ dependency_context += f"{dep_task.get('description')}\n\n"
414
+ dependency_context += f"{dep_task.get('result', '')}\n"
415
+ dependency_context += f"--- END OF DEPENDENCY RESULT ---\n"
416
+
417
+ # Add dependency results to task context
418
+ if dependency_context:
419
+ if task["context"]:
420
+ task["context"] += f"\n\nRESULTS FROM DEPENDENCY TASKS:\n{dependency_context}"
421
+ else:
422
+ task["context"] = f"RESULTS FROM DEPENDENCY TASKS:\n{dependency_context}"
423
+
424
+ # Mark dependencies as met
425
+ task["dependencies_met"] = True
426
+ tasks[task_id] = task
427
+ team_leader.set_data("tasks", tasks)
428
+
429
+ # Update task status
430
+ task["status"] = "executing"
431
+ tasks[task_id] = task
432
+ team_leader.set_data("tasks", tasks)
433
+
434
+ # Calculate team progress for context
435
+ total_tasks = len(tasks)
436
+ completed_tasks = sum(1 for t in tasks.values() if t.get("status") == "completed")
437
+
438
+ # Find dependent tasks for this task (tasks that depend on this one)
439
+ dependent_tasks = []
440
+ for t_id, t_data in tasks.items():
441
+ if task_id in t_data.get("depends_on", []):
442
+ if t_data["agent_id"] in team_members:
443
+ dependent_role = team_members[t_data["agent_id"]].get("role", "unknown")
444
+ dependent_tasks.append(f"{dependent_role} (Task {t_id}): {t_data['description'][:30]}...")
445
+
446
+ # Create summary of completed tasks for context
447
+ team_results_summary = []
448
+ for t_id, t_data in tasks.items():
449
+ if t_data["status"] == "completed" and t_id != task_id:
450
+ # Skip direct dependencies as they will be included in full in the context
451
+ if t_id in task.get("depends_on", []):
452
+ continue
453
+
454
+ if t_data["agent_id"] in team_members:
455
+ task_role = team_members[t_data["agent_id"]].get("role", "unknown")
456
+ # Extract a brief summary from the result (first 100 chars)
457
+ result_text = str(t_data.get("result", ""))
458
+ result_summary = result_text[:100] + "..." if len(result_text) > 100 else result_text
459
+ team_results_summary.append(f"{task_role} (Task {t_id}): {t_data['description'][:30]}... | Result summary: {result_summary}")
460
+
461
+ # Format dependency information
462
+ dependency_info = []
463
+ auto_dependency_note = ""
464
+ for dep_id in task.get("depends_on", []):
465
+ if dep_id in tasks:
466
+ dep_data = tasks[dep_id]
467
+ if dep_data["agent_id"] in team_members:
468
+ dep_role = team_members[dep_data["agent_id"]].get("role", "unknown")
469
+ # Find if this was a sequence-based automatic dependency
470
+ if len(task.get("depends_on", [])) == 1 and dep_id in tasks:
471
+ # Check if the current task has an auto-dependency flag
472
+ if task.get("auto_dependency", False):
473
+ auto_dependency_note = f"\nNOTE: Your task automatically depends on the previous task ({dep_id}) due to sequential workflow."
474
+ dependency_info.append(f"{dep_role} (Task {dep_id}): {dep_data['description'][:30]}...")
475
+
476
+ # Enhanced prompt with more comprehensive context
477
+ prompt = f"""You are a {agent_role} with expertise in {', '.join(agent_skills) if agent_skills else 'general tasks'} on the {team_data['name']} team working toward: {team_data['goal']}.
478
+
479
+CONTEXT:
480
+- Team progress: {completed_tasks}/{total_tasks} tasks completed
481
+- Your dependencies: {', '.join(dependency_info) if dependency_info else "None"}{auto_dependency_note}
482
+- Tasks depending on yours: {', '.join(dependent_tasks) if dependent_tasks else "None"}
483
+- Relevant completed work:
484
+{chr(10).join([f" • {summary}" for summary in team_results_summary[:3]])}
485
+{f" • ...and {len(team_results_summary) - 3} more" if len(team_results_summary) > 3 else ""}
486
+
487
+DEPENDENCY RESULTS:
488
+{task['context']}
489
+
490
+YOUR TASK (ID: {task_id}):
491
+{task['description']}
492
+
493
+WORKSPACE FUNDAMENTALS:
494
+- Create complete, well-structured projects before execution
495
+- Save all code to files with logical project structure
496
+- Always verify file creation before trying to run files
497
+- Use consistent file paths throughout your workflow
498
+
499
+SESSION WORKFLOW:
500
+- Session 0: File creation and editing ONLY
501
+- Sessions 1+: Running and testing code ONLY
502
+- Always reset sessions before running new code
503
+- Use the input tool for interactive programs
504
+
505
+ERROR HANDLING STRATEGY:
506
+- If you encounter the same error twice when trying the same approach, switch to an alternative method
507
+- For library/package issues, try a different library or implement a minimal solution from scratch
508
+- When installation fails despite multiple attempts, use a fallback implementation as specified in your task
509
+- Document environment issues and your workaround strategy in your final response
510
+
511
+PROJECT CREATION PATTERN:
512
+1. Create directories and verify structure
513
+2. Create all required files with explicit paths
514
+3. Verify all files exist before execution
515
+4. Run code in separate sessions from creation
516
+5. ALWAYS install packages AND run scripts with terminal runtime to maintain environment consistency
517
+
518
+AVAILABLE TOOLS:
519
+- knowledge_tool: For research and information gathering
520
+- code_execution_tool: For computation, data processing, file operations (prioritize terminal runtime for both package installation AND script execution to maintain environment consistency)
521
+- input: For providing input to interactive programs
522
+- response_tool: REQUIRED for your final output
523
+
524
+TOOL USAGE:
525
+
526
+For file creation ONLY:
527
+```json
528
+{{
529
+ "thoughts": ["Creating project files"],
530
+ "tool_name": "code_execution_tool",
531
+ "tool_args": {{
532
+ "runtime": "python", // Python runtime ONLY for file creation
533
+ "session": 0, // ALWAYS use session 0 for file operations
534
+ "code": "import os\n\n# Create directories\nos.makedirs('project/src', exist_ok=True)\n\n# Create files\nwith open('project/src/main.py', 'w') as f:\n f.write(\"print('Hello world')\")"
535
+ }}
536
+}}
537
+```
538
+
539
+For executing ANY Python code (imports, tests, etc):
540
+```json
541
+{{
542
+ "thoughts": ["Testing code/imports"],
543
+ "tool_name": "code_execution_tool",
544
+ "tool_args": {{
545
+ "runtime": "terminal", // ALWAYS use terminal for running ANY Python code
546
+ "session": 1,
547
+ "code": "python -c 'import pandas; print(pandas.__version__)'"
548
+ }}
549
+}}
550
+```
551
+
552
+For installing packages:
553
+```json
554
+{{
555
+ "thoughts": ["Installing required packages"],
556
+ "tool_name": "code_execution_tool",
557
+ "tool_args": {{
558
+ "runtime": "terminal",
559
+ "session": 1,
560
+ "code": "pip install pandas matplotlib"
561
+ }}
562
+}}
563
+```
564
+
565
+For running and testing code:
566
+```json
567
+{{
568
+ "thoughts": ["Reset session before running"],
569
+ "tool_name": "code_execution_tool",
570
+ "tool_args": {{
571
+ "runtime": "reset",
572
+ "session": 1
573
+ }}
574
+}}
575
+```
576
+```json
577
+{{
578
+ "thoughts": ["Running the created file"],
579
+ "tool_name": "code_execution_tool",
580
+ "tool_args": {{
581
+ "runtime": "terminal",
582
+ "session": 1,
583
+ "code": "python project/src/main.py"
584
+ }}
585
+}}
586
+```
587
+
588
+For checking environment:
589
+```json
590
+{{
591
+ "thoughts": ["Verifying Python environment"],
592
+ "tool_name": "code_execution_tool",
593
+ "tool_args": {{
594
+ "runtime": "terminal",
595
+ "session": 1,
596
+ "code": "which python && python --version && pip list | grep pandas"
597
+ }}
598
+}}
599
+```
600
+
601
+For research:
602
+```json
603
+{{
604
+ "thoughts": ["Need information about X"],
605
+ "tool_name": "knowledge_tool",
606
+ "tool_args": {{
607
+ "question": "Specific question about my task"
608
+ }}
609
+}}
610
+```
611
+
612
+For your final response (REQUIRED):
613
+```json
614
+{{
615
+ "thoughts": ["Task complete, delivering results"],
616
+ "tool_name": "response",
617
+ "tool_args": {{
618
+ "text": "Complete, well-structured deliverable with all necessary details"
619
+ }}
620
+}}
621
+```
622
+
623
+IMPORTANT: When executing terminal commands, monitor the output carefully for errors, especially ModuleNotFoundError or ImportError. If library imports fail after installation, verify that your terminal commands and Python code are using the same environment.
624
+
625
+EXECUTION STRATEGY:
626
+1. UNDERSTAND the task requirements
627
+2. PLAN your approach before writing any code
628
+3. CREATE complete project with all necessary files
629
+4. TEST your implementation thoroughly
630
+5. PIVOT quickly if you encounter repeated errors with the same approach
631
+6. DELIVER using the response tool
632
+
633
+Remember: The response_tool is REQUIRED for your final output.
634
+"""
635
+
636
+ # Execute task using call_subordinate pattern
637
+ # Let the user know we're delegating to a team member
638
+ self.log.update(progress=f"Delegating to {agent_role} agent...")
639
+
640
+ # Log the full prompt being sent to the agent for debugging and transparency
641
+ self.log.update(context=f"Task Context Being Passed:\n\n{prompt}")
642
+
643
+ try:
644
+ # Execute task using call_subordinate pattern
645
+ agent_instance.hist_add_user_message(UserMessage(message=prompt, attachments=[]))
646
+ result = await agent_instance.monologue()
647
+ self.log.update(progress=f"Received response from {agent_role} agent")
648
+ except Exception as e:
649
+ self.log.update(error=f"Error executing task: {str(e)}")
650
+ result = f"Error executing task: {str(e)}"
651
+
652
+ # Update task with result
653
+ task["status"] = "completed"
654
+ task["completed_at"] = time.time()
655
+ task["result"] = result
656
+ tasks[task_id] = task
657
+ team_leader.set_data("tasks", tasks)
658
+
659
+ # Find dependent tasks that can now be executed
660
+ dependent_tasks = []
661
+ for t_id, t_data in tasks.items():
662
+ if task_id in t_data.get("depends_on", []) and t_data["status"] == "assigned":
663
+ dependent_tasks.append(t_id)
664
+
665
+ # Count remaining tasks
666
+ remaining_tasks = sum(1 for t in tasks.values() if t["status"] == "assigned")
667
+ executable_tasks = sum(1 for t_id, t_data in tasks.items()
668
+ if t_data["status"] == "assigned" and
669
+ all(dep_id not in t_data.get("depends_on", []) or
670
+ tasks.get(dep_id, {}).get("status") == "completed"
671
+ for dep_id in t_data.get("depends_on", [])))
672
+
673
+ # Get list of executable tasks
674
+ executable_task_list = []
675
+ for t_id, t_data in tasks.items():
676
+ if (t_data["status"] == "assigned" and
677
+ all(dep_id not in t_data.get("depends_on", []) or
678
+ tasks.get(dep_id, {}).get("status") == "completed"
679
+ for dep_id in t_data.get("depends_on", []))):
680
+ assigned_to = "unknown"
681
+ if t_data["agent_id"] in team_members:
682
+ assigned_to = team_members[t_data["agent_id"]].get("role", "unknown")
683
+ executable_task_list.append(f"{t_id} (assigned to {assigned_to})")
684
+
685
+ if dependent_tasks:
686
+ next_step = f"Step 3 CONTINUE: EXECUTE DEPENDENT TASKS that can now run: {', '.join(dependent_tasks)}. Execute ALL tasks before moving to the next step."
687
+ elif remaining_tasks == 0:
688
+ next_step = "Step 4: COMPILE AND SYNTHESIZE RESULTS using get_results action followed by integrate_results action to create a comprehensive final deliverable."
689
+ elif executable_tasks > 0:
690
+ next_step = f"Step 3 CONTINUE: EXECUTE REMAINING TASKS - {executable_tasks} tasks ready to execute: {', '.join(executable_task_list)}. Complete ALL tasks before proceeding."
691
+ else:
692
+ next_step = f"Step 3 CONTINUE: EXECUTE OTHER TASKS after their dependencies are met. {remaining_tasks} tasks remain. Complete ALL tasks before proceeding."
693
+
694
+ return Response(
695
+ message=self._format_response({
696
+ "team_id": team_id,
697
+ "task_id": task_id,
698
+ "agent_id": agent_id,
699
+ "status": "completed",
700
+ "result_summary": result[:200] + "..." if len(result) > 200 else result,
701
+ "dependent_tasks": dependent_tasks,
702
+ "remaining_tasks": remaining_tasks,
703
+ "next_step": next_step
704
+ }),
705
+ break_loop=False
706
+ )
707
+
708
+ async def _get_task_result(self, team_id, task_id="", **kwargs):
709
+ """Get the result of a specific task"""
710
+ self.log.update(progress=f"Retrieving result for task {task_id} in team {team_id}...")
711
+
712
+ # Get team data
713
+ teams = self.agent.get_data("teams") or {}
714
+ if not team_id or team_id not in teams:
715
+ available_teams = list(teams.keys())
716
+ error_msg = f"Team {team_id} not found"
717
+ self.log.update(error=error_msg)
718
+
719
+ if available_teams:
720
+ self.log.update(progress=f"Available teams: {', '.join(available_teams)}")
721
+
722
+ return Response(
723
+ message=self._format_response({
724
+ "error": error_msg,
725
+ "available_teams": available_teams,
726
+ "next_step": "Create a team first with the 'create' action or use a valid team_id"
727
+ }),
728
+ break_loop=False
729
+ )
730
+
731
+ team_data = teams[team_id]
732
+ team_leader = team_data["leader_agent"]
733
+
734
+ # Get tasks and team members
735
+ tasks = team_leader.get_data("tasks") or {}
736
+ team_members = team_leader.get_data("team_members") or {}
737
+
738
+ # Check if task exists
739
+ if not task_id or task_id not in tasks:
740
+ return Response(
741
+ message=self._format_response({
742
+ "error": f"Task {task_id} not found in team {team_id}",
743
+ "available_tasks": list(tasks.keys()) if tasks else []
744
+ }),
745
+ break_loop=False
746
+ )
747
+
748
+ task_data = tasks[task_id]
749
+
750
+ # Check if task is completed
751
+ if task_data["status"] != "completed":
752
+ return Response(
753
+ message=self._format_response({
754
+ "error": f"Task {task_id} is not completed (current status: {task_data['status']})",
755
+ "task_id": task_id,
756
+ "status": task_data["status"],
757
+ "next_step": "Execute this task before trying to retrieve its result"
758
+ }),
759
+ break_loop=False
760
+ )
761
+
762
+ # Get agent information
763
+ agent_id = task_data["agent_id"]
764
+ agent_role = "unknown"
765
+ if agent_id in team_members:
766
+ agent_role = team_members[agent_id]["role"]
767
+
768
+ # Return task result
769
+ return Response(
770
+ message=self._format_response({
771
+ "team_id": team_id,
772
+ "task_id": task_id,
773
+ "agent_id": agent_id,
774
+ "agent_role": agent_role,
775
+ "task_description": task_data["description"],
776
+ "status": "completed",
777
+ "completed_at": task_data.get("completed_at"),
778
+ "result": task_data["result"],
779
+ "next_step": "Use this result as input for other tasks or incorporate it into your workflow"
780
+ }),
781
+ break_loop=False
782
+ )
783
+
784
+ async def _send_message(self, team_id, from_agent="", to_agent="", content="", **kwargs):
785
+ """Send a message from one agent to another"""
786
+ # Get team data
787
+ teams = self.agent.get_data("teams")
788
+ if not team_id or team_id not in teams:
789
+ return Response(
790
+ message=self._format_response({
791
+ "error": f"Team {team_id} not found",
792
+ "available_teams": list(teams.keys()) if teams else []
793
+ }),
794
+ break_loop=False
795
+ )
796
+
797
+ team_data = teams[team_id]
798
+ team_leader = team_data["leader_agent"]
799
+
800
+ # Get team members
801
+ team_members = team_leader.get_data("team_members") or {}
802
+ if not from_agent or from_agent not in team_members:
803
+ return Response(
804
+ message=self._format_response({
805
+ "error": f"Source agent {from_agent} not found",
806
+ "available_agents": list(team_members.keys()) if team_members else []
807
+ }),
808
+ break_loop=False
809
+ )
810
+
811
+ if not to_agent or to_agent not in team_members:
812
+ return Response(
813
+ message=self._format_response({
814
+ "error": f"Target agent {to_agent} not found",
815
+ "available_agents": list(team_members.keys()) if team_members else []
816
+ }),
817
+ break_loop=False
818
+ )
819
+
820
+ if not content:
821
+ return Response(
822
+ message=self._format_response({
823
+ "error": "Message content is required"
824
+ }),
825
+ break_loop=False
826
+ )
827
+
828
+ # Create message ID
829
+ message_id = f"msg_{str(uuid.uuid4())[:6]}"
830
+
831
+ # Get agent instances
832
+ from_role = team_members[from_agent]["role"]
833
+ to_agent_instance = team_members[to_agent]["agent"]
834
+
835
+ # Format the message
836
+ formatted_message = f"[MESSAGE from {from_role} agent]: {content}"
837
+
838
+ # Store message in recipient's pending messages
839
+ pending_messages = to_agent_instance.get_data("pending_messages") or []
840
+ pending_messages.append(formatted_message)
841
+ to_agent_instance.set_data("pending_messages", pending_messages)
842
+
843
+ # Store message in team history
844
+ messages = team_leader.get_data("messages") or []
845
+ message = {
846
+ "id": message_id,
847
+ "from": from_agent,
848
+ "to": to_agent,
849
+ "content": content,
850
+ "timestamp": time.time()
851
+ }
852
+ messages.append(message)
853
+ team_leader.set_data("messages", messages)
854
+
855
+ return Response(
856
+ message=self._format_response({
857
+ "team_id": team_id,
858
+ "message_id": message_id,
859
+ "from": from_agent,
860
+ "to": to_agent,
861
+ "status": "delivered",
862
+ "next_step": "The message will be delivered when the recipient agent executes its next task"
863
+ }),
864
+ break_loop=False
865
+ )
866
+
867
+ async def _get_results(self, team_id, **kwargs):
868
+ """Get results from all tasks in a team"""
869
+ # Add additional logging for debugging
870
+ self.log.update(progress=f"Retrieving results for team {team_id}...")
871
+
872
+ # Get team data with better error checking
873
+ teams = self.agent.get_data("teams") or {}
874
+ if not team_id or team_id not in teams:
875
+ available_teams = list(teams.keys())
876
+ error_msg = f"Team {team_id} not found"
877
+ self.log.update(error=error_msg)
878
+
879
+ if available_teams:
880
+ self.log.update(progress=f"Available teams: {', '.join(available_teams)}")
881
+
882
+ return Response(
883
+ message=self._format_response({
884
+ "error": error_msg,
885
+ "available_teams": available_teams,
886
+ "next_step": "Create a team first with the 'create' action or use a valid team_id"
887
+ }),
888
+ break_loop=False
889
+ )
890
+
891
+ team_data = teams[team_id]
892
+ team_leader = team_data["leader_agent"]
893
+
894
+ # Get tasks and team members
895
+ tasks = team_leader.get_data("tasks") or {}
896
+ team_members = team_leader.get_data("team_members") or {}
897
+
898
+ # Organize results by agent and task
899
+ results = {}
900
+ completed_tasks = 0
901
+ total_tasks = len(tasks)
902
+
903
+ for task_id, task_data in tasks.items():
904
+ agent_id = task_data["agent_id"]
905
+ if agent_id not in results:
906
+ agent_role = team_members[agent_id]["role"] if agent_id in team_members else "unknown"
907
+ results[agent_id] = {
908
+ "role": agent_role,
909
+ "tasks": {}
910
+ }
911
+
912
+ # Add task result
913
+ task_status = task_data["status"]
914
+ if task_status == "completed":
915
+ completed_tasks += 1
916
+
917
+ results[agent_id]["tasks"][task_id] = {
918
+ "description": task_data["description"],
919
+ "status": task_status,
920
+ "result": task_data.get("result", None) if task_status == "completed" else None
921
+ }
922
+
923
+ # Determine completion status
924
+ completion_status = f"{completed_tasks}/{total_tasks} tasks completed"
925
+
926
+ # Provide appropriate next steps based on completion status
927
+ if completed_tasks < total_tasks:
928
+ pending_tasks = []
929
+ for task_id, task_data in tasks.items():
930
+ if task_data["status"] != "completed":
931
+ agent_id = task_data["agent_id"]
932
+ agent_role = "unknown"
933
+ if agent_id in team_members:
934
+ agent_role = team_members[agent_id]["role"]
935
+ pending_tasks.append(f"{task_id} (assigned to {agent_role})")
936
+
937
+ next_step = f"Step 3 INCOMPLETE: {total_tasks - completed_tasks} TASKS STILL PENDING. Complete these tasks first: {', '.join(pending_tasks)}. Only after ALL tasks are completed, use integrate_results to synthesize the final deliverable."
938
+ else:
939
+ next_step = "Step 4: SYNTHESIZE ALL INFORMATION using the integrate_results action to create a comprehensive final deliverable that addresses the original goal."
940
+
941
+ return Response(
942
+ message=self._format_response({
943
+ "team_id": team_id,
944
+ "name": team_data["name"],
945
+ "goal": team_data["goal"],
946
+ "completion": completion_status,
947
+ "results": results,
948
+ "next_step": next_step
949
+ }),
950
+ break_loop=False
951
+ )
952
+
953
+ def _find_agent_by_role(self, team_id, role):
954
+ """Helper to find agent by role instead of ID"""
955
+ teams = self.agent.get_data("teams") or {}
956
+ if team_id not in teams:
957
+ return None
958
+
959
+ team_leader = teams[team_id]["leader_agent"]
960
+ team_members = team_leader.get_data("team_members") or {}
961
+
962
+ for agent_id, agent_data in team_members.items():
963
+ if agent_data["role"].lower() == role.lower():
964
+ return agent_id
965
+
966
+ return None
967
+
968
+ async def _team_status(self, team_id, **kwargs):
969
+ """Get comprehensive team status"""
970
+ # Add progress logging
971
+ self.log.update(progress=f"Getting status for team {team_id}...")
972
+
973
+ # Get team data with better error checking
974
+ teams = self.agent.get_data("teams") or {}
975
+ if not team_id or team_id not in teams:
976
+ available_teams = list(teams.keys())
977
+ error_msg = f"Team {team_id} not found"
978
+ self.log.update(error=error_msg)
979
+
980
+ if available_teams:
981
+ self.log.update(progress=f"Available teams: {', '.join(available_teams)}")
982
+
983
+ return Response(
984
+ message=self._format_response({
985
+ "error": error_msg,
986
+ "available_teams": available_teams,
987
+ "next_step": "Create a team first with the 'create' action or use a valid team_id"
988
+ }),
989
+ break_loop=False
990
+ )
991
+
992
+ team_data = teams[team_id]
993
+ team_leader = team_data["leader_agent"]
994
+
995
+ # Get tasks and team members
996
+ tasks = team_leader.get_data("tasks") or {}
997
+ team_members = team_leader.get_data("team_members") or {}
998
+ messages = team_leader.get_data("messages") or []
999
+
1000
+ # Calculate statistics
1001
+ total_tasks = len(tasks)
1002
+ completed_tasks = sum(1 for t in tasks.values() if t["status"] == "completed")
1003
+ in_progress_tasks = sum(1 for t in tasks.values() if t["status"] == "executing")
1004
+ pending_tasks = total_tasks - completed_tasks - in_progress_tasks
1005
+
1006
+ # Organize agent workloads
1007
+ agent_workloads = {}
1008
+ for agent_id, agent_data in team_members.items():
1009
+ agent_tasks = [t for t in tasks.values() if t["agent_id"] == agent_id]
1010
+ agent_workloads[agent_id] = {
1011
+ "role": agent_data["role"],
1012
+ "total_tasks": len(agent_tasks),
1013
+ "completed": sum(1 for t in agent_tasks if t["status"] == "completed"),
1014
+ "in_progress": sum(1 for t in agent_tasks if t["status"] == "executing"),
1015
+ "pending": sum(1 for t in agent_tasks if t["status"] == "assigned")
1016
+ }
1017
+
1018
+ # Map of tasks to their dependencies
1019
+ task_dependencies = {}
1020
+ for task_id, task_data in tasks.items():
1021
+ deps = task_data.get("depends_on", [])
1022
+ if deps:
1023
+ task_dependencies[task_id] = {
1024
+ "depends_on": deps,
1025
+ "description": task_data.get("description", ""),
1026
+ "status": task_data.get("status", "unknown")
1027
+ }
1028
+
1029
+ # Find next tasks to execute based on dependencies
1030
+ next_tasks = []
1031
+ for task_id, task_data in tasks.items():
1032
+ if task_data["status"] == "assigned":
1033
+ dependencies_ready = True
1034
+ for dep_id in task_data.get("depends_on", []):
1035
+ if dep_id not in tasks or tasks[dep_id]["status"] != "completed":
1036
+ dependencies_ready = False
1037
+ break
1038
+ if dependencies_ready:
1039
+ next_tasks.append(task_id)
1040
+
1041
+ self.log.update(progress="Team status analysis complete")
1042
+
1043
+ return Response(
1044
+ message=self._format_response({
1045
+ "team_id": team_id,
1046
+ "name": team_data["name"],
1047
+ "goal": team_data["goal"],
1048
+ "statistics": {
1049
+ "total_tasks": total_tasks,
1050
+ "completed_tasks": completed_tasks,
1051
+ "in_progress_tasks": in_progress_tasks,
1052
+ "pending_tasks": pending_tasks,
1053
+ "agent_count": len(team_members),
1054
+ "message_count": len(messages)
1055
+ },
1056
+ "agents": agent_workloads,
1057
+ "task_dependencies": task_dependencies,
1058
+ "next_executable_tasks": next_tasks,
1059
+ "workflow_status": "complete" if pending_tasks == 0 and in_progress_tasks == 0 else "in_progress"
1060
+ }),
1061
+ break_loop=False
1062
+ )
1063
+
1064
+ def _format_response(self, data):
1065
+ """Format the response as a JSON string according to agent zero's requirements"""
1066
+ thoughts = [
1067
+ "Processed team agent request",
1068
+ "Generated appropriate response"
1069
+ ]
1070
+
1071
+ # Add helpful next_step if not present
1072
+ if "error" in data and "next_step" not in data:
1073
+ if "available_teams" in data and data["available_teams"]:
1074
+ data["next_step"] = f"Use a valid team_id from: {', '.join(data['available_teams'])}"
1075
+ else:
1076
+ data["next_step"] = "Create a team first with the 'create' action"
1077
+
1078
+ # Add specific formatting guidance for get_results response
1079
+ if "results" in data and "error" not in data and "next_step" not in data:
1080
+ data["next_step"] = "Format your response to the user as a properly formatted JSON message using the response tool. Synthesize the individual contributions into a cohesive final product that addresses the user's original request."
1081
+
1082
+ # Add specific guidance for integration results
1083
+ if "integrated_result" in data and "error" not in data and "next_step" not in data:
1084
+ data["next_step"] = "Use the response tool to share these integrated results with the user in a format that directly addresses their original request. Consider using code_execution tool if specific file output is needed."
1085
+
1086
+ # Add context and summary for non-error responses to help maintain task focus
1087
+ if "error" not in data and "team_id" in data:
1088
+ # Get team data to add context
1089
+ teams = self.agent.get_data("teams") or {}
1090
+ team_id = data["team_id"]
1091
+
1092
+ if team_id in teams:
1093
+ team_data = teams[team_id]
1094
+
1095
+ # Add team context if not already present
1096
+ if "name" not in data and "goal" not in data:
1097
+ data["team_name"] = team_data.get("name", "Unknown Team")
1098
+ data["team_goal"] = team_data.get("goal", "Unknown Goal")
1099
+
1100
+ # Add progress summary if team leader exists
1101
+ if "leader_agent" in team_data:
1102
+ team_leader = team_data["leader_agent"]
1103
+ tasks = team_leader.get_data("tasks") or {}
1104
+ team_members = team_leader.get_data("team_members") or {}
1105
+
1106
+ # Add team composition summary with agent IDs
1107
+ if team_members and "team_composition" not in data:
1108
+ team_composition = []
1109
+ for agent_id, member_data in team_members.items():
1110
+ if isinstance(member_data, dict) and "role" in member_data:
1111
+ team_composition.append(f"{member_data['role']} ({agent_id})")
1112
+
1113
+ if team_composition:
1114
+ data["team_composition"] = f"{len(team_composition)} members: {', '.join(team_composition)}"
1115
+
1116
+ # Add task progress summary
1117
+ if tasks and "task_progress" not in data:
1118
+ total = len(tasks)
1119
+ completed = sum(1 for t in tasks.values() if t.get("status") == "completed")
1120
+ executing = sum(1 for t in tasks.values() if t.get("status") == "executing")
1121
+ assigned = sum(1 for t in tasks.values() if t.get("status") == "assigned")
1122
+
1123
+ data["task_progress"] = f"{completed}/{total} tasks completed, {executing} executing, {assigned} pending"
1124
+
1125
+ # Add task details summary if relevant
1126
+ if "task_id" in data and data["task_id"] in tasks:
1127
+ task_data = tasks[data["task_id"]]
1128
+ agent_id = task_data.get("agent_id", "unknown")
1129
+ agent_role = "unknown"
1130
+ if agent_id in team_members and isinstance(team_members[agent_id], dict):
1131
+ agent_role = team_members[agent_id].get("role", "unknown")
1132
+
1133
+ # Add a short task summary with keywords
1134
+ description = task_data.get("description", "")
1135
+ keywords = " ".join(description.split()[:5]) + "..." if len(description.split()) > 5 else description
1136
+
1137
+ data["task_summary"] = f"Task {data['task_id']} assigned to {agent_role} ({agent_id}): {keywords}"
1138
+
1139
+ # Add comprehensive ordered task list
1140
+ if tasks:
1141
+ # First try to sort by explicit sequence number, fall back to creation timestamp
1142
+ sorted_tasks = sorted(tasks.items(), key=lambda x: (
1143
+ x[1].get("sequence_num", float('inf')), # Sort by sequence first
1144
+ x[1].get("created_at", 0) # Then by creation time
1145
+ ))
1146
+
1147
+ tasks_ordered = []
1148
+ for task_id, task_data in sorted_tasks:
1149
+ agent_id = task_data.get("agent_id", "unknown")
1150
+ agent_role = "unknown"
1151
+ if agent_id in team_members and isinstance(team_members[agent_id], dict):
1152
+ agent_role = team_members[agent_id].get("role", "unknown")
1153
+
1154
+ # Create a concise description
1155
+ description = task_data.get("description", "")
1156
+ short_desc = " ".join(description.split()[:6]) + "..." if len(description.split()) > 6 else description
1157
+
1158
+ # Add dependencies info if any
1159
+ deps_info = ""
1160
+ if task_data.get("depends_on"):
1161
+ deps_info = f" (depends on: {', '.join(task_data['depends_on'])})"
1162
+
1163
+ # Format the task entry with status, sequence number, and indices
1164
+ status = task_data.get("status", "unknown")
1165
+ seq_num = task_data.get("sequence_num", "?")
1166
+ task_entry = f"#{seq_num} {task_id} [{status}]: {agent_role} - {short_desc}{deps_info}"
1167
+ tasks_ordered.append(task_entry)
1168
+
1169
+ if tasks_ordered:
1170
+ data["tasks_ordered"] = tasks_ordered
1171
+
1172
+ # Add task overview if this is a team status response (keep this for backward compatibility)
1173
+ if "task_overview" not in data and len(tasks) > 0 and "task_id" not in data:
1174
+ task_overview = []
1175
+ for task_id, task_data in tasks.items():
1176
+ agent_id = task_data.get("agent_id", "unknown")
1177
+ status = task_data.get("status", "unknown")
1178
+ description = task_data.get("description", "")
1179
+ short_desc = " ".join(description.split()[:3]) + "..." if len(description.split()) > 3 else description
1180
+
1181
+ agent_role = "unknown"
1182
+ if agent_id in team_members and isinstance(team_members[agent_id], dict):
1183
+ agent_role = team_members[agent_id].get("role", "unknown")
1184
+
1185
+ task_overview.append(f"{task_id} ({status}): {agent_role} - {short_desc}")
1186
+
1187
+ if task_overview:
1188
+ data["task_overview"] = task_overview[:5] # Limit to 5 tasks to avoid clutter
1189
+ if len(task_overview) > 5:
1190
+ data["task_overview"].append(f"...and {len(task_overview) - 5} more tasks")
1191
+
1192
+ formatted_response = {
1193
+ "thoughts": thoughts,
1194
+ "tool_name": "team_agent",
1195
+ "tool_args": data
1196
+ }
1197
+
1198
+ return json.dumps(formatted_response, indent=2)
1199
+
1200
+ async def _integrate_results(self, team_id, **kwargs):
1201
+ """Integrate results from all team members into a final product"""
1202
+ # Get team data
1203
+ teams = self.agent.get_data("teams") or {}
1204
+ if not team_id or team_id not in teams:
1205
+ available_teams = list(teams.keys())
1206
+ error_msg = f"Team {team_id} not found"
1207
+ self.log.update(error=error_msg)
1208
+
1209
+ if available_teams:
1210
+ self.log.update(progress=f"Available teams: {', '.join(available_teams)}")
1211
+
1212
+ return Response(
1213
+ message=self._format_response({
1214
+ "error": error_msg,
1215
+ "available_teams": available_teams,
1216
+ "next_step": "Create a team first with the 'create' action or use a valid team_id"
1217
+ }),
1218
+ break_loop=False
1219
+ )
1220
+
1221
+ team_data = teams[team_id]
1222
+ team_leader = team_data["leader_agent"]
1223
+ tasks = team_leader.get_data("tasks") or {}
1224
+ team_members = team_leader.get_data("team_members") or {}
1225
+
1226
+ # Collect all completed results
1227
+ completed_results = {}
1228
+ for task_id, task_data in tasks.items():
1229
+ if task_data["status"] == "completed":
1230
+ agent_id = task_data["agent_id"]
1231
+ if agent_id in team_members:
1232
+ role = team_members[agent_id]["role"]
1233
+ completed_results[role] = {
1234
+ "task": task_data["description"],
1235
+ "result": task_data["result"]
1236
+ }
1237
+
1238
+ if not completed_results:
1239
+ return Response(
1240
+ message=self._format_response({
1241
+ "team_id": team_id,
1242
+ "error": "No completed tasks found to integrate",
1243
+ "next_step": "Execute tasks first with the execute_task action before attempting integration"
1244
+ }),
1245
+ break_loop=False
1246
+ )
1247
+
1248
+ # Check for any pending tasks and provide warning
1249
+ pending_tasks = sum(1 for t in tasks.values() if t["status"] != "completed")
1250
+ pending_warning = ""
1251
+ if pending_tasks > 0:
1252
+ pending_warning = f"\n\nNOTE: There are still {pending_tasks} pending tasks in this team. This integration only includes completed tasks."
1253
+
1254
+ # Enhanced integration prompt with better guidance
1255
+ integration_prompt = f"""
1256
+ As the leader of the {team_data['name']} team, your critical responsibility is to synthesize all team contributions
1257
+ into a cohesive, polished final product that fulfills our goal: {team_data['goal']}
1258
+
1259
+ COMPLETED TEAM CONTRIBUTIONS:
1260
+ {json.dumps(completed_results, indent=2)}
1261
+ {pending_warning}
1262
+
1263
+ INTEGRATION OBJECTIVE:
1264
+ Transform these separate contributions into a seamless, unified deliverable that achieves our team goal and meets the user's needs.
1265
+
1266
+ YOUR INTEGRATION ROLE:
1267
+ 1. Identify the key insights and valuable content from each contribution
1268
+ 2. Resolve any inconsistencies or conflicts between contributions
1269
+ 3. Establish a logical flow and structure for the integrated result
1270
+ 4. Ensure all critical information is included without unnecessary repetition
1271
+ 5. Maintain a consistent voice, style, and level of technical detail
1272
+ 6. Verify that the final product directly addresses the original goal
1273
+
1274
+ INTEGRATION METHODOLOGY:
1275
+ - Begin with a high-level synthesis plan
1276
+ - Extract core content from each contribution
1277
+ - Create a unified structure that builds logically
1278
+ - Fill gaps and eliminate redundancies
1279
+ - Add transitions to create seamless flow between sections
1280
+ - Review for completeness, coherence, and alignment with the goal
1281
+
1282
+ QUALITY CRITERIA FOR FINAL DELIVERABLE:
1283
+ - Comprehensiveness: Covers all essential aspects of the topic
1284
+ - Coherence: Presents a unified perspective rather than disjointed views
1285
+ - Clarity: Communicates ideas in a clear, accessible manner
1286
+ - Conciseness: Avoids unnecessary repetition while maintaining completeness
1287
+ - Alignment: Directly addresses the original goal
1288
+ - Readability: Well-structured with appropriate transitions and flow
1289
+
1290
+ OUTPUT FORMAT REQUIREMENTS:
1291
+ You MUST respond using the exact JSON format below to ensure proper delivery to the user:
1292
+
1293
+ ```json
1294
+ {{
1295
+ "thoughts": [
1296
+ "Your integration strategy and approach",
1297
+ "How you synthesized the different contributions",
1298
+ "Your assessment of the integrated final product"
1299
+ ],
1300
+ "tool_name": "response",
1301
+ "tool_args": {{
1302
+ "text": "Your complete integrated result here. This should be comprehensive, cohesive, and directly address the team goal."
1303
+ }}
1304
+ }}
1305
+ ```
1306
+
1307
+ The "text" field must contain the complete integrated final product, ready for delivery to the user.
1308
+ """
1309
+
1310
+ # Let team leader create the integrated result
1311
+ self.log.update(progress="Asking team leader to integrate results...")
1312
+
1313
+ try:
1314
+ # Execute integration using call to team leader
1315
+ team_leader.hist_add_user_message(UserMessage(message=integration_prompt, attachments=[]))
1316
+ integrated_result = await team_leader.monologue()
1317
+ self.log.update(progress="Received integrated response from team leader")
1318
+ except Exception as e:
1319
+ self.log.update(error=f"Error during integration: {str(e)}")
1320
+ integrated_result = f"Error during integration: {str(e)}"
1321
+
1322
+ # Create appropriate next steps based on task status
1323
+ if pending_tasks > 0:
1324
+ next_step = f"Step 5: DELIVER FINAL PRODUCT - Summarize and present integrated results to the user using the response tool. To get a more complete result, consider completing the remaining {pending_tasks} tasks first."
1325
+ else:
1326
+ next_step = "Step 5: DELIVER FINAL PRODUCT - Summarize and present these integrated results to the user as a comprehensive deliverable using the response tool. Use the text field to provide the complete answer that addresses the original request."
1327
+
1328
+ return Response(
1329
+ message=self._format_response({
1330
+ "team_id": team_id,
1331
+ "status": "integrated",
1332
+ "integrated_result": integrated_result,
1333
+ "pending_tasks": pending_tasks,
1334
+ "next_step": next_step
1335
+ }),
1336
+ break_loop=False
1337
+ )
\ No newline at end of file