Skip to content
178 changes: 94 additions & 84 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,53 @@
# Build a simple gmail agent with Composio and FastAPI
# Building an AI Agent with Composio and FastAPI

With Composio's managed authentication and tool calling, it's easy to build the AI agents that can interact with the real world while reducing the boilerplate required to setup and manage the authentication. This cookbook will walk you through the process of building and serving agents using `Composio`, `OpenAI` and `FastAPI`.
In this guide you will learn how to build a **Gmail Agent** powered by **Composio**. The agent will be able to use various Gmail tools, listed [here](https://docs.composio.dev/toolkits/gmail#tool-list).

## Features

## Requirements
* Composio comes with built in support for gmail authentication and actions (and [300+ more toolkits](https://docs.composio.dev/toolkits/introduction))
* You can easily use any providers like **OpenAI**, **Anthropic**, **LangChain**, **Vercel AI SDK**, and [more](https://docs.composio.dev/providers/openai).

## Prerequisites

* Python3.x
* [UV](https://docs.astral.sh/uv/getting-started/installation/)
* Composio API key
* OpenAI API key
* Basic knowledge of OAuth
* Understanding of building HTTP services (preferably using FastAPI)
* [Composio](https://platform.composio.dev/auth) API key - Sign up here and navigate to **Settings** in your project dashboard.
* [OpenAI API key](https://platform.openai.com/api-keys)

## Setup

**1. Clone the Repository**

```bash
git clone git@github.com:composiohq/composio-fastapi
cd composio-fastapi/
```

**2. Setup Environment Variables**

## Building an AI agent that can interact with `gmail` service
Copy the example .env file to create your own:

```bash
cp .env.example .env
```

**3. Fill in the necessary API keys:**

```dotenv
COMPOSIO_API_KEY=your-composio-api-key
OPENAI_API_KEY=your-openai-api-key
```

First, let's start with building a simple AI agent embedded with tools from Composio that let's the agent interact with the `gmail` service.
**4. Create the virtual environment and activate it:**

```bash
make env
source .venv/bin/activate
```

## Building an AI agent to interact with gmail

Let's build a simple AI agent that has access to the **gmail** toolkit.

```python
from openai import OpenAI
Expand All @@ -26,13 +58,13 @@ from composio_openai import OpenAIProvider
def run_gmail_agent(
composio_client: Composio[OpenAIProvider],
openai_client: OpenAI,
user_id: str, # User ID is what composio uses to store and access user level authentication tokens
user_id: str, # Composio uses User ID to store and access user level authentication tokens
prompt: str,
):
"""
Run the Gmail agent using composio and openai clients.
"""
# Step 1: Fetch the list of necessary Gmail tools with Composio
# Step 1: Fetch the list of necessary Gmail tools using Composio
tools = composio_client.tools.get(
user_id=user_id,
tools=[
Expand All @@ -56,13 +88,13 @@ def run_gmail_agent(

> **NOTE**: This is a very simple agent without any state management and agentic loop implementation, so the agent won't be able to perform very complicated tasks. If you want to understand how composio can be used with agentic loops, check other cookbooks with more agentic frameworks.

Now, to invoke this agent you need to authenticate your users with Composio's managed authentication service.
To **invoke** this agent you need to authenticate your users with Composio's managed authentication service.

## Authenticating users
## Creating Auth Config

<!-- TODO: redirect them to dashboard and remove complexity -->

To authenticate your users with Composio you need an authentication config for the given app, Nn this case you need one for gmail. To create an authentication config for `gmail` you need `client_id` and `client_secret` from your [Google OAuth Console](https://developers.google.com/identity/protocols/oauth2). Once you have the required credentials you can use the following piece of code to set up authentication for `gmail`.
To authenticate your users with Composio you need an authentication config for the given toolkit(gmail). To create an authentication config for `gmail` you need `client_id` and `client_secret` from your [Google OAuth Console](https://developers.google.com/identity/protocols/oauth2). Once you have the required credentials you can use the following piece of code to set up authentication for `gmail`.

```python
from composio import Composio
Expand Down Expand Up @@ -91,24 +123,35 @@ def create_auth_config(composio_client: Composio[OpenAIProvider]):
)
```

This will create an authencation config for `gmail` which you can use to authenticate your users for your app. Ideally you should just create one authentication object per project, so check for an existing auth config before you create a new one.

> **NOTE**:
> 1. "One Authentication Config Per Project": Ideally, you only need to create one authentication config per project. Before creating a new one, check for an existing auth config in your project.
> 2. "Composio's Managed Authentication": Composio platform provides native managed authentication to help you fast-track your development. You can use these default auth configs for development. For production, always use your own OAuth app configuration to ensure secure and scalable authentication.

## Authenticating users

### Fetch the Auth Config

The following function fetches the auth config for the **Gmail** toolkit:

```python
def fetch_auth_config(composio_client: Composio[OpenAIProvider]):
"""
Fetch the auth config for a given user id.
"""
auth_configs = composio_client.auth_configs.list()
auth_configs = composio_client.auth_configs.list() # Fetch all auth configs
for auth_config in auth_configs.items:
if auth_config.toolkit == "GMAIL":
return auth_config
if auth_config.toolkit == "GMAIL": # Check for Gmail-specific auth config
return auth_config # Return None if no Gmail auth config is found
else:
raise ValueError("No Gmail auth config found. Please create one before proceeding.")

return None
```

> **NOTE**: Composio platform provides composio managed authentication for some apps to help you fast-track your development, `gmail` being one of them. You can use these default auth configs for development, but for production you should always use your own oauth app configuration.
### Creating a connected account for the Auth Config

Once you have authentication management in place, we can start with connecting your users to your `gmail` app. Let's implement a function to connect the users to your `gmail` app via composio.
To authenticate users, you need to initiate a connection for them using the auth config you just fetched. This is done through the Composio connected accounts API.

```python
from fastapi import FastAPI
Expand All @@ -120,8 +163,6 @@ def create_connection(composio_client: Composio[OpenAIProvider], user_id: str):
"""
# Fetch or create the auth config for the gmail toolkit
auth_config = fetch_auth_config(composio_client=composio_client)
if not auth_config:
auth_config = create_auth_config(composio_client=composio_client)

# Create a connection for the user
return composio_client.connected_accounts.initiate(
Expand Down Expand Up @@ -152,15 +193,13 @@ def _create_connection(
}
```

Now, on your client app you can make a request to this endpoint and your user will get a URL which they can use to authenticate.

## Set Up FastAPI service
**From your client app, call this endpoint to obtain the **redirect URL** for user authentication.**

We will use [`FastApi`](https://fastapi.tiangolo.com/) to build an HTTP service that authenticates your users and let's them interact with your agent. This guide will also provide you with the best practices for using composio client in production environments.

### Setup dependencies
## Setup Composio SDK client

FastAPI allows [dependency injection](https://fastapi.tiangolo.com/reference/dependencies/) to simplify the usage of SDK clients which are required to be singletons. We also recommend you to use `composio` SDK client as singleton.
We recommend you to use the composio SDK client as a singleton. FastAPI allows [dependency injection](https://fastapi.tiangolo.com/reference/dependencies/) to simplify the usage of SDK clients which are required to be singletons.

```python
import os
Expand Down Expand Up @@ -189,11 +228,12 @@ A Composio client dependency.
"""
```

Check [dependencies](./simple_gmail_agent/server/dependencies.py) module for more details.
> Check [dependencies](./simple_gmail_agent/server/dependencies.py) module for more details.


### Invoke agent via FastAPI
## Invoke the agent via FastAPI

When invoking an agent, make sure you validate the `user_id`.
When invoking the agent, make sure to validate the `user_id` to ensure that the request is tied to an authenticated user.

```python
def check_connected_account_exists(
Expand All @@ -203,21 +243,23 @@ def check_connected_account_exists(
"""
Check if a connected account exists for a given user id.
"""
# Fetch all connected accounts for the user
# Fetch all connected accounts for the user
connected_accounts = composio_client.connected_accounts.list(user_ids=[user_id])

# Check if there's an active connected account
for account in connected_accounts.items:
if account.status == "ACTIVE":
return True

# Ideally you should not have inactive accounts, but if you do, you should delete them
# Warning for inactive accounts, ideally delete them if found
print(f"[warning] inactive account {account.id} found for user id: {user_id}")
return False

def validate_user_id(user_id: str, composio_client: ComposioClient):
"""
Validate the user id, if no connected account is found, create a new connection.

Raises an HTTPException if no connected account exists for the user.
"""
if check_connected_account_exists(composio_client=composio_client, user_id=user_id):
return user_id
Expand All @@ -226,20 +268,20 @@ def validate_user_id(user_id: str, composio_client: ComposioClient):
status_code=404, detail={"error": "No connected account found for the user id"}
)

# Endpoint: Run the Gmail agent for a given user id and prompt
# Endpoint: Run the Gmail agent for a given user ID and prompt
@app.post("/agent")
def _run_gmail_agent(
request: RunGmailAgentRequest,
composio_client: ComposioClient,
openai_client: OpenAIClient, # OpenAI client will be injected as dependency
composio_client: ComposioClient, # Injected Composio client
openai_client: OpenAIClient, # Injected OpenAI client for generating responses
) -> List[ToolExecutionResponse]:
"""
Run the Gmail agent for a given user id and prompt.
"""
# For demonstration, using a default user_id. Replace with real user logic in production.
# For demonstration, we are using a default user_id. Replace this with actual user ID value in production
user_id = "default"

# Validate the user id before proceeding
# Validate the user ID before invoking the agent
user_id = validate_user_id(user_id=user_id, composio_client=composio_client)

# Run the Gmail agent using Composio and OpenAI
Expand All @@ -254,73 +296,41 @@ def _run_gmail_agent(

> **NOTE**: Check [server](./simple_gmail_agent/server/) module for service implementation

## Putting everything together
## Running the service

So far, we have created an agent with ability to interact with `gmail` using the `composio` SDK, functions to manage connected accounts for users and a FastAPI service. Now let's run the service.

> Before you proceed check the [code](./simple_gmail_agent/server/api.py), there are some utility endpoints that we have not discussed in the cookbook.


1. Clone the repository
```bash
git clone git@github.com:composiohq/composio-fastapi
cd composio-fastapi/
```
2. Setup environment
```bash
cp .env.example .env
```
We've built an agent that interacts with Gmail using the Composio toolkit, handles connected user accounts. Now, let's run the service.

Fill the api keys
```dotenv
COMPOSIO_API_KEY=
OPENAI_API_KEY=
```
> For additional utility endpoints not discussed here, check the [code](./simple_gmail_agent/server/api.py)

Create the virtual env
```bash
make env
source .venv/bin/activate
```
3. Run the HTTP server
Run the HTTP server
```bash
uvicorn simple_gmail_agent.server.api:create_app --factory
```

## Using Composio for managed auth and tools

Composio reduces a lot of boilerplate for building AI agents with ability access and use a wide variety of apps. For example in this cookbook, to build `gmail` integration without composio you would have to write code to
- manage `gmail` oauth app
- manage user connections
- tools for your agents to interact with `gmail`

Using composio simplifies all of the above to a few lines of code as we've seen the cookbook.

## Best practices

**🎯 Effective Prompts**:
- Be specific: "Send email to john@company.com about tomorrow's 2pm meeting" works better than "send email"
- Include context: "Reply to Sarah's email about the budget with our approval"
- Use natural language: The agent understands conversational requests
- Be specific: "Send email to john@company.com about tomorrow's 2pm meeting" is clearer than "send email"
- Provide useful context: "Reply to Sarah's email about the budget with our approval"

**🔒 User Management**:
- Use unique, consistent `user_id` values for each person
- Each user maintains their own Gmail connection
- User IDs can be email addresses, usernames, or any unique identifier

- Use unique, consistent `user_id` for each person.
- Ensure each user has their own Gmail connected account.
- Keep user_id consistent across requests.

## Troubleshooting

**Connection Issues**:
- Ensure your `.env` file has valid `COMPOSIO_API_KEY` and `OPENAI_API_KEY`
- Check that the user has completed Gmail authorization
- Verify the user_id matches exactly between requests
- Verify your `.env` file has valid `COMPOSIO_API_KEY` and `OPENAI_API_KEY`
- Verify that the user has completed Gmail authorization
- Verify that the user_id matches between requests

**API Errors**:
- Check the server logs for detailed error messages
- Ensure request payloads match the expected format
- Check server logs for detailed error messages
- Ensure request payloads follow the expected format.
- Visit `/docs` endpoint for API schema validation

**Gmail API Limits**:
- Gmail has rate limits; the agent will handle these gracefully
- For high-volume usage, consider implementing request queuing
- For high-volume usage, consider implementing request queuing