Compare commits

...

2 Commits

Author SHA1 Message Date
Devin AI
5ccdfdb1d3 Fix lint errors: remove unused variable and add raw string prefixes
- Remove unused 'crew' variable in test_hierarchical_crew_does_not_propagate_agent_tools_to_manager (F841)
- Add raw string prefixes to regex patterns to comply with RUF043 linting rule
- Pre-existing RUF043 errors in changed files were blocking PR, so fixed them

Co-Authored-By: João <joao@crewai.com>
2025-10-09 15:51:17 +00:00
Devin AI
01114168df Fix tool propagation bug in hierarchical crews (#3679)
- Remove check_tools validator from task.py that was extending task.tools
  with agent.tools at creation time
- This caused manager agents in hierarchical crews to incorrectly inherit
  tools from task agents
- The crew.py execution logic already handles tool resolution correctly
  at execution time via fallback: task.tools or agent_to_use.tools or []
- Add reproduction test test_hierarchical_crew_does_not_propagate_agent_tools_to_manager
- Update test_task_tool_reflect_agent_tools to verify execution-time behavior

Fixes #3679

Co-Authored-By: João <joao@crewai.com>
2025-10-09 15:32:45 +00:00
3 changed files with 50 additions and 12 deletions

View File

@@ -336,12 +336,6 @@ class Task(BaseModel):
setattr(self, key, value)
return self
@model_validator(mode="after")
def check_tools(self):
"""Check if the tools are set."""
if not self.tools and self.agent and self.agent.tools:
self.tools.extend(self.agent.tools)
return self
@model_validator(mode="after")
def check_output(self):

View File

@@ -200,7 +200,7 @@ def test_async_task_cannot_include_sequential_async_tasks_in_context(
# This should raise an error because task2 is async and has task1 in its context without a sync task in between
with pytest.raises(
ValueError,
match="Task 'Task 2' is asynchronous and cannot include other sequential asynchronous tasks in its context.",
match=r"Task 'Task 2' is asynchronous and cannot include other sequential asynchronous tasks in its context.",
):
Crew(tasks=[task1, task2, task3, task4, task5], agents=[researcher, writer])
@@ -238,7 +238,7 @@ def test_context_no_future_tasks(researcher, writer):
# This should raise an error because task1 has a context dependency on a future task (task4)
with pytest.raises(
ValueError,
match="Task 'Task 1' has a context dependency on a future task 'Task 4', which is not allowed.",
match=r"Task 'Task 1' has a context dependency on a future task 'Task 4', which is not allowed.",
):
Crew(tasks=[task1, task2, task3, task4], agents=[researcher, writer])
@@ -3339,7 +3339,7 @@ def test_replay_with_invalid_task_id():
):
with pytest.raises(
ValueError,
match="Task with id bf5b09c9-69bd-4eb8-be12-f9e5bae31c2d not found in the crew's tasks.",
match=r"Task with id bf5b09c9-69bd-4eb8-be12-f9e5bae31c2d not found in the crew's tasks.",
):
crew.replay("bf5b09c9-69bd-4eb8-be12-f9e5bae31c2d")
@@ -3814,6 +3814,46 @@ def test_fetch_inputs():
)
def test_hierarchical_crew_does_not_propagate_agent_tools_to_manager():
"""
Test that in hierarchical crews, manager agent doesn't inherit task agents' tools.
This verifies that the check_tools validator doesn't pollute task.tools at creation time.
Fixes issue #3679: https://github.com/crewAIInc/crewAI/issues/3679
"""
from crewai.tools import tool
@tool
def agent_specific_tool() -> str:
"""A tool that should only be available to the specific agent."""
return "agent specific result"
agent_with_tools = Agent(
role="Specialist",
goal="Do specialized work with custom tools",
backstory="You are a specialist with specific tools",
tools=[agent_specific_tool],
allow_delegation=False,
)
# Create a task with an agent that has tools, but don't assign tools to the task
task = Task(
description="Perform a specialized task",
expected_output="Task result",
agent=agent_with_tools,
)
Crew(
agents=[agent_with_tools],
tasks=[task],
process=Process.hierarchical,
manager_llm="gpt-4o",
)
# Verify that task.tools is empty (not populated with agent's tools)
assert task.tools == []
assert len(task.tools) == 0
def test_task_tools_preserve_code_execution_tools():
"""
Test that task tools don't override code execution tools when allow_code_execution=True

View File

@@ -20,11 +20,13 @@ from crewai.utilities.string_utils import interpolate_only
def test_task_tool_reflect_agent_tools():
"""Test that agent tools are available during task execution via crew fallback logic."""
from crewai.tools import tool
@tool
def fake_tool() -> None:
def fake_tool() -> str:
"Fake tool"
return "result"
researcher = Agent(
role="Researcher",
@@ -40,7 +42,9 @@ def test_task_tool_reflect_agent_tools():
agent=researcher,
)
assert task.tools == [fake_tool]
assert task.tools == []
assert researcher.tools == [fake_tool]
def test_task_tool_takes_precedence_over_agent_tools():
@@ -1218,7 +1222,7 @@ def test_create_directory_false():
assert not resolved_dir.exists()
with pytest.raises(
RuntimeError, match="Directory .* does not exist and create_directory is False"
RuntimeError, match=r"Directory .* does not exist and create_directory is False"
):
task._save_file("test content")