How to build a "Chat with Attio" AI Slackbot | Replit

How to build a "Chat with Attio" AI Slackbot

A guide by

Horacio Lopez

Introduction

In this guide, we'll walk you through creating a Slackbot that uses AI to answer questions about Attio deals. This bot leverages the power of CrewAI, Attio's API, and OpenAI's language models to provide intelligent responses to deal-related queries.

By the end of this tutorial, you'll have an AI Slackbot that can fetch and answer queries about your Attio deals data.

Getting Started

To begin, fork this template by clicking "Use Template" below:

Use the template

Setting Up

Slack App

Create a new Slack app

In Replit, go to the Secrets tab (Tools > Secrets) and add the credentials to your secrets within SLACK_APP_TOKEN and SLACK_BOT_TOKEN respectively.

If you want a character for your new Slack App, feel free to download this little guy:

Attio Private Key

OpenAI API Key

Understanding the Code

CrewAI Concepts

This project uses CrewAI, a framework for creating AI agents that work together. Here are the key concepts:

To learn more about CrewAI, be sure to visit their documentation.

Fetching Deal Data

One unique feature of this implementation is how it fetches deal data from Attio. Let's look at the relevant tool:

class ListDealsTool(BaseTool):
    name: str = "List Deals"
    description: str = "Fetches deals from Attio based on given filters and sorts"
    args_schema: type[BaseModel] = ListDealsToolInput

def _run(self, filter: Optional[Filter] = None, sorts: List[Sort] = ..., limit: int = 5, offset: int = 0) -> List[Dict]:
        url = "https://api.attio.com/v2/objects/deals/records/query"
        headers = {
            "accept": "application/json",
            "authorization": f"Bearer {attio_token}",
            "content-type": "application/json"
        }
        payload = {
            "sorts": [sort.model_dump() for sort in sorts],
            "limit": limit,
            "offset": offset
        }
        if filter:
            filter_dict = filter.model_dump(exclude_none=True)
            if filter_dict:  # Only add filter if it's not empty
                payload["filter"] = filter_dict

try:
            print(f"FINAL QUERY: {payload}")
            response = requests.post(url, json=payload, headers=headers)
            response.raise_for_status()
            raw_data = response.json()['data']
            clean_data = clean_attio_data(raw_data)
            return clean_data
        except requests.exceptions.RequestException as e:
            print(f"Error fetching deals: {e}")
            print(f"Response content: {response.text if response else 'No response'}")
            return []

This tool fetches deals from Attio based on the provided filters and sorts. It's used by the AI to find relevant deals based on the user's query.

Fetching Matching Deals

The DealSearcher agent uses the ListDealsTool to search for deals based on the user's query. Here's a snippet of the task that uses this agent:

query_deals_task = Task(
    description=dedent(f"""
        Using the filter (if provided) and sorts from the previous task, search for relevant deals using the ListDealsTool.
        The previous task output is a JSON object with 'sorts' key and optionally 'filter' key.

Use this exact structure when calling the ListDealsTool:
        Action: List Deals
        Action Input: {{
            "sorts": <insert sorts from previous task>,
            "limit": 5
        }}

If a filter was provided by the previous task, include it in the Action Input like this:
        Action Input: {{
            "filter": <insert filter from previous task>,
            "sorts": <insert sorts from previous task>,
            "limit": 5
        }}

If no filter was provided, omit the 'filter' key entirely from the Action Input.

Do not modify the filter or sorts. Use them exactly as they are provided by the previous task.
        If no deals are found initially, report this information accurately.
        Return the list of matching deals or an explanation if no deals were found.
        Original query: {query}
    """),
    agent=DealSearcher,
    context=[understand_query_task],
    expected_output=
    "A list of deal objects or an explanation if no deals were found.")

This task instructs the AI on how to use the ListDealsTool to find relevant deals based on the user's query.

Summarizing Results

The final step involves summarizing the found deal data. This is handled by the MessageSummarizer agent and its associated task:

create_summarization_task = Task(
    description=dedent(f"""
        Summarize the information found in the earlier deal research and
        output a 1-2 sentence summary of the findings.

If you need to aggregate the deals to answer the query: {query}
        Then use the AggregateDealDataTool to process the results.

Only use the aggregator tools if an aggregation is requested in the query
        and you don't already have the aggregated data.

If you already have aggregated data or a summary from previous steps,
        use that information directly without recalculating.

Do not invent or create data. Only use what is provided by earlier tasks with data.
    """),
    agent=MessageSummarizer,
    expected_output=
    "A 1-2 sentence summary of the findings based on the deal data and user query."
)

This task ensures that the bot provides a concise, relevant summary based on the deals found and the user's original query.

Running Your Bot

To run your bot:

  1. Make sure all required secrets are set in the Replit Secrets tab.
  2. Click the "Run" button in Replit.
  3. Your bot should now be active in your Slack workspace. You'll see a message "⚡️ Bolt app is running!" in the Console.

To interact with your bot, mention it in a channel where it's been invited, followed by your query about Attio deals.

Deploying Your Bot

In order to keep your bot running 24/7 and receive requests whenever someone mentions it in Slack, you'll need to deploy it on a hosted server.

Open a new tab in the Workspace and search for “Deployments” or open the control console by typing ⌘ + K (or Ctrl + K) and type "deploy". You should find a screen like this.

For bots like this that need always need to be up listening to requests, we recommend using a Reserved VM. On the next screen, click Approve and configure build settings most internal bots work fine with the default machine settings but if you need more power later, you can always come back and change these settings later. You can monitor your usage and billing at any time at: replit.com/usage.

On the next screen, you’ll be able to set your primary domain and edit the Secrets that will be in your production deployment. Usually, we keep these settings as they are.

Finally, click Deploy and watch your bot go live!

What's Next

To further improve your Attio AI Slackbot, consider:

Happy coding!