Skip to main content

CrewAI Integration

Use AgentDrop as a custom tool in CrewAI to let your agents send and receive files as part of multi-agent workflows.

Install Dependencies

pip install crewai requests

Create AgentDrop Tools

Define two CrewAI tools: one for sending files, one for receiving.
import os
import requests
from crewai.tools import tool

AGENTDROP_URL = "https://agentdrop-production.up.railway.app"
AGENTDROP_KEY = os.environ["AGENTDROP_API_KEY"]
HEADERS = {"Authorization": f"Bearer {AGENTDROP_KEY}"}


@tool("Send File via AgentDrop")
def send_file(filepath: str, recipient: str) -> str:
    """Upload a file to AgentDrop for another agent to download.
    Returns the transfer ID."""
    with open(filepath, "rb") as f:
        response = requests.post(
            f"{AGENTDROP_URL}/v1/transfers",
            headers=HEADERS,
            data={
                "sender": "crewai-agent",
                "recipient": recipient,
                "expires_in": "24h",
            },
            files={"files": f},
        )
    response.raise_for_status()
    transfer = response.json()
    return f"Transfer created: {transfer['id']} (expires {transfer['expires_at']})"


@tool("Receive File via AgentDrop")
def receive_file(transfer_id: str, save_as: str) -> str:
    """Download a file from AgentDrop using a transfer ID.
    Saves the file locally and returns the path."""
    response = requests.get(
        f"{AGENTDROP_URL}/v1/transfers/{transfer_id}/download",
        headers=HEADERS,
    )
    response.raise_for_status()

    with open(save_as, "wb") as f:
        f.write(response.content)

    remaining = response.headers.get("X-Downloads-Remaining", "unknown")
    return f"File saved to {save_as} ({remaining} downloads remaining)"

Define Your Agents

from crewai import Agent

research_agent = Agent(
    role="Research Analyst",
    goal="Gather data and produce research reports",
    backstory="You are a thorough research analyst who produces detailed reports.",
    tools=[send_file],
    verbose=True,
)

summary_agent = Agent(
    role="Executive Summary Writer",
    goal="Take research reports and produce executive summaries",
    backstory="You distill complex reports into clear executive summaries.",
    tools=[receive_file],
    verbose=True,
)

Build the Crew

from crewai import Crew, Task

# Research agent produces a report and uploads it
research_task = Task(
    description=(
        "Research Q1 2026 market trends for AI infrastructure. "
        "Save your findings to 'q1-report.md', then send the file "
        "via AgentDrop to 'summary-agent'."
    ),
    expected_output="Transfer ID of the uploaded report",
    agent=research_agent,
)

# Summary agent downloads the report and summarizes it
summary_task = Task(
    description=(
        "Download the research report using the transfer ID from the "
        "previous task. Read it and produce a 1-page executive summary. "
        "Save the summary to 'exec-summary.md'."
    ),
    expected_output="Path to the executive summary file",
    agent=summary_agent,
)

crew = Crew(
    agents=[research_agent, summary_agent],
    tasks=[research_task, summary_task],
    verbose=True,
)

result = crew.kickoff()
print(result)

What Happens

  1. The research agent writes its report to disk
  2. It calls send_file to upload the report to AgentDrop
  3. AgentDrop returns a transfer ID
  4. The summary agent receives the transfer ID from the task context
  5. It calls receive_file to download the report
  6. It reads the file and produces the summary
No shared filesystem needed. The agents communicate through AgentDrop’s locker model.

Adding a Status Check Tool

For workflows where timing matters, add a tool to check if a transfer is ready:
@tool("Check Transfer Status")
def check_transfer(transfer_id: str) -> str:
    """Check the status of an AgentDrop transfer."""
    response = requests.get(
        f"{AGENTDROP_URL}/v1/transfers/{transfer_id}",
        headers=HEADERS,
    )
    response.raise_for_status()
    transfer = response.json()
    return (
        f"Status: {transfer['status']}, "
        f"Downloads: {transfer['download_count']}/{transfer['max_downloads']}, "
        f"Expires: {transfer['expires_at']}"
    )

Tips

  • Set meaningful sender/recipient names. They show up in your transfer list and make debugging easier.
  • Use encrypted=True for sensitive data. Add "encrypted": "true" to the data dict in send_file.
  • Set short expiry for ephemeral workflows. expires_in="1h" keeps your storage clean.
  • One transfer per logical unit. Send related files together in one transfer, not separately.