mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-18 20:38:13 +00:00
Compare commits
2 Commits
devin/1768
...
devin/1763
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
93116895d9 | ||
|
|
4e0ee7d570 |
@@ -950,15 +950,34 @@ class Crew(FlowTrackable, BaseModel):
|
|||||||
|
|
||||||
def _handle_crew_planning(self) -> None:
|
def _handle_crew_planning(self) -> None:
|
||||||
"""Handles the Crew planning."""
|
"""Handles the Crew planning."""
|
||||||
|
import re
|
||||||
|
|
||||||
self._logger.log("info", "Planning the crew execution")
|
self._logger.log("info", "Planning the crew execution")
|
||||||
result = CrewPlanner(
|
result = CrewPlanner(
|
||||||
tasks=self.tasks, planning_agent_llm=self.planning_llm
|
tasks=self.tasks, planning_agent_llm=self.planning_llm
|
||||||
)._handle_crew_planning()
|
)._handle_crew_planning()
|
||||||
|
|
||||||
for task, step_plan in zip(
|
plan_map: dict[int, str] = {}
|
||||||
self.tasks, result.list_of_plans_per_task, strict=False
|
for step_plan in result.list_of_plans_per_task:
|
||||||
):
|
match = re.search(r"Task Number (\d+)", step_plan.task, re.IGNORECASE)
|
||||||
task.description += step_plan.plan
|
if match:
|
||||||
|
task_number = int(match.group(1))
|
||||||
|
plan_map[task_number] = step_plan.plan
|
||||||
|
else:
|
||||||
|
self._logger.log(
|
||||||
|
"warning",
|
||||||
|
f"Could not extract task number from plan task field: {step_plan.task}",
|
||||||
|
)
|
||||||
|
|
||||||
|
for idx, task in enumerate(self.tasks):
|
||||||
|
task_number = idx + 1 # Task numbers are 1-indexed
|
||||||
|
if task_number in plan_map:
|
||||||
|
task.description += plan_map[task_number]
|
||||||
|
else:
|
||||||
|
self._logger.log(
|
||||||
|
"warning",
|
||||||
|
f"No plan found for task {task_number}. Task description: {task.description}",
|
||||||
|
)
|
||||||
|
|
||||||
def _store_execution_log(
|
def _store_execution_log(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -4772,3 +4772,93 @@ def test_ensure_exchanged_messages_are_propagated_to_external_memory():
|
|||||||
assert "Researcher" in messages[0]["content"]
|
assert "Researcher" in messages[0]["content"]
|
||||||
assert messages[1]["role"] == "user"
|
assert messages[1]["role"] == "user"
|
||||||
assert "Research a topic to teach a kid aged 6 about math" in messages[1]["content"]
|
assert "Research a topic to teach a kid aged 6 about math" in messages[1]["content"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_crew_planning_with_mismatched_task_order():
|
||||||
|
"""Test that crew planning correctly matches plans to tasks even when LLM returns them out of order.
|
||||||
|
|
||||||
|
This test reproduces the bug reported in issue #3953 where the task planner
|
||||||
|
returns plans in the wrong order (e.g., starting with Task 21 instead of Task 1),
|
||||||
|
causing plans to be attached to the wrong tasks.
|
||||||
|
"""
|
||||||
|
from crewai.utilities.planning_handler import PlanPerTask, PlannerTaskPydanticOutput
|
||||||
|
|
||||||
|
# Create 5 tasks with distinct descriptions
|
||||||
|
tasks = []
|
||||||
|
agents = []
|
||||||
|
for i in range(1, 6):
|
||||||
|
agent = Agent(
|
||||||
|
role=f"Agent {i}",
|
||||||
|
goal=f"Goal {i}",
|
||||||
|
backstory=f"Backstory {i}",
|
||||||
|
)
|
||||||
|
agents.append(agent)
|
||||||
|
task = Task(
|
||||||
|
description=f"Task {i} description",
|
||||||
|
expected_output=f"Output {i}",
|
||||||
|
agent=agent,
|
||||||
|
)
|
||||||
|
tasks.append(task)
|
||||||
|
|
||||||
|
crew = Crew(
|
||||||
|
agents=agents,
|
||||||
|
tasks=tasks,
|
||||||
|
planning=True,
|
||||||
|
planning_llm="gpt-4o-mini",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Mock the LLM response to return plans in the WRONG order
|
||||||
|
# Simulating the bug where Task 5 plan comes first, then Task 3, etc.
|
||||||
|
wrong_order_plans = [
|
||||||
|
PlanPerTask(
|
||||||
|
task="Task Number 5 - Task 5 description",
|
||||||
|
plan="\n\nPlan for task 5"
|
||||||
|
),
|
||||||
|
PlanPerTask(
|
||||||
|
task="Task Number 3 - Task 3 description",
|
||||||
|
plan="\n\nPlan for task 3"
|
||||||
|
),
|
||||||
|
PlanPerTask(
|
||||||
|
task="Task Number 1 - Task 1 description",
|
||||||
|
plan="\n\nPlan for task 1"
|
||||||
|
),
|
||||||
|
PlanPerTask(
|
||||||
|
task="Task Number 4 - Task 4 description",
|
||||||
|
plan="\n\nPlan for task 4"
|
||||||
|
),
|
||||||
|
PlanPerTask(
|
||||||
|
task="Task Number 2 - Task 2 description",
|
||||||
|
plan="\n\nPlan for task 2"
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
with patch.object(Task, "execute_sync") as mock_execute:
|
||||||
|
mock_execute.return_value = TaskOutput(
|
||||||
|
description="Planning task",
|
||||||
|
agent="planner",
|
||||||
|
pydantic=PlannerTaskPydanticOutput(
|
||||||
|
list_of_plans_per_task=wrong_order_plans
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Call the planning method
|
||||||
|
crew._handle_crew_planning()
|
||||||
|
|
||||||
|
# Verify that each task has the CORRECT plan appended to its description
|
||||||
|
# Task 1 should have "Plan for task 1", not "Plan for task 5"
|
||||||
|
assert "Plan for task 1" in crew.tasks[0].description, \
|
||||||
|
f"Task 1 should have 'Plan for task 1' but got: {crew.tasks[0].description}"
|
||||||
|
assert "Plan for task 2" in crew.tasks[1].description, \
|
||||||
|
f"Task 2 should have 'Plan for task 2' but got: {crew.tasks[1].description}"
|
||||||
|
assert "Plan for task 3" in crew.tasks[2].description, \
|
||||||
|
f"Task 3 should have 'Plan for task 3' but got: {crew.tasks[2].description}"
|
||||||
|
assert "Plan for task 4" in crew.tasks[3].description, \
|
||||||
|
f"Task 4 should have 'Plan for task 4' but got: {crew.tasks[3].description}"
|
||||||
|
assert "Plan for task 5" in crew.tasks[4].description, \
|
||||||
|
f"Task 5 should have 'Plan for task 5' but got: {crew.tasks[4].description}"
|
||||||
|
|
||||||
|
# Also verify that wrong plans are NOT in the wrong tasks
|
||||||
|
assert "Plan for task 5" not in crew.tasks[0].description, \
|
||||||
|
"Task 1 should not have Plan for task 5"
|
||||||
|
assert "Plan for task 3" not in crew.tasks[1].description, \
|
||||||
|
"Task 2 should not have Plan for task 3"
|
||||||
|
|||||||
Reference in New Issue
Block a user