Slack Search & Media Tools

Run SlackContextProvider with Gemini sub-agents, enabling search_messages and opt-in media tools for file download and upload.

Both the outer agent and Slack sub-agents use gemini-3.5-flash. The example exposes optional media tools, but its main prompt demonstrates text search; it does not download or upload a file.

The source comments describe a broader search surface than this CLI configures. search_messages is registered only with a user token; a bot-only run has channel-history tools. search_workspace requires an action token in run metadata from Slack’s assistant integration. A user token alone does not enable it.

slack_search_media.py
"""
Slack Search & Media Tools
==========================

Demonstrates SlackContextProvider with:

- **search_messages** — Search using the legacy API (works with user
  tokens `xoxp-`). Both bot and assisted read agents now have this
  enabled alongside `search_workspace`.
- **enable_media_tools** — Opt-in file handling:
  - `download_file` on read agents (fetch images/files for multimodal)
  - `upload_file` on write agent (post generated content)

This example uses Gemini as the sub-agent model for Slack operations,
while the outer agent uses a different model. This pattern is useful
when you want faster/cheaper tool calls but stronger reasoning on top.

Requires:
    GOOGLE_API_KEY
    SLACK_BOT_TOKEN  (xoxb-) — uses channel history, no search

Optional:
    SLACK_USER_TOKEN (xoxp-) — enables search_messages API

With a bot token, search_messages returns `not_allowed_token_type` and
the agent falls back to get_channel_history. With a user token, both
search methods are available.

Usage:
    python cookbook/12_context/06_slack_search_media.py
"""

from __future__ import annotations

import asyncio

from agno.agent import Agent
from agno.context.slack import SlackContextProvider
from agno.models.google import Gemini

slack = SlackContextProvider(
    model=Gemini(id="gemini-3.5-flash"),
    enable_media_tools=True,
)

agent = Agent(
    model=Gemini(id="gemini-3.5-flash"),
    tools=slack.get_tools(),
    instructions=slack.instructions(),
    markdown=True,
)


async def main() -> None:
    print(f"slack.status() = {slack.status()}\n")

    search_prompt = "Search Slack for recent discussions about 'deployment'. Summarize the top 3 results."
    print(f"> {search_prompt}\n")
    await agent.aprint_response(search_prompt)


if __name__ == "__main__":
    asyncio.run(main())

Run the Example

Set up your virtual environment

uv venv --python 3.12
source .venv/bin/activate

Install dependencies

uv pip install -U "agno[slack]" google-genai

Export environment variables

export GOOGLE_API_KEY="your_google_api_key_here"
export SLACK_BOT_TOKEN="your_slack_bot_token_here"

Configure Slack access

Install your Slack app in a test workspace. For public-channel history, grant the bot channels:read, channels:history, and users:read, then invite it to a test channel. To run the supplied search prompt, also grant your app the user-token scope search:read and export that user token:

export SLACK_USER_TOKEN="xoxp-your-user-token"

For a bot-only run, replace search_prompt with a request to summarize recent messages in the test channel the bot has joined. Media operations need their corresponding Slack file scopes when you add a media prompt.

Run the example

Save the code above as slack_search_media.py, then run:

python slack_search_media.py

Full source: cookbook/12_context/06_slack_search_media.py