> ## Documentation Index
> Fetch the complete documentation index at: https://trytilde.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# CrewAI

> Run a CrewAI agent on Tilde with the trytilde-crewai adapter.

The CrewAI adapter runs a CrewAI `Agent`, configured with `@CrewBase` YAML, on Tilde. It works with CrewAI 1.15 and later.

<Card title="Example agent" icon="github" href="https://github.com/trytilde/tilde/tree/main/sdk/py/examples/example-agent-crewai" horizontal>
  A complete CrewAI agent with YAML configuration, bundled tools, and skills, in the Tilde open-source repository.
</Card>

## Install

```bash theme={"system"}
pip install trytilde trytilde-crewai crewai
```

CrewAI needs a different major version of the `openai` package from the OpenAI Agents SDK. Install it in its own environment.

## How it works

CrewAI's `LLM` does not take an HTTP client, so the adapter provides an interceptor that routes each request through Tilde's inference gateway. Importing the adapter also registers a hook that passes new user input to the model before each call.

Build the crew for each invocation, with the Tilde tools and skills directory for that invocation.

```python agent.py theme={"system"}
from pathlib import Path

import tilde
from crewai import LLM, Agent
from crewai.project import CrewBase, agent
from tilde_crewai import convert_to_crewai_messages, inference_interceptor, with_tilde_tools

from bundled_tools import TOOLS

INFERENCE = tilde.inference("default")
llm = LLM(
    model="openai/gpt-4o-mini",
    base_url=INFERENCE.base_url,
    api_key=INFERENCE.api_key,
    interceptor=inference_interceptor(INFERENCE),
)

SKILLS = tilde.define_skills("skills")

@CrewBase
class SupportCrew:
    agents_config = "config/agents.yaml"

    def __init__(self, tools, registry_skills: Path) -> None:
        self.tools = tools
        self.registry_skills = registry_skills

    @agent
    def responder(self) -> Agent:
        return Agent(
            config=self.agents_config["responder"],
            llm=llm,
            tools=self.tools,
            skills=[SKILLS.path, self.registry_skills],
        )

async def respond(ctx: tilde.AgentContext) -> None:
    history = await ctx.message.history()
    messages = await convert_to_crewai_messages(history.items, context=ctx)
    tools = await with_tilde_tools(ctx, TOOLS.tools, options=TOOLS.options)
    skills = Path(await ctx.skills.directory())
    await SupportCrew(tools, skills).responder().kickoff_async(messages)
```

## Feature compatibility

| Feature | Support | Notes |
| - | - | - |
| Inference gateway | Yes | Through `inference_interceptor`. |
| Framework trace spans | Partial | Tilde records its own spans. Set `CREWAI_DISABLE_TELEMETRY=true` to stop CrewAI sending its own telemetry. |
| Tilde and channel tools | Partial | See below. |
| Bundled tools | Partial | Write CrewAI `BaseTool` tools. See below. |
| Prompt versioning | Partial | Registers the `role`, `goal`, and `backstory` of each agent, and the `description` and `expected_output` of each task, from `@CrewBase` YAML. |
| Native skills | Yes | YAML `skills:` paths ship at deploy. Skills you pass in code need `define_skills`. |
| New input during a run | Yes | |

## Limitations

* **Strict tool schemas.** CrewAI makes every tool field required, including optional ones.
* **Tool names.** CrewAI converts tool names to lowercase snake case.
* **Tool call IDs.** CrewAI does not expose the model's tool call ID. Tilde records each call with a generated ID instead.
* **Agents built in code.** Prompts of agents built in Python, rather than YAML, are not versioned. Discovery warns.
* **Attachments.** Attachments on the latest user message are dropped.
* **Memory.** Leave CrewAI `memory` off. Tilde supplies the history.
