# CrewAI Integration
crewai-arcade enables you to add Arcade tools and Arcade Auth into your
CrewAI applications. Just create an `ArcadeToolManager` and add your
tools to your CrewAI Agent/Tasks.
## Initializing the ArcadeToolManager
There are two main ways to initialize your `ArcadeToolManager`
1. Default handling of tool authorization and execution:
```py
"""
When you provide a user id to the ArcadeToolManger,
it will handle the tool authorization and tool execution for you
"""
manager = ArcadeToolManager(default_user_id="me@example.com,
api_key="...")
```
2. Custom handling of tool authorization and execution
```py
"""
Provide a callback function to the `ArcadeToolManager` that handles
tool authorization and tool execution. The callback function will be
called whenever your CrewAI
application wants to call a tool.
"""
def custom_tool_executor(
manager: ArcadeToolManager, tool_name: str, **tool_input: dict[str, Any]
) -> Any:
"""Custom tool executor for the ArcadeToolManager
ArcadeToolManager's default executor handles authorization and tool
execution.
This function overrides the default executor to handle authorization and
tool execution
in a custom way.
"""
# Your custom tool auth logic goes here
# Your custom tool execution logic goes here
...
manager = ArcadeToolManager(executor=custom_tool_executor,
api_key="...")
```
## Tool Registration
1. Initialize the tools in the manager
```py
"""
Clears any existing tools in the manager and replaces them with tools
and toolkits that are provided.
"""
manager.init_tools(tools=["Google.ListEmails"], toolkits=["Slack"])
```
2. Add tools to the manager
```py
"""
Adds tools and toolkits to the manager's internal tool list.
"""
manager.add_tools(tools=["Google.ListEmails"], toolkits=["Slack"])
```
3. Retrieve tools and toolkits from the manager
```py
"""
Retrieves the provided tools and toolkits as CrewAI StructuredTools.
"""
manager.get_tools(tools=["Google.ListEmails"], toolkits=["Slack"])
```
## Auth Helpers
The `ArcadeToolManager` provides multiple helper methods for when you
need to create
a custom auth flow.
1. `authorize_tool` handles the whole authorization flow for you. This
is used internally when a custom auth flow is not needed.
2. `requires_auth(tool_name)` checks if the provided tool has
authorization requirements.
3. `authorize(tool_name, user_id)` authorizes the use of the provided
tool for the provided user ID
4. `is_authorized(tool_name, user_id)` checks if a tool is authorized
for use by the provided user ID
5. `wait_for_auth(auth_response)` waits for an authorization process to
complete before returning
## Tool Execution Helpers
1. `execute_tool` handles the whole tool execution flow for you. This is
used internally when a custom tool execution flow is not needed.
---------
Co-authored-by: lgesuellip <lgesuellipinto@uade.edu.ar>
Co-authored-by: lpetralli <123559656+lpetralli@users.noreply.github.com>
Co-authored-by: lgesuellip <102637283+lgesuellip@users.noreply.github.com>
Co-authored-by: “lgesuellip” <“lgesuellipinto@uade.edu.ar”>
92 lines
2.8 KiB
Python
92 lines
2.8 KiB
Python
import pytest
|
|
from crewai import Agent, Crew, Task
|
|
from crewai_arcade.structured import StructuredTool
|
|
from pydantic import BaseModel
|
|
|
|
|
|
class CalculatorInput(BaseModel):
|
|
x: float
|
|
y: float
|
|
|
|
|
|
def add_numbers(x: float, y: float) -> float:
|
|
"""Add two numbers together."""
|
|
return x + y
|
|
|
|
|
|
def unnamed_function(x: float, y: float) -> float:
|
|
return x + y
|
|
|
|
|
|
def test_structured_tool_basic():
|
|
# Test basic functionality with explicit name and description
|
|
calculator_tool = StructuredTool.from_function(
|
|
func=add_numbers,
|
|
args_schema=CalculatorInput,
|
|
name="Calculator",
|
|
description="A tool that adds two numbers together",
|
|
)
|
|
|
|
expected_description = (
|
|
"Tool Name: Calculator\n"
|
|
"Tool Arguments: {'x': {'description': None, 'type': 'float'}, 'y': {'description': None, 'type': 'float'}}\n"
|
|
"Tool Description: A tool that adds two numbers together"
|
|
)
|
|
assert calculator_tool.description == expected_description
|
|
assert calculator_tool.func(2, 3) == 5
|
|
|
|
|
|
def test_structured_tool_auto_name_description():
|
|
# Test automatic name and description generation from function
|
|
calculator_tool = StructuredTool.from_function(func=add_numbers, args_schema=CalculatorInput)
|
|
|
|
expected_description = (
|
|
"Tool Name: add_numbers\n"
|
|
"Tool Arguments: {'x': {'description': None, 'type': 'float'}, 'y': {'description': None, 'type': 'float'}}\n"
|
|
"Tool Description: Add two numbers together."
|
|
)
|
|
assert calculator_tool.description == expected_description
|
|
|
|
|
|
def test_structured_tool_validation_errors():
|
|
# Test missing docstring
|
|
with pytest.raises(
|
|
ValueError, match="Function must have a docstring if description not provided."
|
|
):
|
|
StructuredTool.from_function(func=unnamed_function, args_schema=CalculatorInput)
|
|
|
|
|
|
def test_structured_tool_in_crew():
|
|
calculator_tool = StructuredTool.from_function(
|
|
func=add_numbers,
|
|
args_schema=CalculatorInput,
|
|
)
|
|
|
|
calculator_agent = Agent(
|
|
role="Math Expert",
|
|
goal="Perform mathematical calculations accurately",
|
|
backstory="An expert mathematician who specializes in calculations",
|
|
tools=[calculator_tool],
|
|
verbose=True,
|
|
cache=False,
|
|
)
|
|
|
|
addition_task = Task(
|
|
description="Add the numbers 5 and 3 together",
|
|
expected_output="The sum of 5 and 3 is 8",
|
|
agent=calculator_agent,
|
|
)
|
|
|
|
crew = Crew(
|
|
agents=[calculator_agent],
|
|
tasks=[addition_task],
|
|
)
|
|
|
|
# Assert crew structure
|
|
assert len(crew.agents) == 1
|
|
assert len(crew.tasks) == 1
|
|
assert crew.agents[0] == calculator_agent
|
|
assert crew.tasks[0] == addition_task
|
|
assert crew.tasks[0].agent == calculator_agent
|
|
assert len(crew.agents[0].tools) == 1
|
|
assert isinstance(crew.agents[0].tools[0], StructuredTool)
|