# Slack Search & Media Tools (/examples/context/slack-search-media)



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.

```python title="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 [#run-the-example]

<Steps>
    <Step title="Set up your virtual environment">
      <CodeBlockTabs defaultValue="Mac">
        <CodeBlockTabsList>
          <CodeBlockTabsTrigger value="Mac">
            Mac
          </CodeBlockTabsTrigger>

          <CodeBlockTabsTrigger value="Windows">
            Windows
          </CodeBlockTabsTrigger>
        </CodeBlockTabsList>

        <CodeBlockTab value="Mac">
          ```bash
          uv venv --python 3.12
          source .venv/bin/activate
          ```
        </CodeBlockTab>

        <CodeBlockTab value="Windows">
          ```bash
          uv venv --python 3.12
          .venv\Scripts\activate
          ```
        </CodeBlockTab>
      </CodeBlockTabs>
    </Step>

  <Step title="Install dependencies">
    ```bash
    uv pip install -U "agno[slack]" google-genai
    ```
  </Step>

  <Step title="Export environment variables">
    <CodeBlockTabs defaultValue="Mac/Linux">
      <CodeBlockTabsList>
        <CodeBlockTabsTrigger value="Mac/Linux">
          Mac/Linux
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="Windows">
          Windows
        </CodeBlockTabsTrigger>
      </CodeBlockTabsList>

      <CodeBlockTab value="Mac/Linux">
        ```bash
        export GOOGLE_API_KEY="your_google_api_key_here"
        export SLACK_BOT_TOKEN="your_slack_bot_token_here"
        ```
      </CodeBlockTab>

      <CodeBlockTab value="Windows">
        ```bash
        $Env:GOOGLE_API_KEY="your_google_api_key_here"
        $Env:SLACK_BOT_TOKEN="your_slack_bot_token_here"
        ```
      </CodeBlockTab>
    </CodeBlockTabs>
  </Step>

  <Step title="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:

    <CodeBlockTabs defaultValue="Mac/Linux">
      <CodeBlockTabsList>
        <CodeBlockTabsTrigger value="Mac/Linux">
          Mac/Linux
        </CodeBlockTabsTrigger>

        <CodeBlockTabsTrigger value="Windows">
          Windows
        </CodeBlockTabsTrigger>
      </CodeBlockTabsList>

      <CodeBlockTab value="Mac/Linux">
        ```bash
        export SLACK_USER_TOKEN="xoxp-your-user-token"
        ```
      </CodeBlockTab>

      <CodeBlockTab value="Windows">
        ```bash
        $Env:SLACK_USER_TOKEN="xoxp-your-user-token"
        ```
      </CodeBlockTab>
    </CodeBlockTabs>

    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.
  </Step>

  <Step title="Run the example">
    Save the code above as `slack_search_media.py`, then run:

    ```bash
    python slack_search_media.py
    ```
  </Step>
</Steps>

Full source: [cookbook/12\_context/06\_slack\_search\_media.py](https://github.com/agno-agi/agno/blob/8f36eaf2d18e91afa7b327eec66a3cd3685dcb87/cookbook/12_context/06_slack_search_media.py)
