mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-15 19:18:30 +00:00
feat: Add ToolCollection class for named tool access (#339)
This change allows accessing tools by name (tools["tool_name"]) in addition to index (tools[0]), making it more intuitive and convenient to work with multiple tools without needing to remember their position in the list
This commit is contained in:
@@ -4,7 +4,7 @@ import logging
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from crewai.tools import BaseTool
|
||||
|
||||
from crewai_tools.adapters.tool_collection import ToolCollection
|
||||
"""
|
||||
MCPServer for CrewAI.
|
||||
|
||||
@@ -114,7 +114,7 @@ class MCPServerAdapter:
|
||||
self._adapter.__exit__(None, None, None)
|
||||
|
||||
@property
|
||||
def tools(self) -> list[BaseTool]:
|
||||
def tools(self) -> ToolCollection[BaseTool]:
|
||||
"""The CrewAI tools available from the MCP server.
|
||||
|
||||
Raises:
|
||||
@@ -127,7 +127,7 @@ class MCPServerAdapter:
|
||||
raise ValueError(
|
||||
"MCP server not started, run `mcp_server.start()` first before accessing `tools`"
|
||||
)
|
||||
return self._tools
|
||||
return ToolCollection(self._tools)
|
||||
|
||||
def __enter__(self):
|
||||
"""
|
||||
|
||||
59
src/crewai_tools/adapters/tool_collection.py
Normal file
59
src/crewai_tools/adapters/tool_collection.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from typing import List, Optional, Union, TypeVar, Generic, Dict
|
||||
from crewai.tools import BaseTool
|
||||
|
||||
T = TypeVar('T', bound=BaseTool)
|
||||
|
||||
class ToolCollection(list, Generic[T]):
|
||||
"""
|
||||
A collection of tools that can be accessed by index or name
|
||||
|
||||
This class extends the built-in list to provide dictionary-like
|
||||
access to tools based on their name property.
|
||||
|
||||
Usage:
|
||||
tools = ToolCollection(list_of_tools)
|
||||
# Access by index (regular list behavior)
|
||||
first_tool = tools[0]
|
||||
# Access by name (new functionality)
|
||||
search_tool = tools["search"]
|
||||
"""
|
||||
|
||||
def __init__(self, tools: Optional[List[T]] = None):
|
||||
super().__init__(tools or [])
|
||||
self._name_cache: Dict[str, T] = {}
|
||||
self._build_name_cache()
|
||||
|
||||
def _build_name_cache(self) -> None:
|
||||
self._name_cache = {tool.name: tool for tool in self}
|
||||
|
||||
def __getitem__(self, key: Union[int, str]) -> T:
|
||||
if isinstance(key, str):
|
||||
return self._name_cache[key]
|
||||
return super().__getitem__(key)
|
||||
|
||||
def append(self, tool: T) -> None:
|
||||
super().append(tool)
|
||||
self._name_cache[tool.name] = tool
|
||||
|
||||
def extend(self, tools: List[T]) -> None:
|
||||
super().extend(tools)
|
||||
self._build_name_cache()
|
||||
|
||||
def insert(self, index: int, tool: T) -> None:
|
||||
super().insert(index, tool)
|
||||
self._name_cache[tool.name] = tool
|
||||
|
||||
def remove(self, tool: T) -> None:
|
||||
super().remove(tool)
|
||||
if tool.name in self._name_cache:
|
||||
del self._name_cache[tool.name]
|
||||
|
||||
def pop(self, index: int = -1) -> T:
|
||||
tool = super().pop(index)
|
||||
if tool.name in self._name_cache:
|
||||
del self._name_cache[tool.name]
|
||||
return tool
|
||||
|
||||
def clear(self) -> None:
|
||||
super().clear()
|
||||
self._name_cache.clear()
|
||||
@@ -7,6 +7,7 @@ import typing as t
|
||||
import logging
|
||||
from crewai.tools import BaseTool
|
||||
from crewai_tools.adapters.enterprise_adapter import EnterpriseActionKitToolAdapter
|
||||
from crewai_tools.adapters.tool_collection import ToolCollection
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -16,7 +17,7 @@ def CrewaiEnterpriseTools(
|
||||
actions_list: t.Optional[t.List[str]] = None,
|
||||
enterprise_action_kit_project_id: t.Optional[str] = None,
|
||||
enterprise_action_kit_project_url: t.Optional[str] = None,
|
||||
) -> t.List[BaseTool]:
|
||||
) -> ToolCollection[BaseTool]:
|
||||
"""Factory function that returns crewai enterprise tools.
|
||||
|
||||
Args:
|
||||
@@ -24,9 +25,11 @@ def CrewaiEnterpriseTools(
|
||||
If not provided, will try to use CREWAI_ENTERPRISE_TOOLS_TOKEN env var.
|
||||
actions_list: Optional list of specific tool names to include.
|
||||
If provided, only tools with these names will be returned.
|
||||
enterprise_action_kit_project_id: Optional ID of the Enterprise Action Kit project.
|
||||
enterprise_action_kit_project_url: Optional URL of the Enterprise Action Kit project.
|
||||
|
||||
Returns:
|
||||
A list of BaseTool instances for enterprise actions
|
||||
A ToolCollection of BaseTool instances for enterprise actions
|
||||
"""
|
||||
if enterprise_token is None:
|
||||
enterprise_token = os.environ.get("CREWAI_ENTERPRISE_TOOLS_TOKEN")
|
||||
@@ -47,7 +50,8 @@ def CrewaiEnterpriseTools(
|
||||
all_tools = adapter.tools()
|
||||
|
||||
if actions_list is None:
|
||||
return all_tools
|
||||
return ToolCollection(all_tools)
|
||||
|
||||
# Filter tools based on the provided list
|
||||
return [tool for tool in all_tools if tool.name in actions_list]
|
||||
filtered_tools = [tool for tool in all_tools if tool.name in actions_list]
|
||||
return ToolCollection(filtered_tools)
|
||||
|
||||
Reference in New Issue
Block a user