Added: Task edit/update/delete methods, auto dependency true/false toggle, team leader planning phase, and task document handling, team leader integrate results task document handling *allows for persistent development between teams by leveraging team leader as an investigative task manager before and after team agent task execution cycles*

Added: Task edit/update/delete methods, auto dependency true/false toggle, team leader planning phase, and task document handling, team leader integrate results task document handling *allows for persistent development between teams by leveraging team leader as an investigative task manager before and after team agent task execution cycles*

deci committed May 12, 2025 at 18:58 UTC bc32c16e63ada9db32e56b5ee5be83e9bce7c87f
1 file changed +681 -53
python/tools/team_agent.py
+681 -53
@@ -3,6 +3,7 @@ from python.helpers.tool import Tool, Response
3 import uuid
4 import json
5 import time
6 +import os
7
8 class TeamAgent(Tool):
9 """
@@ -33,9 +34,73 @@ class TeamAgent(Tool):
34 team_id = self.agent.get_data("active_team_id")
35 self.log.update(progress=f"Using active team ID: {team_id}")
36
36 - # Handle different actions
37 + # Enhanced handling for create action to include document status and separate planning
38 if action == "create":
38 - return await self._create_team(**kwargs)
39 + # Determine project name for doc path
40 + project_name = kwargs.get("name", "project").replace(" ", "_").lower()
41 + doc_dir = "/root/team_task"
42 + doc_path = os.path.join(doc_dir, f"{project_name}.md")
43 + template_path = os.path.join(doc_dir, "template_project_name.md")
44 +
45 + # Log start of document check and planning phase
46 + self.log.update(progress=f"Starting planning phase for project: {project_name}...")
47 +
48 + # --- Step 1: Run Planning Phase ---
49 + # The planning phase now handles doc existence checks, reading, template use, and updates internally.
50 + # It returns a dictionary containing the planning summary and confirmed doc_path.
51 + planning_result = await self._team_planning_phase(**kwargs)
52 +
53 + # Extract planning details (handle potential errors if planning fails, though _team_planning_phase should manage its errors)
54 + planning_summary = planning_result.get("planning_summary", "Planning phase failed to generate summary.")
55 + # Use the doc_path confirmed/returned by the planning phase
56 + doc_path_from_planning = planning_result.get("doc_path", doc_path) # Fallback to original if needed
57 + planning_status = planning_result.get("status", "unknown")
58 +
59 + self.log.update(progress=f"Planning phase complete. Status: {planning_status}. Document at: {doc_path_from_planning}")
60 +
61 + # --- Step 2: Create the Team ---
62 + # Now that planning is done and the doc is handled, create the team structure.
63 + # Pass the confirmed doc_path to _create_team.
64 + self.log.update(progress="Creating team data structure...")
65 + # Pass kwargs and the confirmed doc_path
66 + create_response = await self._create_team(doc_path=doc_path_from_planning, **kwargs)
67 +
68 + # Extract team_id from the create_response message (which should be JSON)
69 + team_id_from_create = None
70 + create_data = {}
71 + try:
72 + # Assuming create_response.message is a JSON string from _format_response
73 + create_data = json.loads(create_response.message)
74 + # Access the actual arguments passed to the tool via 'tool_args'
75 + team_id_from_create = create_data.get("tool_args", {}).get("team_id")
76 + except (json.JSONDecodeError, AttributeError, TypeError) as e:
77 + self.log.update(error=f"Failed to parse team_id from _create_team response: {e}")
78 + # Handle error: maybe return an error response or log critical failure
79 + return Response(
80 + message=self._format_response({
81 + "error": "Failed to create team properly - could not extract team_id.",
82 + "planning_summary": planning_summary,
83 + "doc_path": doc_path_from_planning,
84 + "next_step": "Internal error during team creation. Please report this issue."
85 + }),
86 + break_loop=True # Stop the loop on critical failure
87 + )
88 +
89 + # --- Step 3: Combine and Return ---
90 + # Combine planning info and creation info into one response for the user.
91 + self.log.update(progress=f"Team {team_id_from_create} created successfully.")
92 + return Response(
93 + message=self._format_response({
94 + "status": "team_created",
95 + "team_id": team_id_from_create, # Use the extracted team_id
96 + "planning_summary": planning_summary, # Include the planning summary
97 + "doc_path": doc_path_from_planning, # Use the confirmed doc path
98 + "doc_status": "updated", # Indicate doc was handled in planning
99 + "next_step": f"Team created with ID '{team_id_from_create}'. Planning document updated at '{doc_path_from_planning}'.\n\nNEXT: Use 'add_agent' with team_id '{team_id_from_create}' to add ALL necessary team members BEFORE assigning any tasks. Use the 'Role-Specific Task Assignment Guidance' from the planning summary when assigning tasks later."
100 + }),
101 + break_loop=False # Continue after successful creation
102 + )
103 +
104 # Handle actions with better logging
105 try:
106 if action == "create":
@@ -45,7 +110,8 @@ class TeamAgent(Tool):
110 return await self._add_agent(team_id, **kwargs)
111 elif action == "assign_task":
112 self.log.update(progress=f"Assigning task to agent in team {team_id}...")
48 - return await self._assign_task(team_id, **kwargs)
113 + disable_auto_dependency = kwargs.pop("disable_auto_dependency", False)
114 + return await self._assign_task(team_id, disable_auto_dependency=disable_auto_dependency, **kwargs)
115 elif action == "execute_task":
116 self.log.update(progress=f"Executing task in team {team_id}...")
117 return await self._execute_task(team_id, **kwargs)
@@ -60,10 +126,30 @@ class TeamAgent(Tool):
126 return await self._team_status(team_id, **kwargs)
127 elif action == "integrate_results":
128 self.log.update(progress=f"Integrating results from team {team_id}...")
63 - return await self._integrate_results(team_id, **kwargs)
129 + # Explicitly extract step and review_summary from kwargs
130 + step = kwargs.pop("step", None)
131 + review_summary = kwargs.pop("review_summary", None)
132 + # Pass extracted parameters and remaining kwargs
133 + response = await self._integrate_results(team_id, step=step, review_summary=review_summary, **kwargs)
134 + if not isinstance(response, Response):
135 + return Response(
136 + message=self._format_response({
137 + "team_id": team_id,
138 + "error": "Integration did not return a valid Response object.",
139 + "next_step": "Check the _integrate_results implementation."
140 + }),
141 + break_loop=False
142 + )
143 + return response
144 elif action == "get_task_result":
145 self.log.update(progress=f"Getting specific task result from team {team_id}...")
146 return await self._get_task_result(team_id, **kwargs)
147 + elif action == "delete_task":
148 + self.log.update(progress=f"Deleting task in team {team_id}...")
149 + return await self._delete_task(team_id, **kwargs)
150 + elif action == "update_task":
151 + self.log.update(progress=f"Updating task in team {team_id}...")
152 + return await self._update_task(team_id, **kwargs)
153 else:
154 self.log.update(error=f"Unknown action: {action}")
155 return Response(
@@ -72,7 +158,8 @@ class TeamAgent(Tool):
158 "available_actions": [
159 "create", "add_agent", "assign_task",
160 "execute_task", "message", "get_results",
75 - "team_status", "integrate_results", "get_task_result"
161 + "team_status", "integrate_results", "get_task_result",
162 + "delete_task", "update_task"
163 ]
164 }),
165 break_loop=False
@@ -97,7 +184,8 @@ class TeamAgent(Tool):
184 "available_actions": [
185 "create", "add_agent", "assign_task",
186 "execute_task", "message", "get_results",
100 - "team_status", "integrate_results", "get_task_result"
187 + "team_status", "integrate_results", "get_task_result",
188 + "delete_task", "update_task"
189 ]
190 }),
191 break_loop=False
@@ -118,27 +206,42 @@ class TeamAgent(Tool):
206 team_leader.set_data("tasks", {})
207 team_leader.set_data("created_at", time.time())
208
209 + # Retrieve the confirmed document path passed from the execute method
210 + doc_path = kwargs.get("doc_path", None) # Get doc_path from kwargs
211 + if not doc_path:
212 + # Fallback or log error if doc_path is missing - indicates an issue in the execute flow
213 + self.log.update(error=f"Critical: doc_path missing during _create_team for {team_id}")
214 + # Determine project name for fallback doc path calculation
215 + project_name = kwargs.get("name", "project").replace(" ", "_").lower()
216 + doc_dir = "/root/team_task" # Assuming this is the standard doc_dir
217 + doc_path = os.path.join(doc_dir, f"{project_name}.md")
218 + self.log.update(progress=f"Using fallback doc_path: {doc_path}")
219 +
220 # Store team in agent's data
122 - teams = self.agent.get_data("teams")
221 + teams = self.agent.get_data("teams") or {} # Ensure teams is initialized
222 teams[team_id] = {
223 "id": team_id,
224 "name": name,
225 "goal": goal,
226 "leader_agent": team_leader,
128 - "created_at": time.time()
227 + "created_at": time.time(),
228 + "doc_path": doc_path # Store the confirmed document path
229 }
230 self.agent.set_data("teams", teams)
231
232 # Set as the active team
233 self.agent.set_data("active_team_id", team_id)
234
235 + # Return response containing the team_id and next steps
236 + # Note: The planning summary is handled in the main execute block
237 return Response(
238 message=self._format_response({
239 "team_id": team_id,
240 "name": name,
241 "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."
242 + "doc_path": doc_path, # Include doc_path for confirmation
243 + "status": "created", # Indicate team structure is created
244 + "next_step": "Team structure created. Follow instructions from the previous 'create' action response to add agents." # Simplified next_step, main guidance is in execute
245 }),
246 break_loop=False
247 )
@@ -190,7 +293,7 @@ class TeamAgent(Tool):
293 # Count existing team members
294 member_count = len(team_members)
295
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."
296 + 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.\n\nIMPORTANT: Assign each agent their unique, role-appropriate task as defined in the 'Role-Specific Task Assignment Guidance' section of the planning summary. Do NOT assign the same review or implementation task to multiple agents. Each agent's task should leverage their specific expertise and responsibilities."
297
298 return Response(
299 message=self._format_response({
@@ -203,8 +306,22 @@ class TeamAgent(Tool):
306 break_loop=False
307 )
308
206 - async def _assign_task(self, team_id, agent_id="", task="", context="", depends_on=None, **kwargs):
207 - """Assign a task to a team member"""
309 + def _has_circular_dependency(self, tasks, start_task_id, new_depends_on):
310 + """Detect if adding new_depends_on to start_task_id would create a cycle"""
311 + visited = set()
312 + stack = list(new_depends_on)
313 + while stack:
314 + current = stack.pop()
315 + if current == start_task_id:
316 + return True
317 + if current in visited or current not in tasks:
318 + continue
319 + visited.add(current)
320 + stack.extend(tasks[current].get("depends_on", []))
321 + return False
322 +
323 + async def _assign_task(self, team_id, agent_id="", task="", context="", depends_on=None, disable_auto_dependency=False, **kwargs):
324 + """Assign a task to a team member.\n\nREMINDER: When assigning a task, use the unique, role-appropriate task for this agent as defined in the planning summary's 'Role-Specific Task Assignment Guidance' section. Avoid assigning the same generic review or implementation task to multiple agents."""
325 if depends_on is None:
326 depends_on = []
327
@@ -246,17 +363,15 @@ class TeamAgent(Tool):
363 sequence_num = len(tasks) + 1 # Start from 1
364
365 # If no dependencies were explicitly provided, automatically set the most recent task as a dependency
249 - if not depends_on and tasks:
366 + if not disable_auto_dependency and not depends_on and tasks:
367 # Find the most recent assigned or completed task by highest sequence number
368 most_recent_task = None
369 highest_seq = 0
253 -
370 for task_id, task_data in tasks.items():
371 task_seq = task_data.get("sequence_num", 0)
372 if task_seq > highest_seq:
373 most_recent_task = task_id
374 highest_seq = task_seq
259 -
375 if most_recent_task:
376 depends_on = [most_recent_task]
377 self.log.update(progress=f"Automatically set task dependency on prior task: {most_recent_task}")
@@ -264,6 +379,17 @@ class TeamAgent(Tool):
379 # Create task ID
380 task_id = f"task_{str(uuid.uuid4())[:6]}"
381
382 + # Circular dependency check
383 + if self._has_circular_dependency(tasks, task_id, depends_on):
384 + return Response(
385 + message=self._format_response({
386 + "error": f"Circular dependency detected: assigning these dependencies would create a cycle.",
387 + "proposed_depends_on": depends_on,
388 + "next_step": "Revise dependencies to avoid cycles. Use update_task to change dependencies, delete_task to remove problematic tasks, or use disable_auto_dependency: true in assign_task to prevent automatic dependencies."
389 + }),
390 + break_loop=False
391 + )
392 +
393 # Create task
394 task_data = {
395 "id": task_id,
@@ -276,7 +402,7 @@ class TeamAgent(Tool):
402 "sequence_num": sequence_num, # Add explicit sequence number
403 "completed_at": None,
404 "result": None,
279 - "auto_dependency": True if not kwargs.get("depends_on") and depends_on else False
405 + "auto_dependency": True if not disable_auto_dependency and depends_on else False
406 }
407
408 # Store task in team leader's data
@@ -310,10 +436,16 @@ class TeamAgent(Tool):
436 if not any(t["agent_id"] == aid for t in tasks.values()):
437 agents_without_tasks.append(f"{adata['role']} ({aid})")
438
439 + # Enhanced next_step with auto-dependency context
440 + auto_dep_note = ""
441 + if not disable_auto_dependency and not kwargs.get("depends_on") and tasks:
442 + auto_dep_note = " This task was automatically set to depend on the previous task. To prevent this in the future, use disable_auto_dependency: true in assign_task."
443 + elif disable_auto_dependency and not depends_on:
444 + auto_dep_note = " This task has no dependencies. If you want to automatically depend on the previous task, omit disable_auto_dependency or set it to false."
445 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."
446 + 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. If you need to change or remove a task, use update_task or delete_task.{auto_dep_note}\n\nREMINDER: Use the unique, role-appropriate task for each agent as defined in the planning summary's 'Role-Specific Task Assignment Guidance' section. Avoid assigning the same generic review or implementation task to multiple agents."
447 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."
448 + next_step = f"Step 3: EXECUTE ALL TASKS by using execute_task for each task in sequence. Start with tasks that have no dependencies. If you need to change or remove a task, use update_task or delete_task.{auto_dep_note}\n\nREMINDER: All agents should have unique, role-appropriate tasks as defined in the planning summary."
449
450 return Response(
451 message=self._format_response({
@@ -326,7 +458,7 @@ class TeamAgent(Tool):
458 "dependencies": depends_on if depends_on else [],
459 "sequence_num": sequence_num, # Include sequence number in response
460 "has_context": bool(context),
329 - "auto_dependency": True if not kwargs.get("depends_on") and depends_on else False,
461 + "auto_dependency": True if not disable_auto_dependency and depends_on else False,
462 "next_step": next_step
463 }),
464 break_loop=False
@@ -503,7 +635,7 @@ SESSION WORKFLOW:
635 - Use the input tool for interactive programs
636
637 ERROR HANDLING STRATEGY:
506 -- If you encounter the same error twice when trying the same approach, switch to an alternative method
638 +- If you encounter the same error twice when trying the same approach, switch to an alternative, more reliable method (such as reading the entire file, editing in memory, and writing back as a single multi-line string, or using EOF CAT-style edits). Document the fallback method used in your response.
639 - For library/package issues, try a different library or implement a minimal solution from scratch
640 - When installation fails despite multiple attempts, use a fallback implementation as specified in your task
641 - Document environment issues and your workaround strategy in your final response
@@ -631,6 +763,12 @@ EXECUTION STRATEGY:
763 6. DELIVER using the response tool
764
765 Remember: The response_tool is REQUIRED for your final output.
766 +
767 +CODE EDITING BEST PRACTICE:
768 +- Strongly discourage naive string or line replacements for code edits, especially in Python or structured files, as this can easily break indentation, structure, or introduce subtle bugs.
769 +- Read the file to identify the exact issues. After reviewing the content, implement the necessary fixes to ensure proper syntax throughout the file.
770 +- The most reliable and robust approach is to always read the entire file into memory, make your edits there, and write back the full, updated content as a single multi-line string (or using a 'cat' style overwrite). This ensures file integrity and preserves formatting.
771 +- For all file edits, especially in Python or markdown, always prefer this full overwrite method over partial or regex-based replacements.
772 """
773
774 # Execute task using call_subordinate pattern
@@ -1074,7 +1212,21 @@ Remember: The response_tool is REQUIRED for your final output.
1212 data["next_step"] = f"Use a valid team_id from: {', '.join(data['available_teams'])}"
1213 else:
1214 data["next_step"] = "Create a team first with the 'create' action"
1077 -
1215 +
1216 + # Add document context if applicable
1217 + if "doc_path" in data and "doc_status" not in data:
1218 + data["doc_status"] = "available" # Default status if path exists but status isn't specified
1219 +
1220 + # Add specific context for document operations
1221 + if "status" in data:
1222 + if data["status"] == "team_created":
1223 + if "doc_path" in data:
1224 + thoughts.append(f"Team created with planning document at {data['doc_path']}")
1225 + elif data["status"] == "integration_review":
1226 + thoughts.append("Completed document review phase of integration")
1227 + elif data["status"] == "integrated":
1228 + thoughts.append("Completed document update and integration of team results")
1229 +
1230 # Add specific formatting guidance for get_results response
1231 if "results" in data and "error" not in data and "next_step" not in data:
1232 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."
@@ -1197,18 +1349,20 @@ Remember: The response_tool is REQUIRED for your final output.
1349
1350 return json.dumps(formatted_response, indent=2)
1351
1200 - async def _integrate_results(self, team_id, **kwargs):
1201 - """Integrate results from all team members into a final product"""
1352 + async def _integrate_results(self, team_id, step=None, review_summary=None, **kwargs):
1353 + """Integrate results from all team members into a final product, now as a two-step process: review, then edit/update.\\n\\nBEST PRACTICE: For all markdown or code section edits, always read the entire file into memory, construct the full updated content, and overwrite the file in one write operation (single multi-line string). After writing, read the file back to confirm the update. Do NOT use regex, partial, or line-by-line replacements for in-place section updates—these are unreliable and discouraged."""
1354 + # Enhanced progress tracking
1355 + progress_prefix = f"Team {team_id} Integration"
1356 + self.log.update(progress=f"{progress_prefix}: Starting integration process... Step: {step if step else 'default (review -> edit)'}")
1357 +
1358 # Get team data
1359 teams = self.agent.get_data("teams") or {}
1360 if not team_id or team_id not in teams:
1361 available_teams = list(teams.keys())
1362 error_msg = f"Team {team_id} not found"
1363 self.log.update(error=error_msg)
1208 -
1364 if available_teams:
1365 self.log.update(progress=f"Available teams: {', '.join(available_teams)}")
1211 -
1366 return Response(
1367 message=self._format_response({
1368 "error": error_msg,
@@ -1217,12 +1371,24 @@ Remember: The response_tool is REQUIRED for your final output.
1371 }),
1372 break_loop=False
1373 )
1220 -
1374 +
1375 team_data = teams[team_id]
1376 team_leader = team_data["leader_agent"]
1377 tasks = team_leader.get_data("tasks") or {}
1378 team_members = team_leader.get_data("team_members") or {}
1225 -
1379 +
1380 + # Calculate overall progress and pending tasks early
1381 + total_tasks = len(tasks)
1382 + completed_tasks = sum(1 for t in tasks.values() if t["status"] == "completed")
1383 + pending_tasks = total_tasks - completed_tasks # Define pending_tasks here
1384 + progress_percentage = f"{completed_tasks}/{total_tasks} tasks completed ({int(completed_tasks/total_tasks*100) if total_tasks else 0}%)"
1385 + self.log.update(progress=f"{progress_prefix}: {progress_percentage}")
1386 +
1387 + # Initialize pending_warning
1388 + pending_warning = ""
1389 + if pending_tasks > 0:
1390 + pending_warning = f"\\n\\nNOTE: There are still {pending_tasks} pending tasks in this team. This integration only includes completed tasks."
1391 +
1392 # Collect all completed results
1393 completed_results = {}
1394 for task_id, task_data in tasks.items():
@@ -1234,7 +1400,8 @@ Remember: The response_tool is REQUIRED for your final output.
1400 "task": task_data["description"],
1401 "result": task_data["result"]
1402 }
1237 -
1403 +
1404 + # Check if there are any completed results to integrate
1405 if not completed_results:
1406 return Response(
1407 message=self._format_response({
@@ -1244,24 +1411,485 @@ Remember: The response_tool is REQUIRED for your final output.
1411 }),
1412 break_loop=False
1413 )
1414 +
1415 + # Retrieve stored doc_path, with fallback
1416 + doc_path = team_data.get("doc_path")
1417 + if not doc_path:
1418 + # Fallback calculation if doc_path wasn't stored
1419 + project_name_fallback = team_data.get("name", "project").replace(" ", "_").lower()
1420 + doc_dir = "/root/team_task"
1421 + doc_path = os.path.join(doc_dir, f"{project_name_fallback}.md")
1422 + # Store it back for future use
1423 + team_data["doc_path"] = doc_path
1424 + teams[team_id] = team_data
1425 + self.agent.set_data("teams", teams) # Ensure teams data is updated in the agent
1426 + self.log.update(progress=f"{progress_prefix}: doc_path was not found, using fallback and storing: {doc_path}")
1427 + else:
1428 + self.log.update(progress=f"{progress_prefix}: Using stored doc_path: {doc_path}")
1429 +
1430 + # --- Step Execution Logic ---
1431 +
1432 + if step == "review":
1433 + # Execute only the review step
1434 + return await self._integrate_review_step(
1435 + team_id, team_data, team_leader, tasks, team_members, doc_path, progress_prefix,
1436 + pending_tasks, progress_percentage
1437 + )
1438 + elif step == "edit":
1439 + # Execute only the edit step (requires review_summary)
1440 + if not review_summary:
1441 + return Response(
1442 + message=self._format_response({
1443 + "team_id": team_id,
1444 + "error": "Missing review_summary for edit step.",
1445 + "next_step": "Run the 'review' step first to generate a review_summary, then pass it to the 'edit' step."
1446 + }),
1447 + break_loop=False
1448 + )
1449 + return await self._integrate_edit_step(
1450 + team_id, team_data, team_leader, tasks, team_members, doc_path, progress_prefix,
1451 + review_summary, completed_results, pending_tasks, progress_percentage, pending_warning
1452 + )
1453 + elif step is None:
1454 + # Default: Execute both steps sequentially
1455 + self.log.update(progress=f"{progress_prefix}: Running default two-step integration (review -> edit)...")
1456 +
1457 + # Step 1: Review
1458 + review_response = await self._integrate_review_step(
1459 + team_id, team_data, team_leader, tasks, team_members, doc_path, progress_prefix,
1460 + pending_tasks, progress_percentage
1461 + )
1462 +
1463 + # Check review response for errors
1464 + try:
1465 + review_data = json.loads(review_response.message)
1466 + if "error" in review_data.get("tool_args", {}):
1467 + self.log.update(error=f"{progress_prefix}: Error during review step: {review_data['tool_args']['error']}")
1468 + return review_response # Return the error response from review step
1469 + extracted_review_summary = review_data.get("tool_args", {}).get("review_summary")
1470 + if not extracted_review_summary:
1471 + self.log.update(error=f"{progress_prefix}: Failed to extract review_summary from review step response.")
1472 + return Response(
1473 + message=self._format_response({
1474 + "team_id": team_id,
1475 + "error": "Internal error: Could not extract review summary after review step.",
1476 + "next_step": "Review step completed but summary was missing. Please report this issue."
1477 + }),
1478 + break_loop=False
1479 + )
1480 + except (json.JSONDecodeError, AttributeError, TypeError) as e:
1481 + self.log.update(error=f"{progress_prefix}: Failed to parse review step response: {e}")
1482 + return Response(
1483 + message=self._format_response({
1484 + "team_id": team_id,
1485 + "error": f"Internal error parsing review step response: {e}",
1486 + "next_step": "The review step failed unexpectedly. Please report this issue."
1487 + }),
1488 + break_loop=False
1489 + )
1490 +
1491 + self.log.update(progress=f"{progress_prefix}: Review step completed successfully. Proceeding to edit step.")
1492 +
1493 + # Step 2: Edit (using extracted summary)
1494 + return await self._integrate_edit_step(
1495 + team_id, team_data, team_leader, tasks, team_members, doc_path, progress_prefix,
1496 + extracted_review_summary, completed_results, pending_tasks, progress_percentage, pending_warning
1497 + )
1498 + else:
1499 + # Invalid step value
1500 + return Response(
1501 + message=self._format_response({
1502 + "team_id": team_id,
1503 + "error": f"Invalid step value: '{step}'. Must be 'review', 'edit', or omitted for default flow.",
1504 + "next_step": "Provide a valid step parameter or omit it."
1505 + }),
1506 + break_loop=False
1507 + )
1508 +
1509 + async def _delete_task(self, team_id, task_id, **kwargs):
1510 + """Delete a task from the team and remove it from dependencies of other tasks"""
1511 + teams = self.agent.get_data("teams") or {}
1512 + if not team_id or team_id not in teams:
1513 + return Response(
1514 + message=self._format_response({
1515 + "error": f"Team {team_id} not found",
1516 + "available_teams": list(teams.keys()),
1517 + "next_step": "Create a team first with the 'create' action or use a valid team_id"
1518 + }),
1519 + break_loop=False
1520 + )
1521 + team_data = teams[team_id]
1522 + team_leader = team_data["leader_agent"]
1523 + tasks = team_leader.get_data("tasks") or {}
1524 + if not task_id or task_id not in tasks:
1525 + return Response(
1526 + message=self._format_response({
1527 + "error": f"Task {task_id} not found in team {team_id}",
1528 + "available_tasks": list(tasks.keys()),
1529 + "next_step": "Provide a valid task_id to delete"
1530 + }),
1531 + break_loop=False
1532 + )
1533 + # Remove the task
1534 + del tasks[task_id]
1535 + # Remove this task from any other task's depends_on list
1536 + for t in tasks.values():
1537 + if "depends_on" in t and task_id in t["depends_on"]:
1538 + t["depends_on"] = [dep for dep in t["depends_on"] if dep != task_id]
1539 + team_leader.set_data("tasks", tasks)
1540 + return Response(
1541 + message=self._format_response({
1542 + "team_id": team_id,
1543 + "task_id": task_id,
1544 + "status": "deleted",
1545 + "next_step": "Task deleted. Review remaining tasks and dependencies. Use assign_task to add new tasks or update_task to modify existing ones."
1546 + }),
1547 + break_loop=False
1548 + )
1549 +
1550 + async def _update_task(self, team_id, task_id, **kwargs):
1551 + """Update properties of a task (description, depends_on, context, etc.)"""
1552 + teams = self.agent.get_data("teams") or {}
1553 + if not team_id or team_id not in teams:
1554 + return Response(
1555 + message=self._format_response({
1556 + "error": f"Team {team_id} not found",
1557 + "available_teams": list(teams.keys()),
1558 + "next_step": "Create a team first with the 'create' action or use a valid team_id"
1559 + }),
1560 + break_loop=False
1561 + )
1562 + team_data = teams[team_id]
1563 + team_leader = team_data["leader_agent"]
1564 + tasks = team_leader.get_data("tasks") or {}
1565 + if not task_id or task_id not in tasks:
1566 + return Response(
1567 + message=self._format_response({
1568 + "error": f"Task {task_id} not found in team {team_id}",
1569 + "available_tasks": list(tasks.keys()),
1570 + "next_step": "Provide a valid task_id to update"
1571 + }),
1572 + break_loop=False
1573 + )
1574 + task = tasks[task_id]
1575 + updated_fields = []
1576 + # Circular dependency check if depends_on is being updated
1577 + if "depends_on" in kwargs:
1578 + if self._has_circular_dependency(tasks, task_id, kwargs["depends_on"]):
1579 + return Response(
1580 + message=self._format_response({
1581 + "error": f"Circular dependency detected: updating these dependencies would create a cycle.",
1582 + "proposed_depends_on": kwargs["depends_on"],
1583 + "next_step": "Revise dependencies to avoid cycles."
1584 + }),
1585 + break_loop=False
1586 + )
1587 + # Update allowed fields
1588 + for field in ["description", "depends_on", "context"]:
1589 + if field in kwargs:
1590 + task[field] = kwargs[field]
1591 + updated_fields.append(field)
1592 + tasks[task_id] = task
1593 + team_leader.set_data("tasks", tasks)
1594 + if updated_fields:
1595 + return Response(
1596 + message=self._format_response({
1597 + "team_id": team_id,
1598 + "task_id": task_id,
1599 + "status": "updated",
1600 + "updated_fields": updated_fields,
1601 + "next_step": f"Task updated: {', '.join(updated_fields)}. Review dependencies and proceed as needed. You can use update_task again to make further changes or delete_task to remove this task."
1602 + }),
1603 + break_loop=False
1604 + )
1605 + else:
1606 + return Response(
1607 + message=self._format_response({
1608 + "team_id": team_id,
1609 + "task_id": task_id,
1610 + "status": "no_changes",
1611 + "next_step": "No updatable fields provided. Specify at least one of: description, depends_on, context. Use update_task to modify a task or delete_task to remove it."
1612 + }),
1613 + break_loop=False
1614 + )
1615 +
1616 + async def _team_planning_phase(self, prior_doc="", **kwargs):
1617 + """Step-by-step team planning phase before agent creation, agent-driven doc management"""
1618 + # Initialize progress tracking
1619 + self.log.update(progress="Starting team planning phase...")
1620 +
1621 + planning_context = {}
1622 + user_goal = kwargs.get("goal", "")
1623 + user_name = kwargs.get("name", "Project")
1624 + project_name = user_name.replace(" ", "_").lower()
1625 + doc_dir = "/root/team_task"
1626 + doc_path = os.path.join(doc_dir, f"{project_name}.md")
1627 + template_path = os.path.join(doc_dir, "template_project_name.md")
1628 +
1629 + # Create team leader instance for planning
1630 + team_leader = Agent(self.agent.number, self.agent.config, self.agent.context)
1631
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."
1632 + # Step 1: Document check
1633 + self.log.update(progress="Planning Step 1/7: Checking for existing planning document...")
1634 + doc_check_prompt = (
1635 + f"START OF TEAM PLANNING PHASE.\\n"
1636 + f"Step 1: Initial Document Check (Perform ONCE)\\n"
1637 + f"This is the very first step. Check if the file {doc_path} exists.\\n"
1638 + f"- If it exists: Read the entire file and provide a structured summary of its sections and key content.\\n"
1639 + f"- If it does NOT exist: State that clearly, create it from the template at {template_path}, and then summarize the new file.\\n"
1640 + f"CRITICAL: After summarizing or creating the file THIS ONE TIME, you MUST immediately proceed to Step 2 (Project File Review). Do NOT repeat Step 1. Do NOT re-initiate team creation. Your output for Step 1 is just the summary. Now, continue to Step 2."
1641 + )
1642 + # The agent should summarize and then continue, not loop.
1643 + team_leader.hist_add_user_message(UserMessage(message=doc_check_prompt, attachments=[]))
1644 + doc_check_summary = await team_leader.monologue()
1645 + planning_context["doc_check_summary"] = doc_check_summary
1646 + self.log.update(progress="Planning Step 1/7: Document check complete: " + doc_check_summary[:100] + "...") # Add log here
1647 +
1648 + # Step 2: Project file review (as before, but reference doc)
1649 + self.log.update(progress="Planning Step 2/7: Reviewing project files...") # Add log here
1650 + file_review_prompt = (
1651 + f"Step 2: Project File Review\\n"
1652 + f"User's project goal: {user_goal}\\n"
1653 + f"Team/Project name: {user_name}\n"
1654 + "- List all directories in /root/.\n"
1655 + "- Infer the most relevant project directory from the user's goal or prompt.\n"
1656 + "- Review the contents of that directory. If it contains mostly subdirectories, look one level deeper.\n"
1657 + "- Summarize the directory structure and the most relevant files (not just the first level).\n"
1658 + "- Always state which directories and files you are reviewing in your output.\n"
1659 + f"If a directory path is mentioned (e.g., /root/chess/), use it as the primary context for file review. "
1660 + f"If the directory does not exist or is empty, propose a logical structure for the project under /root/[project_name]. "
1661 + )
1662 + team_leader.hist_add_user_message(UserMessage(message=file_review_prompt, attachments=[]))
1663 + file_review = await team_leader.monologue()
1664 + planning_context["file_review"] = file_review
1665 + self.log.update(progress="Planning Step 2/7: Project file review complete.") # Add log here
1666 +
1667 + # Step 3: Goal/challenge inference
1668 + self.log.update(progress="Planning Step 3/7: Inferring goal and challenges...") # Add log here
1669 + goal_prompt = (
1670 + "Step 3: Project Goal and Challenges\\n"
1671 + "Based on the files and any available project description, summarize what you believe is the main project goal and any key challenges."
1672 + )
1673 + team_leader.hist_add_user_message(UserMessage(message=goal_prompt, attachments=[]))
1674 + goal_summary = await team_leader.monologue()
1675 + planning_context["goal_summary"] = goal_summary
1676 + self.log.update(progress="Planning Step 3/7: Goal inference complete.") # Add log here
1677 +
1678 + # Step 4: Role/skill suggestion
1679 + self.log.update(progress="Planning Step 4/7: Suggesting team roles...") # Add log here
1680 + roles_prompt = (
1681 + "Step 4: Team Roles and Skills\\n"
1682 + "Given the project's structure and goal, suggest the roles and skills needed for the team. For each role, briefly state its purpose."
1683 + )
1684 + team_leader.hist_add_user_message(UserMessage(message=roles_prompt, attachments=[]))
1685 + roles_suggestion = await team_leader.monologue()
1686 + planning_context["roles_suggestion"] = roles_suggestion
1687 + self.log.update(progress="Planning Step 4/7: Role suggestion complete.") # Add log here
1688 +
1689 + # Step 4a: Role-specific task assignment guidance
1690 + self.log.update(progress="Planning Step 4a/7: Generating role-specific task guidance...") # Add log here
1691 + role_task_prompt = (
1692 + "Step 4a: Role-Specific Task Assignment Guidance\\n"
1693 + "For each team role identified, create a unique, role-appropriate task that leverages the agent's expertise. "
1694 + "Do NOT assign the same generic task to all agents. Instead, tailor each task to the agent's role and responsibilities. "
1695 + "Provide a brief description of the task for each role."
1696 + )
1697 + team_leader.hist_add_user_message(UserMessage(message=role_task_prompt, attachments=[]))
1698 + role_task_guidance = await team_leader.monologue()
1699 + planning_context["role_task_guidance"] = role_task_guidance
1700 + self.log.update(progress="Planning Step 4a/7: Task guidance generation complete.") # Add log here
1701 +
1702 + # Step 5: High-level task breakdown
1703 + self.log.update(progress="Planning Step 5/7: Breaking down tasks...") # Add log here
1704 + tasks_prompt = (
1705 + "Step 5: High-Level Task Breakdown\\n"
1706 + "Propose a high-level breakdown of main tasks (and possible subtasks) that the team should complete to achieve the project goal."
1707 + )
1708 + team_leader.hist_add_user_message(UserMessage(message=tasks_prompt, attachments=[]))
1709 + task_breakdown = await team_leader.monologue()
1710 + planning_context["task_breakdown"] = task_breakdown
1711 + self.log.update(progress="Planning Step 5/7: Task breakdown complete.") # Add log here
1712 +
1713 + # Step 6: Clarifications/questions
1714 + self.log.update(progress="Planning Step 6/7: Identifying clarifications...") # Add log here
1715 + clarifications_prompt = (
1716 + "Step 6: Clarifications or Questions\\n"
1717 + "List any questions or missing information that would help you plan more effectively."
1718 + )
1719 + team_leader.hist_add_user_message(UserMessage(message=clarifications_prompt, attachments=[]))
1720 + clarifications = await team_leader.monologue()
1721 + planning_context["clarifications"] = clarifications
1722 + self.log.update(progress="Planning Step 6/7: Clarification identification complete.") # Add log here
1723 +
1724 + # Step 7: Update doc with planning summary
1725 + self.log.update(progress=f"Planning Step 7/7: Updating planning document at {doc_path}...") # Add log here
1726 + # Construct the final planning summary string first
1727 + planning_summary_content = (
1728 + f"{doc_check_summary}\n\n" # Use the summary from step 1
1729 + f"## Project File Review\n{file_review}\n\n"
1730 + f"## Project Goal and Challenges\n{goal_summary}\n\n"
1731 + f"## Team Roles and Skills\n{roles_suggestion}\n\n"
1732 + f"## Role-Specific Task Assignment Guidance\n{role_task_guidance}\n\n"
1733 + f"## High-Level Task Breakdown\n{task_breakdown}\n\n"
1734 + f"## Clarifications or Questions\n{clarifications}\n"
1735 + )
1736 +
1737 + # Use the reliable full-overwrite method to update the document's overview section
1738 + doc_update_prompt = (
1739 + f"Step 7: Update Planning Document ({doc_path})\\n"
1740 + f"Task: Read the entire document at '{doc_path}'. Find the '## Project Overview' section. Replace the content *under* this header with the new planning summary provided below. If the section doesn't exist, add it. Construct the full, updated markdown content in memory. Overwrite the file at '{doc_path}' in one single write operation using the full updated content. After writing, read the file back to confirm the '## Project Overview' section contains the new summary.\\n"
1741 + f"CRITICAL: Use the full overwrite method (read all -> modify in memory -> write all). Do NOT use partial replacements.\\n"
1742 + f"\n--- New Project Overview Content ---\n{planning_summary_content}\n--- End New Content ---"
1743 + )
1744 +
1745 + team_leader.hist_add_user_message(UserMessage(message=doc_update_prompt, attachments=[]))
1746 + doc_update_confirmation = await team_leader.monologue() # This should contain confirmation from the agent
1747 + planning_context["doc_update_confirmation"] = doc_update_confirmation
1748 + self.log.update(progress=f"Planning Step 7/7: Document update requested. Confirmation: {doc_update_confirmation[:100]}...") # Add log here
1749 +
1750 + # Final step with comprehensive log update
1751 + self.log.update(progress=f"Planning phase complete. Planning document updated at {doc_path}") # Add final log here
1752 +
1753 + # Compose the complete planning summary for return
1754 + # This includes the initial doc check summary and the confirmation from the update step
1755 + final_planning_summary = (
1756 + f"{doc_check_summary}\n\n" # Include initial doc check summary
1757 + f"--- Planning Summary ---\n"
1758 + f"Project File Review:\n{file_review}\n\n"
1759 + f"Project Goal and Challenges:\n{goal_summary}\n\n"
1760 + f"Team Roles and Skills:\n{roles_suggestion}\n\n"
1761 + f"Role-Specific Task Assignment Guidance:\n{role_task_guidance}\n\n"
1762 + f"High-Level Task Breakdown:\n{task_breakdown}\n\n"
1763 + f"Clarifications or Questions:\n{clarifications}\n\n"
1764 + f"--- Document Update Confirmation ---\n{doc_update_confirmation}\n" # Include update confirmation
1765 + )
1766 +
1767 + # Return planning summary along with confirmed doc_path and status
1768 + return {
1769 + "planning_summary": final_planning_summary, # Return the combined summary
1770 + "doc_path": doc_path, # Return the confirmed doc_path used
1771 + "status": "planning_complete" # Indicate planning is done
1772 + }
1773 +
1774 + async def _integrate_review_step(self, team_id, team_data, team_leader, tasks, team_members, doc_path, progress_prefix, pending_tasks, progress_percentage):
1775 + """Handles the 'review' step of the integration process."""
1776 + self.log.update(progress=f"{progress_prefix} - STEP 1/2: Starting document review...")
1777 + review_doc_prompt = (
1778 + f"Integration Step 1: Review Planning/Results Document\\\\n" # Escaped newline
1779 + f"Read the current planning/results document at {doc_path}. Summarize its contents, especially the Project Overview and any previous Integration Review sections.\\\\n" # Escaped newline
1780 + f"Then review the current project directory and files. Validate that all deliverables are present and organized. Summarize results, check for gaps, and provide recommendations.\\\\n" # Escaped newline
1781 + f"Your response should include:\\\\n" # Escaped newline
1782 + f"- Directory/file review (list and describe key files and structure)\\\\n" # Escaped newline
1783 + f"- Checklist of deliverables (what was expected, what is present, what is missing)\\\\n" # Escaped newline
1784 + f"- Summary of results (from all completed tasks)\\\\n" # Escaped newline
1785 + f"- Recommendations for improvement or next steps\\\\n" # Escaped newline
1786 + f"Always state which directories and files you are reviewing in your output."
1787 + )
1788 + team_leader.hist_add_user_message(UserMessage(message=review_doc_prompt, attachments=[]))
1789 + review_response = await team_leader.monologue()
1790 +
1791 + self.log.update(progress=f"{progress_prefix} - STEP 1/2: Document review complete.")
1792 +
1793 + return Response(
1794 + message=self._format_response({
1795 + "team_id": team_id,
1796 + "status": "integration_review",
1797 + "review_summary": review_response,
1798 + "pending_tasks": pending_tasks, # Use the calculated value
1799 + "team_progress": progress_percentage, # Add progress
1800 + "doc_path": doc_path, # Add doc path
1801 + "team_name": team_data.get("name", "Unknown"), # Add team name
1802 + "team_goal": team_data.get("goal", "Unknown"), # Add team goal
1803 + "next_step": "Step 2: Use the 'edit' step to update the document and synthesize the final integration based on this review. Pass the review_summary as input."
1804 + }),
1805 + break_loop=False
1806 + )
1807 +
1808 + async def _integrate_edit_step(self, team_id, team_data, team_leader, tasks, team_members, doc_path, progress_prefix, review_summary, completed_results, pending_tasks, progress_percentage, pending_warning):
1809 + """Handles the 'edit' step of the integration process."""
1810 + self.log.update(progress=f"{progress_prefix} - STEP 2/2: Starting document update...")
1811 + if not review_summary:
1812 + return Response(
1813 + message=self._format_response({
1814 + "team_id": team_id,
1815 + "error": "Missing review_summary for edit step.",
1816 + "next_step": "Run the 'review' step first to generate a review_summary, then pass it to the 'edit' step."
1817 + }),
1818 + break_loop=False
1819 + )
1820 +
1821 + # Ensure doc_path is valid before proceeding
1822 + if not doc_path: # Check if doc_path is None or empty after potential fallback
1823 + return Response(
1824 + message=self._format_response({
1825 + "team_id": team_id,
1826 + "error": "Document path could not be determined for editing.",
1827 + "next_step": "Verify team data and naming conventions."
1828 + }),
1829 + break_loop=False
1830 + )
1831 +
1832 + # Update Integration Review section
1833 + def update_markdown_section(file_path, section_header, new_content):
1834 + try:
1835 + with open(file_path, 'r', encoding='utf-8') as f:
1836 + lines = f.readlines()
1837 + except FileNotFoundError:
1838 + lines = []
1839 + start_idx = None
1840 + end_idx = None
1841 + for i, line in enumerate(lines):
1842 + if line.strip() == section_header:
1843 + start_idx = i
1844 + for j in range(i+1, len(lines)):
1845 + if lines[j].startswith('## ') and lines[j].strip() != section_header:
1846 + end_idx = j
1847 + break
1848 + if end_idx is None:
1849 + end_idx = len(lines)
1850 + break
1851 + section_block = [section_header + '\\n', new_content.strip() + '\\n'] # Escaped newlines
1852 + if start_idx is not None:
1853 + new_lines = lines[:start_idx] + section_block + lines[end_idx:]
1854 + else:
1855 + if lines and not lines[-1].endswith('\\n'): # Escaped newline
1856 + lines[-1] += '\\n' # Escaped newline
1857 + new_lines = lines + ['\\n'] + section_block # Escaped newline
1858 + with open(file_path, 'w', encoding='utf-8') as f:
1859 + f.writelines(new_lines)
1860 +
1861 + update_markdown_section(doc_path, '## Integration Review', review_summary)
1862 + # Note: doc_update_confirmation below gets overwritten by the monologue call
1863 + # This initial string serves mainly as a placeholder in case the monologue fails.
1864 + doc_update_confirmation_initial = f"Integration Review section updated in {doc_path}."
1865 +
1866 + # Prompt the agent to review and update the entire document
1867 + doc_update_prompt = (
1868 + f"Integration Step 2: Update Planning/Results Document\\n" # Escaped newline
1869 + f"Read the entire document at {doc_path}. Review all sections, especially Project Overview and Integration Review. "
1870 + f"Update the document to reflect the latest results, recommendations, and integration review. "
1871 + f"Save the updated document, ensuring all sections are well-structured and up to date. Confirm the update."
1872 + )
1873 + team_leader.hist_add_user_message(UserMessage(message=doc_update_prompt, attachments=[]))
1874 + doc_update_confirmation = await team_leader.monologue()
1875
1876 # 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
1877 + integration_prompt = f'''
1878 + As the leader of the {team_data['name']} team, your critical responsibility is to synthesize all team contributions
1879 into a cohesive, polished final product that fulfills our goal: {team_data['goal']}
1880
1881 COMPLETED TEAM CONTRIBUTIONS:
1882 {json.dumps(completed_results, indent=2)}
1261 - {pending_warning}
1883 + {pending_warning} # Use the initialized pending_warning
1884 +
1885 + INTEGRATION REVIEW:
1886 + {review_summary}
1887 +
1888 + DOCUMENT UPDATE CONFIRMATION:
1889 + {doc_update_confirmation}
1890
1891 INTEGRATION OBJECTIVE:
1264 - Transform these separate contributions into a seamless, unified deliverable that achieves our team goal and meets the user's needs.
1892 + Transform these separate contributions into a seamless, unified deliverable that achieves our team goal and meets the user\\'s needs.
1893
1894 YOUR INTEGRATION ROLE:
1895 1. Identify the key insights and valuable content from each contribution
@@ -1275,7 +1903,7 @@ Remember: The response_tool is REQUIRED for your final output.
1903 - Begin with a high-level synthesis plan
1904 - Extract core content from each contribution
1905 - Create a unified structure that builds logically
1278 - - Fill gaps and eliminate redundancies
1906 + - Fill gaps and eliminate redundancies
1907 - Add transitions to create seamless flow between sections
1908 - Review for completeness, coherence, and alignment with the goal
1909
@@ -1305,32 +1933,32 @@ Remember: The response_tool is REQUIRED for your final output.
1933 ```
1934
1935 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 -
1936 + '''
1937 + self.log.update(progress=f"{progress_prefix} - STEP 2/2: Document update complete. Integration in progress...")
1938 try:
1314 - # Execute integration using call to team leader
1939 team_leader.hist_add_user_message(UserMessage(message=integration_prompt, attachments=[]))
1940 integrated_result = await team_leader.monologue()
1317 - self.log.update(progress="Received integrated response from team leader")
1941 + self.log.update(progress=f"{progress_prefix}: Integration complete.") # Update log here
1942 except Exception as e:
1943 self.log.update(error=f"Error during integration: {str(e)}")
1944 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."
1945 +
1946 + if pending_tasks > 0: # Use the calculated value
1947 + next_step = f"Step 3: 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."
1948 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 -
1949 + next_step = "Step 3: 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."
1950 +
1951 return Response(
1952 message=self._format_response({
1953 "team_id": team_id,
1954 "status": "integrated",
1955 + "team_name": team_data.get("name", "Unknown"), # Add team name
1956 + "team_goal": team_data.get("goal", "Unknown"), # Add team goal
1957 + "team_progress": progress_percentage, # Add progress
1958 + "doc_path": doc_path, # Add doc path
1959 + "document_status": "updated", # Add doc status
1960 "integrated_result": integrated_result,
1333 - "pending_tasks": pending_tasks,
1961 + "pending_tasks": pending_tasks, # Use the calculated value
1962 "next_step": next_step
1963 }),
1964 break_loop=False