fix: Resolve type-checker errors for mixed tool types

- Add Union types to handle both BaseTool and dict in tool parameters
- Update tool utility functions to handle mixed types safely
- Filter raw tool definitions in agent adapters
- Fix experimental evaluation metrics to handle mixed tool types
- Maintain backward compatibility while adding hosted tools support

Co-Authored-By: João <joao@crewai.com>
This commit is contained in:
Devin AI
2025-08-18 14:03:40 +00:00
parent 95d3b5dbc3
commit be09b519c4
5 changed files with 22 additions and 15 deletions

View File

@@ -1,5 +1,5 @@
from abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional
from typing import Any, Dict, List, Optional, Union
from pydantic import PrivateAttr
@@ -25,11 +25,11 @@ class BaseAgentAdapter(BaseAgent, ABC):
self._agent_config = agent_config
@abstractmethod
def configure_tools(self, tools: Optional[List[BaseTool]] = None) -> None:
def configure_tools(self, tools: Optional[List[Union[BaseTool, dict]]] = None) -> None:
"""Configure and adapt tools for the specific agent implementation.
Args:
tools: Optional list of BaseTool instances to be configured
tools: Optional list of BaseTool instances and raw tool definitions to be configured
"""
pass

View File

@@ -1,4 +1,4 @@
from typing import Any, AsyncIterable, Dict, List, Optional
from typing import Any, AsyncIterable, Dict, List, Optional, Union
from pydantic import Field, PrivateAttr
@@ -202,11 +202,13 @@ class LangGraphAgentAdapter(BaseAgentAdapter):
"""Configure the LangGraph agent for execution."""
self.configure_tools(tools)
def configure_tools(self, tools: Optional[List[BaseTool]] = None) -> None:
def configure_tools(self, tools: Optional[List[Union[BaseTool, dict]]] = None) -> None:
"""Configure tools for the LangGraph agent."""
if tools:
all_tools = list(self.tools or []) + list(tools or [])
self._tool_adapter.configure_tools(all_tools)
base_tools = [tool for tool in tools if isinstance(tool, BaseTool)]
all_tools = list(self.tools or []) + list(base_tools or [])
if all_tools:
self._tool_adapter.configure_tools(all_tools)
available_tools = self._tool_adapter.tools()
self._graph.tools = available_tools

View File

@@ -1,4 +1,4 @@
from typing import Any, List, Optional
from typing import Any, List, Optional, Union
from pydantic import Field, PrivateAttr
@@ -152,10 +152,12 @@ class OpenAIAgentAdapter(BaseAgentAdapter):
self.agent_executor = Runner
def configure_tools(self, tools: Optional[List[BaseTool]] = None) -> None:
def configure_tools(self, tools: Optional[List[Union[BaseTool, dict]]] = None) -> None:
"""Configure tools for the OpenAI Assistant"""
if tools:
self._tool_adapter.configure_tools(tools)
base_tools = [tool for tool in tools if isinstance(tool, BaseTool)]
if base_tools:
self._tool_adapter.configure_tools(base_tools)
if self._tool_adapter.converted_tools:
self._openai_agent.tools = self._tool_adapter.converted_tools

View File

@@ -43,7 +43,9 @@ class ToolSelectionEvaluator(BaseEvaluator):
available_tools_info = ""
if agent.tools:
for tool in agent.tools:
available_tools_info += f"- {tool.name}: {tool.description}\n"
tool_name = tool.name if hasattr(tool, 'name') else tool.get('name', 'unknown')
tool_desc = tool.description if hasattr(tool, 'description') else tool.get('description', 'No description')
available_tools_info += f"- {tool_name}: {tool_desc}\n"
else:
available_tools_info = "No tools available"

View File

@@ -1,4 +1,4 @@
from typing import Any, Dict, List, Optional
from typing import Any, Dict, List, Optional, Union
from crewai.agents.parser import AgentAction
from crewai.security import Fingerprint
@@ -10,7 +10,7 @@ from crewai.utilities.i18n import I18N
def execute_tool_and_check_finality(
agent_action: AgentAction,
tools: List[CrewStructuredTool],
tools: List[Union[CrewStructuredTool, dict]],
i18n: I18N,
agent_key: Optional[str] = None,
agent_role: Optional[str] = None,
@@ -37,7 +37,8 @@ def execute_tool_and_check_finality(
ToolResult containing the execution result and whether it should be treated as a final answer
"""
try:
tool_name_to_tool_map = {tool.name: tool for tool in tools}
executable_tools = [tool for tool in tools if hasattr(tool, 'name') and hasattr(tool, 'result_as_answer')]
tool_name_to_tool_map = {tool.name: tool for tool in executable_tools}
if agent_key and agent_role and agent:
fingerprint_context = fingerprint_context or {}
@@ -82,7 +83,7 @@ def execute_tool_and_check_finality(
# Handle invalid tool name
tool_result = i18n.errors("wrong_tool_name").format(
tool=tool_calling.tool_name,
tools=", ".join([tool.name.casefold() for tool in tools]),
tools=", ".join([tool.name.casefold() for tool in executable_tools]),
)
return ToolResult(tool_result, False)