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 abc import ABC, abstractmethod
from typing import Any, Dict, List, Optional from typing import Any, Dict, List, Optional, Union
from pydantic import PrivateAttr from pydantic import PrivateAttr
@@ -25,11 +25,11 @@ class BaseAgentAdapter(BaseAgent, ABC):
self._agent_config = agent_config self._agent_config = agent_config
@abstractmethod @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. """Configure and adapt tools for the specific agent implementation.
Args: Args:
tools: Optional list of BaseTool instances to be configured tools: Optional list of BaseTool instances and raw tool definitions to be configured
""" """
pass 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 from pydantic import Field, PrivateAttr
@@ -202,11 +202,13 @@ class LangGraphAgentAdapter(BaseAgentAdapter):
"""Configure the LangGraph agent for execution.""" """Configure the LangGraph agent for execution."""
self.configure_tools(tools) 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.""" """Configure tools for the LangGraph agent."""
if tools: if tools:
all_tools = list(self.tools or []) + list(tools or []) base_tools = [tool for tool in tools if isinstance(tool, BaseTool)]
self._tool_adapter.configure_tools(all_tools) 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() available_tools = self._tool_adapter.tools()
self._graph.tools = available_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 from pydantic import Field, PrivateAttr
@@ -152,10 +152,12 @@ class OpenAIAgentAdapter(BaseAgentAdapter):
self.agent_executor = Runner 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""" """Configure tools for the OpenAI Assistant"""
if tools: 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: if self._tool_adapter.converted_tools:
self._openai_agent.tools = 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 = "" available_tools_info = ""
if agent.tools: if agent.tools:
for tool in 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: else:
available_tools_info = "No tools available" 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.agents.parser import AgentAction
from crewai.security import Fingerprint from crewai.security import Fingerprint
@@ -10,7 +10,7 @@ from crewai.utilities.i18n import I18N
def execute_tool_and_check_finality( def execute_tool_and_check_finality(
agent_action: AgentAction, agent_action: AgentAction,
tools: List[CrewStructuredTool], tools: List[Union[CrewStructuredTool, dict]],
i18n: I18N, i18n: I18N,
agent_key: Optional[str] = None, agent_key: Optional[str] = None,
agent_role: 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 ToolResult containing the execution result and whether it should be treated as a final answer
""" """
try: 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: if agent_key and agent_role and agent:
fingerprint_context = fingerprint_context or {} fingerprint_context = fingerprint_context or {}
@@ -82,7 +83,7 @@ def execute_tool_and_check_finality(
# Handle invalid tool name # Handle invalid tool name
tool_result = i18n.errors("wrong_tool_name").format( tool_result = i18n.errors("wrong_tool_name").format(
tool=tool_calling.tool_name, 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) return ToolResult(tool_result, False)