From 65c90152af34ab3837d2640c130f6a82a66413e4 Mon Sep 17 00:00:00 2001 From: lorenzejay Date: Fri, 11 Apr 2025 09:27:28 -0700 Subject: [PATCH] feat: implement BaseToolAdapter for tool integration - Introduced BaseToolAdapter as an abstract base class for tool adapters in CrewAI. - Updated LangGraphToolAdapter and OpenAIAgentToolAdapter to inherit from BaseToolAdapter, enhancing their structure and functionality. - Improved tool configuration methods to support better integration with various frameworks. - Added type hints and documentation for clarity and maintainability. --- .../agent_adapters/base_tool_adapter.py | 32 +++++++++++++++++ .../langgraph/langgraph_adapter.py | 15 ++++---- .../langgraph/langgraph_tool_adapter.py | 34 +++++++++---------- .../openai_agents/openai_adapter.py | 1 - .../openai_agent_tool_adapter.py | 11 +++--- 5 files changed, 60 insertions(+), 33 deletions(-) create mode 100644 src/crewai/agents/agent_adapters/base_tool_adapter.py diff --git a/src/crewai/agents/agent_adapters/base_tool_adapter.py b/src/crewai/agents/agent_adapters/base_tool_adapter.py new file mode 100644 index 000000000..001df2e38 --- /dev/null +++ b/src/crewai/agents/agent_adapters/base_tool_adapter.py @@ -0,0 +1,32 @@ +from abc import ABC, abstractmethod +from typing import Any, List, Optional + +from crewai.tools.base_tool import BaseTool + + +class BaseToolAdapter(ABC): + """Base class for all tool adapters in CrewAI. + + This abstract class defines the common interface that all tool adapters + must implement. It provides the structure for adapting CrewAI tools to + different frameworks and platforms. + """ + + original_tools: List[BaseTool] = [] + converted_tools: List[Any] = [] + + def __init__(self, tools: Optional[List[BaseTool]] = None): + self.tools = tools or [] + + @abstractmethod + def configure_tools(self, tools: List[BaseTool]) -> None: + """Configure and convert tools for the specific implementation. + + Args: + tools: List of BaseTool instances to be configured and converted + """ + pass + + def all_tools(self) -> List[Any]: + """Return all converted tools.""" + return self.converted_tools diff --git a/src/crewai/agents/agent_adapters/langgraph/langgraph_adapter.py b/src/crewai/agents/agent_adapters/langgraph/langgraph_adapter.py index 49ac2b224..1ea2b457d 100644 --- a/src/crewai/agents/agent_adapters/langgraph/langgraph_adapter.py +++ b/src/crewai/agents/agent_adapters/langgraph/langgraph_adapter.py @@ -37,7 +37,6 @@ class LangGraphAgentAdapter(BaseAgentAdapter): function_calling_llm: Any = Field(default=None) step_callback: Any = Field(default=None) - # Config parameters for LangGraph model: str = Field(default="gpt-4o") verbose: bool = Field(default=False) @@ -81,7 +80,6 @@ class LangGraphAgentAdapter(BaseAgentAdapter): tools=converted_tools, checkpointer=self._memory, ) - print("langgraph graph", self._graph) except ImportError as e: self._logger.log( @@ -94,15 +92,15 @@ class LangGraphAgentAdapter(BaseAgentAdapter): def _build_system_prompt(self) -> str: """Build a system prompt for the LangGraph agent.""" - base_prompt = f"""You are {self.role}. + base_prompt = f""" + You are {self.role}. -Your goal is: {self.goal} + Your goal is: {self.goal} -Your backstory: {self.backstory} + Your backstory: {self.backstory} -When working on tasks, think step-by-step and use the available tools when necessary. -""" - # Enhance with structured output instructions if configured + When working on tasks, think step-by-step and use the available tools when necessary. + """ return self._converter_adapter.enhance_system_prompt(base_prompt) def execute_task( @@ -114,7 +112,6 @@ When working on tasks, think step-by-step and use the available tools when neces """Execute a task using the LangGraph workflow.""" self.create_agent_executor(tools) - # Configure structured output if needed self.configure_structured_output(task) try: diff --git a/src/crewai/agents/agent_adapters/langgraph/langgraph_tool_adapter.py b/src/crewai/agents/agent_adapters/langgraph/langgraph_tool_adapter.py index cff6804fd..cdbf4bc5c 100644 --- a/src/crewai/agents/agent_adapters/langgraph/langgraph_tool_adapter.py +++ b/src/crewai/agents/agent_adapters/langgraph/langgraph_tool_adapter.py @@ -1,30 +1,29 @@ from typing import Any, List, Optional +from crewai.agents.agent_adapters.base_tool_adapter import BaseToolAdapter from crewai.tools.base_tool import BaseTool -class LangGraphToolAdapter: - """Adapts CrewAI tools to LangGraph-compatible format""" +class LangGraphToolAdapter(BaseToolAdapter): + """Adapts CrewAI tools to LangGraph agent tool compatible format""" def __init__(self, tools: Optional[List[BaseTool]] = None): - self.tools = tools or [] - self.converted_tools = [] + self.original_tools = tools or [] def configure_tools(self, tools: List[BaseTool]) -> None: - """Convert CrewAI tools to LangGraph tools""" - self.tools = tools - self.converted_tools = self._convert_tools(tools) - - def _convert_tools(self, tools: List[BaseTool]) -> List[Any]: """ - Convert CrewAI tools to LangGraph-compatible tools - LangGraph expects tools in langchain_core.tools format + Configure and convert CrewAI tools to LangGraph-compatible format. + LangGraph expects tools in langchain_core.tools format. """ from langchain_core.tools import StructuredTool - converted_tools = [] - - for tool in tools: + self.tools = tools + self.converted_tools = [] + if self.original_tools: + all_tools = tools + self.original_tools + else: + all_tools = tools + for tool in all_tools: # Create a wrapper function that matches LangGraph's expected format def tool_wrapper(*args, tool=tool, **kwargs): # Extract inputs based on the tool's schema @@ -36,12 +35,13 @@ class LangGraphToolAdapter: return tool.run(**kwargs) converted_tool = StructuredTool( - name=tool.name, + name=tool.name.replace(" ", "_"), description=tool.description, func=tool_wrapper, args_schema=tool.args_schema, ) - converted_tools.append(converted_tool) + self.converted_tools.append(converted_tool) - return converted_tools + def all_tools(self) -> List[Any]: + return self.converted_tools diff --git a/src/crewai/agents/agent_adapters/openai_agents/openai_adapter.py b/src/crewai/agents/agent_adapters/openai_agents/openai_adapter.py index 1f941d02a..d0f74f0c4 100644 --- a/src/crewai/agents/agent_adapters/openai_agents/openai_adapter.py +++ b/src/crewai/agents/agent_adapters/openai_agents/openai_adapter.py @@ -31,7 +31,6 @@ class OpenAIAgentAdapter(BaseAgentAdapter): _active_thread: Optional[str] = PrivateAttr(default=None) function_calling_llm: Any = Field(default=None) step_callback: Any = Field(default=None) - converted_tools: Optional[List[Tool]] = Field(default=None) _tool_adapter: OpenAIAgentToolAdapter = PrivateAttr() _converter_adapter: OpenAIConverterAdapter = PrivateAttr() diff --git a/src/crewai/agents/agent_adapters/openai_agents/openai_agent_tool_adapter.py b/src/crewai/agents/agent_adapters/openai_agents/openai_agent_tool_adapter.py index 5e0ee033c..0c7a56c6b 100644 --- a/src/crewai/agents/agent_adapters/openai_agents/openai_agent_tool_adapter.py +++ b/src/crewai/agents/agent_adapters/openai_agents/openai_agent_tool_adapter.py @@ -2,21 +2,20 @@ from typing import Any, List, Optional from agents import FunctionTool, Tool +from crewai.agents.agent_adapters.base_tool_adapter import BaseToolAdapter from crewai.tools import BaseTool -class OpenAIAgentToolAdapter: +class OpenAIAgentToolAdapter(BaseToolAdapter): """Adapter for OpenAI Assistant tools""" - converted_tools: Optional[List[Tool]] = None - def __init__(self, tools: Optional[List[BaseTool]] = None): - self.tools = tools + self.original_tools = tools or [] def configure_tools(self, tools: List[BaseTool]) -> None: """Configure tools for the OpenAI Assistant""" - if self.tools: - all_tools = tools + self.tools + if self.original_tools: + all_tools = tools + self.original_tools else: all_tools = tools if all_tools: