From 403890d8e82e24df600ac94e50490a68e7efa8ff Mon Sep 17 00:00:00 2001 From: Brandon Hancock Date: Thu, 13 Mar 2025 11:02:28 -0400 Subject: [PATCH] wip --- src/crewai/agents/agent_builder/base_agent.py | 4 +-- src/crewai/crew.py | 34 ++++++++++++------- src/crewai/tools/agent_tools/agent_tools.py | 2 +- tests/crew_test.py | 6 +++- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/src/crewai/agents/agent_builder/base_agent.py b/src/crewai/agents/agent_builder/base_agent.py index 12351dbff..223d5a7a2 100644 --- a/src/crewai/agents/agent_builder/base_agent.py +++ b/src/crewai/agents/agent_builder/base_agent.py @@ -62,7 +62,7 @@ class BaseAgent(ABC, BaseModel): Abstract method to create an agent executor. _parse_tools(tools: List[BaseTool]) -> List[Any]: Abstract method to parse tools. - get_delegation_tools(agents: Sequence["BaseAgent"]) -> List[BaseTool]: + get_delegation_tools(agents: Sequence["BaseAgent"]) -> Sequence[BaseTool]: Abstract method to set the agents task tools for handling delegation and question asking to other agents in crew. get_output_converter(llm, model, instructions): Abstract method to get the converter class for the agent to create json/pydantic outputs. @@ -253,7 +253,7 @@ class BaseAgent(ABC, BaseModel): pass @abstractmethod - def get_delegation_tools(self, agents: Sequence["BaseAgent"]) -> List[BaseTool]: + def get_delegation_tools(self, agents: Sequence["BaseAgent"]) -> Sequence[BaseTool]: """Set the task tools that init BaseAgenTools class.""" pass diff --git a/src/crewai/crew.py b/src/crewai/crew.py index e26929e4d..c7e8a5dc7 100644 --- a/src/crewai/crew.py +++ b/src/crewai/crew.py @@ -6,7 +6,7 @@ import warnings from concurrent.futures import Future from copy import copy as shallow_copy from hashlib import md5 -from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union +from typing import Any, Callable, Dict, List, Optional, Sequence, Set, Tuple, Union from pydantic import ( UUID4, @@ -35,6 +35,7 @@ from crewai.process import Process from crewai.task import Task from crewai.tasks.conditional_task import ConditionalTask from crewai.tasks.task_output import TaskOutput +from crewai.tools import BaseTool from crewai.tools.agent_tools.agent_tools import AgentTools from crewai.tools.base_tool import Tool from crewai.types.usage_metrics import UsageMetrics @@ -871,8 +872,8 @@ class Crew(BaseModel): return None def _prepare_tools( - self, agent: BaseAgent, task: Task, tools: List[Tool] - ) -> List[Tool]: + self, agent: BaseAgent, task: Task, tools: Sequence[BaseTool] + ) -> Sequence[BaseTool]: # Add delegation tools if agent allows delegation if agent.allow_delegation: if self.process == Process.hierarchical: @@ -887,10 +888,10 @@ class Crew(BaseModel): tools = self._add_delegation_tools(task, tools) # Add code execution tools if agent allows code execution - if agent.allow_code_execution: + if hasattr(agent, "allow_code_execution") and agent.allow_code_execution: tools = self._add_code_execution_tools(agent, tools) - if agent and agent.multimodal: + if hasattr(agent, "multimodal") and agent.multimodal: tools = self._add_multimodal_tools(agent, tools) return tools @@ -901,8 +902,8 @@ class Crew(BaseModel): return task.agent def _merge_tools( - self, existing_tools: List[Tool], new_tools: List[Tool] - ) -> List[Tool]: + self, existing_tools: Sequence[BaseTool], new_tools: Sequence[BaseTool] + ) -> Sequence[BaseTool]: """Merge new tools into existing tools list, avoiding duplicates by tool name.""" if not new_tools: return existing_tools @@ -919,20 +920,29 @@ class Crew(BaseModel): return tools def _inject_delegation_tools( - self, tools: List[Tool], task_agent: BaseAgent, agents: List[BaseAgent] + self, + tools: Sequence[BaseTool], + task_agent: BaseAgent, + agents: Sequence[BaseAgent], ): delegation_tools = task_agent.get_delegation_tools(agents) return self._merge_tools(tools, delegation_tools) - def _add_multimodal_tools(self, agent: BaseAgent, tools: List[Tool]): + def _add_multimodal_tools( + self, agent: BaseAgent, tools: Sequence[BaseTool] + ) -> Sequence[BaseTool]: multimodal_tools = agent.get_multimodal_tools() return self._merge_tools(tools, multimodal_tools) - def _add_code_execution_tools(self, agent: BaseAgent, tools: List[Tool]): + def _add_code_execution_tools( + self, agent: BaseAgent, tools: Sequence[BaseTool] + ) -> Sequence[BaseTool]: code_tools = agent.get_code_execution_tools() return self._merge_tools(tools, code_tools) - def _add_delegation_tools(self, task: Task, tools: List[Tool]): + def _add_delegation_tools( + self, task: Task, tools: Sequence[BaseTool] + ) -> Sequence[BaseTool]: # If the agent has specific agents to delegate to, use those if task.agent and task.agent.delegate_to is not None: agents_for_delegation = task.agent.delegate_to @@ -956,7 +966,7 @@ class Crew(BaseModel): task_name=task.name, task=task.description, agent=role, status="started" ) - def _update_manager_tools(self, task: Task, tools: List[Tool]): + def _update_manager_tools(self, task: Task, tools: Sequence[BaseTool]): if self.manager_agent: if task.agent: tools = self._inject_delegation_tools(tools, task.agent, [task.agent]) diff --git a/src/crewai/tools/agent_tools/agent_tools.py b/src/crewai/tools/agent_tools/agent_tools.py index ebfff84de..5de12d662 100644 --- a/src/crewai/tools/agent_tools/agent_tools.py +++ b/src/crewai/tools/agent_tools/agent_tools.py @@ -15,7 +15,7 @@ class AgentTools: self.agents = agents self.i18n = i18n - def tools(self) -> list[BaseTool]: + def tools(self) -> Sequence[BaseTool]: """Get all available agent tools""" coworkers = ", ".join([f"{agent.role}" for agent in self.agents]) diff --git a/tests/crew_test.py b/tests/crew_test.py index 11fadd795..692eba39f 100644 --- a/tests/crew_test.py +++ b/tests/crew_test.py @@ -723,13 +723,14 @@ def test_task_tools_override_agent_tools(): crew.kickoff() # Verify task tools override agent tools + assert task.tools is not None assert len(task.tools) == 1 # AnotherTestTool assert any(isinstance(tool, AnotherTestTool) for tool in task.tools) assert not any(isinstance(tool, TestTool) for tool in task.tools) # Verify agent tools remain unchanged + assert new_researcher.tools is not None assert len(new_researcher.tools) == 1 - assert isinstance(new_researcher.tools[0], TestTool) @pytest.mark.vcr(filter_headers=["authorization"]) @@ -1595,6 +1596,8 @@ def test_crew_function_calling_llm(): crew = Crew(agents=[agent1], tasks=[essay]) result = crew.kickoff() assert result.raw == "Howdy!" + assert agent1.tools is not None + assert len(agent1.tools) == 0 @pytest.mark.vcr(filter_headers=["authorization"]) @@ -4157,6 +4160,7 @@ def test_manager_agent_with_tools_and_delegation(): crew._create_manager_agent() # Verify that the manager agent has tools + assert manager.tools is not None assert len(manager.tools) == 1 assert manager.tools[0].name == "Simple Test Tool"