From 91aadf1a1c436bf2a178c2c29c0d2bad9d73edfb Mon Sep 17 00:00:00 2001 From: Sam Partee Date: Sun, 16 Mar 2025 14:23:01 -0700 Subject: [PATCH 1/4] Example update --- README.md | 79 +++++++++++++++++---------- example.py => examples/email_agent.py | 21 +++---- examples/github.py | 37 +++++++++++++ 3 files changed, 97 insertions(+), 40 deletions(-) rename example.py => examples/email_agent.py (52%) create mode 100644 examples/github.py diff --git a/README.md b/README.md index ef6beb9..93b82e7 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ >
-

Arcade Integration for OpenAI Agents

+

Arcade Library for OpenAI Agents

License @@ -16,14 +16,16 @@

Arcade Documentation • - Toolkits • + IntegrationsArcade Python ClientOpenAI Agents

# agents-arcade -`agents-arcade` provides an integration between [Arcade](https://docs.arcade.dev) and the [OpenAI Agents Library](https://github.com/openai/openai-python). This allows you to enhance your AI agents with Arcade's extensive toolkit ecosystem, including tools that reqwuire authorization like Google Mail, Linkedin, X, and more. +`agents-arcade` provides an integration between [Arcade](https://docs.arcade.dev) and the [OpenAI Agents Library](https://github.com/openai/openai-python). This allows you to enhance your AI agents with Arcade tools like Google Mail, Linkedin, X, or ones you build yourself with the [Tool SDK](https://github.com/ArcadeAI/arcade-ai). + +For a list of all hosted tools and auth providers you can use to build your own, see the [Arcade Integrations](https://docs.arcade.dev/toolkits) documentation. ## Installation @@ -33,30 +35,42 @@ pip install agents-arcade ## Basic Usage +Below shows a basic example of how to use the `agents-arcade` library to create an agent that can use the +GitHub toolkit hosted in Arcade Cloud. You can use other hosted tools like Google, or you can build your own +and host them to the agents library with the [Tool SDK](https://github.com/ArcadeAI/arcade-ai). + ```python -from agents import Agent, RunConfig, Runner +from agents import Agent, Runner from arcadepy import AsyncArcade from agents_arcade import get_arcade_tools +from agents_arcade.errors import AuthorizationError async def main(): client = AsyncArcade() - tools = await get_arcade_tools(client, ["google"]) - - google_agent = Agent( - name="Google agent", - instructions="You are a helpful assistant that can assist with Google API calls.", + # Use the "github" toolkit for this example + # You can use other toolkits like "google", "linkedin", "x", etc. + tools = await get_arcade_tools(client, ["github"]) + + # Create an agent that can use the github toolkit + github_agent = Agent( + name="GitHub agent", + instructions="You are a helpful assistant that can assist with GitHub API calls.", model="gpt-4o-mini", tools=tools, ) - result = await Runner.run( - starting_agent=google_agent, - input="What are my latest emails?", - context={"user_id": "user@example.com"}, - ) - print("Final output:\n\n", result.final_output) + try: + result = await Runner.run( + starting_agent=github_agent, + input="Star the arcadeai/arcade-ai repo", + # make sure you pass a UNIQUE user_id for auth + context={"user_id": "user@example.comiii"}, + ) + print("Final output:\n\n", result.final_output) + except AuthorizationError as e: + print("Please Login to Github:", e) if __name__ == "__main__": @@ -65,6 +79,26 @@ if __name__ == "__main__": asyncio.run(main()) ``` +If you haven't auth'd Arcade with GitHub yet, you'll see a message similar to this: + +```bash +> python examples/github.py +Please Login to Github: Authorization required: https://github.com/login/oauth/authorize... +``` + +You can then visit the URL in your browser to auth'd Arcade with GitHub and run the script again. + +```bash +> python examples/github.py +The repository **arcadeai/arcade-ai** has been successfully starred! If you need any more assistance, feel free to ask. +``` + +You can also wait for authorization to complete before running the script using the helper +methods in arcadepy. + +Once you have auth'd Arcade with a tool, you can use the tool in your agent by passing the `user_id` +and never having to worry about auth'ing for that specific tool again. + ## Key Features - **Easy Integration**: Simple API (one function) to connect Arcade tools with OpenAI Agents @@ -72,21 +106,6 @@ if __name__ == "__main__": - **Asynchronous Support**: Built with async/await for compatibility with OpenAI's Agent framework - **Authentication Handling**: Manages authorization for tools requiring user permissions like Google, LinkedIn, etc -## Available Toolkits - -Arcade provides many toolkits including: - -- **Google**: Gmail, Google Drive, Google Calendar -- **Search**: Google search, Bing search -- **Web**: Crawling, scraping, etc -- **Github**: Repository operations -- **Slack**: Sending messages to Slack -- **LinkedIn**: Posting to LinkedIn -- **X**: Posting and reading tweets on X -- And many more - -For a complete list, see the [Arcade Toolkits documentation](https://docs.arcade.dev/toolkits). - ## Authentication Many Arcade tools require user authentication. The authentication flow is managed by Arcade and can be triggered by providing a `user_id` in the context when running your agent. Refer to the Arcade documentation for more details on managing tool authentication. diff --git a/example.py b/examples/email_agent.py similarity index 52% rename from example.py rename to examples/email_agent.py index b2173a5..ad19e71 100644 --- a/example.py +++ b/examples/email_agent.py @@ -1,7 +1,8 @@ -from agents import Agent, RunConfig, Runner +from agents import Agent Runner from arcadepy import AsyncArcade from agents_arcade import get_arcade_tools +from agents_arcade.errors import AuthorizationError async def main(): @@ -15,15 +16,15 @@ async def main(): tools=tools, ) - result = await Runner.run( - starting_agent=google_agent, - input="What are my latest emails?", - context={"user_id": "user@example.com3"}, - run_config=RunConfig( - tracing_disabled=True, - ), - ) - print("Final output:\n\n", result.final_output) + try: + result = await Runner.run( + starting_agent=google_agent, + input="What are my latest emails?", + context={"user_id": "user@example.com"}, + ) + print("Final output:\n\n", result.final_output) + except AuthorizationError as e: + print("Please Login to Google:", e) if __name__ == "__main__": diff --git a/examples/github.py b/examples/github.py new file mode 100644 index 0000000..f016619 --- /dev/null +++ b/examples/github.py @@ -0,0 +1,37 @@ +from agents import Agent, Runner +from arcadepy import AsyncArcade + +from agents_arcade import get_arcade_tools +from agents_arcade.errors import AuthorizationError + + +async def main(): + client = AsyncArcade() + # Use the "github" toolkit for this example + # You can use other toolkits like "google", "linkedin", "x", etc. + tools = await get_arcade_tools(client, ["github"]) + + # Create an agent that can use the github toolkit + github_agent = Agent( + name="GitHub agent", + instructions="You are a helpful assistant that can assist with GitHub API calls.", + model="gpt-4o-mini", + tools=tools, + ) + + try: + result = await Runner.run( + starting_agent=github_agent, + input="Star the arcadeai/arcade-ai repo", + # make sure you pass a UNIQUE user_id for auth + context={"user_id": "user@example.com"}, + ) + print("Final output:\n\n", result.final_output) + except AuthorizationError as e: + print("Please Login to Github:", e) + + +if __name__ == "__main__": + import asyncio + + asyncio.run(main()) From d1b317d876559d04589e259d6543e8f7ec8e135a Mon Sep 17 00:00:00 2001 From: Sam Partee Date: Sun, 16 Mar 2025 14:23:21 -0700 Subject: [PATCH 2/4] Example update 2 --- examples/email_agent.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/email_agent.py b/examples/email_agent.py index ad19e71..2b7963f 100644 --- a/examples/email_agent.py +++ b/examples/email_agent.py @@ -1,4 +1,4 @@ -from agents import Agent Runner +from agents import Agent, Runner from arcadepy import AsyncArcade from agents_arcade import get_arcade_tools From a71c2858f95bb259a576b510a9d94b28dec0fabf Mon Sep 17 00:00:00 2001 From: Sam Partee Date: Wed, 2 Apr 2025 00:12:37 -0700 Subject: [PATCH 3/4] all --- .github/workflows/docs-check.yml | 35 +++ .github/workflows/docs.yml | 31 ++ README.md | 25 ++ agents_arcade/_utils.py | 28 +- agents_arcade/tools.py | 18 +- build_docs.sh | 37 +++ docs/README.md | 67 +++++ docs/api/errors.md | 115 +++++++ docs/api/tools.md | 89 ++++++ docs/api/utils.md | 102 +++++++ docs/contributing.md | 120 ++++++++ docs/examples/email.md | 144 +++++++++ docs/examples/github.md | 136 +++++++++ docs/examples/multi-toolkit.md | 192 ++++++++++++ docs/getting-started/authentication.md | 121 ++++++++ docs/getting-started/installation.md | 56 ++++ docs/getting-started/quickstart.md | 100 +++++++ docs/guides/custom-usage.md | 399 +++++++++++++++++++++++++ docs/guides/error-handling.md | 259 ++++++++++++++++ docs/guides/toolkits.md | 166 ++++++++++ docs/index.md | 76 +++++ examples/github.py | 2 +- mkdocs.yml | 74 +++++ 23 files changed, 2378 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/docs-check.yml create mode 100644 .github/workflows/docs.yml create mode 100755 build_docs.sh create mode 100644 docs/README.md create mode 100644 docs/api/errors.md create mode 100644 docs/api/tools.md create mode 100644 docs/api/utils.md create mode 100644 docs/contributing.md create mode 100644 docs/examples/email.md create mode 100644 docs/examples/github.md create mode 100644 docs/examples/multi-toolkit.md create mode 100644 docs/getting-started/authentication.md create mode 100644 docs/getting-started/installation.md create mode 100644 docs/getting-started/quickstart.md create mode 100644 docs/guides/custom-usage.md create mode 100644 docs/guides/error-handling.md create mode 100644 docs/guides/toolkits.md create mode 100644 docs/index.md create mode 100644 mkdocs.yml diff --git a/.github/workflows/docs-check.yml b/.github/workflows/docs-check.yml new file mode 100644 index 0000000..913c36e --- /dev/null +++ b/.github/workflows/docs-check.yml @@ -0,0 +1,35 @@ +name: Documentation Check + +on: + pull_request: + paths: + - "docs/**" + - "mkdocs.yml" + - ".github/workflows/docs*.yml" + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: 3.9 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install ".[dev]" + + - name: Build documentation + run: mkdocs build --strict 2>&1 | tee build-log.txt + + - name: Check for warnings + run: | + if grep -q "WARNING" build-log.txt; then + echo "Documentation build produced warnings:" + cat build-log.txt | grep "WARNING" + exit 1 + else + echo "Documentation build completed successfully without warnings." + fi diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..a35060d --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,31 @@ +name: Deploy Documentation + +on: + push: + branches: + - main + paths: + - "docs/**" + - "mkdocs.yml" + - ".github/workflows/docs.yml" + workflow_dispatch: # Allow manual triggering + +permissions: + contents: write + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: 3.9 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install ".[dev]" + + - name: Deploy documentation + run: mkdocs gh-deploy --force diff --git a/README.md b/README.md index 93b82e7..a042be1 100644 --- a/README.md +++ b/README.md @@ -113,3 +113,28 @@ Many Arcade tools require user authentication. The authentication flow is manage ## License This project is licensed under the MIT License - see the LICENSE file for details. + +## Documentation + +The project documentation is available at [docs.arcadeai.dev/agents-arcade](https://docs.arcadeai.dev/agents-arcade/) and includes: + +- Installation instructions +- Quickstart guides +- API reference +- Advanced usage patterns +- Toolkit guides +- Examples + +To build and serve the documentation locally: + +```bash +# Install development dependencies +pip install -e ".[dev]" + +# Serve the documentation +make serve-docs +# or +mkdocs serve +``` + +Then visit `http://localhost:8000` in your browser. diff --git a/agents_arcade/_utils.py b/agents_arcade/_utils.py index 18537ce..7763304 100644 --- a/agents_arcade/_utils.py +++ b/agents_arcade/_utils.py @@ -1,19 +1,22 @@ import asyncio import json +import os from typing import Any from arcadepy import AsyncArcade -def convert_output_to_json(output: Any) -> str: - if isinstance(output, dict) or isinstance(output, list): - return json.dumps(output) - else: - return str(output) - - -async def get_arcade_client() -> AsyncArcade: - return AsyncArcade() +def get_arcade_client( + base_url: str = "https://api.arcade.dev", + api_key: str = os.getenv("ARCADE_API_KEY", None), + **kwargs: dict[str, Any], +) -> AsyncArcade: + """ + Returns an AsyncArcade client. + """ + if api_key is None: + raise ValueError("ARCADE_API_KEY is not set") + return AsyncArcade(base_url=base_url, api_key=api_key, **kwargs) async def _get_arcade_tool_definitions( @@ -53,3 +56,10 @@ async def _get_arcade_tool_definitions( tool_auth_requirements[tool_name] = requires_auth return tool_auth_requirements + + +def convert_output_to_json(output: Any) -> str: + if isinstance(output, dict) or isinstance(output, list): + return json.dumps(output) + else: + return str(output) diff --git a/agents_arcade/tools.py b/agents_arcade/tools.py index 84d8b41..660e8cb 100644 --- a/agents_arcade/tools.py +++ b/agents_arcade/tools.py @@ -1,5 +1,6 @@ import json from functools import partial +from typing import Any from agents.run_context import RunContextWrapper from agents.tool import FunctionTool @@ -26,10 +27,12 @@ async def _authorize_tool(client: AsyncArcade, context: RunContextWrapper, tool_ async def _async_invoke_arcade_tool( - context: RunContextWrapper, tool_args: str, tool_name: str, requires_auth: bool + context: RunContextWrapper, + tool_args: str, + tool_name: str, + requires_auth: bool, + client: AsyncArcade, ): - client = await get_arcade_client() - args = json.loads(tool_args) if requires_auth: await _authorize_tool(client, context, tool_name) @@ -47,8 +50,14 @@ async def _async_invoke_arcade_tool( async def get_arcade_tools( - client: AsyncArcade, toolkits: list[str], tools: list[str] | None = None + client: AsyncArcade | None = None, + toolkits: list[str] | None = None, + tools: list[str] | None = None, + **kwargs: dict[str, Any], ) -> list[FunctionTool]: + if not client: + client = get_arcade_client(**kwargs) + tool_formats = await client.tools.formatted.list(toolkit=toolkits, format="openai") auth_spec = await _get_arcade_tool_definitions(client, toolkits, tools) @@ -66,6 +75,7 @@ async def get_arcade_tools( _async_invoke_arcade_tool, tool_name=tool_name, requires_auth=requires_auth, + client=client, ), strict_json_schema=False, ) diff --git a/build_docs.sh b/build_docs.sh new file mode 100755 index 0000000..458ac20 --- /dev/null +++ b/build_docs.sh @@ -0,0 +1,37 @@ +#!/bin/bash +set -e # Exit on first error + +# Check if virtual environment exists, if not create one +if [ ! -d ".venv" ]; then + echo "Creating virtual environment..." + python -m venv .venv +fi + +# Activate virtual environment +if [[ "$OSTYPE" == "msys" || "$OSTYPE" == "win32" ]]; then + source .venv/Scripts/activate +else + source .venv/bin/activate +fi + +# Install dependencies +echo "Installing dependencies..." +pip install -e ".[dev]" + +# Build the documentation +echo "Building documentation..." +mkdocs build + +# Optional: Serve the documentation locally +if [[ "$1" == "--serve" ]]; then + echo "Serving documentation locally at http://localhost:8000" + mkdocs serve +fi + +# Optional: Deploy to GitHub Pages +if [[ "$1" == "--deploy" ]]; then + echo "Deploying documentation to GitHub Pages..." + mkdocs gh-deploy --force +fi + +echo "Documentation build complete! Find the built site in the 'site' directory." \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..879eb3e --- /dev/null +++ b/docs/README.md @@ -0,0 +1,67 @@ +# Agents Arcade Documentation + +This directory contains the documentation for the Agents Arcade project, built with [MkDocs](https://www.mkdocs.org/) and the [Material for MkDocs](https://squidfunk.github.io/mkdocs-material/) theme. + +## Documentation Structure + +- **api/**: API reference documentation for each module +- **examples/**: Detailed example walkthroughs +- **getting-started/**: Installation and quickstart guides +- **guides/**: More in-depth guides on specific topics + +## Building the Documentation + +To build the documentation locally: + +```bash +# Install development dependencies if you haven't already +pip install -e ".[dev]" + +# Build the docs +mkdocs build + +# Or serve locally with hot-reloading +mkdocs serve +``` + +Then visit `http://localhost:8000` in your browser. + +Alternatively, you can use the provided build script: + +```bash +./build_docs.sh # Just build +./build_docs.sh --serve # Build and serve locally +``` + +## Contributing to the Documentation + +When contributing to the documentation, please follow these guidelines: + +1. **Use Markdown**: All documentation is written in Markdown +2. **Follow the structure**: Place new files in the appropriate directories +3. **Include code examples**: Provide examples for all features when possible +4. **Check links**: Ensure all links to other pages or sections work +5. **Run local builds**: Always check your changes locally before submitting + +## Automatic Deployment + +The documentation is automatically built and deployed when changes are pushed to the main branch. This is handled by the GitHub Actions workflow in `.github/workflows/docs.yml`. + +## Documentation Style Guide + +- Use title case for headings (e.g., "Getting Started with Agents Arcade") +- Use backticks for code, module names, functions, and parameters (e.g., `get_arcade_tools()`) +- Include type annotations in function signatures +- Write in clear, concise language +- Use admonitions for notes, warnings, and tips: + +```markdown +!!! note +This is a note admonition. + +!!! warning +This is a warning admonition. + +!!! tip +This is a tip admonition. +``` diff --git a/docs/api/errors.md b/docs/api/errors.md new file mode 100644 index 0000000..302c953 --- /dev/null +++ b/docs/api/errors.md @@ -0,0 +1,115 @@ +# Errors API Reference + +This page documents the API for the `agents_arcade.errors` module, which defines custom exceptions for error handling in the Agents Arcade integration. + +## Exceptions + +### `ToolError` + +```python +class ToolError(AgentsException) +``` + +Exception raised when an Arcade tool execution fails. This exception is raised when a tool returns an unsuccessful response. + +#### Attributes + +- `result` (`ExecuteToolResponse`): The ExecuteToolResponse object containing error details. + +#### Properties + +- `message` (`str`): A human-readable error message extracted from the response. + +#### Methods + +- `__str__()`: Returns a formatted error message including the tool name and error details. + +#### Example + +```python +from agents_arcade.errors import ToolError +from agents import Runner + +try: + result = await Runner.run( + starting_agent=agent, + input="Perform some action with a tool", + context={"user_id": "user@example.com"}, + ) +except ToolError as e: + print(f"Tool execution failed: {e}") + print(f"Error message: {e.message}") +``` + +### `AuthorizationError` + +```python +class AuthorizationError(AgentsException) +``` + +Exception raised when authorization for an Arcade tool fails or is required. This exception includes a URL that the user should visit to complete the authorization process. + +#### Attributes + +- `result` (`AuthorizationResponse`): The AuthorizationResponse object containing authorization details. + +#### Properties + +- `message` (`str`): A human-readable message indicating that authorization is required, including the authorization URL. + +#### Methods + +- `__str__()`: Returns the authorization error message. + +#### Example + +```python +from agents_arcade.errors import AuthorizationError +from agents import Runner + +try: + result = await Runner.run( + starting_agent=agent, + input="Perform some action with a tool", + context={"user_id": "user@example.com"}, + ) +except AuthorizationError as e: + print(f"Authorization required: {e}") + # The URL to authorize is in e.result.url + print(f"Please visit this URL to authorize: {e.result.url}") +``` + +## Error Handling + +When using Agents Arcade tools, it's important to handle these exceptions appropriately: + +```python +from agents import Runner, Agent +from agents_arcade import get_arcade_tools +from agents_arcade.errors import ToolError, AuthorizationError + +async def run_agent_with_tools(): + tools = await get_arcade_tools(toolkits=["github"]) + agent = Agent( + name="GitHub agent", + instructions="You are a helpful assistant that can assist with GitHub API calls.", + model="gpt-4o-mini", + tools=tools, + ) + + try: + result = await Runner.run( + starting_agent=agent, + input="List my GitHub repositories", + context={"user_id": "user@example.com"}, + ) + return result.final_output + except AuthorizationError as e: + # Handle authorization requirement + print(f"Please authorize: {e}") + return f"Authorization required. Please visit: {e.result.url}" + except ToolError as e: + # Handle tool execution failure + print(f"Tool error: {e}") + return f"Error executing tool: {e.message}" +``` diff --git a/docs/api/tools.md b/docs/api/tools.md new file mode 100644 index 0000000..af92ecc --- /dev/null +++ b/docs/api/tools.md @@ -0,0 +1,89 @@ +# Tools API Reference + +This page documents the API for the `agents_arcade.tools` module, which provides integration between OpenAI Agents and Arcade tools. + +## Functions + +### `get_arcade_tools` + +```python +async def get_arcade_tools( + client: AsyncArcade | None = None, + toolkits: list[str] | None = None, + tools: list[str] | None = None, + **kwargs: dict[str, Any], +) -> list[FunctionTool] +``` + +Asynchronously fetches Arcade tools and converts them into OpenAI Agent-compatible FunctionTool objects. + +!!! note "Not all tools require authentication" +While many Arcade tools require user authentication, some don't. The `get_arcade_tools` function automatically handles the distinction. + +#### Parameters + +- `client` (`AsyncArcade | None`): Optional AsyncArcade client. If not provided, one will be created using environment variables or the provided kwargs. +- `toolkits` (`list[str] | None`): Optional list of toolkit names to fetch tools from (e.g., `["github", "google"]`). +- `tools` (`list[str] | None`): Optional list of specific tool names to include. If None, all tools from the specified toolkits are included. +- `**kwargs` (`dict[str, Any]`): Additional arguments passed to `get_arcade_client` if a client is not provided. + +#### Returns + +- `list[FunctionTool]`: A list of `FunctionTool` objects that can be used with OpenAI Agents. + +#### Exceptions + +- `ValueError`: If no API key is provided and the environment variable is not set. +- Authentication errors are not raised here but when the tools are used. + +#### Example + +```python +from agents_arcade import get_arcade_tools +from arcadepy import AsyncArcade + +# Get all tools from a specific toolkit +client = AsyncArcade() +tools = await get_arcade_tools(client, ["github"]) + +# Get specific tools +tools = await get_arcade_tools( + client, + toolkits=["github"], + tools=["github_get_issues", "github_get_repository"] +) + +# Create a client with a specific API key and base URL +tools = await get_arcade_tools( + None, # No client provided, will create one with the kwargs + toolkits=["google"], + api_key="your_api_key", + base_url="https://api.arcade.dev" +) +``` + +## Internal Functions + +These functions are used internally by the library and are not typically called directly. + +### `_async_invoke_arcade_tool` + +```python +async def _async_invoke_arcade_tool( + context: RunContextWrapper, + tool_args: str, + tool_name: str, + requires_auth: bool, + client: AsyncArcade, +) +``` + +Internal function used to execute Arcade tools. Handles authorization when required and processes tool execution results. + +### `_authorize_tool` + +```python +async def _authorize_tool(client: AsyncArcade, context: RunContextWrapper, tool_name: str) +``` + +Internal function to authorize a tool for a specific user. Raises appropriate exceptions if authorization fails. diff --git a/docs/api/utils.md b/docs/api/utils.md new file mode 100644 index 0000000..a9590b3 --- /dev/null +++ b/docs/api/utils.md @@ -0,0 +1,102 @@ +# Utils API Reference + +This page documents the API for the `agents_arcade._utils` module, which provides utility functions for working with the Arcade API. + +## Functions + +### `get_arcade_client` + +```python +def get_arcade_client( + base_url: str = "https://api.arcade.dev", + api_key: str = os.getenv("ARCADE_API_KEY", None), + **kwargs: dict[str, Any], +) -> AsyncArcade +``` + +Creates and returns an AsyncArcade client. + +#### Parameters + +- `base_url` (`str`): The base URL for the Arcade API. Default is "https://api.arcade.dev". +- `api_key` (`str`): The Arcade API key. If not provided, it will be read from the `ARCADE_API_KEY` environment variable. +- `**kwargs` (`dict[str, Any]`): Additional arguments to pass to the AsyncArcade constructor. + +#### Returns + +- `AsyncArcade`: An initialized AsyncArcade client. + +#### Raises + +- `ValueError`: If no API key is provided and the environment variable is not set. + +#### Example + +```python +from agents_arcade._utils import get_arcade_client + +# Using environment variable for API key +client = get_arcade_client() + +# Explicitly providing API key +client = get_arcade_client(api_key="your_api_key_here") + +# Custom base URL (e.g., for staging environment) +client = get_arcade_client(base_url="https://api.staging.arcade.dev") +``` + +### `_get_arcade_tool_definitions` + +```python +async def _get_arcade_tool_definitions( + client: AsyncArcade, + toolkits: list[str], + tools: list[str] | None = None +) -> dict[str, bool] +``` + +Asynchronously fetches tool definitions from specified toolkits and determines which tools require authorization. + +#### Parameters + +- `client` (`AsyncArcade`): AsyncArcade client to use for API requests. +- `toolkits` (`list[str]`): List of toolkit names to fetch tools from. +- `tools` (`list[str] | None`): Optional list of specific tool names to include. If None, all tools are included. + +#### Returns + +- `dict[str, bool]`: A dictionary mapping tool names to booleans indicating whether each tool requires authorization. + +### `convert_output_to_json` + +```python +def convert_output_to_json(output: Any) -> str +``` + +Converts tool output to a JSON string. + +#### Parameters + +- `output` (`Any`): Any value to convert to JSON. + +#### Returns + +- `str`: A JSON string representation of the output. If the input is already a dict or list, it's converted to JSON. Otherwise, it's converted to a string. + +#### Example + +```python +from agents_arcade._utils import convert_output_to_json + +# Convert a dictionary to JSON +result = convert_output_to_json({"name": "John", "age": 30}) +# '{"name": "John", "age": 30}' + +# Convert a list to JSON +result = convert_output_to_json([1, 2, 3]) +# '[1, 2, 3]' + +# Convert a non-JSON value to string +result = convert_output_to_json("Hello") +# 'Hello' +``` diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000..cf7c192 --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,120 @@ +# Contributing to Agents Arcade + +Thank you for your interest in contributing to Agents Arcade! This document provides guidelines and instructions for contributing to the project. + +## Getting Started + +### Prerequisites + +- Python 3.9 or higher +- Git +- A GitHub account + +### Development Setup + +1. Fork the repository on GitHub +2. Clone your fork locally: + ```bash + git clone https://github.com/your-username/agents-arcade.git + cd agents-arcade + ``` +3. Create a virtual environment and install dependencies: + ```bash + python -m venv .venv + source .venv/bin/activate # On Windows: .venv\Scripts\activate + pip install -e ".[dev]" + ``` + +## Development Workflow + +### Branching Strategy + +We follow a simple branching model: + +- `main` - the main development branch +- feature branches - for new features or significant changes +- bug fix branches - for bug fixes + +When working on a new feature or bug fix, create a new branch from `main`: + +```bash +git checkout -b feature/your-feature-name +# or +git checkout -b fix/your-bug-fix +``` + +### Coding Standards + +We use the following tools to maintain code quality: + +- **Ruff** - for code formatting and linting +- **MyPy** - for type checking + +Make sure your code passes all checks before submitting a pull request: + +```bash +# Run linter +ruff check . + +# Run type checker +mypy agents_arcade + +# Run tests +pytest +``` + +### Commit Messages + +Please write clear and descriptive commit messages that explain the changes you've made. We follow these conventions: + +- Use present tense ("Add feature" not "Added feature") +- First line is a summary (50 chars or less) +- Reference issues and pull requests where appropriate ("Fix #123") + +### Testing + +Please add tests for any new features or bug fixes. We use pytest for testing: + +```bash +# Run all tests +pytest + +# Run specific tests +pytest tests/test_tools.py +``` + +## Pull Request Process + +1. Update the documentation with details of any changes to interfaces, new features, etc. +2. Update the README.md or documentation with details of changes if applicable +3. Make sure all tests pass and the code follows our style guidelines +4. Submit a pull request to the `main` branch +5. Wait for review and address any feedback + +## Documentation + +We use MkDocs with Material theme for our documentation. To run the documentation locally: + +```bash +mkdocs serve +``` + +Then navigate to `http://localhost:8000` in your browser. + +Make sure to update the documentation when adding new features or changing existing ones. The documentation source files are in the `docs` directory. + +## Releasing + +The release process is handled by the maintainers. If you have questions about releasing, please open an issue. + +## Code of Conduct + +Please be respectful and considerate of others when contributing to this project. We aim to foster an inclusive and welcoming environment. + +## License + +By contributing to Agents Arcade, you agree that your contributions will be licensed under the project's MIT license. + +## Questions? + +If you have any questions or need help with the contribution process, please open an issue or reach out to the maintainers. diff --git a/docs/examples/email.md b/docs/examples/email.md new file mode 100644 index 0000000..8476a49 --- /dev/null +++ b/docs/examples/email.md @@ -0,0 +1,144 @@ +# Email Agent Example + +This example demonstrates how to create an agent that can access and manage Gmail using Arcade tools. + +## Prerequisites + +Before running this example, make sure you have: + +1. Installed `agents-arcade` (see [Installation](../getting-started/installation.md)) +2. Set the `ARCADE_API_KEY` environment variable or have your API key ready to use + +## Basic Email Agent + +Here's a complete example of an email agent that can interact with Gmail: + +```python +from agents import Agent, Runner +from arcadepy import AsyncArcade + +from agents_arcade import get_arcade_tools +from agents_arcade.errors import AuthorizationError + + +async def main(): + # Create an Arcade client + client = AsyncArcade() + + # Get Google tools from Arcade (includes Gmail) + tools = await get_arcade_tools(client, ["google"]) + + # Create an OpenAI agent with Google tools + google_agent = Agent( + name="Google agent", + instructions="You are a helpful assistant that can assist with Gmail and other Google services.", + model="gpt-4o-mini", + tools=tools, + ) + + try: + # Run the agent with a specific task + result = await Runner.run( + starting_agent=google_agent, + input="What are my latest emails?", + # A unique user_id is required for Google authorization + context={"user_id": "user@example.com"}, + ) + print("Final output:\n\n", result.final_output) + except AuthorizationError as e: + # Handle authorization errors + print("Please Login to Google:", e) + + +if __name__ == "__main__": + import asyncio + + asyncio.run(main()) +``` + +Save this as `email_agent.py` and run it with `python email_agent.py`. + +## What This Example Does + +1. Creates an Arcade client using your API key +2. Fetches Google tools from Arcade (which include Gmail tools) +3. Creates an OpenAI agent with access to those tools +4. Runs the agent with a specific task ("What are my latest emails?") +5. Handles any authorization errors that might occur + +## Authentication Process + +If this is your first time using the Google toolkit with your user ID, you will see a message like: + +``` +Please Login to Google: Authorization required: https://accounts.google.com/o/oauth2/auth... +``` + +Open this URL in your browser and complete the Google authorization process. After authorizing, you can run the script again, and it should work without requiring authentication. + +## Common Email Tasks + +Your email agent can perform a wide range of Gmail-related tasks. Here are some example prompts you can try: + +- "What are my latest emails?" +- "Send an email to example@example.com with the subject 'Hello' and body 'How are you?'" +- "Show me unread emails from the last week" +- "Find emails with attachments" +- "Summarize emails from a specific sender" +- "Draft a reply to my most recent email" + +## Available Google Tools + +The Google toolkit includes tools for: + +- Gmail (read, send, search, draft) +- Google Drive (list, create, read files) +- Google Calendar (list, create, update events) +- Google Docs (create, read, update) +- Google Sheets (read, update) +- And more + +## Advanced Usage + +### Email-Only Agent + +If you only want to include Gmail-related tools and not other Google services: + +```python +tools = await get_arcade_tools( + client, + toolkits=["google"], + tools=[ + "google_gmail_get_messages", + "google_gmail_send_message", + "google_gmail_search_messages" + ] +) +``` + +### Email Assistant with Specific Instructions + +For a more specialized email assistant: + +```python +email_agent = Agent( + name="Email Assistant", + instructions="""You are a specialized email assistant. + You can help read, summarize, and compose emails. + When asked to send an email, always confirm the recipient, subject, and content. + When summarizing emails, focus on the most important information. + Be concise and professional in your responses.""", + model="gpt-4o-mini", + tools=tools, +) +``` + +### Combining with Other Toolkits + +You can combine Google tools with other Arcade toolkits for a more versatile agent: + +```python +tools = await get_arcade_tools(client, ["google", "github", "linkedin"]) +``` + +This creates an agent that can handle emails, GitHub tasks, and LinkedIn interactions in a single conversation. diff --git a/docs/examples/github.md b/docs/examples/github.md new file mode 100644 index 0000000..b73cf76 --- /dev/null +++ b/docs/examples/github.md @@ -0,0 +1,136 @@ +# GitHub Integration Example + +This example shows how to create an agent that can interact with GitHub using Arcade tools. + +## Prerequisites + +Before running this example, make sure you have: + +1. Installed `agents-arcade` (see [Installation](../getting-started/installation.md)) +2. Set the `ARCADE_API_KEY` environment variable or have your API key ready to use + +## Basic GitHub Agent + +Here's a complete example of a GitHub agent that can interact with the GitHub API: + +```python +from agents import Agent, Runner +from arcadepy import AsyncArcade + +from agents_arcade import get_arcade_tools +from agents_arcade.errors import AuthorizationError + + +async def main(): + # Create an Arcade client + client = AsyncArcade() + + # Get GitHub tools from Arcade + tools = await get_arcade_tools(client, ["github"]) + + # Create an OpenAI agent with the GitHub tools + github_agent = Agent( + name="GitHub agent", + instructions="You are a helpful assistant that can assist with GitHub API calls.", + model="gpt-4o-mini", + tools=tools, + ) + + try: + # Run the agent with a specific task + result = await Runner.run( + starting_agent=github_agent, + input="Star the arcadeai/arcade-ai repo", + # A unique user_id is required for GitHub authorization + context={"user_id": "user@example.com"}, + ) + print("Final output:\n\n", result.final_output) + except AuthorizationError as e: + # Handle authorization errors + print("Please Login to Github:", e) + + +if __name__ == "__main__": + import asyncio + + asyncio.run(main()) +``` + +Save this as `github_example.py` and run it with `python github_example.py`. + +## What This Example Does + +1. Creates an Arcade client using your API key +2. Fetches GitHub tools from Arcade +3. Creates an OpenAI agent with access to those tools +4. Runs the agent with a specific task ("Star the arcadeai/arcade-ai repo") +5. Handles any authorization errors that might occur + +## Authentication Process + +If this is your first time using the GitHub toolkit with your user ID, you will see a message like: + +``` +Please Login to Github: Authorization required: https://github.com/login/oauth/authorize... +``` + +Open this URL in your browser and complete the GitHub authorization process. After authorizing, you can run the script again, and it should work without requiring authentication. + +## Common GitHub Tasks + +Your GitHub agent can perform a wide range of tasks. Here are some example prompts you can try: + +- "List my GitHub repositories" +- "Create a new repository named 'test-repo'" +- "Get information about the openai/openai-python repository" +- "List open issues in the huggingface/transformers repository" +- "Create a new issue in my test-repo repository" + +## Available GitHub Tools + +The GitHub toolkit includes tools for: + +- Repository management (create, get, list, delete) +- Issue management (create, get, list, update) +- Pull request operations +- Star/unstar repositories +- User information +- And more + +## Advanced Usage + +### Filtering Tools + +If you only need specific GitHub tools, you can filter them: + +```python +tools = await get_arcade_tools( + client, + toolkits=["github"], + tools=["github_get_repository", "github_list_user_repositories"] +) +``` + +### Combining with Other Toolkits + +You can combine GitHub tools with other Arcade toolkits: + +```python +tools = await get_arcade_tools(client, ["github", "google", "linkedin"]) +``` + +### Custom Instructions + +For more targeted GitHub tasks, you can customize the agent's instructions: + +```python +github_agent = Agent( + name="GitHub Repository Manager", + instructions="""You are a specialized GitHub repository manager. + You can help users manage their repositories, issues, and pull requests. + Always ask for clarification if the repository name is not specified. + When creating issues or PRs, ask for all necessary details.""", + model="gpt-4o-mini", + tools=tools, +) +``` diff --git a/docs/examples/multi-toolkit.md b/docs/examples/multi-toolkit.md new file mode 100644 index 0000000..7d22ab8 --- /dev/null +++ b/docs/examples/multi-toolkit.md @@ -0,0 +1,192 @@ +# Combining Multiple Toolkits + +This example demonstrates how to create an agent that combines multiple Arcade toolkits to provide a powerful multi-service assistant. + +## Overview + +One of the most powerful features of Agents Arcade is the ability to combine multiple toolkits in a single agent. This example shows how to create an agent that can: + +1. Access GitHub repositories and issues +2. Read and send emails via Gmail +3. Search the web for information + +## Prerequisites + +Before running this example, make sure you have: + +1. Installed `agents-arcade` (see [Installation](../getting-started/installation.md)) +2. Set the `ARCADE_API_KEY` environment variable or have your API key ready to use +3. Have access to the GitHub, Google, and Web toolkits in your Arcade subscription + +## Multi-Toolkit Agent + +Here's a complete example of a multi-toolkit agent: + +```python +from agents import Agent, Runner +from arcadepy import AsyncArcade + +from agents_arcade import get_arcade_tools +from agents_arcade.errors import AuthorizationError + + +async def main(): + # Create an Arcade client + client = AsyncArcade() + + # Get tools from multiple toolkits + tools = await get_arcade_tools( + client, + toolkits=["github", "google", "web"] + ) + + # Create an agent with custom instructions that reference all capabilities + multi_agent = Agent( + name="Multi-service Assistant", + instructions="""You are a helpful assistant that can: + 1. Access GitHub repositories, issues, and pull requests + 2. Read and send emails via Gmail + 3. Search the web for information + + For GitHub tasks: Use the github_* tools to interact with GitHub + For email tasks: Use the google_gmail_* tools to read or send emails + For web searches: Use the web_search tool to find information online + + Always use the most appropriate tools for the user's request. + If authentication is required for a service, inform the user. + """, + model="gpt-4o-mini", + tools=tools, + ) + + try: + # Run the agent with a specific multi-service task + result = await Runner.run( + starting_agent=multi_agent, + input=""" + 1. Check if there are any open issues in the 'arcadeai/arcade-ai' GitHub repo + 2. Then search the web for 'agents and tools architectures' + 3. Finally, draft an email summarizing the findings + """, + # A unique user_id is required for authentication + context={"user_id": "user@example.com"}, + ) + print("Final output:\n\n", result.final_output) + except AuthorizationError as e: + # Handle authorization errors - might need multiple authorizations + print(f"Authorization required: {e}") + print(f"Please visit: {e.result.url}") + + +if __name__ == "__main__": + import asyncio + + asyncio.run(main()) +``` + +Save this as `multi_toolkit_example.py` and run it with `python multi_toolkit_example.py`. + +## Authentication Flow + +When running this example for the first time, you'll need to authenticate with multiple services. The authentication will happen one service at a time: + +1. You might first get a GitHub authentication prompt: + + ``` + Authorization required: https://github.com/login/oauth/authorize... + ``` + +2. After authenticating with GitHub and running again, you might get a Google authentication prompt: + + ``` + Authorization required: https://accounts.google.com/o/oauth2/auth... + ``` + +3. After completing all required authorizations, the agent will be able to execute the tasks. + +## Handling Multiple Authorizations + +For a better user experience, you can implement a more sophisticated authentication flow: + +```python +from arcadepy.auth import wait_for_authorization_completion + +async def run_with_multi_auth(): + client = AsyncArcade() + user_id = "user@example.com" + + # Track which services have been authorized + auth_status = { + "github": False, + "google": False, + "web": False # Some web tools might require auth too + } + + # Keep trying until all services are authorized + while not all(auth_status.values()): + try: + # Get tools for services not yet authorized + toolkits = [tk for tk, status in auth_status.items() if not status] + tools = await get_arcade_tools(client, toolkits) + + # Create agent with the tools + agent = Agent( + name="Multi-service Assistant", + instructions="You are a helpful assistant with multiple service capabilities.", + model="gpt-4o-mini", + tools=tools, + ) + + # Try to run the agent + result = await Runner.run( + starting_agent=agent, + input="Test connection to all services", + context={"user_id": user_id}, + ) + + # If we get here without an AuthorizationError, all services are authorized + print("All services successfully authorized!") + auth_status = {tk: True for tk in auth_status} + + except AuthorizationError as e: + # Extract the toolkit from the tool name (e.g., github_get_issues -> github) + toolkit = e.result.tool_name.split('_')[0] + + print(f"Authorization required for {toolkit}. Please visit: {e.result.url}") + print("Waiting for authorization completion...") + + # Wait for the user to complete authorization + auth_result = await wait_for_authorization_completion( + client, + e.result.authorization_id, + timeout=300 # 5 minutes + ) + + if auth_result.status == "completed": + print(f"{toolkit} authorization completed successfully!") + auth_status[toolkit] = True + else: + print(f"{toolkit} authorization failed or timed out.") + + # Now create the fully authorized agent + tools = await get_arcade_tools(client, list(auth_status.keys())) + return Agent( + name="Multi-service Assistant", + instructions="You are a helpful assistant with multiple service capabilities.", + model="gpt-4o-mini", + tools=tools, + ) +``` + +## Advanced Use Cases + +With a multi-toolkit agent, you can build powerful assistants that can perform complex tasks across different services. Here are some example use cases: + +1. **Research Assistant**: Search the web, save findings to GitHub, and email summaries +2. **Project Manager**: Track GitHub issues, send email updates, and search for solutions +3. **Content Creator**: Research topics online, draft content in Google Docs, and share via email +4. **Customer Support**: Search knowledge bases, check GitHub issues, and respond to customer emails + +## Conclusion + +By combining multiple toolkits, you can create sophisticated agents that seamlessly work across different services. This approach allows you to build truly helpful assistants that can handle complex workflows that span multiple platforms and services. diff --git a/docs/getting-started/authentication.md b/docs/getting-started/authentication.md new file mode 100644 index 0000000..3c5ce41 --- /dev/null +++ b/docs/getting-started/authentication.md @@ -0,0 +1,121 @@ +# Authentication + +Many Arcade tools require user authentication to access third-party services like GitHub, Google, LinkedIn, etc. This guide explains how authentication works in `agents-arcade` and how to implement it properly. + +## Overview + +The authentication flow in `agents-arcade` is handled by Arcade and follows this process: + +1. You provide a unique `user_id` in the agent's context +2. When a tool requires authentication, Arcade checks if the user is already authorized +3. If not authorized, an `AuthorizationError` is raised with a URL for the user to authenticate +4. After authentication, subsequent calls with the same `user_id` will be authorized + +## Implementing Authentication + +### Basic Authentication Flow + +Here's a simple example of handling authentication in your agent: + +```python +from agents import Agent, Runner +from arcadepy import AsyncArcade + +from agents_arcade import get_arcade_tools +from agents_arcade.errors import AuthorizationError + +async def main(): + client = AsyncArcade() + tools = await get_arcade_tools(client, ["github"]) + + github_agent = Agent( + name="GitHub agent", + instructions="You are a helpful assistant that can assist with GitHub API calls.", + model="gpt-4o-mini", + tools=tools, + ) + + try: + result = await Runner.run( + starting_agent=github_agent, + input="Star the arcadeai/arcade-ai repo", + # Provide a unique user_id for authentication + context={"user_id": "user@example.com"}, + ) + print("Final output:", result.final_output) + except AuthorizationError as e: + # Show the authentication URL to the user + print("Please login to GitHub:", e) +``` + +### Waiting for Authentication + +In some scenarios, you might want to wait for the user to complete the authentication before proceeding. You can use the `arcadepy` library's authorization helpers for this: + +```python +from arcadepy import AsyncArcade +from arcadepy.auth import wait_for_authorization_completion +from agents_arcade import get_arcade_tools +from agents_arcade.errors import AuthorizationError + +async def main(): + client = AsyncArcade() + user_id = "user@example.com" + + try: + # Try to use a tool that requires auth + tools = await get_arcade_tools(client, ["github"]) + # Attempt to run your agent... + except AuthorizationError as e: + # Get the auth URL from the error + auth_url = e.result.url + + # Show URL to user + print(f"Please authorize access at: {auth_url}") + + # Wait for the user to complete authorization + authorization = await wait_for_authorization_completion( + client, + e.result.authorization_id, + timeout=300 # Wait up to 5 minutes + ) + + if authorization.status == "completed": + print("Authorization completed successfully!") + # Try again with the authorized user + # ... +``` + +## User ID Best Practices + +The `user_id` is crucial for authentication as it links tool authorizations to specific users: + +- **Use a consistent identifier**: Use the same `user_id` for the same user across sessions +- **Make it unique**: Ensure each user has a unique identifier to avoid authorization conflicts +- **Privacy considerations**: Consider using hashed or anonymized IDs if privacy is a concern +- **Persistent storage**: Store authorized user IDs securely to maintain the user's authorization state + +## Managing Multiple Users + +If your application serves multiple users, you should maintain a mapping between your internal user identifiers and the user IDs you provide to Arcade. + +## Revoking Access + +Users can revoke access to their accounts from the third-party service's settings (e.g., GitHub settings). When access is revoked, the next tool call will raise an `AuthorizationError` again, prompting re-authentication. + +## Troubleshooting + +### Common Issues + +- **Authentication URL not working**: Ensure your Arcade API key has the correct permissions +- **Authorization expired**: Third-party tokens can expire; handle `AuthorizationError` to re-authenticate +- **Authorization stuck**: If authorization seems stuck, check if the timeout value is appropriate + +### Debugging Authentication + +You can enable debug logging in `arcadepy` to see more detailed information about the authentication process: + +```python +import logging +logging.basicConfig(level=logging.DEBUG) +``` diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md new file mode 100644 index 0000000..57cde67 --- /dev/null +++ b/docs/getting-started/installation.md @@ -0,0 +1,56 @@ +# Installation + +This guide covers how to install the `agents-arcade` package and its dependencies. + +## Requirements + +- Python 3.9 or higher +- `openai-agents` 0.0.4 or higher +- `arcadepy` 1.3.0 or higher + +## Installation Options + +### pip + +The recommended way to install `agents-arcade` is using pip: + +```bash +pip install agents-arcade +``` + +### From Source + +You can also install the latest version directly from the GitHub repository: + +```bash +git clone https://github.com/ArcadeAI/agents-arcade.git +cd agents-arcade +pip install -e . +``` + +## Development Installation + +If you're contributing to `agents-arcade` or need the development dependencies: + +```bash +git clone https://github.com/ArcadeAI/agents-arcade.git +cd agents-arcade +pip install -e ".[dev]" +``` + +## Verify Installation + +You can verify that the installation was successful by importing the package in Python: + +```python +from agents_arcade import get_arcade_tools +print("Installation successful!") +``` + +## Next Steps + +Now that you have `agents-arcade` installed, you can: + +- Check out the [Quickstart Guide](quickstart.md) to create your first agent +- Learn about [Authentication](authentication.md) for Arcade tools +- Explore the available [toolkits](../guides/toolkits.md) diff --git a/docs/getting-started/quickstart.md b/docs/getting-started/quickstart.md new file mode 100644 index 0000000..813b7d7 --- /dev/null +++ b/docs/getting-started/quickstart.md @@ -0,0 +1,100 @@ +# Quickstart Guide + +This guide will help you get started with creating an agent that uses Arcade tools. We'll create a simple GitHub agent that can interact with the GitHub API. + +## Prerequisites + +Before you begin, make sure you have: + +1. Installed `agents-arcade` (see [Installation](installation.md)) +2. An Arcade API key (sign up at [arcade.dev](https://arcade.dev) if you don't have one) +3. Set the `ARCADE_API_KEY` environment variable or have your API key ready to use + +## Create a Basic Agent + +Below is a simple example of creating an agent that can use GitHub tools: + +```python +from agents import Agent, Runner +from arcadepy import AsyncArcade + +from agents_arcade import get_arcade_tools +from agents_arcade.errors import AuthorizationError + + +async def main(): + # Create an Arcade client - either supply the API key or use ARCADE_API_KEY env var + client = AsyncArcade() + + # Get GitHub tools from Arcade + tools = await get_arcade_tools(client, ["github"]) + + # Create an OpenAI agent with the GitHub tools + github_agent = Agent( + name="GitHub agent", + instructions="You are a helpful assistant that can assist with GitHub API calls.", + model="gpt-4o-mini", # You can use any OpenAI model here + tools=tools, + ) + + try: + # Run the agent with a specific task + result = await Runner.run( + starting_agent=github_agent, + input="Show me issues from the openai/openai-python repository", + # A unique user_id is required for authorization + context={"user_id": "your-unique-user-id"}, + ) + print("Final output:\n\n", result.final_output) + except AuthorizationError as e: + # Handle authorization errors + print("Please login to GitHub:", e) + + +if __name__ == "__main__": + import asyncio + + asyncio.run(main()) +``` + +## Handle Authentication + +If this is your first time using a particular Arcade toolkit with your user ID, you will see an authorization URL: + +``` +Please login to GitHub: Authorization required: https://github.com/login/oauth/authorize... +``` + +Open this URL in your browser and complete the authorization. After authorizing, you can run your script again, and it should work without requiring authentication again for that user ID. + +## Using Other Toolkits + +You can use any of the available Arcade toolkits by specifying them in the `get_arcade_tools` function: + +```python +# Use the Google toolkit +tools = await get_arcade_tools(client, ["google"]) + +# Use multiple toolkits +tools = await get_arcade_tools(client, ["github", "google", "linkedin"]) +``` + +## Specifying Specific Tools + +If you want to use only specific tools from a toolkit: + +```python +# Get only specific GitHub tools +tools = await get_arcade_tools( + client, + toolkits=["github"], + tools=["github_get_issues", "github_get_repository"] +) +``` + +## Next Steps + +- Learn more about [Authentication](authentication.md) +- Explore available [Toolkits and Tools](../guides/toolkits.md) +- See more complex [Examples](../examples/github.md) +- Check out the [API Reference](../api/tools.md) for advanced usage diff --git a/docs/guides/custom-usage.md b/docs/guides/custom-usage.md new file mode 100644 index 0000000..2588d77 --- /dev/null +++ b/docs/guides/custom-usage.md @@ -0,0 +1,399 @@ +# Advanced & Custom Usage + +This guide covers advanced usage patterns and customizations for the `agents-arcade` library, helping you build more sophisticated agent applications with Arcade tools. + +## Custom Client Configuration + +You can configure the Arcade client with custom settings: + +```python +from arcadepy import AsyncArcade +from agents_arcade import get_arcade_tools + +# Custom base URL (e.g., for staging environment) +client = AsyncArcade( + base_url="https://api.staging.arcade.dev", + api_key="your_api_key", + timeout=30 # Custom timeout in seconds +) + +# Get tools using the custom client +tools = await get_arcade_tools(client, ["github"]) +``` + +Alternatively, you can pass configuration directly to `get_arcade_tools`: + +```python +tools = await get_arcade_tools( + client=None, # No client provided, will create one with the kwargs + toolkits=["github"], + base_url="https://api.staging.arcade.dev", + api_key="your_api_key", + timeout=30 +) +``` + +## Building Multi-Agent Systems + +You can create multiple specialized agents with different tools: + +```python +from agents import Agent, Runner, Message + +# Create specialized agents +github_tools = await get_arcade_tools(client, ["github"]) +github_agent = Agent( + name="GitHub Specialist", + instructions="You are a GitHub expert. Help users with GitHub tasks.", + model="gpt-4o-mini", + tools=github_tools, +) + +google_tools = await get_arcade_tools(client, ["google"]) +google_agent = Agent( + name="Google Workspace Specialist", + instructions="You are a Google Workspace expert. Help users with Gmail, Drive, etc.", + model="gpt-4o-mini", + tools=google_tools, +) + +# Create a coordinator agent +coordinator = Agent( + name="Coordinator", + instructions="""You are a coordination agent. Based on the user's request, + determine whether to route to the GitHub Specialist or Google Workspace Specialist. + For GitHub tasks: {{ to: "GitHub Specialist", task: "specific github task" }} + For Google tasks: {{ to: "Google Workspace Specialist", task: "specific google task" }} + """, + model="gpt-4o-mini", +) + +# Set up the agent network +coordinator.add_tool_agent(github_agent) +coordinator.add_tool_agent(google_agent) + +# Run with a single context for authentication +result = await Runner.run( + starting_agent=coordinator, + input="Create a GitHub repository and then send an email about it", + context={"user_id": "user@example.com"}, +) +``` + +## Customizing Tool Behavior + +You can create custom tool wrappers to add functionality: + +```python +from agents.tool import FunctionTool +from functools import partial + +# Get the original tools +original_tools = await get_arcade_tools(client, ["github"]) + +# Create enhanced versions with logging and error handling +enhanced_tools = [] +for tool in original_tools: + # Create a wrapped version of the tool's invoke function + async def wrapped_invoke(context, tool_args, original_invoke): + print(f"[LOG] Executing tool: {tool.name} with args: {tool_args}") + try: + result = await original_invoke(context, tool_args) + print(f"[LOG] Tool {tool.name} completed successfully") + return result + except Exception as e: + print(f"[ERROR] Tool {tool.name} failed: {e}") + raise + + # Create a new tool with the wrapped invoke function + enhanced_tool = FunctionTool( + name=tool.name, + description=tool.description, + params_json_schema=tool.params_json_schema, + on_invoke_tool=partial(wrapped_invoke, original_invoke=tool.on_invoke_tool), + strict_json_schema=tool.strict_json_schema, + ) + enhanced_tools.append(enhanced_tool) + +# Use the enhanced tools +agent = Agent( + name="GitHub agent", + instructions="You are a helpful assistant that can assist with GitHub API calls.", + model="gpt-4o-mini", + tools=enhanced_tools, +) +``` + +## Building Web Applications + +Here's an example of integrating `agents-arcade` with a FastAPI web application: + +```python +from fastapi import FastAPI, BackgroundTasks, HTTPException, Depends +from fastapi.security import APIKeyHeader +from pydantic import BaseModel +from typing import Dict, List, Optional +import asyncio +import uuid + +from agents import Agent, Runner +from arcadepy import AsyncArcade +from agents_arcade import get_arcade_tools +from agents_arcade.errors import AuthorizationError, ToolError + +app = FastAPI() +api_key_header = APIKeyHeader(name="X-API-Key") + +# Store active jobs +active_jobs = {} + +# Models +class AgentRequest(BaseModel): + user_id: str + input: str + toolkits: List[str] + model: str = "gpt-4o-mini" + +class AgentResponse(BaseModel): + job_id: str + status: str + output: Optional[str] = None + authorization_url: Optional[str] = None + +# Authentication dependency +def get_api_key(api_key: str = Depends(api_key_header)): + if api_key != "your-api-key": # Replace with actual API key validation + raise HTTPException(status_code=403, detail="Invalid API key") + return api_key + +# Create an Arcade client +arcade_client = AsyncArcade() + +@app.post("/agent/run", response_model=AgentResponse) +async def run_agent(request: AgentRequest, api_key: str = Depends(get_api_key), background_tasks: BackgroundTasks = None): + # Generate a job ID + job_id = str(uuid.uuid4()) + + # Store initial job status + active_jobs[job_id] = { + "status": "pending", + "output": None, + "authorization_url": None + } + + # Start the agent task in the background + background_tasks.add_task(process_agent_request, job_id, request) + + return AgentResponse( + job_id=job_id, + status="pending" + ) + +async def process_agent_request(job_id: str, request: AgentRequest): + try: + # Get the requested tools + tools = await get_arcade_tools(arcade_client, request.toolkits) + + # Create the agent + agent = Agent( + name="API Agent", + instructions="You are a helpful assistant with access to various tools.", + model=request.model, + tools=tools, + ) + + # Run the agent + result = await Runner.run( + starting_agent=agent, + input=request.input, + context={"user_id": request.user_id}, + ) + + # Update job status + active_jobs[job_id] = { + "status": "completed", + "output": result.final_output, + "authorization_url": None + } + + except AuthorizationError as e: + # Update job status with authorization URL + active_jobs[job_id] = { + "status": "authorization_required", + "output": None, + "authorization_url": e.result.url + } + + except ToolError as e: + # Update job status with error + active_jobs[job_id] = { + "status": "error", + "output": f"Tool error: {e.message}", + "authorization_url": None + } + + except Exception as e: + # Update job status with error + active_jobs[job_id] = { + "status": "error", + "output": f"Error: {str(e)}", + "authorization_url": None + } + +@app.get("/agent/status/{job_id}", response_model=AgentResponse) +async def get_job_status(job_id: str, api_key: str = Depends(get_api_key)): + if job_id not in active_jobs: + raise HTTPException(status_code=404, detail="Job not found") + + job = active_jobs[job_id] + return AgentResponse( + job_id=job_id, + status=job["status"], + output=job["output"], + authorization_url=job["authorization_url"] + ) +``` + +## Caching Tool Results + +For performance optimization, you might want to cache tool results: + +```python +import functools +import asyncio +import json + +# Simple in-memory cache +cache = {} +cache_ttl = 300 # 5 minutes + +# Create a caching decorator for tool calls +def cache_tool_result(ttl=cache_ttl): + def decorator(func): + @functools.wraps(func) + async def wrapper(context, tool_args, *args, **kwargs): + # Create a cache key from the tool name and arguments + tool_name = kwargs.get("tool_name", "unknown_tool") + cache_key = f"{tool_name}:{tool_args}" + + # Check if result is in cache and not expired + if cache_key in cache: + timestamp, result = cache[cache_key] + if (asyncio.get_event_loop().time() - timestamp) < ttl: + print(f"Cache hit for {tool_name}") + return result + + # Execute the tool and cache the result + result = await func(context, tool_args, *args, **kwargs) + cache[cache_key] = (asyncio.get_event_loop().time(), result) + return result + return wrapper + return decorator + +# Apply the cache decorator to _async_invoke_arcade_tool +from agents_arcade.tools import _async_invoke_arcade_tool + +# Cached version +@cache_tool_result(ttl=300) +async def cached_invoke_arcade_tool(context, tool_args, tool_name, requires_auth, client): + return await _async_invoke_arcade_tool( + context=context, + tool_args=tool_args, + tool_name=tool_name, + requires_auth=requires_auth, + client=client + ) + +# Replace the original function with the cached version in your tools +# Note: This requires modifying the tool construction process +``` + +## Persistent User Storage + +For applications with many users, you might want to store user authentication state: + +```python +import sqlite3 +import json +from contextlib import contextmanager + +# Simple SQLite-based user storage +class UserStore: + def __init__(self, db_path="users.db"): + self.db_path = db_path + self._init_db() + + def _init_db(self): + with self._get_conn() as conn: + cursor = conn.cursor() + cursor.execute(""" + CREATE TABLE IF NOT EXISTS users ( + user_id TEXT PRIMARY KEY, + auth_state TEXT, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ) + """) + conn.commit() + + @contextmanager + def _get_conn(self): + conn = sqlite3.connect(self.db_path) + try: + yield conn + finally: + conn.close() + + def get_user(self, user_id): + with self._get_conn() as conn: + cursor = conn.cursor() + cursor.execute("SELECT user_id, auth_state FROM users WHERE user_id = ?", (user_id,)) + row = cursor.fetchone() + if row: + return { + "user_id": row[0], + "auth_state": json.loads(row[1]) if row[1] else {} + } + return None + + def create_or_update_user(self, user_id, auth_state=None): + with self._get_conn() as conn: + cursor = conn.cursor() + existing = self.get_user(user_id) + + if existing: + cursor.execute( + "UPDATE users SET auth_state = ?, updated_at = CURRENT_TIMESTAMP WHERE user_id = ?", + (json.dumps(auth_state), user_id) + ) + else: + cursor.execute( + "INSERT INTO users (user_id, auth_state) VALUES (?, ?)", + (user_id, json.dumps(auth_state) if auth_state else None) + ) + conn.commit() + + def record_authorization(self, user_id, toolkit, status): + user = self.get_user(user_id) + auth_state = user["auth_state"] if user else {} + auth_state[toolkit] = { + "status": status, + "timestamp": datetime.now().isoformat() + } + self.create_or_update_user(user_id, auth_state) + +# Example usage +user_store = UserStore() + +# Before running agent +user = user_store.get_user("user@example.com") +if not user: + user_store.create_or_update_user("user@example.com") + +# After successful authorization +user_store.record_authorization("user@example.com", "github", "authorized") +``` + +## Conclusion + +These advanced techniques should help you build more sophisticated applications with `agents-arcade`. You can combine these patterns to create powerful, robust, and user-friendly agent systems that leverage Arcade's extensive toolkit ecosystem. diff --git a/docs/guides/error-handling.md b/docs/guides/error-handling.md new file mode 100644 index 0000000..56f14e1 --- /dev/null +++ b/docs/guides/error-handling.md @@ -0,0 +1,259 @@ +# Error Handling + +This guide covers how to properly handle errors when using `agents-arcade` with OpenAI Agents. Effective error handling is crucial for creating a smooth user experience, especially when working with tools that require authentication. + +## Common Errors + +When working with Arcade tools, you might encounter several types of errors: + +1. **Authorization Errors**: Occur when a tool requires authentication but the user hasn't completed the authorization flow +2. **Tool Execution Errors**: Occur when a tool fails to execute properly +3. **Client Errors**: Issues with the Arcade client itself, such as invalid API keys or network problems + +## Handling Authorization Errors + +The most common error when using Arcade tools is the `AuthorizationError`, which occurs when a tool requires user authorization. + +### Basic Authorization Error Handling + +```python +from agents import Agent, Runner +from arcadepy import AsyncArcade +from agents_arcade import get_arcade_tools +from agents_arcade.errors import AuthorizationError + +async def run_agent(): + client = AsyncArcade() + tools = await get_arcade_tools(client, ["github"]) + + agent = Agent( + name="GitHub Agent", + instructions="You are a helpful assistant for GitHub.", + model="gpt-4o-mini", + tools=tools, + ) + + try: + result = await Runner.run( + starting_agent=agent, + input="List my repositories", + context={"user_id": "user@example.com"}, + ) + return result.final_output + except AuthorizationError as e: + # Extract the authorization URL and present it to the user + auth_url = e.result.url + return f"Please authorize access at: {auth_url}" +``` + +### Interactive Authorization Flow + +For a better user experience, you might want to guide the user through the authorization process and retry the operation once authorized: + +```python +from arcadepy.auth import wait_for_authorization_completion + +async def run_with_authorization(): + client = AsyncArcade() + user_id = "user@example.com" + + try: + tools = await get_arcade_tools(client, ["github"]) + agent = Agent( + name="GitHub Agent", + instructions="You are a helpful GitHub assistant.", + model="gpt-4o-mini", + tools=tools, + ) + + return await Runner.run( + starting_agent=agent, + input="List my repositories", + context={"user_id": user_id}, + ).final_output + except AuthorizationError as e: + print(f"Authorization required. Please visit: {e.result.url}") + print("Once you've completed authorization, the operation will continue...") + + # Wait for the user to complete authorization + auth_result = await wait_for_authorization_completion( + client, + e.result.authorization_id, + timeout=300 # 5 minutes + ) + + if auth_result.status == "completed": + print("Authorization successful! Retrying operation...") + # Retry the operation now that authorization is complete + return await run_with_authorization() + else: + return "Authorization failed or timed out." +``` + +## Handling Tool Execution Errors + +When a tool fails to execute properly, a `ToolError` is raised with details about what went wrong. + +```python +from agents_arcade.errors import ToolError, AuthorizationError + +async def run_agent_safely(): + try: + tools = await get_arcade_tools(client, ["github"]) + agent = Agent( + name="GitHub Agent", + instructions="You are a helpful GitHub assistant.", + model="gpt-4o-mini", + tools=tools, + ) + + return await Runner.run( + starting_agent=agent, + input="Create a repository named my-repo", + context={"user_id": "user@example.com"}, + ).final_output + except AuthorizationError as e: + return f"Authorization required: {e.result.url}" + except ToolError as e: + # Handle specific tool errors + error_message = e.message + + if "already exists" in error_message.lower(): + return "A repository with that name already exists. Please try a different name." + elif "permission" in error_message.lower(): + return "You don't have permission to perform this action." + else: + return f"An error occurred: {error_message}" +``` + +## Comprehensive Error Handling + +For a production application, you'll want to handle all potential errors: + +```python +from agents_arcade.errors import ToolError, AuthorizationError +from arcadepy.exceptions import ArcadeError + +async def run_with_comprehensive_error_handling(): + try: + # Create client + client = AsyncArcade() + + # Get tools + try: + tools = await get_arcade_tools(client, ["github", "google"]) + except ValueError as e: + return f"Configuration error: {e}" + except ArcadeError as e: + return f"Arcade client error: {e}" + + # Create agent + agent = Agent( + name="Multi-tool Agent", + instructions="You can help with GitHub and Google services.", + model="gpt-4o-mini", + tools=tools, + ) + + # Run agent + try: + result = await Runner.run( + starting_agent=agent, + input="List my GitHub repositories and recent emails", + context={"user_id": "user@example.com"}, + ) + return result.final_output + except AuthorizationError as e: + return f"Authorization required: {e.result.url}" + except ToolError as e: + return f"Tool execution failed: {e.message}" + except Exception as e: + return f"Unexpected error running agent: {e}" + + except Exception as e: + return f"Unexpected error: {e}" +``` + +## User-Friendly Error Messages + +When displaying errors to end users, it's important to provide helpful guidance: + +```python +def handle_arcade_error(error): + if isinstance(error, AuthorizationError): + return { + "type": "auth_required", + "message": "Authentication required", + "details": "Please click the link below to authorize access", + "url": error.result.url, + "auth_id": error.result.authorization_id + } + elif isinstance(error, ToolError): + # Customize based on the tool and error message + tool_name = error.result.tool_name + error_msg = error.message + + if tool_name.startswith("github"): + return handle_github_error(error_msg) + elif tool_name.startswith("google"): + return handle_google_error(error_msg) + else: + return { + "type": "tool_error", + "message": f"Error using {tool_name}", + "details": error_msg + } + else: + return { + "type": "unknown_error", + "message": "An unexpected error occurred", + "details": str(error) + } + +def handle_github_error(error_msg): + if "not found" in error_msg.lower(): + return { + "type": "not_found", + "message": "GitHub repository not found", + "details": "Please check the repository name and try again" + } + # Add more specific GitHub error handling + return { + "type": "github_error", + "message": "GitHub error", + "details": error_msg + } +``` + +## Logging Errors for Debugging + +For debugging and monitoring purposes, it's important to log errors: + +```python +import logging + +# Set up logging +logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' +) +logger = logging.getLogger("agents-arcade") + +async def run_with_logging(): + try: + # Your agent code here + pass + except AuthorizationError as e: + logger.info(f"Authorization required for user: {user_id}, tool: {e.result.tool_name}") + # Handle error for user + except ToolError as e: + logger.error(f"Tool error: {e.result.tool_name} failed with: {e.message}") + # Handle error for user + except Exception as e: + logger.exception(f"Unexpected error: {e}") + # Handle error for user +``` + +## Conclusion + +Proper error handling is essential for creating a good user experience with Arcade tools. By anticipating and gracefully handling different types of errors, you can guide users through authentication processes and provide helpful feedback when things go wrong. diff --git a/docs/guides/toolkits.md b/docs/guides/toolkits.md new file mode 100644 index 0000000..693bb71 --- /dev/null +++ b/docs/guides/toolkits.md @@ -0,0 +1,166 @@ +# Arcade Toolkits Guide + +This guide provides an overview of the available Arcade toolkits that you can use with OpenAI Agents through the `agents-arcade` library. + +## Available Toolkits + +Arcade offers a variety of toolkits that provide access to different services and APIs: + +| Toolkit | Description | Authentication Required | +| ------------- | -------------------------------------------------- | ----------------------- | +| `github` | Interact with GitHub repositories, issues, PRs | Yes | +| `google` | Access Gmail, Drive, Calendar, Docs, etc. | Yes | +| `linkedin` | Interact with LinkedIn (posts, profile, messaging) | Yes | +| `x` | Interact with X/Twitter (tweets, timeline, etc.) | Yes | +| `web` | Web search, browser automation | Partial | +| `news` | Access news articles and headlines | No | +| `maps` | Geolocation, directions, place info | Partial | +| `weather` | Current weather and forecasts | No | +| `datasources` | Connect to databases, APIs, and other data sources | Varies | + +For the most up-to-date list of available toolkits, check the [Arcade Integrations documentation](https://docs.arcade.dev/toolkits). + +## Using Toolkits + +To use a toolkit with your agent, you need to include it when fetching tools: + +```python +from agents_arcade import get_arcade_tools + +# Use a single toolkit +tools = await get_arcade_tools(client, ["github"]) + +# Use multiple toolkits +tools = await get_arcade_tools(client, ["github", "google", "news"]) +``` + +### Filtering Tools Within a Toolkit + +If you only need specific tools from a toolkit, you can filter them: + +```python +# Only get specific GitHub tools +tools = await get_arcade_tools( + client, + toolkits=["github"], + tools=["github_get_repository", "github_list_user_repositories"] +) +``` + +## GitHub Toolkit + +The GitHub toolkit allows agents to interact with GitHub repositories, issues, pull requests, and more. + +### Common GitHub Tools + +- `github_get_repository`: Get repository information +- `github_list_user_repositories`: List repositories for a user +- `github_create_repository`: Create a new repository +- `github_get_issues`: Get issues for a repository +- `github_create_issue`: Create a new issue +- `github_star_repository`: Star a repository + +### Example GitHub Usage + +```python +tools = await get_arcade_tools(client, ["github"]) +agent = Agent( + name="GitHub agent", + instructions="You are a helpful assistant that can assist with GitHub API calls.", + model="gpt-4o-mini", + tools=tools, +) +``` + +## Google Toolkit + +The Google toolkit provides access to Google services like Gmail, Drive, Calendar, Docs, and more. + +### Common Google Tools + +- `google_gmail_get_messages`: Get Gmail messages +- `google_gmail_send_message`: Send an email +- `google_drive_list_files`: List files in Google Drive +- `google_calendar_list_events`: List calendar events +- `google_docs_create_document`: Create a new Google Doc + +### Example Google Usage + +```python +tools = await get_arcade_tools(client, ["google"]) +agent = Agent( + name="Google Assistant", + instructions="You are a helpful assistant that can work with Google services.", + model="gpt-4o-mini", + tools=tools, +) +``` + +## LinkedIn Toolkit + +The LinkedIn toolkit allows agents to interact with LinkedIn profiles, posts, and messaging. + +### Common LinkedIn Tools + +- `linkedin_get_profile`: Get LinkedIn profile information +- `linkedin_create_post`: Create a LinkedIn post +- `linkedin_send_message`: Send a LinkedIn message +- `linkedin_get_feed`: Get the LinkedIn feed + +### Example LinkedIn Usage + +```python +tools = await get_arcade_tools(client, ["linkedin"]) +agent = Agent( + name="LinkedIn Assistant", + instructions="You are a helpful assistant for LinkedIn interactions.", + model="gpt-4o-mini", + tools=tools, +) +``` + +## Web Toolkit + +The Web toolkit provides tools for searching the web and interacting with web content. + +### Common Web Tools + +- `web_search`: Search the web for information +- `web_browse`: Visit and extract content from a specific URL +- `web_scrape`: Extract structured data from web pages + +### Example Web Usage + +```python +tools = await get_arcade_tools(client, ["web"]) +agent = Agent( + name="Web Assistant", + instructions="You are a helpful assistant for web searches and browsing.", + model="gpt-4o-mini", + tools=tools, +) +``` + +## Combining Toolkits + +One of the most powerful features of `agents-arcade` is the ability to combine multiple toolkits in a single agent: + +```python +tools = await get_arcade_tools(client, ["github", "google", "web"]) +agent = Agent( + name="Super Assistant", + instructions="""You are a versatile assistant that can: + - Help with GitHub repositories and issues + - Manage emails and Google documents + - Search the web for information + Always use the most appropriate tools for the user's request.""", + model="gpt-4o-mini", + tools=tools, +) +``` + +This creates a powerful agent that can handle a wide range of tasks across different services, providing a seamless experience for the user. + +## Authentication Considerations + +Remember that many toolkits require authentication. When using multiple authenticated toolkits, the user will need to complete the authentication flow for each service the first time they use it. See the [Authentication](../getting-started/authentication.md) guide for more details. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..4d2b1dc --- /dev/null +++ b/docs/index.md @@ -0,0 +1,76 @@ +# Agents Arcade + +

+ Arcade Logo +

+ +`agents-arcade` provides an integration between [Arcade](https://docs.arcade.dev) and the [OpenAI Agents Library](https://github.com/openai/openai-python). This allows you to enhance your AI agents with Arcade tools like Google Mail, LinkedIn, X, or ones you build yourself with the [Tool SDK](https://github.com/ArcadeAI/arcade-ai). + +For a list of all hosted tools and auth providers you can use to build your own, see the [Arcade Integrations](https://docs.arcade.dev/toolkits) documentation. + +## What is Agents Arcade? + +Agents Arcade connects OpenAI Agents to Arcade's extensive collection of tools and integrations. With Agents Arcade, you can: + +- **Access Powerful Integrations**: Connect your agents to tools like Google Workspace, GitHub, LinkedIn, X, and more +- **Handle Authentication**: Seamlessly manage user authorization for tools that require it +- **Build Custom Tools**: Create and integrate your own tools using Arcade's Tool SDK + +## Key Features + +- **Easy Integration**: Simple API to connect Arcade tools with OpenAI Agents +- **Extensive Toolkit Support**: Access to all Arcade toolkits including Gmail, Google Drive, Search, and more +- **Asynchronous Support**: Built with async/await for compatibility with OpenAI's Agent framework +- **Authentication Handling**: Manages authorization for tools requiring user permissions + +## Installation + +```bash +pip install agents-arcade +``` + +## Quick Example + +```python +from agents import Agent, Runner +from arcadepy import AsyncArcade + +from agents_arcade import get_arcade_tools +from agents_arcade.errors import AuthorizationError + + +async def main(): + client = AsyncArcade() + # Use the "github" toolkit for this example + tools = await get_arcade_tools(client, ["github"]) + + # Create an agent that can use the github toolkit + github_agent = Agent( + name="GitHub agent", + instructions="You are a helpful assistant that can assist with GitHub API calls.", + model="gpt-4o-mini", + tools=tools, + ) + + try: + result = await Runner.run( + starting_agent=github_agent, + input="Star the arcadeai/arcade-ai repo", + # make sure you pass a UNIQUE user_id for auth + context={"user_id": "user@example.com"}, + ) + print("Final output:\n\n", result.final_output) + except AuthorizationError as e: + print("Please Login to Github:", e) +``` + +## Resources + +- [Arcade Documentation](https://docs.arcade.dev) +- [Arcade Integrations](https://docs.arcade.dev/toolkits) +- [Arcade Python Client](https://github.com/ArcadeAI/arcade-py) +- [OpenAI Agents](https://platform.openai.com/docs/guides/agents) + +## License + +This project is licensed under the MIT License - see the LICENSE file for details. diff --git a/examples/github.py b/examples/github.py index f016619..ab71f3b 100644 --- a/examples/github.py +++ b/examples/github.py @@ -6,7 +6,7 @@ async def main(): - client = AsyncArcade() + client = AsyncArcade(api_key="arc_o1SX4VZ563zrDz1oJGgdtfUHFH8FAtvD8JSrxoTjxmsaNo4eap3H") # Use the "github" toolkit for this example # You can use other toolkits like "google", "linkedin", "x", etc. tools = await get_arcade_tools(client, ["github"]) diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000..04c3af5 --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,74 @@ +site_name: Agents Arcade +site_description: Arcade Integration for OpenAI Agents +site_url: https://docs.arcadeai.dev/agents-arcade/ +repo_url: https://github.com/ArcadeAI/agents-arcade +repo_name: ArcadeAI/agents-arcade + +theme: + name: material + logo: https://docs.arcade.dev/images/logo/arcade-logo.png + favicon: https://docs.arcade.dev/images/logo/arcade-logo.png + palette: + primary: indigo + accent: indigo + features: + - navigation.instant + - navigation.tracking + - navigation.expand + - navigation.indexes + - content.code.copy + - content.code.annotate + +markdown_extensions: + - pymdownx.highlight: + anchor_linenums: true + - pymdownx.inlinehilite + - pymdownx.snippets + - pymdownx.superfences + - admonition + - pymdownx.details + - pymdownx.tabbed: + alternate_style: true + - tables + - footnotes + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + +plugins: + - search + - mkdocstrings: + handlers: + python: + paths: [agents_arcade] + options: + show_source: false + show_root_heading: true + heading_level: 3 + +nav: + - Home: index.md + - Getting Started: + - getting-started/installation.md + - getting-started/quickstart.md + - getting-started/authentication.md + - Guides: + - guides/toolkits.md + - guides/error-handling.md + - guides/custom-usage.md + - Examples: + - examples/github.md + - examples/email.md + - examples/multi-toolkit.md + - API Reference: + - api/tools.md + - api/utils.md + - api/errors.md + - Contributing: contributing.md + +extra: + social: + - icon: fontawesome/brands/github + link: https://github.com/ArcadeAI/agents-arcade + - icon: fontawesome/brands/python + link: https://pypi.org/project/agents-arcade/ From 6b18ba6fc3d548de85fe6307bcb20915e5403629 Mon Sep 17 00:00:00 2001 From: Sam Partee Date: Mon, 14 Apr 2025 22:17:48 -0400 Subject: [PATCH 4/4] Apply suggestions from code review Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a042be1..ec2bb7e 100644 --- a/README.md +++ b/README.md @@ -66,12 +66,11 @@ async def main(): starting_agent=github_agent, input="Star the arcadeai/arcade-ai repo", # make sure you pass a UNIQUE user_id for auth - context={"user_id": "user@example.comiii"}, + context={"user_id": "user@example.com"}, ) print("Final output:\n\n", result.final_output) except AuthorizationError as e: - print("Please Login to Github:", e) - + print("Please Login to GitHub:", e) if __name__ == "__main__": import asyncio