mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-10 16:48:30 +00:00
Merge pull request #62 from angrybayblade/feat/composio-tool
Add `composio` CrewAI tool wrapper
This commit is contained in:
@@ -1,28 +1,28 @@
|
|||||||
from .tools.base_tool import BaseTool, Tool, tool
|
|
||||||
from .tools import (
|
from .tools import (
|
||||||
BrowserbaseLoadTool,
|
BrowserbaseLoadTool,
|
||||||
CodeDocsSearchTool,
|
CodeDocsSearchTool,
|
||||||
CodeInterpreterTool,
|
ComposioTool,
|
||||||
CSVSearchTool,
|
CSVSearchTool,
|
||||||
DirectorySearchTool,
|
DirectoryReadTool,
|
||||||
DOCXSearchTool,
|
DirectorySearchTool,
|
||||||
DirectoryReadTool,
|
DOCXSearchTool,
|
||||||
EXASearchTool,
|
EXASearchTool,
|
||||||
FileReadTool,
|
FileReadTool,
|
||||||
GithubSearchTool,
|
GithubSearchTool,
|
||||||
SerperDevTool,
|
JSONSearchTool,
|
||||||
TXTSearchTool,
|
LlamaIndexTool,
|
||||||
JSONSearchTool,
|
MDXSearchTool,
|
||||||
MDXSearchTool,
|
PDFSearchTool,
|
||||||
PDFSearchTool,
|
PGSearchTool,
|
||||||
PGSearchTool,
|
RagTool,
|
||||||
RagTool,
|
ScrapeElementFromWebsiteTool,
|
||||||
ScrapeElementFromWebsiteTool,
|
ScrapeWebsiteTool,
|
||||||
ScrapeWebsiteTool,
|
SeleniumScrapingTool,
|
||||||
SeleniumScrapingTool,
|
SerperDevTool,
|
||||||
WebsiteSearchTool,
|
TXTSearchTool,
|
||||||
XMLSearchTool,
|
WebsiteSearchTool,
|
||||||
YoutubeChannelSearchTool,
|
XMLSearchTool,
|
||||||
YoutubeVideoSearchTool,
|
YoutubeChannelSearchTool,
|
||||||
LlamaIndexTool
|
YoutubeVideoSearchTool,
|
||||||
)
|
)
|
||||||
|
from .tools.base_tool import BaseTool, Tool, tool
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
from .browserbase_load_tool.browserbase_load_tool import BrowserbaseLoadTool
|
from .browserbase_load_tool.browserbase_load_tool import BrowserbaseLoadTool
|
||||||
from .code_docs_search_tool.code_docs_search_tool import CodeDocsSearchTool
|
from .code_docs_search_tool.code_docs_search_tool import CodeDocsSearchTool
|
||||||
from .code_interpreter_tool.code_interpreter_tool import CodeInterpreterTool
|
from .code_interpreter_tool.code_interpreter_tool import CodeInterpreterTool
|
||||||
|
from .composio_tool.composio_tool import ComposioTool
|
||||||
from .csv_search_tool.csv_search_tool import CSVSearchTool
|
from .csv_search_tool.csv_search_tool import CSVSearchTool
|
||||||
from .directory_read_tool.directory_read_tool import DirectoryReadTool
|
from .directory_read_tool.directory_read_tool import DirectoryReadTool
|
||||||
from .directory_search_tool.directory_search_tool import DirectorySearchTool
|
from .directory_search_tool.directory_search_tool import DirectorySearchTool
|
||||||
|
|||||||
72
src/crewai_tools/tools/composio_tool/README.md
Normal file
72
src/crewai_tools/tools/composio_tool/README.md
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# ComposioTool Documentation
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This tools is a wrapper around the composio toolset and gives your agent access to a wide variety of tools from the composio SDK.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
To incorporate this tool into your project, follow the installation instructions below:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
pip install composio-core
|
||||||
|
pip install 'crewai[tools]'
|
||||||
|
```
|
||||||
|
|
||||||
|
after the installation is complete, either run `composio login` or export your composio API key as `COMPOSIO_API_KEY`.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
The following example demonstrates how to initialize the tool and execute a github action:
|
||||||
|
|
||||||
|
1. Initialize toolset
|
||||||
|
|
||||||
|
```python
|
||||||
|
from composio import App
|
||||||
|
from crewai_tools import ComposioTool
|
||||||
|
from crewai import Agent, Task
|
||||||
|
|
||||||
|
|
||||||
|
tools = [ComposioTool.from_action(action=Action.GITHUB_ACTIVITY_STAR_REPO_FOR_AUTHENTICATED_USER)]
|
||||||
|
```
|
||||||
|
|
||||||
|
If you don't know what action you want to use, use `from_app` and `tags` filter to get relevant actions
|
||||||
|
|
||||||
|
```python
|
||||||
|
tools = ComposioTool.from_app(App.GITHUB, tags=["important"])
|
||||||
|
```
|
||||||
|
|
||||||
|
or use `use_case` to search relevant actions
|
||||||
|
|
||||||
|
```python
|
||||||
|
tools = ComposioTool.from_app(App.GITHUB, use_case="Star a github repository")
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Define agent
|
||||||
|
|
||||||
|
```python
|
||||||
|
crewai_agent = Agent(
|
||||||
|
role="Github Agent",
|
||||||
|
goal="You take action on Github using Github APIs",
|
||||||
|
backstory=(
|
||||||
|
"You are AI agent that is responsible for taking actions on Github "
|
||||||
|
"on users behalf. You need to take action on Github using Github APIs"
|
||||||
|
),
|
||||||
|
verbose=True,
|
||||||
|
tools=tools,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Execute task
|
||||||
|
|
||||||
|
```python
|
||||||
|
task = Task(
|
||||||
|
description="Star a repo ComposioHQ/composio on GitHub",
|
||||||
|
agent=crewai_agent,
|
||||||
|
expected_output="if the star happened",
|
||||||
|
)
|
||||||
|
|
||||||
|
task.execute()
|
||||||
|
```
|
||||||
|
|
||||||
|
* More detailed list of tools can be found [here](https://app.composio.dev)
|
||||||
122
src/crewai_tools/tools/composio_tool/composio_tool.py
Normal file
122
src/crewai_tools/tools/composio_tool/composio_tool.py
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
"""
|
||||||
|
Composio tools wrapper.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import typing as t
|
||||||
|
|
||||||
|
import typing_extensions as te
|
||||||
|
|
||||||
|
from crewai_tools.tools.base_tool import BaseTool
|
||||||
|
|
||||||
|
|
||||||
|
class ComposioTool(BaseTool):
|
||||||
|
"""Wrapper for composio tools."""
|
||||||
|
|
||||||
|
composio_action: t.Callable
|
||||||
|
|
||||||
|
def _run(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
|
||||||
|
"""Run the composio action with given arguments."""
|
||||||
|
return self.composio_action(*args, **kwargs)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _check_connected_account(tool: t.Any, toolset: t.Any) -> None:
|
||||||
|
"""Check if connected account is required and if required it exists or not."""
|
||||||
|
from composio import Action
|
||||||
|
from composio.client.collections import ConnectedAccountModel
|
||||||
|
|
||||||
|
tool = t.cast(Action, tool)
|
||||||
|
if tool.no_auth:
|
||||||
|
return
|
||||||
|
|
||||||
|
connections = t.cast(
|
||||||
|
t.List[ConnectedAccountModel],
|
||||||
|
toolset.client.connected_accounts.get(),
|
||||||
|
)
|
||||||
|
if tool.app not in [connection.appUniqueId for connection in connections]:
|
||||||
|
raise RuntimeError(
|
||||||
|
f"No connected account found for app `{tool.app}`; "
|
||||||
|
f"Run `composio add {tool.app}` to fix this"
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_action(
|
||||||
|
cls,
|
||||||
|
action: t.Any,
|
||||||
|
**kwargs: t.Any,
|
||||||
|
) -> te.Self:
|
||||||
|
"""Wrap a composio tool as crewAI tool."""
|
||||||
|
|
||||||
|
from composio import Action, ComposioToolSet
|
||||||
|
from composio.constants import DEFAULT_ENTITY_ID
|
||||||
|
from composio.utils.shared import json_schema_to_model
|
||||||
|
|
||||||
|
toolset = ComposioToolSet()
|
||||||
|
if not isinstance(action, Action):
|
||||||
|
action = Action(action)
|
||||||
|
|
||||||
|
action = t.cast(Action, action)
|
||||||
|
cls._check_connected_account(
|
||||||
|
tool=action,
|
||||||
|
toolset=toolset,
|
||||||
|
)
|
||||||
|
|
||||||
|
(action_schema,) = toolset.get_action_schemas(actions=[action])
|
||||||
|
schema = action_schema.model_dump(exclude_none=True)
|
||||||
|
entity_id = kwargs.pop("entity_id", DEFAULT_ENTITY_ID)
|
||||||
|
|
||||||
|
def function(**kwargs: t.Any) -> t.Dict:
|
||||||
|
"""Wrapper function for composio action."""
|
||||||
|
return toolset.execute_action(
|
||||||
|
action=Action(schema["name"]),
|
||||||
|
params=kwargs,
|
||||||
|
entity_id=entity_id,
|
||||||
|
)
|
||||||
|
|
||||||
|
function.__name__ = schema["name"]
|
||||||
|
function.__doc__ = schema["description"]
|
||||||
|
|
||||||
|
return cls(
|
||||||
|
name=schema["name"],
|
||||||
|
description=schema["description"],
|
||||||
|
args_schema=json_schema_to_model(
|
||||||
|
action_schema.parameters.model_dump(
|
||||||
|
exclude_none=True,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
composio_action=function,
|
||||||
|
**kwargs,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_app(
|
||||||
|
cls,
|
||||||
|
*apps: t.Any,
|
||||||
|
tags: t.Optional[t.List[str]] = None,
|
||||||
|
use_case: t.Optional[str] = None,
|
||||||
|
**kwargs: t.Any,
|
||||||
|
) -> t.List[te.Self]:
|
||||||
|
"""Create toolset from an app."""
|
||||||
|
if len(apps) == 0:
|
||||||
|
raise ValueError("You need to provide at least one app name")
|
||||||
|
|
||||||
|
if use_case is None and tags is None:
|
||||||
|
raise ValueError("Both `use_case` and `tags` cannot be `None`")
|
||||||
|
|
||||||
|
if use_case is not None and tags is not None:
|
||||||
|
raise ValueError(
|
||||||
|
"Cannot use both `use_case` and `tags` to filter the actions"
|
||||||
|
)
|
||||||
|
|
||||||
|
from composio import ComposioToolSet
|
||||||
|
|
||||||
|
toolset = ComposioToolSet()
|
||||||
|
if use_case is not None:
|
||||||
|
return [
|
||||||
|
cls.from_action(action=action, **kwargs)
|
||||||
|
for action in toolset.find_actions_by_use_case(*apps, use_case=use_case)
|
||||||
|
]
|
||||||
|
|
||||||
|
return [
|
||||||
|
cls.from_action(action=action, **kwargs)
|
||||||
|
for action in toolset.find_actions_by_tags(*apps, tags=tags)
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user