# Agents
Source: https://docs.crewai.com/en/concepts/agents

Detailed guide on creating and managing agents within the CrewAI framework.

## Overview of an Agent

In the CrewAI framework, an `Agent` is an autonomous unit that can:

* Perform specific tasks
* Make decisions based on its role and goal
* Use tools to accomplish objectives
* Communicate and collaborate with other agents
* Maintain memory of interactions
* Delegate tasks when allowed

<Tip>
  Think of an agent as a specialized team member with specific skills,
  expertise, and responsibilities. For example, a `Researcher` agent might excel
  at gathering and analyzing information, while a `Writer` agent might be better
  at creating content.
</Tip>

<Note type="info" title="Enterprise Enhancement: Visual Agent Builder">
  CrewAI AMP includes a Visual Agent Builder that simplifies agent creation and configuration without writing code. Design your agents visually and test them in real-time.

  <img alt="Visual Agent Builder Screenshot" />

  The Visual Agent Builder enables:

  * Intuitive agent configuration with form-based interfaces
  * Real-time testing and validation
  * Template library with pre-configured agent types
  * Easy customization of agent attributes and behaviors
</Note>

## Agent Attributes

| Attribute                               | Parameter                | Type                                  | Description                                                                                              |
| :-------------------------------------- | :----------------------- | :------------------------------------ | :------------------------------------------------------------------------------------------------------- |
| **Role**                                | `role`                   | `str`                                 | Defines the agent's function and expertise within the crew.                                              |
| **Goal**                                | `goal`                   | `str`                                 | The individual objective that guides the agent's decision-making.                                        |
| **Backstory**                           | `backstory`              | `str`                                 | Provides context and personality to the agent, enriching interactions.                                   |
| **LLM** *(optional)*                    | `llm`                    | `Union[str, LLM, Any]`                | Language model that powers the agent. Defaults to the model specified in `OPENAI_MODEL_NAME` or "gpt-4". |
| **Tools** *(optional)*                  | `tools`                  | `List[BaseTool]`                      | Capabilities or functions available to the agent. Defaults to an empty list.                             |
| **Function Calling LLM** *(optional)*   | `function_calling_llm`   | `Optional[Any]`                       | Language model for tool calling, overrides crew's LLM if specified.                                      |
| **Max Iterations** *(optional)*         | `max_iter`               | `int`                                 | Maximum iterations before the agent must provide its best answer. Default is 20.                         |
| **Max RPM** *(optional)*                | `max_rpm`                | `Optional[int]`                       | Maximum requests per minute to avoid rate limits.                                                        |
| **Max Execution Time** *(optional)*     | `max_execution_time`     | `Optional[int]`                       | Maximum time (in seconds) for task execution.                                                            |
| **Verbose** *(optional)*                | `verbose`                | `bool`                                | Enable detailed execution logs for debugging. Default is False.                                          |
| **Allow Delegation** *(optional)*       | `allow_delegation`       | `bool`                                | Allow the agent to delegate tasks to other agents. Default is False.                                     |
| **Step Callback** *(optional)*          | `step_callback`          | `Optional[Any]`                       | Function called after each agent step, overrides crew callback.                                          |
| **Cache** *(optional)*                  | `cache`                  | `bool`                                | Enable caching for tool usage. Default is True.                                                          |
| **System Template** *(optional)*        | `system_template`        | `Optional[str]`                       | Custom system prompt template for the agent.                                                             |
| **Prompt Template** *(optional)*        | `prompt_template`        | `Optional[str]`                       | Custom prompt template for the agent.                                                                    |
| **Response Template** *(optional)*      | `response_template`      | `Optional[str]`                       | Custom response template for the agent.                                                                  |
| **Allow Code Execution** *(optional)*   | `allow_code_execution`   | `Optional[bool]`                      | Enable code execution for the agent. Default is False.                                                   |
| **Max Retry Limit** *(optional)*        | `max_retry_limit`        | `int`                                 | Maximum number of retries when an error occurs. Default is 2.                                            |
| **Respect Context Window** *(optional)* | `respect_context_window` | `bool`                                | Keep messages under context window size by summarizing. Default is True.                                 |
| **Code Execution Mode** *(optional)*    | `code_execution_mode`    | `Literal["safe", "unsafe"]`           | Mode for code execution: 'safe' (using Docker) or 'unsafe' (direct). Default is 'safe'.                  |
| **Multimodal** *(optional)*             | `multimodal`             | `bool`                                | Whether the agent supports multimodal capabilities. Default is False.                                    |
| **Inject Date** *(optional)*            | `inject_date`            | `bool`                                | Whether to automatically inject the current date into tasks. Default is False.                           |
| **Date Format** *(optional)*            | `date_format`            | `str`                                 | Format string for date when inject\_date is enabled. Default is "%Y-%m-%d" (ISO format).                 |
| **Reasoning** *(optional)*              | `reasoning`              | `bool`                                | Whether the agent should reflect and create a plan before executing a task. Default is False.            |
| **Max Reasoning Attempts** *(optional)* | `max_reasoning_attempts` | `Optional[int]`                       | Maximum number of reasoning attempts before executing the task. If None, will try until ready.           |
| **Embedder** *(optional)*               | `embedder`               | `Optional[Dict[str, Any]]`            | Configuration for the embedder used by the agent.                                                        |
| **Knowledge Sources** *(optional)*      | `knowledge_sources`      | `Optional[List[BaseKnowledgeSource]]` | Knowledge sources available to the agent.                                                                |
| **Use System Prompt** *(optional)*      | `use_system_prompt`      | `Optional[bool]`                      | Whether to use system prompt (for o1 model support). Default is True.                                    |

## Creating Agents

There are two ways to create agents in CrewAI: using **YAML configuration (recommended)** or defining them **directly in code**.

### YAML Configuration (Recommended)

Using YAML configuration provides a cleaner, more maintainable way to define agents. We strongly recommend using this approach in your CrewAI projects.

After creating your CrewAI project as outlined in the [Installation](/en/installation) section, navigate to the `src/latest_ai_development/config/agents.yaml` file and modify the template to match your requirements.

<Note>
  Variables in your YAML files (like `{topic}`) will be replaced with values from your inputs when running the crew:

  ```python Code theme={null}
  crew.kickoff(inputs={'topic': 'AI Agents'})
  ```
</Note>

Here's an example of how to configure agents using YAML:

```yaml agents.yaml theme={null}
# src/latest_ai_development/config/agents.yaml
researcher:
  role: >
    {topic} Senior Data Researcher
  goal: >
    Uncover cutting-edge developments in {topic}
  backstory: >
    You're a seasoned researcher with a knack for uncovering the latest
    developments in {topic}. Known for your ability to find the most relevant
    information and present it in a clear and concise manner.

reporting_analyst:
  role: >
    {topic} Reporting Analyst
  goal: >
    Create detailed reports based on {topic} data analysis and research findings
  backstory: >
    You're a meticulous analyst with a keen eye for detail. You're known for
    your ability to turn complex data into clear and concise reports, making
    it easy for others to understand and act on the information you provide.
```

To use this YAML configuration in your code, create a crew class that inherits from `CrewBase`:

```python Code theme={null}
# src/latest_ai_development/crew.py
from crewai import Agent, Crew, Process
from crewai.project import CrewBase, agent, crew
from crewai_tools import SerperDevTool

@CrewBase
class LatestAiDevelopmentCrew():
  """LatestAiDevelopment crew"""

  agents_config = "config/agents.yaml"

  @agent
  def researcher(self) -> Agent:
    return Agent(
      config=self.agents_config['researcher'], # type: ignore[index]
      verbose=True,
      tools=[SerperDevTool()]
    )

  @agent
  def reporting_analyst(self) -> Agent:
    return Agent(
      config=self.agents_config['reporting_analyst'], # type: ignore[index]
      verbose=True
    )
```

<Note>
  The names you use in your YAML files (`agents.yaml`) should match the method
  names in your Python code.
</Note>

### Direct Code Definition

You can create agents directly in code by instantiating the `Agent` class. Here's a comprehensive example showing all available parameters:

```python Code theme={null}
from crewai import Agent
from crewai_tools import SerperDevTool

# Create an agent with all available parameters
agent = Agent(
    role="Senior Data Scientist",
    goal="Analyze and interpret complex datasets to provide actionable insights",
    backstory="With over 10 years of experience in data science and machine learning, "
              "you excel at finding patterns in complex datasets.",
    llm="gpt-4",  # Default: OPENAI_MODEL_NAME or "gpt-4"
    function_calling_llm=None,  # Optional: Separate LLM for tool calling
    verbose=False,  # Default: False
    allow_delegation=False,  # Default: False
    max_iter=20,  # Default: 20 iterations
    max_rpm=None,  # Optional: Rate limit for API calls
    max_execution_time=None,  # Optional: Maximum execution time in seconds
    max_retry_limit=2,  # Default: 2 retries on error
    allow_code_execution=False,  # Default: False
    code_execution_mode="safe",  # Default: "safe" (options: "safe", "unsafe")
    respect_context_window=True,  # Default: True
    use_system_prompt=True,  # Default: True
    multimodal=False,  # Default: False
    inject_date=False,  # Default: False
    date_format="%Y-%m-%d",  # Default: ISO format
    reasoning=False,  # Default: False
    max_reasoning_attempts=None,  # Default: None
    tools=[SerperDevTool()],  # Optional: List of tools
    knowledge_sources=None,  # Optional: List of knowledge sources
    embedder=None,  # Optional: Custom embedder configuration
    system_template=None,  # Optional: Custom system prompt template
    prompt_template=None,  # Optional: Custom prompt template
    response_template=None,  # Optional: Custom response template
    step_callback=None,  # Optional: Callback function for monitoring
)
```

Let's break down some key parameter combinations for common use cases:

#### Basic Research Agent

```python Code theme={null}
research_agent = Agent(
    role="Research Analyst",
    goal="Find and summarize information about specific topics",
    backstory="You are an experienced researcher with attention to detail",
    tools=[SerperDevTool()],
    verbose=True  # Enable logging for debugging
)
```

#### Code Development Agent

```python Code theme={null}
dev_agent = Agent(
    role="Senior Python Developer",
    goal="Write and debug Python code",
    backstory="Expert Python developer with 10 years of experience",
    allow_code_execution=True,
    code_execution_mode="safe",  # Uses Docker for safety
    max_execution_time=300,  # 5-minute timeout
    max_retry_limit=3  # More retries for complex code tasks
)
```

#### Long-Running Analysis Agent

```python Code theme={null}
analysis_agent = Agent(
    role="Data Analyst",
    goal="Perform deep analysis of large datasets",
    backstory="Specialized in big data analysis and pattern recognition",
    memory=True,
    respect_context_window=True,
    max_rpm=10,  # Limit API calls
    function_calling_llm="gpt-4o-mini"  # Cheaper model for tool calls
)
```

#### Custom Template Agent

```python Code theme={null}
custom_agent = Agent(
    role="Customer Service Representative",
    goal="Assist customers with their inquiries",
    backstory="Experienced in customer support with a focus on satisfaction",
    system_template="""<|start_header_id|>system<|end_header_id|>
                        {{ .System }}<|eot_id|>""",
    prompt_template="""<|start_header_id|>user<|end_header_id|>
                        {{ .Prompt }}<|eot_id|>""",
    response_template="""<|start_header_id|>assistant<|end_header_id|>
                        {{ .Response }}<|eot_id|>""",
)
```

#### Date-Aware Agent with Reasoning

```python Code theme={null}
strategic_agent = Agent(
    role="Market Analyst",
    goal="Track market movements with precise date references and strategic planning",
    backstory="Expert in time-sensitive financial analysis and strategic reporting",
    inject_date=True,  # Automatically inject current date into tasks
    date_format="%B %d, %Y",  # Format as "May 21, 2025"
    reasoning=True,  # Enable strategic planning
    max_reasoning_attempts=2,  # Limit planning iterations
    verbose=True
)
```

#### Reasoning Agent

```python Code theme={null}
reasoning_agent = Agent(
    role="Strategic Planner",
    goal="Analyze complex problems and create detailed execution plans",
    backstory="Expert strategic planner who methodically breaks down complex challenges",
    reasoning=True,  # Enable reasoning and planning
    max_reasoning_attempts=3,  # Limit reasoning attempts
    max_iter=30,  # Allow more iterations for complex planning
    verbose=True
)
```

#### Multimodal Agent

```python Code theme={null}
multimodal_agent = Agent(
    role="Visual Content Analyst",
    goal="Analyze and process both text and visual content",
    backstory="Specialized in multimodal analysis combining text and image understanding",
    multimodal=True,  # Enable multimodal capabilities
    verbose=True
)
```

### Parameter Details

#### Critical Parameters

* `role`, `goal`, and `backstory` are required and shape the agent's behavior
* `llm` determines the language model used (default: OpenAI's GPT-4)

#### Memory and Context

* `memory`: Enable to maintain conversation history
* `respect_context_window`: Prevents token limit issues
* `knowledge_sources`: Add domain-specific knowledge bases

#### Execution Control

* `max_iter`: Maximum attempts before giving best answer
* `max_execution_time`: Timeout in seconds
* `max_rpm`: Rate limiting for API calls
* `max_retry_limit`: Retries on error

#### Code Execution

* `allow_code_execution`: Must be True to run code
* `code_execution_mode`:
  * `"safe"`: Uses Docker (recommended for production)
  * `"unsafe"`: Direct execution (use only in trusted environments)

<Note>
  This runs a default Docker image. If you want to configure the docker image,
  the checkout the Code Interpreter Tool in the tools section. Add the code
  interpreter tool as a tool in the agent as a tool parameter.
</Note>

#### Advanced Features

* `multimodal`: Enable multimodal capabilities for processing text and visual content
* `reasoning`: Enable agent to reflect and create plans before executing tasks
* `inject_date`: Automatically inject current date into task descriptions

#### Templates

* `system_template`: Defines agent's core behavior
* `prompt_template`: Structures input format
* `response_template`: Formats agent responses

<Note>
  When using custom templates, ensure that both `system_template` and
  `prompt_template` are defined. The `response_template` is optional but
  recommended for consistent output formatting.
</Note>

<Note>
  When using custom templates, you can use variables like `{role}`, `{goal}`,
  and `{backstory}` in your templates. These will be automatically populated
  during execution.
</Note>

## Agent Tools

Agents can be equipped with various tools to enhance their capabilities. CrewAI supports tools from:

* [CrewAI Toolkit](https://github.com/joaomdmoura/crewai-tools)
* [LangChain Tools](https://python.langchain.com/docs/integrations/tools)

Here's how to add tools to an agent:

```python Code theme={null}
from crewai import Agent
from crewai_tools import SerperDevTool, WikipediaTools

# Create tools
search_tool = SerperDevTool()
wiki_tool = WikipediaTools()

# Add tools to agent
researcher = Agent(
    role="AI Technology Researcher",
    goal="Research the latest AI developments",
    tools=[search_tool, wiki_tool],
    verbose=True
)
```

## Agent Memory and Context

Agents can maintain memory of their interactions and use context from previous tasks. This is particularly useful for complex workflows where information needs to be retained across multiple tasks.

```python Code theme={null}
from crewai import Agent

analyst = Agent(
    role="Data Analyst",
    goal="Analyze and remember complex data patterns",
    memory=True,  # Enable memory
    verbose=True
)
```

<Note>
  When `memory` is enabled, the agent will maintain context across multiple
  interactions, improving its ability to handle complex, multi-step tasks.
</Note>

## Context Window Management

CrewAI includes sophisticated automatic context window management to handle situations where conversations exceed the language model's token limits. This powerful feature is controlled by the `respect_context_window` parameter.

### How Context Window Management Works

When an agent's conversation history grows too large for the LLM's context window, CrewAI automatically detects this situation and can either:

1. **Automatically summarize content** (when `respect_context_window=True`)
2. **Stop execution with an error** (when `respect_context_window=False`)

### Automatic Context Handling (`respect_context_window=True`)

This is the **default and recommended setting** for most use cases. When enabled, CrewAI will:

```python Code theme={null}
# Agent with automatic context management (default)
smart_agent = Agent(
    role="Research Analyst",
    goal="Analyze large documents and datasets",
    backstory="Expert at processing extensive information",
    respect_context_window=True,  # 🔑 Default: auto-handle context limits
    verbose=True
)
```

**What happens when context limits are exceeded:**

* ⚠️ **Warning message**: `"Context length exceeded. Summarizing content to fit the model context window."`
* 🔄 **Automatic summarization**: CrewAI intelligently summarizes the conversation history
* ✅ **Continued execution**: Task execution continues seamlessly with the summarized context
* 📝 **Preserved information**: Key information is retained while reducing token count

### Strict Context Limits (`respect_context_window=False`)

When you need precise control and prefer execution to stop rather than lose any information:

```python Code theme={null}
# Agent with strict context limits
strict_agent = Agent(
    role="Legal Document Reviewer",
    goal="Provide precise legal analysis without information loss",
    backstory="Legal expert requiring complete context for accurate analysis",
    respect_context_window=False,  # ❌ Stop execution on context limit
    verbose=True
)
```

**What happens when context limits are exceeded:**

* ❌ **Error message**: `"Context length exceeded. Consider using smaller text or RAG tools from crewai_tools."`
* 🛑 **Execution stops**: Task execution halts immediately
* 🔧 **Manual intervention required**: You need to modify your approach

### Choosing the Right Setting

#### Use `respect_context_window=True` (Default) when:

* **Processing large documents** that might exceed context limits
* **Long-running conversations** where some summarization is acceptable
* **Research tasks** where general context is more important than exact details
* **Prototyping and development** where you want robust execution

```python Code theme={null}
# Perfect for document processing
document_processor = Agent(
    role="Document Analyst",
    goal="Extract insights from large research papers",
    backstory="Expert at analyzing extensive documentation",
    respect_context_window=True,  # Handle large documents gracefully
    max_iter=50,  # Allow more iterations for complex analysis
    verbose=True
)
```

#### Use `respect_context_window=False` when:

* **Precision is critical** and information loss is unacceptable
* **Legal or medical tasks** requiring complete context
* **Code review** where missing details could introduce bugs
* **Financial analysis** where accuracy is paramount

```python Code theme={null}
# Perfect for precision tasks
precision_agent = Agent(
    role="Code Security Auditor",
    goal="Identify security vulnerabilities in code",
    backstory="Security expert requiring complete code context",
    respect_context_window=False,  # Prefer failure over incomplete analysis
    max_retry_limit=1,  # Fail fast on context issues
    verbose=True
)
```

### Alternative Approaches for Large Data

When dealing with very large datasets, consider these strategies:

#### 1. Use RAG Tools

```python Code theme={null}
from crewai_tools import RagTool

# Create RAG tool for large document processing
rag_tool = RagTool()

rag_agent = Agent(
    role="Research Assistant",
    goal="Query large knowledge bases efficiently",
    backstory="Expert at using RAG tools for information retrieval",
    tools=[rag_tool],  # Use RAG instead of large context windows
    respect_context_window=True,
    verbose=True
)
```

#### 2. Use Knowledge Sources

```python Code theme={null}
# Use knowledge sources instead of large prompts
knowledge_agent = Agent(
    role="Knowledge Expert",
    goal="Answer questions using curated knowledge",
    backstory="Expert at leveraging structured knowledge sources",
    knowledge_sources=[your_knowledge_sources],  # Pre-processed knowledge
    respect_context_window=True,
    verbose=True
)
```

### Context Window Best Practices

1. **Monitor Context Usage**: Enable `verbose=True` to see context management in action
2. **Design for Efficiency**: Structure tasks to minimize context accumulation
3. **Use Appropriate Models**: Choose LLMs with context windows suitable for your tasks
4. **Test Both Settings**: Try both `True` and `False` to see which works better for your use case
5. **Combine with RAG**: Use RAG tools for very large datasets instead of relying solely on context windows

### Troubleshooting Context Issues

**If you're getting context limit errors:**

```python Code theme={null}
# Quick fix: Enable automatic handling
agent.respect_context_window = True

# Better solution: Use RAG tools for large data
from crewai_tools import RagTool
agent.tools = [RagTool()]

# Alternative: Break tasks into smaller pieces
# Or use knowledge sources instead of large prompts
```

**If automatic summarization loses important information:**

```python Code theme={null}
# Disable auto-summarization and use RAG instead
agent = Agent(
    role="Detailed Analyst",
    goal="Maintain complete information accuracy",
    backstory="Expert requiring full context",
    respect_context_window=False,  # No summarization
    tools=[RagTool()],  # Use RAG for large data
    verbose=True
)
```

<Note>
  The context window management feature works automatically in the background.
  You don't need to call any special functions - just set
  `respect_context_window` to your preferred behavior and CrewAI handles the
  rest!
</Note>

## Direct Agent Interaction with `kickoff()`

Agents can be used directly without going through a task or crew workflow using the `kickoff()` method. This provides a simpler way to interact with an agent when you don't need the full crew orchestration capabilities.

### How `kickoff()` Works

The `kickoff()` method allows you to send messages directly to an agent and get a response, similar to how you would interact with an LLM but with all the agent's capabilities (tools, reasoning, etc.).

```python Code theme={null}
from crewai import Agent
from crewai_tools import SerperDevTool

# Create an agent
researcher = Agent(
    role="AI Technology Researcher",
    goal="Research the latest AI developments",
    tools=[SerperDevTool()],
    verbose=True
)

# Use kickoff() to interact directly with the agent
result = researcher.kickoff("What are the latest developments in language models?")

# Access the raw response
print(result.raw)
```

### Parameters and Return Values

| Parameter         | Type                               | Description                                                               |
| :---------------- | :--------------------------------- | :------------------------------------------------------------------------ |
| `messages`        | `Union[str, List[Dict[str, str]]]` | Either a string query or a list of message dictionaries with role/content |
| `response_format` | `Optional[Type[Any]]`              | Optional Pydantic model for structured output                             |

The method returns a `LiteAgentOutput` object with the following properties:

* `raw`: String containing the raw output text
* `pydantic`: Parsed Pydantic model (if a `response_format` was provided)
* `agent_role`: Role of the agent that produced the output
* `usage_metrics`: Token usage metrics for the execution

### Structured Output

You can get structured output by providing a Pydantic model as the `response_format`:

```python Code theme={null}
from pydantic import BaseModel
from typing import List

class ResearchFindings(BaseModel):
    main_points: List[str]
    key_technologies: List[str]
    future_predictions: str

# Get structured output
result = researcher.kickoff(
    "Summarize the latest developments in AI for 2025",
    response_format=ResearchFindings
)

# Access structured data
print(result.pydantic.main_points)
print(result.pydantic.future_predictions)
```

### Multiple Messages

You can also provide a conversation history as a list of message dictionaries:

```python Code theme={null}
messages = [
    {"role": "user", "content": "I need information about large language models"},
    {"role": "assistant", "content": "I'd be happy to help with that! What specifically would you like to know?"},
    {"role": "user", "content": "What are the latest developments in 2025?"}
]

result = researcher.kickoff(messages)
```

### Async Support

An asynchronous version is available via `kickoff_async()` with the same parameters:

```python Code theme={null}
import asyncio

async def main():
    result = await researcher.kickoff_async("What are the latest developments in AI?")
    print(result.raw)

asyncio.run(main())
```

<Note>
  The `kickoff()` method uses a `LiteAgent` internally, which provides a simpler
  execution flow while preserving all of the agent's configuration (role, goal,
  backstory, tools, etc.).
</Note>

## Important Considerations and Best Practices

### Security and Code Execution

* When using `allow_code_execution`, be cautious with user input and always validate it
* Use `code_execution_mode: "safe"` (Docker) in production environments
* Consider setting appropriate `max_execution_time` limits to prevent infinite loops

### Performance Optimization

* Use `respect_context_window: true` to prevent token limit issues
* Set appropriate `max_rpm` to avoid rate limiting
* Enable `cache: true` to improve performance for repetitive tasks
* Adjust `max_iter` and `max_retry_limit` based on task complexity

### Memory and Context Management

* Leverage `knowledge_sources` for domain-specific information
* Configure `embedder` when using custom embedding models
* Use custom templates (`system_template`, `prompt_template`, `response_template`) for fine-grained control over agent behavior

### Advanced Features

* Enable `reasoning: true` for agents that need to plan and reflect before executing complex tasks
* Set appropriate `max_reasoning_attempts` to control planning iterations (None for unlimited attempts)
* Use `inject_date: true` to provide agents with current date awareness for time-sensitive tasks
* Customize the date format with `date_format` using standard Python datetime format codes
* Enable `multimodal: true` for agents that need to process both text and visual content

### Agent Collaboration

* Enable `allow_delegation: true` when agents need to work together
* Use `step_callback` to monitor and log agent interactions
* Consider using different LLMs for different purposes:
  * Main `llm` for complex reasoning
  * `function_calling_llm` for efficient tool usage

### Date Awareness and Reasoning

* Use `inject_date: true` to provide agents with current date awareness for time-sensitive tasks
* Customize the date format with `date_format` using standard Python datetime format codes
* Valid format codes include: %Y (year), %m (month), %d (day), %B (full month name), etc.
* Invalid date formats will be logged as warnings and will not modify the task description
* Enable `reasoning: true` for complex tasks that benefit from upfront planning and reflection

### Model Compatibility

* Set `use_system_prompt: false` for older models that don't support system messages
* Ensure your chosen `llm` supports the features you need (like function calling)

## Troubleshooting Common Issues

1. **Rate Limiting**: If you're hitting API rate limits:

   * Implement appropriate `max_rpm`
   * Use caching for repetitive operations
   * Consider batching requests

2. **Context Window Errors**: If you're exceeding context limits:

   * Enable `respect_context_window`
   * Use more efficient prompts
   * Clear agent memory periodically

3. **Code Execution Issues**: If code execution fails:

   * Verify Docker is installed for safe mode
   * Check execution permissions
   * Review code sandbox settings

4. **Memory Issues**: If agent responses seem inconsistent:
   * Check knowledge source configuration
   * Review conversation history management

Remember that agents are most effective when configured according to their specific use case. Take time to understand your requirements and adjust these parameters accordingly.


# CLI
Source: https://docs.crewai.com/en/concepts/cli

Learn how to use the CrewAI CLI to interact with CrewAI.

<Warning>
  Since release 0.140.0, CrewAI AMP started a process of migrating their login
  provider. As such, the authentication flow via CLI was updated. Users that use
  Google to login, or that created their account after July 3rd, 2025 will be
  unable to log in with older versions of the `crewai` library.
</Warning>

## Overview

The CrewAI CLI provides a set of commands to interact with CrewAI, allowing you to create, train, run, and manage crews & flows.

## Installation

To use the CrewAI CLI, make sure you have CrewAI installed:

```shell Terminal theme={null}
pip install crewai
```

## Basic Usage

The basic structure of a CrewAI CLI command is:

```shell Terminal theme={null}
crewai [COMMAND] [OPTIONS] [ARGUMENTS]
```

## Available Commands

### 1. Create

Create a new crew or flow.

```shell Terminal theme={null}
crewai create [OPTIONS] TYPE NAME
```

* `TYPE`: Choose between "crew" or "flow"
* `NAME`: Name of the crew or flow

Example:

```shell Terminal theme={null}
crewai create crew my_new_crew
crewai create flow my_new_flow
```

### 2. Version

Show the installed version of CrewAI.

```shell Terminal theme={null}
crewai version [OPTIONS]
```

* `--tools`: (Optional) Show the installed version of CrewAI tools

Example:

```shell Terminal theme={null}
crewai version
crewai version --tools
```

### 3. Train

Train the crew for a specified number of iterations.

```shell Terminal theme={null}
crewai train [OPTIONS]
```

* `-n, --n_iterations INTEGER`: Number of iterations to train the crew (default: 5)
* `-f, --filename TEXT`: Path to a custom file for training (default: "trained\_agents\_data.pkl")

Example:

```shell Terminal theme={null}
crewai train -n 10 -f my_training_data.pkl
```

### 4. Replay

Replay the crew execution from a specific task.

```shell Terminal theme={null}
crewai replay [OPTIONS]
```

* `-t, --task_id TEXT`: Replay the crew from this task ID, including all subsequent tasks

Example:

```shell Terminal theme={null}
crewai replay -t task_123456
```

### 5. Log-tasks-outputs

Retrieve your latest crew\.kickoff() task outputs.

```shell Terminal theme={null}
crewai log-tasks-outputs
```

### 6. Reset-memories

Reset the crew memories (long, short, entity, latest\_crew\_kickoff\_outputs).

```shell Terminal theme={null}
crewai reset-memories [OPTIONS]
```

* `-l, --long`: Reset LONG TERM memory
* `-s, --short`: Reset SHORT TERM memory
* `-e, --entities`: Reset ENTITIES memory
* `-k, --kickoff-outputs`: Reset LATEST KICKOFF TASK OUTPUTS
* `-kn, --knowledge`: Reset KNOWLEDGE storage
* `-akn, --agent-knowledge`: Reset AGENT KNOWLEDGE storage
* `-a, --all`: Reset ALL memories

Example:

```shell Terminal theme={null}
crewai reset-memories --long --short
crewai reset-memories --all
```

### 7. Test

Test the crew and evaluate the results.

```shell Terminal theme={null}
crewai test [OPTIONS]
```

* `-n, --n_iterations INTEGER`: Number of iterations to test the crew (default: 3)
* `-m, --model TEXT`: LLM Model to run the tests on the Crew (default: "gpt-4o-mini")

Example:

```shell Terminal theme={null}
crewai test -n 5 -m gpt-3.5-turbo
```

### 8. Run

Run the crew or flow.

```shell Terminal theme={null}
crewai run
```

<Note>
  Starting from version 0.103.0, the `crewai run` command can be used to run
  both standard crews and flows. For flows, it automatically detects the type
  from pyproject.toml and runs the appropriate command. This is now the
  recommended way to run both crews and flows.
</Note>

<Note>
  Make sure to run these commands from the directory where your CrewAI project
  is set up. Some commands may require additional configuration or setup within
  your project structure.
</Note>

### 9. Chat

Starting in version `0.98.0`, when you run the `crewai chat` command, you start an interactive session with your crew. The AI assistant will guide you by asking for necessary inputs to execute the crew. Once all inputs are provided, the crew will execute its tasks.

After receiving the results, you can continue interacting with the assistant for further instructions or questions.

```shell Terminal theme={null}
crewai chat
```

<Note>
  Ensure you execute these commands from your CrewAI project's root directory.
</Note>

<Note>
  IMPORTANT: Set the `chat_llm` property in your `crew.py` file to enable this command.

  ```python theme={null}
  @crew
  def crew(self) -> Crew:
      return Crew(
          agents=self.agents,
          tasks=self.tasks,
          process=Process.sequential,
          verbose=True,
          chat_llm="gpt-4o",  # LLM for chat orchestration
      )
  ```
</Note>

### 10. Deploy

Deploy the crew or flow to [CrewAI AMP](https://app.crewai.com).

* **Authentication**: You need to be authenticated to deploy to CrewAI AMP.
  You can login or create an account with:

  ```shell Terminal theme={null}
  crewai login
  ```

* **Create a deployment**: Once you are authenticated, you can create a deployment for your crew or flow from the root of your localproject.
  ```shell Terminal theme={null}
  crewai deploy create
  ```
  * Reads your local project configuration.
  * Prompts you to confirm the environment variables (like `OPENAI_API_KEY`, `SERPER_API_KEY`) found locally. These will be securely stored with the deployment on the Enterprise platform. Ensure your sensitive keys are correctly configured locally (e.g., in a `.env` file) before running this.

### 11. Organization Management

Manage your CrewAI AMP organizations.

```shell Terminal theme={null}
crewai org [COMMAND] [OPTIONS]
```

#### Commands:

* `list`: List all organizations you belong to

```shell Terminal theme={null}
crewai org list
```

* `current`: Display your currently active organization

```shell Terminal theme={null}
crewai org current
```

* `switch`: Switch to a specific organization

```shell Terminal theme={null}
crewai org switch <organization_id>
```

<Note>
  You must be authenticated to CrewAI AMP to use these organization management
  commands.
</Note>

* **Create a deployment** (continued):

  * Links the deployment to the corresponding remote GitHub repository (it usually detects this automatically).

* **Deploy the Crew**: Once you are authenticated, you can deploy your crew or flow to CrewAI AMP.

  ```shell Terminal theme={null}
  crewai deploy push
  ```

  * Initiates the deployment process on the CrewAI AMP platform.
  * Upon successful initiation, it will output the Deployment created successfully! message along with the Deployment Name and a unique Deployment ID (UUID).

* **Deployment Status**: You can check the status of your deployment with:

  ```shell Terminal theme={null}
  crewai deploy status
  ```

  This fetches the latest deployment status of your most recent deployment attempt (e.g., `Building Images for Crew`, `Deploy Enqueued`, `Online`).

* **Deployment Logs**: You can check the logs of your deployment with:

  ```shell Terminal theme={null}
  crewai deploy logs
  ```

  This streams the deployment logs to your terminal.

* **List deployments**: You can list all your deployments with:

  ```shell Terminal theme={null}
  crewai deploy list
  ```

  This lists all your deployments.

* **Delete a deployment**: You can delete a deployment with:

  ```shell Terminal theme={null}
  crewai deploy remove
  ```

  This deletes the deployment from the CrewAI AMP platform.

* **Help Command**: You can get help with the CLI with:
  ```shell Terminal theme={null}
  crewai deploy --help
  ```
  This shows the help message for the CrewAI Deploy CLI.

Watch this video tutorial for a step-by-step demonstration of deploying your crew to [CrewAI AMP](http://app.crewai.com) using the CLI.

<iframe title="CrewAI Deployment Guide" />

### 11. Login

Authenticate with CrewAI AMP using a secure device code flow (no email entry required).

```shell Terminal theme={null}
crewai login
```

What happens:

* A verification URL and short code are displayed in your terminal
* Your browser opens to the verification URL
* Enter/confirm the code to complete authentication

Notes:

* The OAuth2 provider and domain are configured via `crewai config` (defaults use `login.crewai.com`)
* After successful login, the CLI also attempts to authenticate to the Tool Repository automatically
* If you reset your configuration, run `crewai login` again to re-authenticate

### 12. API Keys

When running `crewai create crew` command, the CLI will show you a list of available LLM providers to choose from, followed by model selection for your chosen provider.

Once you've selected an LLM provider and model, you will be prompted for API keys.

#### Available LLM Providers

Here's a list of the most popular LLM providers suggested by the CLI:

* OpenAI
* Groq
* Anthropic
* Google Gemini
* SambaNova

When you select a provider, the CLI will then show you available models for that provider and prompt you to enter your API key.

#### Other Options

If you select "other", you will be able to select from a list of LiteLLM supported providers.

When you select a provider, the CLI will prompt you to enter the Key name and the API key.

See the following link for each provider's key name:

* [LiteLLM Providers](https://docs.litellm.ai/docs/providers)

### 13. Configuration Management

Manage CLI configuration settings for CrewAI.

```shell Terminal theme={null}
crewai config [COMMAND] [OPTIONS]
```

#### Commands:

* `list`: Display all CLI configuration parameters

```shell Terminal theme={null}
crewai config list
```

* `set`: Set a CLI configuration parameter

```shell Terminal theme={null}
crewai config set <key> <value>
```

* `reset`: Reset all CLI configuration parameters to default values

```shell Terminal theme={null}
crewai config reset
```

#### Available Configuration Parameters

* `enterprise_base_url`: Base URL of the CrewAI AMP instance
* `oauth2_provider`: OAuth2 provider used for authentication (e.g., workos, okta, auth0)
* `oauth2_audience`: OAuth2 audience value, typically used to identify the target API or resource
* `oauth2_client_id`: OAuth2 client ID issued by the provider, used during authentication requests
* `oauth2_domain`: OAuth2 provider's domain (e.g., your-org.auth0.com) used for issuing tokens

#### Examples

Display current configuration:

```shell Terminal theme={null}
crewai config list
```

Example output:

| Setting               | Value                                            | Description                                  |
| :-------------------- | :----------------------------------------------- | :------------------------------------------- |
| enterprise\_base\_url | [https://app.crewai.com](https://app.crewai.com) | Base URL of the CrewAI AMP instance          |
| org\_name             | Not set                                          | Name of the currently active organization    |
| org\_uuid             | Not set                                          | UUID of the currently active organization    |
| oauth2\_provider      | workos                                           | OAuth2 provider (e.g., workos, okta, auth0)  |
| oauth2\_audience      | client\_01YYY                                    | Audience identifying the target API/resource |
| oauth2\_client\_id    | client\_01XXX                                    | OAuth2 client ID issued by the provider      |
| oauth2\_domain        | login.crewai.com                                 | Provider domain (e.g., your-org.auth0.com)   |

Set the enterprise base URL:

```shell Terminal theme={null}
crewai config set enterprise_base_url https://my-enterprise.crewai.com
```

Set OAuth2 provider:

```shell Terminal theme={null}
crewai config set oauth2_provider auth0
```

Set OAuth2 domain:

```shell Terminal theme={null}
crewai config set oauth2_domain my-company.auth0.com
```

Reset all configuration to defaults:

```shell Terminal theme={null}
crewai config reset
```

<Tip>
  After resetting configuration, re-run `crewai login` to authenticate again.
</Tip>

### 14. Trace Management

Manage trace collection preferences for your Crew and Flow executions.

```shell Terminal theme={null}
crewai traces [COMMAND]
```

#### Commands:

* `enable`: Enable trace collection for crew/flow executions

```shell Terminal theme={null}
crewai traces enable
```

* `disable`: Disable trace collection for crew/flow executions

```shell Terminal theme={null}
crewai traces disable
```

* `status`: Show current trace collection status

```shell Terminal theme={null}
crewai traces status
```

#### How Tracing Works

Trace collection is controlled by checking three settings in priority order:

1. **Explicit flag in code** (highest priority - can enable OR disable):

   ```python theme={null}
   crew = Crew(agents=[...], tasks=[...], tracing=True)   # Always enable
   crew = Crew(agents=[...], tasks=[...], tracing=False)  # Always disable
   crew = Crew(agents=[...], tasks=[...])                 # Check lower priorities (default)
   ```

   * `tracing=True` will **always enable** tracing (overrides everything)
   * `tracing=False` will **always disable** tracing (overrides everything)
   * `tracing=None` or omitted will check lower priority settings

2. **Environment variable** (second priority):

   ```env theme={null}
   CREWAI_TRACING_ENABLED=true
   ```

   * Checked only if `tracing` is not explicitly set to `True` or `False` in code
   * Set to `true` or `1` to enable tracing

3. **User preference** (lowest priority):
   ```shell Terminal theme={null}
   crewai traces enable
   ```
   * Checked only if `tracing` is not set in code and `CREWAI_TRACING_ENABLED` is not set to `true`
   * Running `crewai traces enable` is sufficient to enable tracing by itself

<Note>
  **To enable tracing**, use any one of these methods:

  * Set `tracing=True` in your Crew/Flow code, OR
  * Add `CREWAI_TRACING_ENABLED=true` to your `.env` file, OR
  * Run `crewai traces enable`

  **To disable tracing**, use any ONE of these methods:

  * Set `tracing=False` in your Crew/Flow code (overrides everything), OR
  * Remove or set to `false` the `CREWAI_TRACING_ENABLED` env var, OR
  * Run `crewai traces disable`

  Higher priority settings override lower ones.
</Note>

<Tip>
  For more information about tracing, see the [Tracing
  documentation](/observability/tracing).
</Tip>

<Tip>
  CrewAI CLI handles authentication to the Tool Repository automatically when
  adding packages to your project. Just append `crewai` before any `uv` command
  to use it. E.g. `crewai uv add requests`. For more information, see [Tool
  Repository](https://docs.crewai.com/enterprise/features/tool-repository) docs.
</Tip>

<Note>
  Configuration settings are stored in `~/.config/crewai/settings.json`. Some
  settings like organization name and UUID are read-only and managed through
  authentication and organization commands. Tool repository related settings are
  hidden and cannot be set directly by users.
</Note>


# Collaboration
Source: https://docs.crewai.com/en/concepts/collaboration

How to enable agents to work together, delegate tasks, and communicate effectively within CrewAI teams.

## Overview

Collaboration in CrewAI enables agents to work together as a team by delegating tasks and asking questions to leverage each other's expertise. When `allow_delegation=True`, agents automatically gain access to powerful collaboration tools.

## Quick Start: Enable Collaboration

```python theme={null}
from crewai import Agent, Crew, Task

# Enable collaboration for agents
researcher = Agent(
    role="Research Specialist",
    goal="Conduct thorough research on any topic",
    backstory="Expert researcher with access to various sources",
    allow_delegation=True,  # 🔑 Key setting for collaboration
    verbose=True
)

writer = Agent(
    role="Content Writer", 
    goal="Create engaging content based on research",
    backstory="Skilled writer who transforms research into compelling content",
    allow_delegation=True,  # 🔑 Enables asking questions to other agents
    verbose=True
)

# Agents can now collaborate automatically
crew = Crew(
    agents=[researcher, writer],
    tasks=[...],
    verbose=True
)
```

## How Agent Collaboration Works

When `allow_delegation=True`, CrewAI automatically provides agents with two powerful tools:

### 1. **Delegate Work Tool**

Allows agents to assign tasks to teammates with specific expertise.

```python theme={null}
# Agent automatically gets this tool:
# Delegate work to coworker(task: str, context: str, coworker: str)
```

### 2. **Ask Question Tool**

Enables agents to ask specific questions to gather information from colleagues.

```python theme={null}
# Agent automatically gets this tool:
# Ask question to coworker(question: str, context: str, coworker: str)
```

## Collaboration in Action

Here's a complete example showing agents collaborating on a content creation task:

```python theme={null}
from crewai import Agent, Crew, Task, Process

# Create collaborative agents
researcher = Agent(
    role="Research Specialist",
    goal="Find accurate, up-to-date information on any topic",
    backstory="""You're a meticulous researcher with expertise in finding 
    reliable sources and fact-checking information across various domains.""",
    allow_delegation=True,
    verbose=True
)

writer = Agent(
    role="Content Writer",
    goal="Create engaging, well-structured content",
    backstory="""You're a skilled content writer who excels at transforming 
    research into compelling, readable content for different audiences.""",
    allow_delegation=True,
    verbose=True
)

editor = Agent(
    role="Content Editor",
    goal="Ensure content quality and consistency",
    backstory="""You're an experienced editor with an eye for detail, 
    ensuring content meets high standards for clarity and accuracy.""",
    allow_delegation=True,
    verbose=True
)

# Create a task that encourages collaboration
article_task = Task(
    description="""Write a comprehensive 1000-word article about 'The Future of AI in Healthcare'.
    
    The article should include:
    - Current AI applications in healthcare
    - Emerging trends and technologies  
    - Potential challenges and ethical considerations
    - Expert predictions for the next 5 years
    
    Collaborate with your teammates to ensure accuracy and quality.""",
    expected_output="A well-researched, engaging 1000-word article with proper structure and citations",
    agent=writer  # Writer leads, but can delegate research to researcher
)

# Create collaborative crew
crew = Crew(
    agents=[researcher, writer, editor],
    tasks=[article_task],
    process=Process.sequential,
    verbose=True
)

result = crew.kickoff()
```

## Collaboration Patterns

### Pattern 1: Research → Write → Edit

```python theme={null}
research_task = Task(
    description="Research the latest developments in quantum computing",
    expected_output="Comprehensive research summary with key findings and sources",
    agent=researcher
)

writing_task = Task(
    description="Write an article based on the research findings",
    expected_output="Engaging 800-word article about quantum computing",
    agent=writer,
    context=[research_task]  # Gets research output as context
)

editing_task = Task(
    description="Edit and polish the article for publication",
    expected_output="Publication-ready article with improved clarity and flow",
    agent=editor,
    context=[writing_task]  # Gets article draft as context
)
```

### Pattern 2: Collaborative Single Task

```python theme={null}
collaborative_task = Task(
    description="""Create a marketing strategy for a new AI product.
    
    Writer: Focus on messaging and content strategy
    Researcher: Provide market analysis and competitor insights
    
    Work together to create a comprehensive strategy.""",
    expected_output="Complete marketing strategy with research backing",
    agent=writer  # Lead agent, but can delegate to researcher
)
```

## Hierarchical Collaboration

For complex projects, use a hierarchical process with a manager agent:

```python theme={null}
from crewai import Agent, Crew, Task, Process

# Manager agent coordinates the team
manager = Agent(
    role="Project Manager",
    goal="Coordinate team efforts and ensure project success",
    backstory="Experienced project manager skilled at delegation and quality control",
    allow_delegation=True,
    verbose=True
)

# Specialist agents
researcher = Agent(
    role="Researcher",
    goal="Provide accurate research and analysis",
    backstory="Expert researcher with deep analytical skills",
    allow_delegation=False,  # Specialists focus on their expertise
    verbose=True
)

writer = Agent(
    role="Writer", 
    goal="Create compelling content",
    backstory="Skilled writer who creates engaging content",
    allow_delegation=False,
    verbose=True
)

# Manager-led task
project_task = Task(
    description="Create a comprehensive market analysis report with recommendations",
    expected_output="Executive summary, detailed analysis, and strategic recommendations",
    agent=manager  # Manager will delegate to specialists
)

# Hierarchical crew
crew = Crew(
    agents=[manager, researcher, writer],
    tasks=[project_task],
    process=Process.hierarchical,  # Manager coordinates everything
    manager_llm="gpt-4o",  # Specify LLM for manager
    verbose=True
)
```

## Best Practices for Collaboration

### 1. **Clear Role Definition**

```python theme={null}
# ✅ Good: Specific, complementary roles
researcher = Agent(role="Market Research Analyst", ...)
writer = Agent(role="Technical Content Writer", ...)

# ❌ Avoid: Overlapping or vague roles  
agent1 = Agent(role="General Assistant", ...)
agent2 = Agent(role="Helper", ...)
```

### 2. **Strategic Delegation Enabling**

```python theme={null}
# ✅ Enable delegation for coordinators and generalists
lead_agent = Agent(
    role="Content Lead",
    allow_delegation=True,  # Can delegate to specialists
    ...
)

# ✅ Disable for focused specialists (optional)
specialist_agent = Agent(
    role="Data Analyst", 
    allow_delegation=False,  # Focuses on core expertise
    ...
)
```

### 3. **Context Sharing**

```python theme={null}
# ✅ Use context parameter for task dependencies
writing_task = Task(
    description="Write article based on research",
    agent=writer,
    context=[research_task],  # Shares research results
    ...
)
```

### 4. **Clear Task Descriptions**

```python theme={null}
# ✅ Specific, actionable descriptions
Task(
    description="""Research competitors in the AI chatbot space.
    Focus on: pricing models, key features, target markets.
    Provide data in a structured format.""",
    ...
)

# ❌ Vague descriptions that don't guide collaboration
Task(description="Do some research about chatbots", ...)
```

## Troubleshooting Collaboration

### Issue: Agents Not Collaborating

**Symptoms:** Agents work in isolation, no delegation occurs

```python theme={null}
# ✅ Solution: Ensure delegation is enabled
agent = Agent(
    role="...",
    allow_delegation=True,  # This is required!
    ...
)
```

### Issue: Too Much Back-and-Forth

**Symptoms:** Agents ask excessive questions, slow progress

```python theme={null}
# ✅ Solution: Provide better context and specific roles
Task(
    description="""Write a technical blog post about machine learning.
    
    Context: Target audience is software developers with basic ML knowledge.
    Length: 1200 words
    Include: code examples, practical applications, best practices
    
    If you need specific technical details, delegate research to the researcher.""",
    ...
)
```

### Issue: Delegation Loops

**Symptoms:** Agents delegate back and forth indefinitely

```python theme={null}
# ✅ Solution: Clear hierarchy and responsibilities
manager = Agent(role="Manager", allow_delegation=True)
specialist1 = Agent(role="Specialist A", allow_delegation=False)  # No re-delegation
specialist2 = Agent(role="Specialist B", allow_delegation=False)
```

## Advanced Collaboration Features

### Custom Collaboration Rules

```python theme={null}
# Set specific collaboration guidelines in agent backstory
agent = Agent(
    role="Senior Developer",
    backstory="""You lead development projects and coordinate with team members.
    
    Collaboration guidelines:
    - Delegate research tasks to the Research Analyst
    - Ask the Designer for UI/UX guidance  
    - Consult the QA Engineer for testing strategies
    - Only escalate blocking issues to the Project Manager""",
    allow_delegation=True
)
```

### Monitoring Collaboration

```python theme={null}
def track_collaboration(output):
    """Track collaboration patterns"""
    if "Delegate work to coworker" in output.raw:
        print("🤝 Delegation occurred")
    if "Ask question to coworker" in output.raw:
        print("❓ Question asked")

crew = Crew(
    agents=[...],
    tasks=[...],
    step_callback=track_collaboration,  # Monitor collaboration
    verbose=True
)
```

## Memory and Learning

Enable agents to remember past collaborations:

```python theme={null}
agent = Agent(
    role="Content Lead",
    memory=True,  # Remembers past interactions
    allow_delegation=True,
    verbose=True
)
```

With memory enabled, agents learn from previous collaborations and improve their delegation decisions over time.

## Next Steps

* **Try the examples**: Start with the basic collaboration example
* **Experiment with roles**: Test different agent role combinations
* **Monitor interactions**: Use `verbose=True` to see collaboration in action
* **Optimize task descriptions**: Clear tasks lead to better collaboration
* **Scale up**: Try hierarchical processes for complex projects

Collaboration transforms individual AI agents into powerful teams that can tackle complex, multi-faceted challenges together.


# Crews
Source: https://docs.crewai.com/en/concepts/crews

Understanding and utilizing crews in the crewAI framework with comprehensive attributes and functionalities.

## Overview

A crew in crewAI represents a collaborative group of agents working together to achieve a set of tasks. Each crew defines the strategy for task execution, agent collaboration, and the overall workflow.

## Crew Attributes

| Attribute                             | Parameters             | Description                                                                                                                                                                                           |   |
| :------------------------------------ | :--------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | - |
| **Tasks**                             | `tasks`                | A list of tasks assigned to the crew.                                                                                                                                                                 |   |
| **Agents**                            | `agents`               | A list of agents that are part of the crew.                                                                                                                                                           |   |
| **Process** *(optional)*              | `process`              | The process flow (e.g., sequential, hierarchical) the crew follows. Default is `sequential`.                                                                                                          |   |
| **Verbose** *(optional)*              | `verbose`              | The verbosity level for logging during execution. Defaults to `False`.                                                                                                                                |   |
| **Manager LLM** *(optional)*          | `manager_llm`          | The language model used by the manager agent in a hierarchical process. **Required when using a hierarchical process.**                                                                               |   |
| **Function Calling LLM** *(optional)* | `function_calling_llm` | If passed, the crew will use this LLM to do function calling for tools for all agents in the crew. Each agent can have its own LLM, which overrides the crew's LLM for function calling.              |   |
| **Config** *(optional)*               | `config`               | Optional configuration settings for the crew, in `Json` or `Dict[str, Any]` format.                                                                                                                   |   |
| **Max RPM** *(optional)*              | `max_rpm`              | Maximum requests per minute the crew adheres to during execution. Defaults to `None`.                                                                                                                 |   |
| **Memory** *(optional)*               | `memory`               | Utilized for storing execution memories (short-term, long-term, entity memory).                                                                                                                       |   |
| **Cache** *(optional)*                | `cache`                | Specifies whether to use a cache for storing the results of tools' execution. Defaults to `True`.                                                                                                     |   |
| **Embedder** *(optional)*             | `embedder`             | Configuration for the embedder to be used by the crew. Mostly used by memory for now. Default is `{"provider": "openai"}`.                                                                            |   |
| **Step Callback** *(optional)*        | `step_callback`        | A function that is called after each step of every agent. This can be used to log the agent's actions or to perform other operations; it won't override the agent-specific `step_callback`.           |   |
| **Task Callback** *(optional)*        | `task_callback`        | A function that is called after the completion of each task. Useful for monitoring or additional operations post-task execution.                                                                      |   |
| **Share Crew** *(optional)*           | `share_crew`           | Whether you want to share the complete crew information and execution with the crewAI team to make the library better, and allow us to train models.                                                  |   |
| **Output Log File** *(optional)*      | `output_log_file`      | Set to True to save logs as logs.txt in the current directory or provide a file path. Logs will be in JSON format if the filename ends in .json, otherwise .txt. Defaults to `None`.                  |   |
| **Manager Agent** *(optional)*        | `manager_agent`        | `manager` sets a custom agent that will be used as a manager.                                                                                                                                         |   |
| **Prompt File** *(optional)*          | `prompt_file`          | Path to the prompt JSON file to be used for the crew.                                                                                                                                                 |   |
| **Planning** *(optional)*             | `planning`             | Adds planning ability to the Crew. When activated before each Crew iteration, all Crew data is sent to an AgentPlanner that will plan the tasks and this plan will be added to each task description. |   |
| **Planning LLM** *(optional)*         | `planning_llm`         | The language model used by the AgentPlanner in a planning process.                                                                                                                                    |   |
| **Knowledge Sources** *(optional)*    | `knowledge_sources`    | Knowledge sources available at the crew level, accessible to all the agents.                                                                                                                          |   |
| **Stream** *(optional)*               | `stream`               | Enable streaming output to receive real-time updates during crew execution. Returns a `CrewStreamingOutput` object that can be iterated for chunks. Defaults to `False`.                              |   |

<Tip>
  **Crew Max RPM**: The `max_rpm` attribute sets the maximum number of requests per minute the crew can perform to avoid rate limits and will override individual agents' `max_rpm` settings if you set it.
</Tip>

## Creating Crews

There are two ways to create crews in CrewAI: using **YAML configuration (recommended)** or defining them **directly in code**.

### YAML Configuration (Recommended)

Using YAML configuration provides a cleaner, more maintainable way to define crews and is consistent with how agents and tasks are defined in CrewAI projects.

After creating your CrewAI project as outlined in the [Installation](/en/installation) section, you can define your crew in a class that inherits from `CrewBase` and uses decorators to define agents, tasks, and the crew itself.

#### Example Crew Class with Decorators

```python code theme={null}
from crewai import Agent, Crew, Task, Process
from crewai.project import CrewBase, agent, task, crew, before_kickoff, after_kickoff
from crewai.agents.agent_builder.base_agent import BaseAgent
from typing import List

@CrewBase
class YourCrewName:
    """Description of your crew"""

    agents: List[BaseAgent]
    tasks: List[Task]

    # Paths to your YAML configuration files
    # To see an example agent and task defined in YAML, checkout the following:
    # - Task: https://docs.crewai.com/concepts/tasks#yaml-configuration-recommended
    # - Agents: https://docs.crewai.com/concepts/agents#yaml-configuration-recommended
    agents_config = 'config/agents.yaml'
    tasks_config = 'config/tasks.yaml'

    @before_kickoff
    def prepare_inputs(self, inputs):
        # Modify inputs before the crew starts
        inputs['additional_data'] = "Some extra information"
        return inputs

    @after_kickoff
    def process_output(self, output):
        # Modify output after the crew finishes
        output.raw += "\nProcessed after kickoff."
        return output

    @agent
    def agent_one(self) -> Agent:
        return Agent(
            config=self.agents_config['agent_one'], # type: ignore[index]
            verbose=True
        )

    @agent
    def agent_two(self) -> Agent:
        return Agent(
            config=self.agents_config['agent_two'], # type: ignore[index]
            verbose=True
        )

    @task
    def task_one(self) -> Task:
        return Task(
            config=self.tasks_config['task_one'] # type: ignore[index]
        )

    @task
    def task_two(self) -> Task:
        return Task(
            config=self.tasks_config['task_two'] # type: ignore[index]
        )

    @crew
    def crew(self) -> Crew:
        return Crew(
            agents=self.agents,  # Automatically collected by the @agent decorator
            tasks=self.tasks,    # Automatically collected by the @task decorator.
            process=Process.sequential,
            verbose=True,
        )
```

How to run the above code:

```python code theme={null}
YourCrewName().crew().kickoff(inputs={"any": "input here"})
```

<Note>
  Tasks will be executed in the order they are defined.
</Note>

The `CrewBase` class, along with these decorators, automates the collection of agents and tasks, reducing the need for manual management.

#### Decorators overview from `annotations.py`

CrewAI provides several decorators in the `annotations.py` file that are used to mark methods within your crew class for special handling:

* `@CrewBase`: Marks the class as a crew base class.
* `@agent`: Denotes a method that returns an `Agent` object.
* `@task`: Denotes a method that returns a `Task` object.
* `@crew`: Denotes the method that returns the `Crew` object.
* `@before_kickoff`: (Optional) Marks a method to be executed before the crew starts.
* `@after_kickoff`: (Optional) Marks a method to be executed after the crew finishes.

These decorators help in organizing your crew's structure and automatically collecting agents and tasks without manually listing them.

### Direct Code Definition (Alternative)

Alternatively, you can define the crew directly in code without using YAML configuration files.

```python code theme={null}
from crewai import Agent, Crew, Task, Process
from crewai_tools import YourCustomTool

class YourCrewName:
    def agent_one(self) -> Agent:
        return Agent(
            role="Data Analyst",
            goal="Analyze data trends in the market",
            backstory="An experienced data analyst with a background in economics",
            verbose=True,
            tools=[YourCustomTool()]
        )

    def agent_two(self) -> Agent:
        return Agent(
            role="Market Researcher",
            goal="Gather information on market dynamics",
            backstory="A diligent researcher with a keen eye for detail",
            verbose=True
        )

    def task_one(self) -> Task:
        return Task(
            description="Collect recent market data and identify trends.",
            expected_output="A report summarizing key trends in the market.",
            agent=self.agent_one()
        )

    def task_two(self) -> Task:
        return Task(
            description="Research factors affecting market dynamics.",
            expected_output="An analysis of factors influencing the market.",
            agent=self.agent_two()
        )

    def crew(self) -> Crew:
        return Crew(
            agents=[self.agent_one(), self.agent_two()],
            tasks=[self.task_one(), self.task_two()],
            process=Process.sequential,
            verbose=True
        )
```

How to run the above code:

```python code theme={null}
YourCrewName().crew().kickoff(inputs={})
```

In this example:

* Agents and tasks are defined directly within the class without decorators.
* We manually create and manage the list of agents and tasks.
* This approach provides more control but can be less maintainable for larger projects.

## Crew Output

The output of a crew in the CrewAI framework is encapsulated within the `CrewOutput` class.
This class provides a structured way to access results of the crew's execution, including various formats such as raw strings, JSON, and Pydantic models.
The `CrewOutput` includes the results from the final task output, token usage, and individual task outputs.

### Crew Output Attributes

| Attribute        | Parameters     | Type                       | Description                                                                                          |
| :--------------- | :------------- | :------------------------- | :--------------------------------------------------------------------------------------------------- |
| **Raw**          | `raw`          | `str`                      | The raw output of the crew. This is the default format for the output.                               |
| **Pydantic**     | `pydantic`     | `Optional[BaseModel]`      | A Pydantic model object representing the structured output of the crew.                              |
| **JSON Dict**    | `json_dict`    | `Optional[Dict[str, Any]]` | A dictionary representing the JSON output of the crew.                                               |
| **Tasks Output** | `tasks_output` | `List[TaskOutput]`         | A list of `TaskOutput` objects, each representing the output of a task in the crew.                  |
| **Token Usage**  | `token_usage`  | `Dict[str, Any]`           | A summary of token usage, providing insights into the language model's performance during execution. |

### Crew Output Methods and Properties

| Method/Property | Description                                                                                       |
| :-------------- | :------------------------------------------------------------------------------------------------ |
| **json**        | Returns the JSON string representation of the crew output if the output format is JSON.           |
| **to\_dict**    | Converts the JSON and Pydantic outputs to a dictionary.                                           |
| \***\*str\*\*** | Returns the string representation of the crew output, prioritizing Pydantic, then JSON, then raw. |

### Accessing Crew Outputs

Once a crew has been executed, its output can be accessed through the `output` attribute of the `Crew` object. The `CrewOutput` class provides various ways to interact with and present this output.

#### Example

```python Code theme={null}
# Example crew execution
crew = Crew(
    agents=[research_agent, writer_agent],
    tasks=[research_task, write_article_task],
    verbose=True
)

crew_output = crew.kickoff()

# Accessing the crew output
print(f"Raw Output: {crew_output.raw}")
if crew_output.json_dict:
    print(f"JSON Output: {json.dumps(crew_output.json_dict, indent=2)}")
if crew_output.pydantic:
    print(f"Pydantic Output: {crew_output.pydantic}")
print(f"Tasks Output: {crew_output.tasks_output}")
print(f"Token Usage: {crew_output.token_usage}")
```

## Accessing Crew Logs

You can see real time log of the crew execution, by setting `output_log_file` as a `True(Boolean)` or a `file_name(str)`. Supports logging of events as both `file_name.txt` and `file_name.json`.
In case of `True(Boolean)` will save as `logs.txt`.

In case of `output_log_file` is set as `False(Boolean)` or `None`, the logs will not be populated.

```python Code theme={null}
# Save crew logs
crew = Crew(output_log_file = True)  # Logs will be saved as logs.txt
crew = Crew(output_log_file = file_name)  # Logs will be saved as file_name.txt
crew = Crew(output_log_file = file_name.txt)  # Logs will be saved as file_name.txt
crew = Crew(output_log_file = file_name.json)  # Logs will be saved as file_name.json
```

## Memory Utilization

Crews can utilize memory (short-term, long-term, and entity memory) to enhance their execution and learning over time. This feature allows crews to store and recall execution memories, aiding in decision-making and task execution strategies.

## Cache Utilization

Caches can be employed to store the results of tools' execution, making the process more efficient by reducing the need to re-execute identical tasks.

## Crew Usage Metrics

After the crew execution, you can access the `usage_metrics` attribute to view the language model (LLM) usage metrics for all tasks executed by the crew. This provides insights into operational efficiency and areas for improvement.

```python Code theme={null}
# Access the crew's usage metrics
crew = Crew(agents=[agent1, agent2], tasks=[task1, task2])
crew.kickoff()
print(crew.usage_metrics)
```

## Crew Execution Process

* **Sequential Process**: Tasks are executed one after another, allowing for a linear flow of work.
* **Hierarchical Process**: A manager agent coordinates the crew, delegating tasks and validating outcomes before proceeding. **Note**: A `manager_llm` or `manager_agent` is required for this process and it's essential for validating the process flow.

### Kicking Off a Crew

Once your crew is assembled, initiate the workflow with the `kickoff()` method. This starts the execution process according to the defined process flow.

```python Code theme={null}
# Start the crew's task execution
result = my_crew.kickoff()
print(result)
```

### Different Ways to Kick Off a Crew

Once your crew is assembled, initiate the workflow with the appropriate kickoff method. CrewAI provides several methods for better control over the kickoff process.

#### Synchronous Methods

* `kickoff()`: Starts the execution process according to the defined process flow.
* `kickoff_for_each()`: Executes tasks sequentially for each provided input event or item in the collection.

#### Asynchronous Methods

CrewAI offers two approaches for async execution:

| Method                     | Type         | Description                                            |
| -------------------------- | ------------ | ------------------------------------------------------ |
| `akickoff()`               | Native async | True async/await throughout the entire execution chain |
| `akickoff_for_each()`      | Native async | Native async execution for each input in a list        |
| `kickoff_async()`          | Thread-based | Wraps synchronous execution in `asyncio.to_thread`     |
| `kickoff_for_each_async()` | Thread-based | Thread-based async for each input in a list            |

<Note>
  For high-concurrency workloads, `akickoff()` and `akickoff_for_each()` are recommended as they use native async for task execution, memory operations, and knowledge retrieval.
</Note>

```python Code theme={null}
# Start the crew's task execution
result = my_crew.kickoff()
print(result)

# Example of using kickoff_for_each
inputs_array = [{'topic': 'AI in healthcare'}, {'topic': 'AI in finance'}]
results = my_crew.kickoff_for_each(inputs=inputs_array)
for result in results:
    print(result)

# Example of using native async with akickoff
inputs = {'topic': 'AI in healthcare'}
async_result = await my_crew.akickoff(inputs=inputs)
print(async_result)

# Example of using native async with akickoff_for_each
inputs_array = [{'topic': 'AI in healthcare'}, {'topic': 'AI in finance'}]
async_results = await my_crew.akickoff_for_each(inputs=inputs_array)
for async_result in async_results:
    print(async_result)

# Example of using thread-based kickoff_async
inputs = {'topic': 'AI in healthcare'}
async_result = await my_crew.kickoff_async(inputs=inputs)
print(async_result)

# Example of using thread-based kickoff_for_each_async
inputs_array = [{'topic': 'AI in healthcare'}, {'topic': 'AI in finance'}]
async_results = await my_crew.kickoff_for_each_async(inputs=inputs_array)
for async_result in async_results:
    print(async_result)
```

These methods provide flexibility in how you manage and execute tasks within your crew, allowing for both synchronous and asynchronous workflows tailored to your needs. For detailed async examples, see the [Kickoff Crew Asynchronously](/en/learn/kickoff-async) guide.

### Streaming Crew Execution

For real-time visibility into crew execution, you can enable streaming to receive output as it's generated:

```python Code theme={null}
# Enable streaming
crew = Crew(
    agents=[researcher],
    tasks=[task],
    stream=True
)

# Iterate over streaming output
streaming = crew.kickoff(inputs={"topic": "AI"})
for chunk in streaming:
    print(chunk.content, end="", flush=True)

# Access final result
result = streaming.result
```

Learn more about streaming in the [Streaming Crew Execution](/en/learn/streaming-crew-execution) guide.

### Replaying from a Specific Task

You can now replay from a specific task using our CLI command `replay`.

The replay feature in CrewAI allows you to replay from a specific task using the command-line interface (CLI). By running the command `crewai replay -t <task_id>`, you can specify the `task_id` for the replay process.

Kickoffs will now save the latest kickoffs returned task outputs locally for you to be able to replay from.

### Replaying from a Specific Task Using the CLI

To use the replay feature, follow these steps:

1. Open your terminal or command prompt.
2. Navigate to the directory where your CrewAI project is located.
3. Run the following command:

To view the latest kickoff task IDs, use:

```shell theme={null}
crewai log-tasks-outputs
```

Then, to replay from a specific task, use:

```shell theme={null}
crewai replay -t <task_id>
```

These commands let you replay from your latest kickoff tasks, still retaining context from previously executed tasks.


# Event Listeners
Source: https://docs.crewai.com/en/concepts/event-listener

Tap into CrewAI events to build custom integrations and monitoring

## Overview

CrewAI provides a powerful event system that allows you to listen for and react to various events that occur during the execution of your Crew. This feature enables you to build custom integrations, monitoring solutions, logging systems, or any other functionality that needs to be triggered based on CrewAI's internal events.

## How It Works

CrewAI uses an event bus architecture to emit events throughout the execution lifecycle. The event system is built on the following components:

1. **CrewAIEventsBus**: A singleton event bus that manages event registration and emission
2. **BaseEvent**: Base class for all events in the system
3. **BaseEventListener**: Abstract base class for creating custom event listeners

When specific actions occur in CrewAI (like a Crew starting execution, an Agent completing a task, or a tool being used), the system emits corresponding events. You can register handlers for these events to execute custom code when they occur.

<Note type="info" title="Enterprise Enhancement: Prompt Tracing">
  CrewAI AMP provides a built-in Prompt Tracing feature that leverages the event system to track, store, and visualize all prompts, completions, and associated metadata. This provides powerful debugging capabilities and transparency into your agent operations.

  <img alt="Prompt Tracing Dashboard" />

  With Prompt Tracing you can:

  * View the complete history of all prompts sent to your LLM
  * Track token usage and costs
  * Debug agent reasoning failures
  * Share prompt sequences with your team
  * Compare different prompt strategies
  * Export traces for compliance and auditing
</Note>

## Creating a Custom Event Listener

To create a custom event listener, you need to:

1. Create a class that inherits from `BaseEventListener`
2. Implement the `setup_listeners` method
3. Register handlers for the events you're interested in
4. Create an instance of your listener in the appropriate file

Here's a simple example of a custom event listener class:

```python theme={null}
from crewai.events import (
    CrewKickoffStartedEvent,
    CrewKickoffCompletedEvent,
    AgentExecutionCompletedEvent,
)
from crewai.events import BaseEventListener

class MyCustomListener(BaseEventListener):
    def __init__(self):
        super().__init__()

    def setup_listeners(self, crewai_event_bus):
        @crewai_event_bus.on(CrewKickoffStartedEvent)
        def on_crew_started(source, event):
            print(f"Crew '{event.crew_name}' has started execution!")

        @crewai_event_bus.on(CrewKickoffCompletedEvent)
        def on_crew_completed(source, event):
            print(f"Crew '{event.crew_name}' has completed execution!")
            print(f"Output: {event.output}")

        @crewai_event_bus.on(AgentExecutionCompletedEvent)
        def on_agent_execution_completed(source, event):
            print(f"Agent '{event.agent.role}' completed task")
            print(f"Output: {event.output}")
```

## Properly Registering Your Listener

Simply defining your listener class isn't enough. You need to create an instance of it and ensure it's imported in your application. This ensures that:

1. The event handlers are registered with the event bus
2. The listener instance remains in memory (not garbage collected)
3. The listener is active when events are emitted

### Option 1: Import and Instantiate in Your Crew or Flow Implementation

The most important thing is to create an instance of your listener in the file where your Crew or Flow is defined and executed:

#### For Crew-based Applications

Create and import your listener at the top of your Crew implementation file:

```python theme={null}
# In your crew.py file
from crewai import Agent, Crew, Task
from my_listeners import MyCustomListener

# Create an instance of your listener
my_listener = MyCustomListener()

class MyCustomCrew:
    # Your crew implementation...

    def crew(self):
        return Crew(
            agents=[...],
            tasks=[...],
            # ...
        )
```

#### For Flow-based Applications

Create and import your listener at the top of your Flow implementation file:

```python theme={null}
# In your main.py or flow.py file
from crewai.flow import Flow, listen, start
from my_listeners import MyCustomListener

# Create an instance of your listener
my_listener = MyCustomListener()

class MyCustomFlow(Flow):
    # Your flow implementation...

    @start()
    def first_step(self):
        # ...
```

This ensures that your listener is loaded and active when your Crew or Flow is executed.

### Option 2: Create a Package for Your Listeners

For a more structured approach, especially if you have multiple listeners:

1. Create a package for your listeners:

```
my_project/
  ├── listeners/
  │   ├── __init__.py
  │   ├── my_custom_listener.py
  │   └── another_listener.py
```

2. In `my_custom_listener.py`, define your listener class and create an instance:

```python theme={null}
# my_custom_listener.py
from crewai.events import BaseEventListener
# ... import events ...

class MyCustomListener(BaseEventListener):
    # ... implementation ...

# Create an instance of your listener
my_custom_listener = MyCustomListener()
```

3. In `__init__.py`, import the listener instances to ensure they're loaded:

```python theme={null}
# __init__.py
from .my_custom_listener import my_custom_listener
from .another_listener import another_listener

# Optionally export them if you need to access them elsewhere
__all__ = ['my_custom_listener', 'another_listener']
```

4. Import your listeners package in your Crew or Flow file:

```python theme={null}
# In your crew.py or flow.py file
import my_project.listeners  # This loads all your listeners

class MyCustomCrew:
    # Your crew implementation...
```

This is how third-party event listeners are registered in the CrewAI codebase.

## Available Event Types

CrewAI provides a wide range of events that you can listen for:

### Crew Events

* **CrewKickoffStartedEvent**: Emitted when a Crew starts execution
* **CrewKickoffCompletedEvent**: Emitted when a Crew completes execution
* **CrewKickoffFailedEvent**: Emitted when a Crew fails to complete execution
* **CrewTestStartedEvent**: Emitted when a Crew starts testing
* **CrewTestCompletedEvent**: Emitted when a Crew completes testing
* **CrewTestFailedEvent**: Emitted when a Crew fails to complete testing
* **CrewTrainStartedEvent**: Emitted when a Crew starts training
* **CrewTrainCompletedEvent**: Emitted when a Crew completes training
* **CrewTrainFailedEvent**: Emitted when a Crew fails to complete training

### Agent Events

* **AgentExecutionStartedEvent**: Emitted when an Agent starts executing a task
* **AgentExecutionCompletedEvent**: Emitted when an Agent completes executing a task
* **AgentExecutionErrorEvent**: Emitted when an Agent encounters an error during execution

### Task Events

* **TaskStartedEvent**: Emitted when a Task starts execution
* **TaskCompletedEvent**: Emitted when a Task completes execution
* **TaskFailedEvent**: Emitted when a Task fails to complete execution
* **TaskEvaluationEvent**: Emitted when a Task is evaluated

### Tool Usage Events

* **ToolUsageStartedEvent**: Emitted when a tool execution is started
* **ToolUsageFinishedEvent**: Emitted when a tool execution is completed
* **ToolUsageErrorEvent**: Emitted when a tool execution encounters an error
* **ToolValidateInputErrorEvent**: Emitted when a tool input validation encounters an error
* **ToolExecutionErrorEvent**: Emitted when a tool execution encounters an error
* **ToolSelectionErrorEvent**: Emitted when there's an error selecting a tool

### Knowledge Events

* **KnowledgeRetrievalStartedEvent**: Emitted when a knowledge retrieval is started
* **KnowledgeRetrievalCompletedEvent**: Emitted when a knowledge retrieval is completed
* **KnowledgeQueryStartedEvent**: Emitted when a knowledge query is started
* **KnowledgeQueryCompletedEvent**: Emitted when a knowledge query is completed
* **KnowledgeQueryFailedEvent**: Emitted when a knowledge query fails
* **KnowledgeSearchQueryFailedEvent**: Emitted when a knowledge search query fails

### LLM Guardrail Events

* **LLMGuardrailStartedEvent**: Emitted when a guardrail validation starts. Contains details about the guardrail being applied and retry count.
* **LLMGuardrailCompletedEvent**: Emitted when a guardrail validation completes. Contains details about validation success/failure, results, and error messages if any.

### Flow Events

* **FlowCreatedEvent**: Emitted when a Flow is created
* **FlowStartedEvent**: Emitted when a Flow starts execution
* **FlowFinishedEvent**: Emitted when a Flow completes execution
* **FlowPlotEvent**: Emitted when a Flow is plotted
* **MethodExecutionStartedEvent**: Emitted when a Flow method starts execution
* **MethodExecutionFinishedEvent**: Emitted when a Flow method completes execution
* **MethodExecutionFailedEvent**: Emitted when a Flow method fails to complete execution

### LLM Events

* **LLMCallStartedEvent**: Emitted when an LLM call starts
* **LLMCallCompletedEvent**: Emitted when an LLM call completes
* **LLMCallFailedEvent**: Emitted when an LLM call fails
* **LLMStreamChunkEvent**: Emitted for each chunk received during streaming LLM responses

### Memory Events

* **MemoryQueryStartedEvent**: Emitted when a memory query is started. Contains the query, limit, and optional score threshold.
* **MemoryQueryCompletedEvent**: Emitted when a memory query is completed successfully. Contains the query, results, limit, score threshold, and query execution time.
* **MemoryQueryFailedEvent**: Emitted when a memory query fails. Contains the query, limit, score threshold, and error message.
* **MemorySaveStartedEvent**: Emitted when a memory save operation is started. Contains the value to be saved, metadata, and optional agent role.
* **MemorySaveCompletedEvent**: Emitted when a memory save operation is completed successfully. Contains the saved value, metadata, agent role, and save execution time.
* **MemorySaveFailedEvent**: Emitted when a memory save operation fails. Contains the value, metadata, agent role, and error message.
* **MemoryRetrievalStartedEvent**: Emitted when memory retrieval for a task prompt starts. Contains the optional task ID.
* **MemoryRetrievalCompletedEvent**: Emitted when memory retrieval for a task prompt completes successfully. Contains the task ID, memory content, and retrieval execution time.

## Event Handler Structure

Each event handler receives two parameters:

1. **source**: The object that emitted the event
2. **event**: The event instance, containing event-specific data

The structure of the event object depends on the event type, but all events inherit from `BaseEvent` and include:

* **timestamp**: The time when the event was emitted
* **type**: A string identifier for the event type

Additional fields vary by event type. For example, `CrewKickoffCompletedEvent` includes `crew_name` and `output` fields.

## Advanced Usage: Scoped Handlers

For temporary event handling (useful for testing or specific operations), you can use the `scoped_handlers` context manager:

```python theme={null}
from crewai.events import crewai_event_bus, CrewKickoffStartedEvent

with crewai_event_bus.scoped_handlers():
    @crewai_event_bus.on(CrewKickoffStartedEvent)
    def temp_handler(source, event):
        print("This handler only exists within this context")

    # Do something that emits events

# Outside the context, the temporary handler is removed
```

## Use Cases

Event listeners can be used for a variety of purposes:

1. **Logging and Monitoring**: Track the execution of your Crew and log important events
2. **Analytics**: Collect data about your Crew's performance and behavior
3. **Debugging**: Set up temporary listeners to debug specific issues
4. **Integration**: Connect CrewAI with external systems like monitoring platforms, databases, or notification services
5. **Custom Behavior**: Trigger custom actions based on specific events

## Best Practices

1. **Keep Handlers Light**: Event handlers should be lightweight and avoid blocking operations
2. **Error Handling**: Include proper error handling in your event handlers to prevent exceptions from affecting the main execution
3. **Cleanup**: If your listener allocates resources, ensure they're properly cleaned up
4. **Selective Listening**: Only listen for events you actually need to handle
5. **Testing**: Test your event listeners in isolation to ensure they behave as expected

By leveraging CrewAI's event system, you can extend its functionality and integrate it seamlessly with your existing infrastructure.


# Files
Source: https://docs.crewai.com/en/concepts/files

Pass images, PDFs, audio, video, and text files to your agents for multimodal processing.

## Overview

CrewAI supports native multimodal file inputs, allowing you to pass images, PDFs, audio, video, and text files directly to your agents. Files are automatically formatted for each LLM provider's API requirements.

<Note type="info" title="Optional Dependency">
  File support requires the optional `crewai-files` package. Install it with:

  ```bash theme={null}
  uv add 'crewai[file-processing]'
  ```
</Note>

<Note type="warning" title="Early Access">
  The file processing API is currently in early access.
</Note>

## File Types

CrewAI supports five specific file types plus a generic `File` class that auto-detects the type:

| Type        | Class       | Use Cases                             |
| :---------- | :---------- | :------------------------------------ |
| **Image**   | `ImageFile` | Photos, screenshots, diagrams, charts |
| **PDF**     | `PDFFile`   | Documents, reports, papers            |
| **Audio**   | `AudioFile` | Voice recordings, podcasts, meetings  |
| **Video**   | `VideoFile` | Screen recordings, presentations      |
| **Text**    | `TextFile`  | Code files, logs, data files          |
| **Generic** | `File`      | Auto-detect type from content         |

```python theme={null}
from crewai_files import File, ImageFile, PDFFile, AudioFile, VideoFile, TextFile

image = ImageFile(source="screenshot.png")
pdf = PDFFile(source="report.pdf")
audio = AudioFile(source="meeting.mp3")
video = VideoFile(source="demo.mp4")
text = TextFile(source="data.csv")

file = File(source="document.pdf")
```

## File Sources

The `source` parameter accepts multiple input types and auto-detects the appropriate handler:

### From Path

```python theme={null}
from crewai_files import ImageFile

image = ImageFile(source="./images/chart.png")
```

### From URL

```python theme={null}
from crewai_files import ImageFile

image = ImageFile(source="https://example.com/image.png")
```

### From Bytes

```python theme={null}
from crewai_files import ImageFile, FileBytes

image_bytes = download_image_from_api()
image = ImageFile(source=FileBytes(data=image_bytes, filename="downloaded.png"))
image = ImageFile(source=image_bytes)
```

## Using Files

Files can be passed at multiple levels, with more specific levels taking precedence.

### With Crews

Pass files when kicking off a crew:

```python theme={null}
from crewai import Crew
from crewai_files import ImageFile

crew = Crew(agents=[analyst], tasks=[analysis_task])

result = crew.kickoff(
    inputs={"topic": "Q4 Sales"},
    input_files={
        "chart": ImageFile(source="sales_chart.png"),
        "report": PDFFile(source="quarterly_report.pdf"),
    }
)
```

### With Tasks

Attach files to specific tasks:

```python theme={null}
from crewai import Task
from crewai_files import ImageFile

task = Task(
    description="Analyze the sales chart and identify trends in {chart}",
    expected_output="A summary of key trends",
    input_files={
        "chart": ImageFile(source="sales_chart.png"),
    }
)
```

### With Flows

Pass files to flows, which automatically inherit to crews:

```python theme={null}
from crewai.flow.flow import Flow, start
from crewai_files import ImageFile

class AnalysisFlow(Flow):
    @start()
    def analyze(self):
        return self.analysis_crew.kickoff()

flow = AnalysisFlow()
result = flow.kickoff(
    input_files={"image": ImageFile(source="data.png")}
)
```

### With Standalone Agents

Pass files directly to agent kickoff:

```python theme={null}
from crewai import Agent
from crewai_files import ImageFile

agent = Agent(
    role="Image Analyst",
    goal="Analyze images",
    backstory="Expert at visual analysis",
    llm="gpt-4o",
)

result = agent.kickoff(
    messages="What's in this image?",
    input_files={"photo": ImageFile(source="photo.jpg")},
)
```

## File Precedence

When files are passed at multiple levels, more specific levels override broader ones:

```
Flow input_files < Crew input_files < Task input_files
```

For example, if both Flow and Task define a file named `"chart"`, the Task's version is used.

## Provider Support

Different providers support different file types. CrewAI automatically formats files for each provider's API.

| Provider                                 | Image | PDF | Audio | Video | Text |
| :--------------------------------------- | :---: | :-: | :---: | :---: | :--: |
| **OpenAI** (completions API)             |   ✓   |     |       |       |      |
| **OpenAI** (responses API)               |   ✓   |  ✓  |   ✓   |       |      |
| **Anthropic** (claude-3.x)               |   ✓   |  ✓  |       |       |      |
| **Google Gemini** (gemini-1.5, 2.0, 2.5) |   ✓   |  ✓  |   ✓   |   ✓   |   ✓  |
| **AWS Bedrock** (claude-3)               |   ✓   |  ✓  |       |       |      |
| **Azure OpenAI** (gpt-4o)                |   ✓   |     |   ✓   |       |      |

<Note type="info" title="Gemini for Maximum File Support">
  Google Gemini models support all file types including video (up to 1 hour, 2GB). Use Gemini when you need to process video content.
</Note>

<Note type="warning" title="Unsupported File Types">
  If you pass a file type that the provider doesn't support (e.g., video to OpenAI), you'll receive an `UnsupportedFileTypeError`. Choose your provider based on the file types you need to process.
</Note>

## How Files Are Sent

CrewAI automatically chooses the optimal method to send files to each provider:

| Method              | Description                                | Used When                         |
| :------------------ | :----------------------------------------- | :-------------------------------- |
| **Inline Base64**   | File embedded directly in the request      | Small files (\< 5MB typically)    |
| **File Upload API** | File uploaded separately, referenced by ID | Large files that exceed threshold |
| **URL Reference**   | Direct URL passed to the model             | File source is already a URL      |

### Provider Transmission Methods

| Provider          | Inline Base64 | File Upload API | URL References |
| :---------------- | :-----------: | :-------------: | :------------: |
| **OpenAI**        |       ✓       |    ✓ (> 5 MB)   |        ✓       |
| **Anthropic**     |       ✓       |    ✓ (> 5 MB)   |        ✓       |
| **Google Gemini** |       ✓       |   ✓ (> 20 MB)   |        ✓       |
| **AWS Bedrock**   |       ✓       |                 |   ✓ (S3 URIs)  |
| **Azure OpenAI**  |       ✓       |                 |        ✓       |

<Note type="info" title="Automatic Optimization">
  You don't need to manage this yourself. CrewAI automatically uses the most efficient method based on file size and provider capabilities. Providers without file upload APIs use inline base64 for all files.
</Note>

## File Handling Modes

Control how files are processed when they exceed provider limits:

```python theme={null}
from crewai_files import ImageFile, PDFFile

image = ImageFile(source="large.png", mode="strict")
image = ImageFile(source="large.png", mode="auto")
image = ImageFile(source="large.png", mode="warn")
pdf = PDFFile(source="large.pdf", mode="chunk")
```

## Provider Constraints

Each provider has specific limits for file sizes and dimensions:

### OpenAI

* **Images**: Max 20 MB, up to 10 images per request
* **PDFs**: Max 32 MB, up to 100 pages
* **Audio**: Max 25 MB, up to 25 minutes

### Anthropic

* **Images**: Max 5 MB, max 8000x8000 pixels, up to 100 images
* **PDFs**: Max 32 MB, up to 100 pages

### Google Gemini

* **Images**: Max 100 MB
* **PDFs**: Max 50 MB
* **Audio**: Max 100 MB, up to 9.5 hours
* **Video**: Max 2 GB, up to 1 hour

### AWS Bedrock

* **Images**: Max 4.5 MB, max 8000x8000 pixels
* **PDFs**: Max 3.75 MB, up to 100 pages

## Referencing Files in Prompts

Use the file's key name in your task descriptions to reference files:

```python theme={null}
task = Task(
    description="""
    Analyze the provided materials:
    1. Review the chart in {sales_chart}
    2. Cross-reference with data in {quarterly_report}
    3. Summarize key findings
    """,
    expected_output="Analysis summary with key insights",
    input_files={
        "sales_chart": ImageFile(source="chart.png"),
        "quarterly_report": PDFFile(source="report.pdf"),
    }
)
```


# Flows
Source: https://docs.crewai.com/en/concepts/flows

Learn how to create and manage AI workflows using CrewAI Flows.

## Overview

CrewAI Flows is a powerful feature designed to streamline the creation and management of AI workflows. Flows allow developers to combine and coordinate coding tasks and Crews efficiently, providing a robust framework for building sophisticated AI automations.

Flows allow you to create structured, event-driven workflows. They provide a seamless way to connect multiple tasks, manage state, and control the flow of execution in your AI applications. With Flows, you can easily design and implement multi-step processes that leverage the full potential of CrewAI's capabilities.

1. **Simplified Workflow Creation**: Easily chain together multiple Crews and tasks to create complex AI workflows.

2. **State Management**: Flows make it super easy to manage and share state between different tasks in your workflow.

3. **Event-Driven Architecture**: Built on an event-driven model, allowing for dynamic and responsive workflows.

4. **Flexible Control Flow**: Implement conditional logic, loops, and branching within your workflows.

## Getting Started

Let's create a simple Flow where you will use OpenAI to generate a random city in one task and then use that city to generate a fun fact in another task.

```python Code theme={null}

from crewai.flow.flow import Flow, listen, start
from dotenv import load_dotenv
from litellm import completion


class ExampleFlow(Flow):
    model = "gpt-4o-mini"

    @start()
    def generate_city(self):
        print("Starting flow")
        # Each flow state automatically gets a unique ID
        print(f"Flow State ID: {self.state['id']}")

        response = completion(
            model=self.model,
            messages=[
                {
                    "role": "user",
                    "content": "Return the name of a random city in the world.",
                },
            ],
        )

        random_city = response["choices"][0]["message"]["content"]
        # Store the city in our state
        self.state["city"] = random_city
        print(f"Random City: {random_city}")

        return random_city

    @listen(generate_city)
    def generate_fun_fact(self, random_city):
        response = completion(
            model=self.model,
            messages=[
                {
                    "role": "user",
                    "content": f"Tell me a fun fact about {random_city}",
                },
            ],
        )

        fun_fact = response["choices"][0]["message"]["content"]
        # Store the fun fact in our state
        self.state["fun_fact"] = fun_fact
        return fun_fact



flow = ExampleFlow()
flow.plot()
result = flow.kickoff()

print(f"Generated fun fact: {result}")
```

<img alt="Flow Visual image" />

In the above example, we have created a simple Flow that generates a random city using OpenAI and then generates a fun fact about that city. The Flow consists of two tasks: `generate_city` and `generate_fun_fact`. The `generate_city` task is the starting point of the Flow, and the `generate_fun_fact` task listens for the output of the `generate_city` task.

Each Flow instance automatically receives a unique identifier (UUID) in its state, which helps track and manage flow executions. The state can also store additional data (like the generated city and fun fact) that persists throughout the flow's execution.

When you run the Flow, it will:

1. Generate a unique ID for the flow state
2. Generate a random city and store it in the state
3. Generate a fun fact about that city and store it in the state
4. Print the results to the console

The state's unique ID and stored data can be useful for tracking flow executions and maintaining context between tasks.

**Note:** Ensure you have set up your `.env` file to store your `OPENAI_API_KEY`. This key is necessary for authenticating requests to the OpenAI API.

### @start()

The `@start()` decorator marks entry points for a Flow. You can:

* Declare multiple unconditional starts: `@start()`
* Gate a start on a prior method or router label: `@start("method_or_label")`
* Provide a callable condition to control when a start should fire

All satisfied `@start()` methods will execute (often in parallel) when the Flow begins or resumes.

### @listen()

The `@listen()` decorator is used to mark a method as a listener for the output of another task in the Flow. The method decorated with `@listen()` will be executed when the specified task emits an output. The method can access the output of the task it is listening to as an argument.

#### Usage

The `@listen()` decorator can be used in several ways:

1. **Listening to a Method by Name**: You can pass the name of the method you want to listen to as a string. When that method completes, the listener method will be triggered.

   ```python Code theme={null}
   @listen("generate_city")
   def generate_fun_fact(self, random_city):
       # Implementation
   ```

2. **Listening to a Method Directly**: You can pass the method itself. When that method completes, the listener method will be triggered.
   ```python Code theme={null}
   @listen(generate_city)
   def generate_fun_fact(self, random_city):
       # Implementation
   ```

### Flow Output

Accessing and handling the output of a Flow is essential for integrating your AI workflows into larger applications or systems. CrewAI Flows provide straightforward mechanisms to retrieve the final output, access intermediate results, and manage the overall state of your Flow.

#### Retrieving the Final Output

When you run a Flow, the final output is determined by the last method that completes. The `kickoff()` method returns the output of this final method.

Here's how you can access the final output:

<CodeGroup>
  ```python Code theme={null}
  from crewai.flow.flow import Flow, listen, start

  class OutputExampleFlow(Flow):
      @start()
      def first_method(self):
          return "Output from first_method"

      @listen(first_method)
      def second_method(self, first_output):
          return f"Second method received: {first_output}"


  flow = OutputExampleFlow()
  flow.plot("my_flow_plot")
  final_output = flow.kickoff()

  print("---- Final Output ----")
  print(final_output)
  ```

  ```text Output theme={null}
  ---- Final Output ----
  Second method received: Output from first_method
  ```
</CodeGroup>

<img alt="Flow Visual image" />

In this example, the `second_method` is the last method to complete, so its output will be the final output of the Flow.
The `kickoff()` method will return the final output, which is then printed to the console. The `plot()` method will generate the HTML file, which will help you understand the flow.

#### Accessing and Updating State

In addition to retrieving the final output, you can also access and update the state within your Flow. The state can be used to store and share data between different methods in the Flow. After the Flow has run, you can access the state to retrieve any information that was added or updated during the execution.

Here's an example of how to update and access the state:

<CodeGroup>
  ```python Code theme={null}
  from crewai.flow.flow import Flow, listen, start
  from pydantic import BaseModel

  class ExampleState(BaseModel):
      counter: int = 0
      message: str = ""

  class StateExampleFlow(Flow[ExampleState]):

      @start()
      def first_method(self):
          self.state.message = "Hello from first_method"
          self.state.counter += 1

      @listen(first_method)
      def second_method(self):
          self.state.message += " - updated by second_method"
          self.state.counter += 1
          return self.state.message

  flow = StateExampleFlow()
  flow.plot("my_flow_plot")
  final_output = flow.kickoff()
  print(f"Final Output: {final_output}")
  print("Final State:")
  print(flow.state)
  ```

  ```text Output theme={null}
  Final Output: Hello from first_method - updated by second_method
  Final State:
  counter=2 message='Hello from first_method - updated by second_method'
  ```
</CodeGroup>

<img alt="Flow Visual image" />

In this example, the state is updated by both `first_method` and `second_method`.
After the Flow has run, you can access the final state to see the updates made by these methods.

By ensuring that the final method's output is returned and providing access to the state, CrewAI Flows make it easy to integrate the results of your AI workflows into larger applications or systems,
while also maintaining and accessing the state throughout the Flow's execution.

## Flow State Management

Managing state effectively is crucial for building reliable and maintainable AI workflows. CrewAI Flows provides robust mechanisms for both unstructured and structured state management,
allowing developers to choose the approach that best fits their application's needs.

### Unstructured State Management

In unstructured state management, all state is stored in the `state` attribute of the `Flow` class.
This approach offers flexibility, enabling developers to add or modify state attributes on the fly without defining a strict schema.
Even with unstructured states, CrewAI Flows automatically generates and maintains a unique identifier (UUID) for each state instance.

```python Code theme={null}
from crewai.flow.flow import Flow, listen, start

class UnstructuredExampleFlow(Flow):

    @start()
    def first_method(self):
        # The state automatically includes an 'id' field
        print(f"State ID: {self.state['id']}")
        self.state['counter'] = 0
        self.state['message'] = "Hello from structured flow"

    @listen(first_method)
    def second_method(self):
        self.state['counter'] += 1
        self.state['message'] += " - updated"

    @listen(second_method)
    def third_method(self):
        self.state['counter'] += 1
        self.state['message'] += " - updated again"

        print(f"State after third_method: {self.state}")


flow = UnstructuredExampleFlow()
flow.plot("my_flow_plot")
flow.kickoff()
```

<img alt="Flow Visual image" />

**Note:** The `id` field is automatically generated and preserved throughout the flow's execution. You don't need to manage or set it manually, and it will be maintained even when updating the state with new data.

**Key Points:**

* **Flexibility:** You can dynamically add attributes to `self.state` without predefined constraints.
* **Simplicity:** Ideal for straightforward workflows where state structure is minimal or varies significantly.

### Structured State Management

Structured state management leverages predefined schemas to ensure consistency and type safety across the workflow.
By using models like Pydantic's `BaseModel`, developers can define the exact shape of the state, enabling better validation and auto-completion in development environments.

Each state in CrewAI Flows automatically receives a unique identifier (UUID) to help track and manage state instances. This ID is automatically generated and managed by the Flow system.

```python Code theme={null}
from crewai.flow.flow import Flow, listen, start
from pydantic import BaseModel


class ExampleState(BaseModel):
    # Note: 'id' field is automatically added to all states
    counter: int = 0
    message: str = ""


class StructuredExampleFlow(Flow[ExampleState]):

    @start()
    def first_method(self):
        # Access the auto-generated ID if needed
        print(f"State ID: {self.state.id}")
        self.state.message = "Hello from structured flow"

    @listen(first_method)
    def second_method(self):
        self.state.counter += 1
        self.state.message += " - updated"

    @listen(second_method)
    def third_method(self):
        self.state.counter += 1
        self.state.message += " - updated again"

        print(f"State after third_method: {self.state}")


flow = StructuredExampleFlow()
flow.kickoff()
```

<img alt="Flow Visual image" />

**Key Points:**

* **Defined Schema:** `ExampleState` clearly outlines the state structure, enhancing code readability and maintainability.
* **Type Safety:** Leveraging Pydantic ensures that state attributes adhere to the specified types, reducing runtime errors.
* **Auto-Completion:** IDEs can provide better auto-completion and error checking based on the defined state model.

### Choosing Between Unstructured and Structured State Management

* **Use Unstructured State Management when:**

  * The workflow's state is simple or highly dynamic.
  * Flexibility is prioritized over strict state definitions.
  * Rapid prototyping is required without the overhead of defining schemas.

* **Use Structured State Management when:**
  * The workflow requires a well-defined and consistent state structure.
  * Type safety and validation are important for your application's reliability.
  * You want to leverage IDE features like auto-completion and type checking for better developer experience.

By providing both unstructured and structured state management options, CrewAI Flows empowers developers to build AI workflows that are both flexible and robust, catering to a wide range of application requirements.

## Flow Persistence

The @persist decorator enables automatic state persistence in CrewAI Flows, allowing you to maintain flow state across restarts or different workflow executions. This decorator can be applied at either the class level or method level, providing flexibility in how you manage state persistence.

### Class-Level Persistence

When applied at the class level, the @persist decorator automatically persists all flow method states:

```python theme={null}
@persist  # Using SQLiteFlowPersistence by default
class MyFlow(Flow[MyState]):
    @start()
    def initialize_flow(self):
        # This method will automatically have its state persisted
        self.state.counter = 1
        print("Initialized flow. State ID:", self.state.id)

    @listen(initialize_flow)
    def next_step(self):
        # The state (including self.state.id) is automatically reloaded
        self.state.counter += 1
        print("Flow state is persisted. Counter:", self.state.counter)
```

### Method-Level Persistence

For more granular control, you can apply @persist to specific methods:

```python theme={null}
class AnotherFlow(Flow[dict]):
    @persist  # Persists only this method's state
    @start()
    def begin(self):
        if "runs" not in self.state:
            self.state["runs"] = 0
        self.state["runs"] += 1
        print("Method-level persisted runs:", self.state["runs"])
```

### How It Works

1. **Unique State Identification**
   * Each flow state automatically receives a unique UUID
   * The ID is preserved across state updates and method calls
   * Supports both structured (Pydantic BaseModel) and unstructured (dictionary) states

2. **Default SQLite Backend**
   * SQLiteFlowPersistence is the default storage backend
   * States are automatically saved to a local SQLite database
   * Robust error handling ensures clear messages if database operations fail

3. **Error Handling**
   * Comprehensive error messages for database operations
   * Automatic state validation during save and load
   * Clear feedback when persistence operations encounter issues

### Important Considerations

* **State Types**: Both structured (Pydantic BaseModel) and unstructured (dictionary) states are supported
* **Automatic ID**: The `id` field is automatically added if not present
* **State Recovery**: Failed or restarted flows can automatically reload their previous state
* **Custom Implementation**: You can provide your own FlowPersistence implementation for specialized storage needs

### Technical Advantages

1. **Precise Control Through Low-Level Access**
   * Direct access to persistence operations for advanced use cases
   * Fine-grained control via method-level persistence decorators
   * Built-in state inspection and debugging capabilities
   * Full visibility into state changes and persistence operations

2. **Enhanced Reliability**
   * Automatic state recovery after system failures or restarts
   * Transaction-based state updates for data integrity
   * Comprehensive error handling with clear error messages
   * Robust validation during state save and load operations

3. **Extensible Architecture**
   * Customizable persistence backend through FlowPersistence interface
   * Support for specialized storage solutions beyond SQLite
   * Compatible with both structured (Pydantic) and unstructured (dict) states
   * Seamless integration with existing CrewAI flow patterns

The persistence system's architecture emphasizes technical precision and customization options, allowing developers to maintain full control over state management while benefiting from built-in reliability features.

## Flow Control

### Conditional Logic: `or`

The `or_` function in Flows allows you to listen to multiple methods and trigger the listener method when any of the specified methods emit an output.

<CodeGroup>
  ```python Code theme={null}
  from crewai.flow.flow import Flow, listen, or_, start

  class OrExampleFlow(Flow):

      @start()
      def start_method(self):
          return "Hello from the start method"

      @listen(start_method)
      def second_method(self):
          return "Hello from the second method"

      @listen(or_(start_method, second_method))
      def logger(self, result):
          print(f"Logger: {result}")



  flow = OrExampleFlow()
  flow.plot("my_flow_plot")
  flow.kickoff()
  ```

  ```text Output theme={null}
  Logger: Hello from the start method
  Logger: Hello from the second method
  ```
</CodeGroup>

<img alt="Flow Visual image" />

When you run this Flow, the `logger` method will be triggered by the output of either the `start_method` or the `second_method`.
The `or_` function is used to listen to multiple methods and trigger the listener method when any of the specified methods emit an output.

### Conditional Logic: `and`

The `and_` function in Flows allows you to listen to multiple methods and trigger the listener method only when all the specified methods emit an output.

<CodeGroup>
  ```python Code theme={null}
  from crewai.flow.flow import Flow, and_, listen, start

  class AndExampleFlow(Flow):

      @start()
      def start_method(self):
          self.state["greeting"] = "Hello from the start method"

      @listen(start_method)
      def second_method(self):
          self.state["joke"] = "What do computers eat? Microchips."

      @listen(and_(start_method, second_method))
      def logger(self):
          print("---- Logger ----")
          print(self.state)

  flow = AndExampleFlow()
  flow.plot()
  flow.kickoff()
  ```

  ```text Output theme={null}
  ---- Logger ----
  {'greeting': 'Hello from the start method', 'joke': 'What do computers eat? Microchips.'}
  ```
</CodeGroup>

<img alt="Flow Visual image" />

When you run this Flow, the `logger` method will be triggered only when both the `start_method` and the `second_method` emit an output.
The `and_` function is used to listen to multiple methods and trigger the listener method only when all the specified methods emit an output.

### Router

The `@router()` decorator in Flows allows you to define conditional routing logic based on the output of a method.
You can specify different routes based on the output of the method, allowing you to control the flow of execution dynamically.

<CodeGroup>
  ```python Code theme={null}
  import random
  from crewai.flow.flow import Flow, listen, router, start
  from pydantic import BaseModel

  class ExampleState(BaseModel):
      success_flag: bool = False

  class RouterFlow(Flow[ExampleState]):

      @start()
      def start_method(self):
          print("Starting the structured flow")
          random_boolean = random.choice([True, False])
          self.state.success_flag = random_boolean

      @router(start_method)
      def second_method(self):
          if self.state.success_flag:
              return "success"
          else:
              return "failed"

      @listen("success")
      def third_method(self):
          print("Third method running")

      @listen("failed")
      def fourth_method(self):
          print("Fourth method running")


  flow = RouterFlow()
  flow.plot("my_flow_plot")
  flow.kickoff()
  ```

  ```text Output theme={null}
  Starting the structured flow
  Third method running
  Fourth method running
  ```
</CodeGroup>

<img alt="Flow Visual image" />

In the above example, the `start_method` generates a random boolean value and sets it in the state.
The `second_method` uses the `@router()` decorator to define conditional routing logic based on the value of the boolean.
If the boolean is `True`, the method returns `"success"`, and if it is `False`, the method returns `"failed"`.
The `third_method` and `fourth_method` listen to the output of the `second_method` and execute based on the returned value.

When you run this Flow, the output will change based on the random boolean value generated by the `start_method`.

### Human in the Loop (human feedback)

<Note>
  The `@human_feedback` decorator requires **CrewAI version 1.8.0 or higher**.
</Note>

The `@human_feedback` decorator enables human-in-the-loop workflows by pausing flow execution to collect feedback from a human. This is useful for approval gates, quality review, and decision points that require human judgment.

```python Code theme={null}
from crewai.flow.flow import Flow, start, listen
from crewai.flow.human_feedback import human_feedback, HumanFeedbackResult

class ReviewFlow(Flow):
    @start()
    @human_feedback(
        message="Do you approve this content?",
        emit=["approved", "rejected", "needs_revision"],
        llm="gpt-4o-mini",
        default_outcome="needs_revision",
    )
    def generate_content(self):
        return "Content to be reviewed..."

    @listen("approved")
    def on_approval(self, result: HumanFeedbackResult):
        print(f"Approved! Feedback: {result.feedback}")

    @listen("rejected")
    def on_rejection(self, result: HumanFeedbackResult):
        print(f"Rejected. Reason: {result.feedback}")
```

When `emit` is specified, the human's free-form feedback is interpreted by an LLM and collapsed into one of the specified outcomes, which then triggers the corresponding `@listen` decorator.

You can also use `@human_feedback` without routing to simply collect feedback:

```python Code theme={null}
@start()
@human_feedback(message="Any comments on this output?")
def my_method(self):
    return "Output for review"

@listen(my_method)
def next_step(self, result: HumanFeedbackResult):
    # Access feedback via result.feedback
    # Access original output via result.output
    pass
```

Access all feedback collected during a flow via `self.last_human_feedback` (most recent) or `self.human_feedback_history` (all feedback as a list).

For a complete guide on human feedback in flows, including **async/non-blocking feedback** with custom providers (Slack, webhooks, etc.), see [Human Feedback in Flows](/en/learn/human-feedback-in-flows).

## Adding Agents to Flows

Agents can be seamlessly integrated into your flows, providing a lightweight alternative to full Crews when you need simpler, focused task execution. Here's an example of how to use an Agent within a flow to perform market research:

```python theme={null}
import asyncio
from typing import Any, Dict, List

from crewai_tools import SerperDevTool
from pydantic import BaseModel, Field

from crewai.agent import Agent
from crewai.flow.flow import Flow, listen, start


# Define a structured output format
class MarketAnalysis(BaseModel):
    key_trends: List[str] = Field(description="List of identified market trends")
    market_size: str = Field(description="Estimated market size")
    competitors: List[str] = Field(description="Major competitors in the space")


# Define flow state
class MarketResearchState(BaseModel):
    product: str = ""
    analysis: MarketAnalysis | None = None


# Create a flow class
class MarketResearchFlow(Flow[MarketResearchState]):
    @start()
    def initialize_research(self) -> Dict[str, Any]:
        print(f"Starting market research for {self.state.product}")
        return {"product": self.state.product}

    @listen(initialize_research)
    async def analyze_market(self) -> Dict[str, Any]:
        # Create an Agent for market research
        analyst = Agent(
            role="Market Research Analyst",
            goal=f"Analyze the market for {self.state.product}",
            backstory="You are an experienced market analyst with expertise in "
            "identifying market trends and opportunities.",
            tools=[SerperDevTool()],
            verbose=True,
        )

        # Define the research query
        query = f"""
        Research the market for {self.state.product}. Include:
        1. Key market trends
        2. Market size
        3. Major competitors

        Format your response according to the specified structure.
        """

        # Execute the analysis with structured output format
        result = await analyst.kickoff_async(query, response_format=MarketAnalysis)
        if result.pydantic:
            print("result", result.pydantic)
        else:
            print("result", result)

        # Return the analysis to update the state
        return {"analysis": result.pydantic}

    @listen(analyze_market)
    def present_results(self, analysis) -> None:
        print("\nMarket Analysis Results")
        print("=====================")

        if isinstance(analysis, dict):
            # If we got a dict with 'analysis' key, extract the actual analysis object
            market_analysis = analysis.get("analysis")
        else:
            market_analysis = analysis

        if market_analysis and isinstance(market_analysis, MarketAnalysis):
            print("\nKey Market Trends:")
            for trend in market_analysis.key_trends:
                print(f"- {trend}")

            print(f"\nMarket Size: {market_analysis.market_size}")

            print("\nMajor Competitors:")
            for competitor in market_analysis.competitors:
                print(f"- {competitor}")
        else:
            print("No structured analysis data available.")
            print("Raw analysis:", analysis)


# Usage example
async def run_flow():
    flow = MarketResearchFlow()
    flow.plot("MarketResearchFlowPlot")
    result = await flow.kickoff_async(inputs={"product": "AI-powered chatbots"})
    return result


# Run the flow
if __name__ == "__main__":
    asyncio.run(run_flow())
```

<img alt="Flow Visual image" />

This example demonstrates several key features of using Agents in flows:

1. **Structured Output**: Using Pydantic models to define the expected output format (`MarketAnalysis`) ensures type safety and structured data throughout the flow.

2. **State Management**: The flow state (`MarketResearchState`) maintains context between steps and stores both inputs and outputs.

3. **Tool Integration**: Agents can use tools (like `WebsiteSearchTool`) to enhance their capabilities.

## Adding Crews to Flows

Creating a flow with multiple crews in CrewAI is straightforward.

You can generate a new CrewAI project that includes all the scaffolding needed to create a flow with multiple crews by running the following command:

```bash theme={null}
crewai create flow name_of_flow
```

This command will generate a new CrewAI project with the necessary folder structure. The generated project includes a prebuilt crew called `poem_crew` that is already working. You can use this crew as a template by copying, pasting, and editing it to create other crews.

### Folder Structure

After running the `crewai create flow name_of_flow` command, you will see a folder structure similar to the following:

| Directory/File         | Description                                                         |
| :--------------------- | :------------------------------------------------------------------ |
| `name_of_flow/`        | Root directory for the flow.                                        |
| ├── `crews/`           | Contains directories for specific crews.                            |
| │ └── `poem_crew/`     | Directory for the "poem\_crew" with its configurations and scripts. |
| │ ├── `config/`        | Configuration files directory for the "poem\_crew".                 |
| │ │ ├── `agents.yaml`  | YAML file defining the agents for "poem\_crew".                     |
| │ │ └── `tasks.yaml`   | YAML file defining the tasks for "poem\_crew".                      |
| │ ├── `poem_crew.py`   | Script for "poem\_crew" functionality.                              |
| ├── `tools/`           | Directory for additional tools used in the flow.                    |
| │ └── `custom_tool.py` | Custom tool implementation.                                         |
| ├── `main.py`          | Main script for running the flow.                                   |
| ├── `README.md`        | Project description and instructions.                               |
| ├── `pyproject.toml`   | Configuration file for project dependencies and settings.           |
| └── `.gitignore`       | Specifies files and directories to ignore in version control.       |

### Building Your Crews

In the `crews` folder, you can define multiple crews. Each crew will have its own folder containing configuration files and the crew definition file. For example, the `poem_crew` folder contains:

* `config/agents.yaml`: Defines the agents for the crew.
* `config/tasks.yaml`: Defines the tasks for the crew.
* `poem_crew.py`: Contains the crew definition, including agents, tasks, and the crew itself.

You can copy, paste, and edit the `poem_crew` to create other crews.

### Connecting Crews in `main.py`

The `main.py` file is where you create your flow and connect the crews together. You can define your flow by using the `Flow` class and the decorators `@start` and `@listen` to specify the flow of execution.

Here's an example of how you can connect the `poem_crew` in the `main.py` file:

```python Code theme={null}
#!/usr/bin/env python
from random import randint

from pydantic import BaseModel
from crewai.flow.flow import Flow, listen, start
from .crews.poem_crew.poem_crew import PoemCrew

class PoemState(BaseModel):
    sentence_count: int = 1
    poem: str = ""

class PoemFlow(Flow[PoemState]):

    @start()
    def generate_sentence_count(self):
        print("Generating sentence count")
        self.state.sentence_count = randint(1, 5)

    @listen(generate_sentence_count)
    def generate_poem(self):
        print("Generating poem")
        result = PoemCrew().crew().kickoff(inputs={"sentence_count": self.state.sentence_count})

        print("Poem generated", result.raw)
        self.state.poem = result.raw

    @listen(generate_poem)
    def save_poem(self):
        print("Saving poem")
        with open("poem.txt", "w") as f:
            f.write(self.state.poem)

def kickoff():
    poem_flow = PoemFlow()
    poem_flow.kickoff()


def plot():
    poem_flow = PoemFlow()
    poem_flow.plot("PoemFlowPlot")

if __name__ == "__main__":
    kickoff()
    plot()
```

In this example, the `PoemFlow` class defines a flow that generates a sentence count, uses the `PoemCrew` to generate a poem, and then saves the poem to a file. The flow is kicked off by calling the `kickoff()` method. The PoemFlowPlot will be generated by `plot()` method.

<img alt="Flow Visual image" />

### Running the Flow

(Optional) Before running the flow, you can install the dependencies by running:

```bash theme={null}
crewai install
```

Once all of the dependencies are installed, you need to activate the virtual environment by running:

```bash theme={null}
source .venv/bin/activate
```

After activating the virtual environment, you can run the flow by executing one of the following commands:

```bash theme={null}
crewai flow kickoff
```

or

```bash theme={null}
uv run kickoff
```

The flow will execute, and you should see the output in the console.

## Plot Flows

Visualizing your AI workflows can provide valuable insights into the structure and execution paths of your flows. CrewAI offers a powerful visualization tool that allows you to generate interactive plots of your flows, making it easier to understand and optimize your AI workflows.

### What are Plots?

Plots in CrewAI are graphical representations of your AI workflows. They display the various tasks, their connections, and the flow of data between them. This visualization helps in understanding the sequence of operations, identifying bottlenecks, and ensuring that the workflow logic aligns with your expectations.

### How to Generate a Plot

CrewAI provides two convenient methods to generate plots of your flows:

#### Option 1: Using the `plot()` Method

If you are working directly with a flow instance, you can generate a plot by calling the `plot()` method on your flow object. This method will create an HTML file containing the interactive plot of your flow.

```python Code theme={null}
# Assuming you have a flow instance
flow.plot("my_flow_plot")
```

This will generate a file named `my_flow_plot.html` in your current directory. You can open this file in a web browser to view the interactive plot.

#### Option 2: Using the Command Line

If you are working within a structured CrewAI project, you can generate a plot using the command line. This is particularly useful for larger projects where you want to visualize the entire flow setup.

```bash theme={null}
crewai flow plot
```

This command will generate an HTML file with the plot of your flow, similar to the `plot()` method. The file will be saved in your project directory, and you can open it in a web browser to explore the flow.

### Understanding the Plot

The generated plot will display nodes representing the tasks in your flow, with directed edges indicating the flow of execution. The plot is interactive, allowing you to zoom in and out, and hover over nodes to see additional details.

By visualizing your flows, you can gain a clearer understanding of the workflow's structure, making it easier to debug, optimize, and communicate your AI processes to others.

### Conclusion

Plotting your flows is a powerful feature of CrewAI that enhances your ability to design and manage complex AI workflows. Whether you choose to use the `plot()` method or the command line, generating plots will provide you with a visual representation of your workflows, aiding in both development and presentation.

## Next Steps

If you're interested in exploring additional examples of flows, we have a variety of recommendations in our examples repository. Here are four specific flow examples, each showcasing unique use cases to help you match your current problem type to a specific example:

1. **Email Auto Responder Flow**: This example demonstrates an infinite loop where a background job continually runs to automate email responses. It's a great use case for tasks that need to be performed repeatedly without manual intervention. [View Example](https://github.com/crewAIInc/crewAI-examples/tree/main/email_auto_responder_flow)

2. **Lead Score Flow**: This flow showcases adding human-in-the-loop feedback and handling different conditional branches using the router. It's an excellent example of how to incorporate dynamic decision-making and human oversight into your workflows. [View Example](https://github.com/crewAIInc/crewAI-examples/tree/main/lead-score-flow)

3. **Write a Book Flow**: This example excels at chaining multiple crews together, where the output of one crew is used by another. Specifically, one crew outlines an entire book, and another crew generates chapters based on the outline. Eventually, everything is connected to produce a complete book. This flow is perfect for complex, multi-step processes that require coordination between different tasks. [View Example](https://github.com/crewAIInc/crewAI-examples/tree/main/write_a_book_with_flows)

4. **Meeting Assistant Flow**: This flow demonstrates how to broadcast one event to trigger multiple follow-up actions. For instance, after a meeting is completed, the flow can update a Trello board, send a Slack message, and save the results. It's a great example of handling multiple outcomes from a single event, making it ideal for comprehensive task management and notification systems. [View Example](https://github.com/crewAIInc/crewAI-examples/tree/main/meeting_assistant_flow)

By exploring these examples, you can gain insights into how to leverage CrewAI Flows for various use cases, from automating repetitive tasks to managing complex, multi-step processes with dynamic decision-making and human feedback.

Also, check out our YouTube video on how to use flows in CrewAI below!

<iframe title="CrewAI Flows overview" />

## Running Flows

There are two ways to run a flow:

### Using the Flow API

You can run a flow programmatically by creating an instance of your flow class and calling the `kickoff()` method:

```python theme={null}
flow = ExampleFlow()
result = flow.kickoff()
```

### Streaming Flow Execution

For real-time visibility into flow execution, you can enable streaming to receive output as it's generated:

```python theme={null}
class StreamingFlow(Flow):
    stream = True  # Enable streaming

    @start()
    def research(self):
        # Your flow implementation
        pass

# Iterate over streaming output
flow = StreamingFlow()
streaming = flow.kickoff()
for chunk in streaming:
    print(chunk.content, end="", flush=True)

# Access final result
result = streaming.result
```

Learn more about streaming in the [Streaming Flow Execution](/en/learn/streaming-flow-execution) guide.

## Memory in Flows

Every Flow automatically has access to CrewAI's unified [Memory](/concepts/memory) system. You can store, recall, and extract memories directly inside any flow method using three built-in convenience methods.

### Built-in Methods

| Method                             | Description                                                                                |
| :--------------------------------- | :----------------------------------------------------------------------------------------- |
| `self.remember(content, **kwargs)` | Store content in memory. Accepts optional `scope`, `categories`, `metadata`, `importance`. |
| `self.recall(query, **kwargs)`     | Retrieve relevant memories. Accepts optional `scope`, `categories`, `limit`, `depth`.      |
| `self.extract_memories(content)`   | Break raw text into discrete, self-contained memory statements.                            |

A default `Memory()` instance is created automatically when the Flow initializes. You can also pass a custom one:

```python theme={null}
from crewai.flow.flow import Flow
from crewai import Memory

custom_memory = Memory(
    recency_weight=0.5,
    recency_half_life_days=7,
    embedder={"provider": "ollama", "config": {"model_name": "mxbai-embed-large"}},
)

flow = MyFlow(memory=custom_memory)
```

### Example: Research and Analyze Flow

```python theme={null}
from crewai.flow.flow import Flow, listen, start


class ResearchAnalysisFlow(Flow):
    @start()
    def gather_data(self):
        # Simulate research findings
        findings = (
            "PostgreSQL handles 10k concurrent connections with connection pooling. "
            "MySQL caps at around 5k. MongoDB scales horizontally but adds complexity."
        )

        # Extract atomic facts and remember each one
        memories = self.extract_memories(findings)
        for mem in memories:
            self.remember(mem, scope="/research/databases")

        return findings

    @listen(gather_data)
    def analyze(self, raw_findings):
        # Recall relevant past research (from this run or previous runs)
        past = self.recall("database performance and scaling", limit=10, depth="shallow")

        context_lines = [f"- {m.record.content}" for m in past]
        context = "\n".join(context_lines) if context_lines else "No prior context."

        return {
            "new_findings": raw_findings,
            "prior_context": context,
            "total_memories": len(past),
        }


flow = ResearchAnalysisFlow()
result = flow.kickoff()
print(result)
```

Because memory persists across runs (backed by LanceDB on disk), the `analyze` step will recall findings from previous executions too -- enabling flows that learn and accumulate knowledge over time.

See the [Memory documentation](/concepts/memory) for details on scopes, slices, composite scoring, embedder configuration, and more.

### Using the CLI

Starting from version 0.103.0, you can run flows using the `crewai run` command:

```shell theme={null}
crewai run
```

This command automatically detects if your project is a flow (based on the `type = "flow"` setting in your pyproject.toml) and runs it accordingly. This is the recommended way to run flows from the command line.

For backward compatibility, you can also use:

```shell theme={null}
crewai flow kickoff
```

However, the `crewai run` command is now the preferred method as it works for both crews and flows.


# Knowledge
Source: https://docs.crewai.com/en/concepts/knowledge

What is knowledge in CrewAI and how to use it.

## Overview

Knowledge in CrewAI is a powerful system that allows AI agents to access and utilize external information sources during their tasks.
Think of it as giving your agents a reference library they can consult while working.

<Info>
  Key benefits of using Knowledge:

  * Enhance agents with domain-specific information
  * Support decisions with real-world data
  * Maintain context across conversations
  * Ground responses in factual information
</Info>

## Quickstart Examples

<Tip>
  For file-based Knowledge Sources, make sure to place your files in a `knowledge` directory at the root of your project.
  Also, use relative paths from the `knowledge` directory when creating the source.
</Tip>

### Vector store (RAG) client configuration

CrewAI exposes a provider-neutral RAG client abstraction for vector stores. The default provider is ChromaDB, and Qdrant is supported as well. You can switch providers using configuration utilities.

Supported today:

* ChromaDB (default)
* Qdrant

```python Code theme={null}
from crewai.rag.config.utils import set_rag_config, get_rag_client, clear_rag_config

# ChromaDB (default)
from crewai.rag.chromadb.config import ChromaDBConfig
set_rag_config(ChromaDBConfig())
chromadb_client = get_rag_client()

# Qdrant
from crewai.rag.qdrant.config import QdrantConfig
set_rag_config(QdrantConfig())
qdrant_client = get_rag_client()

# Example operations (same API for any provider)
client = qdrant_client  # or chromadb_client
client.create_collection(collection_name="docs")
client.add_documents(
    collection_name="docs",
    documents=[{"id": "1", "content": "CrewAI enables collaborative AI agents."}],
)
results = client.search(collection_name="docs", query="collaborative agents", limit=3)

clear_rag_config()  # optional reset
```

This RAG client is separate from Knowledge’s built-in storage. Use it when you need direct vector-store control or custom retrieval pipelines.

### Basic String Knowledge Example

```python Code theme={null}
from crewai import Agent, Task, Crew, Process, LLM
from crewai.knowledge.source.string_knowledge_source import StringKnowledgeSource

# Create a knowledge source
content = "Users name is John. He is 30 years old and lives in San Francisco."
string_source = StringKnowledgeSource(content=content)

# Create an LLM with a temperature of 0 to ensure deterministic outputs
llm = LLM(model="gpt-4o-mini", temperature=0)

# Create an agent with the knowledge store
agent = Agent(
    role="About User",
    goal="You know everything about the user.",
    backstory="You are a master at understanding people and their preferences.",
    verbose=True,
    allow_delegation=False,
    llm=llm,
)

task = Task(
    description="Answer the following questions about the user: {question}",
    expected_output="An answer to the question.",
    agent=agent,
)

crew = Crew(
    agents=[agent],
    tasks=[task],
    verbose=True,
    process=Process.sequential,
    knowledge_sources=[string_source], # Enable knowledge by adding the sources here
)

result = crew.kickoff(inputs={"question": "What city does John live in and how old is he?"})
```

### Web Content Knowledge Example

<Note>
  You need to install `docling` for the following example to work: `uv add docling`
</Note>

```python Code theme={null}
from crewai import LLM, Agent, Crew, Process, Task
from crewai.knowledge.source.crew_docling_source import CrewDoclingSource

# Create a knowledge source from web content
content_source = CrewDoclingSource(
    file_paths=[
        "https://lilianweng.github.io/posts/2024-11-28-reward-hacking",
        "https://lilianweng.github.io/posts/2024-07-07-hallucination",
    ],
)

# Create an LLM with a temperature of 0 to ensure deterministic outputs
llm = LLM(model="gpt-4o-mini", temperature=0)

# Create an agent with the knowledge store
agent = Agent(
    role="About papers",
    goal="You know everything about the papers.",
    backstory="You are a master at understanding papers and their content.",
    verbose=True,
    allow_delegation=False,
    llm=llm,
)

task = Task(
    description="Answer the following questions about the papers: {question}",
    expected_output="An answer to the question.",
    agent=agent,
)

crew = Crew(
    agents=[agent],
    tasks=[task],
    verbose=True,
    process=Process.sequential,
    knowledge_sources=[content_source],
)

result = crew.kickoff(
    inputs={"question": "What is the reward hacking paper about? Be sure to provide sources."}
)
```

## Supported Knowledge Sources

CrewAI supports various types of knowledge sources out of the box:

<CardGroup>
  <Card title="Text Sources" icon="text">
    * Raw strings
    * Text files (.txt)
    * PDF documents
  </Card>

  <Card title="Structured Data" icon="table">
    * CSV files
    * Excel spreadsheets
    * JSON documents
  </Card>
</CardGroup>

### Text File Knowledge Source

```python theme={null}
from crewai.knowledge.source.text_file_knowledge_source import TextFileKnowledgeSource

text_source = TextFileKnowledgeSource(
    file_paths=["document.txt", "another.txt"]
)
```

### PDF Knowledge Source

```python theme={null}
from crewai.knowledge.source.pdf_knowledge_source import PDFKnowledgeSource

pdf_source = PDFKnowledgeSource(
    file_paths=["document.pdf", "another.pdf"]
)
```

### CSV Knowledge Source

```python theme={null}
from crewai.knowledge.source.csv_knowledge_source import CSVKnowledgeSource

csv_source = CSVKnowledgeSource(
    file_paths=["data.csv"]
)
```

### Excel Knowledge Source

```python theme={null}
from crewai.knowledge.source.excel_knowledge_source import ExcelKnowledgeSource

excel_source = ExcelKnowledgeSource(
    file_paths=["spreadsheet.xlsx"]
)
```

### JSON Knowledge Source

```python theme={null}
from crewai.knowledge.source.json_knowledge_source import JSONKnowledgeSource

json_source = JSONKnowledgeSource(
    file_paths=["data.json"]
)
```

<Note>
  Please ensure that you create the ./knowledge folder. All source files (e.g., .txt, .pdf, .xlsx, .json) should be placed in this folder for centralized management.
</Note>

## Agent vs Crew Knowledge: Complete Guide

<Info>
  **Understanding Knowledge Levels**: CrewAI supports knowledge at both agent and crew levels. This section clarifies exactly how each works, when they're initialized, and addresses common misconceptions about dependencies.
</Info>

### How Knowledge Initialization Actually Works

Here's exactly what happens when you use knowledge:

#### Agent-Level Knowledge (Independent)

```python theme={null}
from crewai import Agent, Task, Crew
from crewai.knowledge.source.string_knowledge_source import StringKnowledgeSource

# Agent with its own knowledge - NO crew knowledge needed
specialist_knowledge = StringKnowledgeSource(
    content="Specialized technical information for this agent only"
)

specialist_agent = Agent(
    role="Technical Specialist",
    goal="Provide technical expertise",
    backstory="Expert in specialized technical domains",
    knowledge_sources=[specialist_knowledge]  # Agent-specific knowledge
)

task = Task(
    description="Answer technical questions",
    agent=specialist_agent,
    expected_output="Technical answer"
)

# No crew-level knowledge required
crew = Crew(
    agents=[specialist_agent],
    tasks=[task]
)

result = crew.kickoff()  # Agent knowledge works independently
```

#### What Happens During `crew.kickoff()`

When you call `crew.kickoff()`, here's the exact sequence:

```python theme={null}
# During kickoff
for agent in self.agents:
    agent.crew = self  # Agent gets reference to crew
    agent.set_knowledge(crew_embedder=self.embedder)  # Agent knowledge initialized
    agent.create_agent_executor()
```

#### Storage Independence

Each knowledge level uses independent storage collections:

```python theme={null}
# Agent knowledge storage
agent_collection_name = agent.role  # e.g., "Technical Specialist"

# Crew knowledge storage  
crew_collection_name = "crew"

# Both stored in same ChromaDB instance but different collections
# Path: ~/.local/share/CrewAI/{project}/knowledge/
#   ├── crew/                    # Crew knowledge collection
#   ├── Technical Specialist/    # Agent knowledge collection
#   └── Another Agent Role/      # Another agent's collection
```

### Complete Working Examples

#### Example 1: Agent-Only Knowledge

```python theme={null}
from crewai import Agent, Task, Crew
from crewai.knowledge.source.string_knowledge_source import StringKnowledgeSource

# Agent-specific knowledge
agent_knowledge = StringKnowledgeSource(
    content="Agent-specific information that only this agent needs"
)

agent = Agent(
    role="Specialist",
    goal="Use specialized knowledge",
    backstory="Expert with specific knowledge",
    knowledge_sources=[agent_knowledge],
    embedder={  # Agent can have its own embedder
        "provider": "openai",
        "config": {"model": "text-embedding-3-small"}
    }
)

task = Task(
    description="Answer using your specialized knowledge",
    agent=agent,
    expected_output="Answer based on agent knowledge"
)

# No crew knowledge needed
crew = Crew(agents=[agent], tasks=[task])
result = crew.kickoff()  # Works perfectly
```

#### Example 2: Both Agent and Crew Knowledge

```python theme={null}
# Crew-wide knowledge (shared by all agents)
crew_knowledge = StringKnowledgeSource(
    content="Company policies and general information for all agents"
)

# Agent-specific knowledge
specialist_knowledge = StringKnowledgeSource(
    content="Technical specifications only the specialist needs"
)

specialist = Agent(
    role="Technical Specialist",
    goal="Provide technical expertise",
    backstory="Technical expert",
    knowledge_sources=[specialist_knowledge]  # Agent-specific
)

generalist = Agent(
    role="General Assistant", 
    goal="Provide general assistance",
    backstory="General helper"
    # No agent-specific knowledge
)

crew = Crew(
    agents=[specialist, generalist],
    tasks=[...],
    knowledge_sources=[crew_knowledge]  # Crew-wide knowledge
)

# Result:
# - specialist gets: crew_knowledge + specialist_knowledge
# - generalist gets: crew_knowledge only
```

#### Example 3: Multiple Agents with Different Knowledge

```python theme={null}
# Different knowledge for different agents
sales_knowledge = StringKnowledgeSource(content="Sales procedures and pricing")
tech_knowledge = StringKnowledgeSource(content="Technical documentation")
support_knowledge = StringKnowledgeSource(content="Support procedures")

sales_agent = Agent(
    role="Sales Representative",
    knowledge_sources=[sales_knowledge],
    embedder={"provider": "openai", "config": {"model": "text-embedding-3-small"}}
)

tech_agent = Agent(
    role="Technical Expert", 
    knowledge_sources=[tech_knowledge],
    embedder={"provider": "ollama", "config": {"model": "mxbai-embed-large"}}
)

support_agent = Agent(
    role="Support Specialist",
    knowledge_sources=[support_knowledge]
    # Will use crew embedder as fallback
)

crew = Crew(
    agents=[sales_agent, tech_agent, support_agent],
    tasks=[...],
    embedder={  # Fallback embedder for agents without their own
        "provider": "google-generativeai",
        "config": {"model_name": "gemini-embedding-001"}
    }
)

# Each agent gets only their specific knowledge
# Each can use different embedding providers
```

<Tip>
  Unlike retrieval from a vector database using a tool, agents preloaded with knowledge will not need a retrieval persona or task.
  Simply add the relevant knowledge sources your agent or crew needs to function.

  Knowledge sources can be added at the agent or crew level.
  Crew level knowledge sources will be used by **all agents** in the crew.
  Agent level knowledge sources will be used by the **specific agent** that is preloaded with the knowledge.
</Tip>

## Knowledge Configuration

You can configure the knowledge configuration for the crew or agent.

```python Code theme={null}
from crewai.knowledge.knowledge_config import KnowledgeConfig

knowledge_config = KnowledgeConfig(results_limit=10, score_threshold=0.5)

agent = Agent(
    ...
    knowledge_config=knowledge_config
)
```

<Tip>
  `results_limit`: is the number of relevant documents to return. Default is 3.
  `score_threshold`: is the minimum score for a document to be considered relevant. Default is 0.35.
</Tip>

## Supported Knowledge Parameters

<ParamField type="List[BaseKnowledgeSource]">
  List of knowledge sources that provide content to be stored and queried. Can include PDF, CSV, Excel, JSON, text files, or string content.
</ParamField>

<ParamField type="str">
  Name of the collection where the knowledge will be stored. Used to identify different sets of knowledge. Defaults to "knowledge" if not provided.
</ParamField>

<ParamField type="Optional[KnowledgeStorage]">
  Custom storage configuration for managing how the knowledge is stored and retrieved. If not provided, a default storage will be created.
</ParamField>

## Knowledge Storage Transparency

<Info>
  **Understanding Knowledge Storage**: CrewAI automatically stores knowledge sources in platform-specific directories using ChromaDB for vector storage. Understanding these locations and defaults helps with production deployments, debugging, and storage management.
</Info>

### Where CrewAI Stores Knowledge Files

By default, CrewAI uses the same storage system as memory, storing knowledge in platform-specific directories:

#### Default Storage Locations by Platform

**macOS:**

```
~/Library/Application Support/CrewAI/{project_name}/
└── knowledge/                    # Knowledge ChromaDB files
    ├── chroma.sqlite3           # ChromaDB metadata
    ├── {collection_id}/         # Vector embeddings
    └── knowledge_{collection}/  # Named collections
```

**Linux:**

```
~/.local/share/CrewAI/{project_name}/
└── knowledge/
    ├── chroma.sqlite3
    ├── {collection_id}/
    └── knowledge_{collection}/
```

**Windows:**

```
C:\Users\{username}\AppData\Local\CrewAI\{project_name}\
└── knowledge\
    ├── chroma.sqlite3
    ├── {collection_id}\
    └── knowledge_{collection}\
```

### Finding Your Knowledge Storage Location

To see exactly where CrewAI is storing your knowledge files:

```python theme={null}
from crewai.utilities.paths import db_storage_path
import os

# Get the knowledge storage path
knowledge_path = os.path.join(db_storage_path(), "knowledge")
print(f"Knowledge storage location: {knowledge_path}")

# List knowledge collections and files
if os.path.exists(knowledge_path):
    print("\nKnowledge storage contents:")
    for item in os.listdir(knowledge_path):
        item_path = os.path.join(knowledge_path, item)
        if os.path.isdir(item_path):
            print(f"📁 Collection: {item}/")
            # Show collection contents
            try:
                for subitem in os.listdir(item_path):
                    print(f"   └── {subitem}")
            except PermissionError:
                print(f"   └── (permission denied)")
        else:
            print(f"📄 {item}")
else:
    print("No knowledge storage found yet.")
```

### Controlling Knowledge Storage Locations

#### Option 1: Environment Variable (Recommended)

```python theme={null}
import os
from crewai import Crew

# Set custom storage location for all CrewAI data
os.environ["CREWAI_STORAGE_DIR"] = "./my_project_storage"

# All knowledge will now be stored in ./my_project_storage/knowledge/
crew = Crew(
    agents=[...],
    tasks=[...],
    knowledge_sources=[...]
)
```

#### Option 2: Custom Knowledge Storage

```python theme={null}
from crewai.knowledge.storage.knowledge_storage import KnowledgeStorage
from crewai.knowledge.source.string_knowledge_source import StringKnowledgeSource

# Create custom storage with specific embedder
custom_storage = KnowledgeStorage(
    embedder={
        "provider": "ollama",
        "config": {"model": "mxbai-embed-large"}
    },
    collection_name="my_custom_knowledge"
)

# Use with knowledge sources
knowledge_source = StringKnowledgeSource(
    content="Your knowledge content here"
)
knowledge_source.storage = custom_storage
```

#### Option 3: Project-Specific Knowledge Storage

```python theme={null}
import os
from pathlib import Path

# Store knowledge in project directory
project_root = Path(__file__).parent
knowledge_dir = project_root / "knowledge_storage"

os.environ["CREWAI_STORAGE_DIR"] = str(knowledge_dir)

# Now all knowledge will be stored in your project directory
```

### Default Embedding Provider Behavior

<Info>
  **Default Embedding Provider**: CrewAI defaults to OpenAI embeddings (`text-embedding-3-small`) for knowledge storage, even when using different LLM providers. You can easily customize this to match your setup.
</Info>

#### Understanding Default Behavior

```python theme={null}
from crewai import Agent, Crew, LLM
from crewai.knowledge.source.string_knowledge_source import StringKnowledgeSource

# When using Claude as your LLM...
agent = Agent(
    role="Researcher",
    goal="Research topics",
    backstory="Expert researcher",
    llm=LLM(provider="anthropic", model="claude-3-sonnet")  # Using Claude
)

# CrewAI will still use OpenAI embeddings by default for knowledge
# This ensures consistency but may not match your LLM provider preference
knowledge_source = StringKnowledgeSource(content="Research data...")

crew = Crew(
    agents=[agent],
    tasks=[...],
    knowledge_sources=[knowledge_source]
    # Default: Uses OpenAI embeddings even with Claude LLM
)
```

#### Customizing Knowledge Embedding Providers

```python theme={null}
# Option 1: Use Voyage AI (recommended by Anthropic for Claude users)
crew = Crew(
    agents=[agent],
    tasks=[...],
    knowledge_sources=[knowledge_source],
    embedder={
        "provider": "voyageai",  # Recommended for Claude users
        "config": {
            "api_key": "your-voyage-api-key",
            "model": "voyage-3"  # or "voyage-3-large" for best quality
        }
    }
)

# Option 2: Use local embeddings (no external API calls)
crew = Crew(
    agents=[agent],
    tasks=[...],
    knowledge_sources=[knowledge_source],
    embedder={
        "provider": "ollama",
        "config": {
            "model": "mxbai-embed-large",
            "url": "http://localhost:11434/api/embeddings"
        }
    }
)

# Option 3: Agent-level embedding customization
agent = Agent(
    role="Researcher",
    goal="Research topics",
    backstory="Expert researcher",
    knowledge_sources=[knowledge_source],
    embedder={
        "provider": "google-generativeai",
        "config": {
            "model_name": "gemini-embedding-001",
            "api_key": "your-google-key"
        }
    }
)
```

#### Configuring Azure OpenAI Embeddings

When using Azure OpenAI embeddings:

1. Make sure you deploy the embedding model in Azure platform first
2. Then you need to use the following configuration:

```python theme={null}
agent = Agent(
    role="Researcher",
    goal="Research topics",
    backstory="Expert researcher",
    knowledge_sources=[knowledge_source],
    embedder={
        "provider": "azure",
        "config": {
            "api_key": "your-azure-api-key",
            "model": "text-embedding-ada-002", # change to the model you are using and is deployed in Azure
            "api_base": "https://your-azure-endpoint.openai.azure.com/",
            "api_version": "2024-02-01"
        }
    }
)
```

## Advanced Features

### Query Rewriting

CrewAI implements an intelligent query rewriting mechanism to optimize knowledge retrieval. When an agent needs to search through knowledge sources, the raw task prompt is automatically transformed into a more effective search query.

#### How Query Rewriting Works

1. When an agent executes a task with knowledge sources available, the `_get_knowledge_search_query` method is triggered
2. The agent's LLM is used to transform the original task prompt into an optimized search query
3. This optimized query is then used to retrieve relevant information from knowledge sources

#### Benefits of Query Rewriting

<CardGroup>
  <Card title="Improved Retrieval Accuracy" icon="bullseye-arrow">
    By focusing on key concepts and removing irrelevant content, query rewriting helps retrieve more relevant information.
  </Card>

  <Card title="Context Awareness" icon="brain">
    The rewritten queries are designed to be more specific and context-aware for vector database retrieval.
  </Card>
</CardGroup>

#### Example

```python theme={null}
# Original task prompt
task_prompt = "Answer the following questions about the user's favorite movies: What movie did John watch last week? Format your answer in JSON."

# Behind the scenes, this might be rewritten as:
rewritten_query = "What movies did John watch last week?"
```

The rewritten query is more focused on the core information need and removes irrelevant instructions about output formatting.

<Tip>
  This mechanism is fully automatic and requires no configuration from users. The agent's LLM is used to perform the query rewriting, so using a more capable LLM can improve the quality of rewritten queries.
</Tip>

### Knowledge Events

CrewAI emits events during the knowledge retrieval process that you can listen for using the event system. These events allow you to monitor, debug, and analyze how knowledge is being retrieved and used by your agents.

#### Available Knowledge Events

* **KnowledgeRetrievalStartedEvent**: Emitted when an agent starts retrieving knowledge from sources
* **KnowledgeRetrievalCompletedEvent**: Emitted when knowledge retrieval is completed, including the query used and the retrieved content
* **KnowledgeQueryStartedEvent**: Emitted when a query to knowledge sources begins
* **KnowledgeQueryCompletedEvent**: Emitted when a query completes successfully
* **KnowledgeQueryFailedEvent**: Emitted when a query to knowledge sources fails
* **KnowledgeSearchQueryFailedEvent**: Emitted when a search query fails

#### Example: Monitoring Knowledge Retrieval

```python theme={null}
from crewai.events import (
    KnowledgeRetrievalStartedEvent,
    KnowledgeRetrievalCompletedEvent,
    BaseEventListener,
)

class KnowledgeMonitorListener(BaseEventListener):
    def setup_listeners(self, crewai_event_bus):
        @crewai_event_bus.on(KnowledgeRetrievalStartedEvent)
        def on_knowledge_retrieval_started(source, event):
            print(f"Agent '{event.agent.role}' started retrieving knowledge")
            
        @crewai_event_bus.on(KnowledgeRetrievalCompletedEvent)
        def on_knowledge_retrieval_completed(source, event):
            print(f"Agent '{event.agent.role}' completed knowledge retrieval")
            print(f"Query: {event.query}")
            print(f"Retrieved {len(event.retrieved_knowledge)} knowledge chunks")

# Create an instance of your listener
knowledge_monitor = KnowledgeMonitorListener()
```

For more information on using events, see the [Event Listeners](/en/concepts/event-listener) documentation.

### Custom Knowledge Sources

CrewAI allows you to create custom knowledge sources for any type of data by extending the `BaseKnowledgeSource` class. Let's create a practical example that fetches and processes space news articles.

#### Space News Knowledge Source Example

<CodeGroup>
  ```python Code theme={null}
  from crewai import Agent, Task, Crew, Process, LLM
  from crewai.knowledge.source.base_knowledge_source import BaseKnowledgeSource
  import requests
  from datetime import datetime
  from typing import Dict, Any
  from pydantic import BaseModel, Field

  class SpaceNewsKnowledgeSource(BaseKnowledgeSource):
      """Knowledge source that fetches data from Space News API."""

      api_endpoint: str = Field(description="API endpoint URL")
      limit: int = Field(default=10, description="Number of articles to fetch")

      def load_content(self) -> Dict[Any, str]:
          """Fetch and format space news articles."""
          try:
              response = requests.get(
                  f"{self.api_endpoint}?limit={self.limit}"
              )
              response.raise_for_status()

              data = response.json()
              articles = data.get('results', [])

              formatted_data = self.validate_content(articles)
              return {self.api_endpoint: formatted_data}
          except Exception as e:
              raise ValueError(f"Failed to fetch space news: {str(e)}")

      def validate_content(self, articles: list) -> str:
          """Format articles into readable text."""
          formatted = "Space News Articles:\n\n"
          for article in articles:
              formatted += f"""
                  Title: {article['title']}
                  Published: {article['published_at']}
                  Summary: {article['summary']}
                  News Site: {article['news_site']}
                  URL: {article['url']}
                  -------------------"""
          return formatted

      def add(self) -> None:
          """Process and store the articles."""
          content = self.load_content()
          for _, text in content.items():
              chunks = self._chunk_text(text)
              self.chunks.extend(chunks)

          self._save_documents()

  # Create knowledge source
  recent_news = SpaceNewsKnowledgeSource(
      api_endpoint="https://api.spaceflightnewsapi.net/v4/articles",
      limit=10,
  )

  # Create specialized agent
  space_analyst = Agent(
      role="Space News Analyst",
      goal="Answer questions about space news accurately and comprehensively",
      backstory="""You are a space industry analyst with expertise in space exploration,
      satellite technology, and space industry trends. You excel at answering questions
      about space news and providing detailed, accurate information.""",
      knowledge_sources=[recent_news],
      llm=LLM(model="gpt-4", temperature=0.0)
  )

  # Create task that handles user questions
  analysis_task = Task(
      description="Answer this question about space news: {user_question}",
      expected_output="A detailed answer based on the recent space news articles",
      agent=space_analyst
  )

  # Create and run the crew
  crew = Crew(
      agents=[space_analyst],
      tasks=[analysis_task],
      verbose=True,
      process=Process.sequential
  )

  # Example usage
  result = crew.kickoff(
      inputs={"user_question": "What are the latest developments in space exploration?"}
  )
  ```

  ```output Output theme={null}
  # Agent: Space News Analyst
  ## Task: Answer this question about space news: What are the latest developments in space exploration?


  # Agent: Space News Analyst
  ## Final Answer:
  The latest developments in space exploration, based on recent space news articles, include the following:

  1. SpaceX has received the final regulatory approvals to proceed with the second integrated Starship/Super Heavy launch, scheduled for as soon as the morning of Nov. 17, 2023. This is a significant step in SpaceX's ambitious plans for space exploration and colonization. [Source: SpaceNews](https://spacenews.com/starship-cleared-for-nov-17-launch/)

  2. SpaceX has also informed the US Federal Communications Commission (FCC) that it plans to begin launching its first next-generation Starlink Gen2 satellites. This represents a major upgrade to the Starlink satellite internet service, which aims to provide high-speed internet access worldwide. [Source: Teslarati](https://www.teslarati.com/spacex-first-starlink-gen2-satellite-launch-2022/)

  3. AI startup Synthetaic has raised $15 million in Series B funding. The company uses artificial intelligence to analyze data from space and air sensors, which could have significant applications in space exploration and satellite technology. [Source: SpaceNews](https://spacenews.com/ai-startup-synthetaic-raises-15-million-in-series-b-funding/)

  4. The Space Force has formally established a unit within the U.S. Indo-Pacific Command, marking a permanent presence in the Indo-Pacific region. This could have significant implications for space security and geopolitics. [Source: SpaceNews](https://spacenews.com/space-force-establishes-permanent-presence-in-indo-pacific-region/)

  5. Slingshot Aerospace, a space tracking and data analytics company, is expanding its network of ground-based optical telescopes to increase coverage of low Earth orbit. This could improve our ability to track and analyze objects in low Earth orbit, including satellites and space debris. [Source: SpaceNews](https://spacenews.com/slingshots-space-tracking-network-to-extend-coverage-of-low-earth-orbit/)

  6. The National Natural Science Foundation of China has outlined a five-year project for researchers to study the assembly of ultra-large spacecraft. This could lead to significant advancements in spacecraft technology and space exploration capabilities. [Source: SpaceNews](https://spacenews.com/china-researching-challenges-of-kilometer-scale-ultra-large-spacecraft/)

  7. The Center for AEroSpace Autonomy Research (CAESAR) at Stanford University is focusing on spacecraft autonomy. The center held a kickoff event on May 22, 2024, to highlight the industry, academia, and government collaboration it seeks to foster. This could lead to significant advancements in autonomous spacecraft technology. [Source: SpaceNews](https://spacenews.com/stanford-center-focuses-on-spacecraft-autonomy/)
  ```
</CodeGroup>

## Debugging and Troubleshooting

### Debugging Knowledge Issues

#### Check Agent Knowledge Initialization

```python theme={null}
from crewai import Agent, Crew, Task
from crewai.knowledge.source.string_knowledge_source import StringKnowledgeSource

knowledge_source = StringKnowledgeSource(content="Test knowledge")

agent = Agent(
    role="Test Agent",
    goal="Test knowledge",
    backstory="Testing",
    knowledge_sources=[knowledge_source]
)

crew = Crew(agents=[agent], tasks=[Task(...)])

# Before kickoff - knowledge not initialized
print(f"Before kickoff - Agent knowledge: {getattr(agent, 'knowledge', None)}")

crew.kickoff()

# After kickoff - knowledge initialized
print(f"After kickoff - Agent knowledge: {agent.knowledge}")
print(f"Agent knowledge collection: {agent.knowledge.storage.collection_name}")
print(f"Number of sources: {len(agent.knowledge.sources)}")
```

#### Verify Knowledge Storage Locations

```python theme={null}
import os
from crewai.utilities.paths import db_storage_path

# Check storage structure
storage_path = db_storage_path()
knowledge_path = os.path.join(storage_path, "knowledge")

if os.path.exists(knowledge_path):
    print("Knowledge collections found:")
    for collection in os.listdir(knowledge_path):
        collection_path = os.path.join(knowledge_path, collection)
        if os.path.isdir(collection_path):
            print(f"  - {collection}/")
            # Show collection contents
            for item in os.listdir(collection_path):
                print(f"    └── {item}")
```

#### Test Knowledge Retrieval

```python theme={null}
# Test agent knowledge retrieval
if hasattr(agent, 'knowledge') and agent.knowledge:
    test_query = ["test query"]
    results = agent.knowledge.query(test_query)
    print(f"Agent knowledge results: {len(results)} documents found")
    
    # Test crew knowledge retrieval (if exists)
    if hasattr(crew, 'knowledge') and crew.knowledge:
        crew_results = crew.query_knowledge(test_query)
        print(f"Crew knowledge results: {len(crew_results)} documents found")
```

#### Inspect Knowledge Collections

```python theme={null}
import chromadb
from crewai.utilities.paths import db_storage_path
import os

# Connect to CrewAI's knowledge ChromaDB
knowledge_path = os.path.join(db_storage_path(), "knowledge")

if os.path.exists(knowledge_path):
    client = chromadb.PersistentClient(path=knowledge_path)
    collections = client.list_collections()
    
    print("Knowledge Collections:")
    for collection in collections:
        print(f"  - {collection.name}: {collection.count()} documents")
        
        # Sample a few documents to verify content
        if collection.count() > 0:
            sample = collection.peek(limit=2)
            print(f"    Sample content: {sample['documents'][0][:100]}...")
else:
    print("No knowledge storage found")
```

#### Check Knowledge Processing

```python theme={null}
from crewai.knowledge.source.string_knowledge_source import StringKnowledgeSource

# Create a test knowledge source
test_source = StringKnowledgeSource(
    content="Test knowledge content for debugging",
    chunk_size=100,  # Small chunks for testing
    chunk_overlap=20
)

# Check chunking behavior
print(f"Original content length: {len(test_source.content)}")
print(f"Chunk size: {test_source.chunk_size}")
print(f"Chunk overlap: {test_source.chunk_overlap}")

# Process and inspect chunks
test_source.add()
print(f"Number of chunks created: {len(test_source.chunks)}")
for i, chunk in enumerate(test_source.chunks[:3]):  # Show first 3 chunks
    print(f"Chunk {i+1}: {chunk[:50]}...")
```

### Common Knowledge Storage Issues

**"File not found" errors:**

```python theme={null}
# Ensure files are in the correct location
from crewai.utilities.constants import KNOWLEDGE_DIRECTORY
import os

knowledge_dir = KNOWLEDGE_DIRECTORY  # Usually "knowledge"
file_path = os.path.join(knowledge_dir, "your_file.pdf")

if not os.path.exists(file_path):
    print(f"File not found: {file_path}")
    print(f"Current working directory: {os.getcwd()}")
    print(f"Expected knowledge directory: {os.path.abspath(knowledge_dir)}")
```

**"Embedding dimension mismatch" errors:**

```python theme={null}
# This happens when switching embedding providers
# Reset knowledge storage to clear old embeddings
crew.reset_memories(command_type='knowledge')

# Or use consistent embedding providers
crew = Crew(
    agents=[...],
    tasks=[...],
    knowledge_sources=[...],
    embedder={"provider": "openai", "config": {"model": "text-embedding-3-small"}}
)
```

**"ChromaDB permission denied" errors:**

```bash theme={null}
# Fix storage permissions
chmod -R 755 ~/.local/share/CrewAI/
```

**Knowledge not persisting between runs:**

```python theme={null}
# Verify storage location consistency
import os
from crewai.utilities.paths import db_storage_path

print("CREWAI_STORAGE_DIR:", os.getenv("CREWAI_STORAGE_DIR"))
print("Computed storage path:", db_storage_path())
print("Knowledge path:", os.path.join(db_storage_path(), "knowledge"))
```

### Knowledge Reset Commands

```python theme={null}
# Reset only agent-specific knowledge
crew.reset_memories(command_type='agent_knowledge')

# Reset both crew and agent knowledge  
crew.reset_memories(command_type='knowledge')

# CLI commands
# crewai reset-memories --agent-knowledge  # Agent knowledge only
# crewai reset-memories --knowledge        # All knowledge
```

### Clearing Knowledge

If you need to clear the knowledge stored in CrewAI, you can use the `crewai reset-memories` command with the `--knowledge` option.

```bash Command theme={null}
crewai reset-memories --knowledge
```

This is useful when you've updated your knowledge sources and want to ensure that the agents are using the most recent information.

## Best Practices

<AccordionGroup>
  <Accordion title="Content Organization">
    * Keep chunk sizes appropriate for your content type
    * Consider content overlap for context preservation
    * Organize related information into separate knowledge sources
  </Accordion>

  <Accordion title="Performance Tips">
    * Adjust chunk sizes based on content complexity
    * Configure appropriate embedding models
    * Consider using local embedding providers for faster processing
  </Accordion>

  <Accordion title="One Time Knowledge">
    * With the typical file structure provided by CrewAI, knowledge sources are embedded every time the kickoff is triggered.
    * If the knowledge sources are large, this leads to inefficiency and increased latency, as the same data is embedded each time.
    * To resolve this, directly initialize the knowledge parameter instead of the knowledge\_sources parameter.
    * Link to the issue to get complete idea [Github Issue](https://github.com/crewAIInc/crewAI/issues/2755)
  </Accordion>

  <Accordion title="Knowledge Management">
    * Use agent-level knowledge for role-specific information
    * Use crew-level knowledge for shared information all agents need
    * Set embedders at agent level if you need different embedding strategies
    * Use consistent collection naming by keeping agent roles descriptive
    * Test knowledge initialization by checking agent.knowledge after kickoff
    * Monitor storage locations to understand where knowledge is stored
    * Reset knowledge appropriately using the correct command types
  </Accordion>

  <Accordion title="Production Best Practices">
    * Set `CREWAI_STORAGE_DIR` to a known location in production
    * Choose explicit embedding providers to match your LLM setup and avoid API key conflicts
    * Monitor knowledge storage size as it grows with document additions
    * Organize knowledge sources by domain or purpose using collection names
    * Include knowledge directories in your backup and deployment strategies
    * Set appropriate file permissions for knowledge files and storage directories
    * Use environment variables for API keys and sensitive configuration
  </Accordion>
</AccordionGroup>


# LLMs
Source: https://docs.crewai.com/en/concepts/llms

A comprehensive guide to configuring and using Large Language Models (LLMs) in your CrewAI projects

## Overview

CrewAI integrates with multiple LLM providers through providers native sdks, giving you the flexibility to choose the right model for your specific use case. This guide will help you understand how to configure and use different LLM providers in your CrewAI projects.

## What are LLMs?

Large Language Models (LLMs) are the core intelligence behind CrewAI agents. They enable agents to understand context, make decisions, and generate human-like responses. Here's what you need to know:

<CardGroup>
  <Card title="LLM Basics" icon="brain">
    Large Language Models are AI systems trained on vast amounts of text data. They power the intelligence of your CrewAI agents, enabling them to understand and generate human-like text.
  </Card>

  <Card title="Context Window" icon="window">
    The context window determines how much text an LLM can process at once. Larger windows (e.g., 128K tokens) allow for more context but may be more expensive and slower.
  </Card>

  <Card title="Temperature" icon="temperature-three-quarters">
    Temperature (0.0 to 1.0) controls response randomness. Lower values (e.g., 0.2) produce more focused, deterministic outputs, while higher values (e.g., 0.8) increase creativity and variability.
  </Card>

  <Card title="Provider Selection" icon="server">
    Each LLM provider (e.g., OpenAI, Anthropic, Google) offers different models with varying capabilities, pricing, and features. Choose based on your needs for accuracy, speed, and cost.
  </Card>
</CardGroup>

## Setting up your LLM

There are different places in CrewAI code where you can specify the model to use. Once you specify the model you are using, you will need to provide the configuration (like an API key) for each of the model providers you use. See the [provider configuration examples](#provider-configuration-examples) section for your provider.

<Tabs>
  <Tab title="1. Environment Variables">
    The simplest way to get started. Set the model in your environment directly, through an `.env` file or in your app code. If you used `crewai create` to bootstrap your project, it will be set already.

    ```bash .env theme={null}
    MODEL=model-id  # e.g. gpt-4o, gemini-2.0-flash, claude-3-sonnet-...

    # Be sure to set your API keys here too. See the Provider
    # section below.
    ```

    <Warning>
      Never commit API keys to version control. Use environment files (.env) or your system's secret management.
    </Warning>
  </Tab>

  <Tab title="2. YAML Configuration">
    Create a YAML file to define your agent configurations. This method is great for version control and team collaboration:

    ```yaml agents.yaml {6} theme={null}
    researcher:
        role: Research Specialist
        goal: Conduct comprehensive research and analysis
        backstory: A dedicated research professional with years of experience
        verbose: true
        llm: provider/model-id  # e.g. openai/gpt-4o, google/gemini-2.0-flash, anthropic/claude...
        # (see provider configuration examples below for more)
    ```

    <Info>
      The YAML configuration allows you to:

      * Version control your agent settings
      * Easily switch between different models
      * Share configurations across team members
      * Document model choices and their purposes
    </Info>
  </Tab>

  <Tab title="3. Direct Code">
    For maximum flexibility, configure LLMs directly in your Python code:

    ```python {4,8} theme={null}
    from crewai import LLM

    # Basic configuration
    llm = LLM(model="model-id-here")  # gpt-4o, gemini-2.0-flash, anthropic/claude...

    # Advanced configuration with detailed parameters
    llm = LLM(
        model="model-id-here",  # gpt-4o, gemini-2.0-flash, anthropic/claude...
        temperature=0.7,        # Higher for more creative outputs
        timeout=120,            # Seconds to wait for response
        max_tokens=4000,        # Maximum length of response
        top_p=0.9,              # Nucleus sampling parameter
        frequency_penalty=0.1 , # Reduce repetition
        presence_penalty=0.1,   # Encourage topic diversity
        response_format={"type": "json"},  # For structured outputs
        seed=42                 # For reproducible results
    )
    ```

    <Info>
      Parameter explanations:

      * `temperature`: Controls randomness (0.0-1.0)
      * `timeout`: Maximum wait time for response
      * `max_tokens`: Limits response length
      * `top_p`: Alternative to temperature for sampling
      * `frequency_penalty`: Reduces word repetition
      * `presence_penalty`: Encourages new topics
      * `response_format`: Specifies output structure
      * `seed`: Ensures consistent outputs
    </Info>
  </Tab>
</Tabs>

<Info>
  CrewAI provides native SDK integrations for OpenAI, Anthropic, Google (Gemini API), Azure, and AWS Bedrock — no extra install needed beyond the provider-specific extras (e.g. `uv add "crewai[openai]"`).

  All other providers are powered by **LiteLLM**. If you plan to use any of them, add it as a dependency to your project:

  ```bash theme={null}
  uv add 'crewai[litellm]'
  ```
</Info>

## Provider Configuration Examples

CrewAI supports a multitude of LLM providers, each offering unique features, authentication methods, and model capabilities.
In this section, you'll find detailed examples that help you select, configure, and optimize the LLM that best fits your project's needs.

<AccordionGroup>
  <Accordion title="OpenAI">
    CrewAI provides native integration with OpenAI through the OpenAI Python SDK.

    ```toml Code theme={null}
    # Required
    OPENAI_API_KEY=sk-...

    # Optional
    OPENAI_BASE_URL=<custom-base-url>
    ```

    **Basic Usage:**

    ```python Code theme={null}
    from crewai import LLM

    llm = LLM(
        model="openai/gpt-4o",
        api_key="your-api-key",  # Or set OPENAI_API_KEY
        temperature=0.7,
        max_tokens=4000
    )
    ```

    **Advanced Configuration:**

    ```python Code theme={null}
    from crewai import LLM

    llm = LLM(
        model="openai/gpt-4o",
        api_key="your-api-key",
        base_url="https://api.openai.com/v1",  # Optional custom endpoint
        organization="org-...",  # Optional organization ID
        project="proj_...",  # Optional project ID
        temperature=0.7,
        max_tokens=4000,
        max_completion_tokens=4000,  # For newer models
        top_p=0.9,
        frequency_penalty=0.1,
        presence_penalty=0.1,
        stop=["END"],
        seed=42,  # For reproducible outputs
        stream=True,  # Enable streaming
        timeout=60.0,  # Request timeout in seconds
        max_retries=3,  # Maximum retry attempts
        logprobs=True,  # Return log probabilities
        top_logprobs=5,  # Number of most likely tokens
        reasoning_effort="medium"  # For o1 models: low, medium, high
    )
    ```

    **Structured Outputs:**

    ```python Code theme={null}
    from pydantic import BaseModel
    from crewai import LLM

    class ResponseFormat(BaseModel):
        name: str
        age: int
        summary: str

    llm = LLM(
        model="openai/gpt-4o",
    )
    ```

    **Supported Environment Variables:**

    * `OPENAI_API_KEY`: Your OpenAI API key (required)
    * `OPENAI_BASE_URL`: Custom base URL for OpenAI API (optional)

    **Features:**

    * Native function calling support (except o1 models)
    * Structured outputs with JSON schema
    * Streaming support for real-time responses
    * Token usage tracking
    * Stop sequences support (except o1 models)
    * Log probabilities for token-level insights
    * Reasoning effort control for o1 models

    **Supported Models:**

    | Model        | Context Window | Best For                                    |
    | ------------ | -------------- | ------------------------------------------- |
    | gpt-4.1      | 1M tokens      | Latest model with enhanced capabilities     |
    | gpt-4.1-mini | 1M tokens      | Efficient version with large context        |
    | gpt-4.1-nano | 1M tokens      | Ultra-efficient variant                     |
    | gpt-4o       | 128,000 tokens | Optimized for speed and intelligence        |
    | gpt-4o-mini  | 200,000 tokens | Cost-effective with large context           |
    | gpt-4-turbo  | 128,000 tokens | Long-form content, document analysis        |
    | gpt-4        | 8,192 tokens   | High-accuracy tasks, complex reasoning      |
    | o1           | 200,000 tokens | Advanced reasoning, complex problem-solving |
    | o1-preview   | 128,000 tokens | Preview of reasoning capabilities           |
    | o1-mini      | 128,000 tokens | Efficient reasoning model                   |
    | o3-mini      | 200,000 tokens | Lightweight reasoning model                 |
    | o4-mini      | 200,000 tokens | Next-gen efficient reasoning                |

    **Responses API:**

    OpenAI offers two APIs: Chat Completions (default) and the newer Responses API. The Responses API was designed from the ground up with native multimodal support—text, images, audio, and function calls are all first-class citizens. It provides better performance with reasoning models and supports additional features like auto-chaining and built-in tools.

    ```python Code theme={null}
    from crewai import LLM

    # Use the Responses API instead of Chat Completions
    llm = LLM(
        model="openai/gpt-4o",
        api="responses",  # Enable Responses API
        store=True,  # Store responses for multi-turn (optional)
        auto_chain=True,  # Auto-chain for reasoning models (optional)
    )
    ```

    **Responses API Parameters:**

    * `api`: Set to `"responses"` to use the Responses API (default: `"completions"`)
    * `instructions`: System-level instructions (Responses API only)
    * `store`: Whether to store responses for multi-turn conversations
    * `previous_response_id`: ID of previous response for multi-turn
    * `include`: Additional data to include in response (e.g., `["reasoning.encrypted_content"]`)
    * `builtin_tools`: List of OpenAI built-in tools: `"web_search"`, `"file_search"`, `"code_interpreter"`, `"computer_use"`
    * `parse_tool_outputs`: Return structured `ResponsesAPIResult` with parsed built-in tool outputs
    * `auto_chain`: Automatically track and use response IDs for multi-turn conversations
    * `auto_chain_reasoning`: Track encrypted reasoning items for ZDR (Zero Data Retention) compliance

    <Tip>
      Use the Responses API for new projects, especially when working with reasoning models (o1, o3, o4) or when you need native multimodal support for [files](/en/concepts/files).
    </Tip>

    **Note:** To use OpenAI, install the required dependencies:

    ```bash theme={null}
    uv add "crewai[openai]"
    ```
  </Accordion>

  <Accordion title="Meta-Llama">
    Meta's Llama API provides access to Meta's family of large language models.
    The API is available through the [Meta Llama API](https://llama.developer.meta.com?utm_source=partner-crewai\&utm_medium=website).
    Set the following environment variables in your `.env` file:

    ```toml Code theme={null}
    # Meta Llama API Key Configuration
    LLAMA_API_KEY=LLM|your_api_key_here
    ```

    Example usage in your CrewAI project:

    ```python Code theme={null}
    from crewai import LLM

    # Initialize Meta Llama LLM
    llm = LLM(
        model="meta_llama/Llama-4-Scout-17B-16E-Instruct-FP8",
        temperature=0.8,
        stop=["END"],
        seed=42
    )
    ```

    All models listed here [https://llama.developer.meta.com/docs/models/](https://llama.developer.meta.com/docs/models/) are supported.

    | Model ID                                            | Input context length | Output context length | Input Modalities | Output Modalities |
    | --------------------------------------------------- | -------------------- | --------------------- | ---------------- | ----------------- |
    | `meta_llama/Llama-4-Scout-17B-16E-Instruct-FP8`     | 128k                 | 4028                  | Text, Image      | Text              |
    | `meta_llama/Llama-4-Maverick-17B-128E-Instruct-FP8` | 128k                 | 4028                  | Text, Image      | Text              |
    | `meta_llama/Llama-3.3-70B-Instruct`                 | 128k                 | 4028                  | Text             | Text              |
    | `meta_llama/Llama-3.3-8B-Instruct`                  | 128k                 | 4028                  | Text             | Text              |

    **Note:** This provider uses LiteLLM. Add it as a dependency to your project:

    ```bash theme={null}
    uv add 'crewai[litellm]'
    ```
  </Accordion>

  <Accordion title="Anthropic">
    CrewAI provides native integration with Anthropic through the Anthropic Python SDK.

    ```toml Code theme={null}
    # Required
    ANTHROPIC_API_KEY=sk-ant-...
    ```

    **Basic Usage:**

    ```python Code theme={null}
    from crewai import LLM

    llm = LLM(
        model="anthropic/claude-3-5-sonnet-20241022",
        api_key="your-api-key",  # Or set ANTHROPIC_API_KEY
        max_tokens=4096  # Required for Anthropic
    )
    ```

    **Advanced Configuration:**

    ```python Code theme={null}
    from crewai import LLM

    llm = LLM(
        model="anthropic/claude-3-5-sonnet-20241022",
        api_key="your-api-key",
        base_url="https://api.anthropic.com",  # Optional custom endpoint
        temperature=0.7,
        max_tokens=4096,  # Required parameter
        top_p=0.9,
        stop_sequences=["END", "STOP"],  # Anthropic uses stop_sequences
        stream=True,  # Enable streaming
        timeout=60.0,  # Request timeout in seconds
        max_retries=3  # Maximum retry attempts
    )
    ```

    **Extended Thinking (Claude Sonnet 4 and Beyond):**

    CrewAI supports Anthropic's Extended Thinking feature, which allows Claude to think through problems in a more human-like way before responding. This is particularly useful for complex reasoning, analysis, and problem-solving tasks.

    ```python Code theme={null}
    from crewai import LLM

    # Enable extended thinking with default settings
    llm = LLM(
        model="anthropic/claude-sonnet-4",
        thinking={"type": "enabled"},
        max_tokens=10000
    )

    # Configure thinking with budget control
    llm = LLM(
        model="anthropic/claude-sonnet-4",
        thinking={
            "type": "enabled",
            "budget_tokens": 5000  # Limit thinking tokens
        },
        max_tokens=10000
    )
    ```

    **Thinking Configuration Options:**

    * `type`: Set to `"enabled"` to activate extended thinking mode
    * `budget_tokens` (optional): Maximum tokens to use for thinking (helps control costs)

    **Models Supporting Extended Thinking:**

    * `claude-sonnet-4` and newer models
    * `claude-3-7-sonnet` (with extended thinking capabilities)

    **When to Use Extended Thinking:**

    * Complex reasoning and multi-step problem solving
    * Mathematical calculations and proofs
    * Code analysis and debugging
    * Strategic planning and decision making
    * Research and analytical tasks

    **Note:** Extended thinking consumes additional tokens but can significantly improve response quality for complex tasks.

    **Supported Environment Variables:**

    * `ANTHROPIC_API_KEY`: Your Anthropic API key (required)

    **Features:**

    * Native tool use support for Claude 3+ models
    * Extended Thinking support for Claude Sonnet 4+
    * Streaming support for real-time responses
    * Automatic system message handling
    * Stop sequences for controlled output
    * Token usage tracking
    * Multi-turn tool use conversations

    **Important Notes:**

    * `max_tokens` is a **required** parameter for all Anthropic models
    * Claude uses `stop_sequences` instead of `stop`
    * System messages are handled separately from conversation messages
    * First message must be from the user (automatically handled)
    * Messages must alternate between user and assistant

    **Supported Models:**

    | Model                      | Context Window | Best For                                   |
    | -------------------------- | -------------- | ------------------------------------------ |
    | claude-sonnet-4            | 200,000 tokens | Latest with extended thinking capabilities |
    | claude-3-7-sonnet          | 200,000 tokens | Advanced reasoning and agentic tasks       |
    | claude-3-5-sonnet-20241022 | 200,000 tokens | Latest Sonnet with best performance        |
    | claude-3-5-haiku           | 200,000 tokens | Fast, compact model for quick responses    |
    | claude-3-opus              | 200,000 tokens | Most capable for complex tasks             |
    | claude-3-sonnet            | 200,000 tokens | Balanced intelligence and speed            |
    | claude-3-haiku             | 200,000 tokens | Fastest for simple tasks                   |
    | claude-2.1                 | 200,000 tokens | Extended context, reduced hallucinations   |
    | claude-2                   | 100,000 tokens | Versatile model for various tasks          |
    | claude-instant             | 100,000 tokens | Fast, cost-effective for everyday tasks    |

    **Note:** To use Anthropic, install the required dependencies:

    ```bash theme={null}
    uv add "crewai[anthropic]"
    ```
  </Accordion>

  <Accordion title="Google (Gemini API)">
    CrewAI provides native integration with Google Gemini through the Google Gen AI Python SDK.

    Set your API key in your `.env` file. If you need a key, check [AI Studio](https://aistudio.google.com/apikey).

    ```toml .env theme={null}
    # Required (one of the following)
    GOOGLE_API_KEY=<your-api-key>
    GEMINI_API_KEY=<your-api-key>

    # For Vertex AI Express mode (API key authentication)
    GOOGLE_GENAI_USE_VERTEXAI=true
    GOOGLE_API_KEY=<your-api-key>

    # For Vertex AI with service account
    GOOGLE_CLOUD_PROJECT=<your-project-id>
    GOOGLE_CLOUD_LOCATION=<location>  # Defaults to us-central1
    ```

    **Basic Usage:**

    ```python Code theme={null}
    from crewai import LLM

    llm = LLM(
        model="gemini/gemini-2.0-flash",
        api_key="your-api-key",  # Or set GOOGLE_API_KEY/GEMINI_API_KEY
        temperature=0.7
    )
    ```

    **Advanced Configuration:**

    ```python Code theme={null}
    from crewai import LLM

    llm = LLM(
        model="gemini/gemini-2.5-flash",
        api_key="your-api-key",
        temperature=0.7,
        top_p=0.9,
        top_k=40,  # Top-k sampling parameter
        max_output_tokens=8192,
        stop_sequences=["END", "STOP"],
        stream=True,  # Enable streaming
        safety_settings={
            "HARM_CATEGORY_HARASSMENT": "BLOCK_NONE",
            "HARM_CATEGORY_HATE_SPEECH": "BLOCK_NONE"
        }
    )
    ```

    **Vertex AI Express Mode (API Key Authentication):**

    Vertex AI Express mode allows you to use Vertex AI with simple API key authentication instead of service account credentials. This is the quickest way to get started with Vertex AI.

    To enable Express mode, set both environment variables in your `.env` file:

    ```toml .env theme={null}
    GOOGLE_GENAI_USE_VERTEXAI=true
    GOOGLE_API_KEY=<your-api-key>
    ```

    Then use the LLM as usual:

    ```python Code theme={null}
    from crewai import LLM

    llm = LLM(
        model="gemini/gemini-2.0-flash",
        temperature=0.7
    )
    ```

    <Info>
      To get an Express mode API key:

      * New Google Cloud users: Get an [express mode API key](https://cloud.google.com/vertex-ai/generative-ai/docs/start/quickstart?usertype=apikey)
      * Existing Google Cloud users: Get a [Google Cloud API key bound to a service account](https://cloud.google.com/docs/authentication/api-keys)

      For more details, see the [Vertex AI Express mode documentation](https://docs.cloud.google.com/vertex-ai/generative-ai/docs/start/quickstart?usertype=apikey).
    </Info>

    **Vertex AI Configuration (Service Account):**

    ```python Code theme={null}
    from crewai import LLM

    llm = LLM(
        model="gemini/gemini-1.5-pro",
        project="your-gcp-project-id",
        location="us-central1"  # GCP region
    )
    ```

    **Supported Environment Variables:**

    * `GOOGLE_API_KEY` or `GEMINI_API_KEY`: Your Google API key (required for Gemini API and Vertex AI Express mode)
    * `GOOGLE_GENAI_USE_VERTEXAI`: Set to `true` to use Vertex AI (required for Express mode)
    * `GOOGLE_CLOUD_PROJECT`: Google Cloud project ID (for Vertex AI with service account)
    * `GOOGLE_CLOUD_LOCATION`: GCP location (defaults to `us-central1`)

    **Features:**

    * Native function calling support for Gemini 1.5+ and 2.x models
    * Streaming support for real-time responses
    * Multimodal capabilities (text, images, video)
    * Safety settings configuration
    * Support for both Gemini API and Vertex AI
    * Automatic system instruction handling
    * Token usage tracking

    **Gemini Models:**

    Google offers a range of powerful models optimized for different use cases.

    | Model                     | Context Window | Best For                                                  |
    | ------------------------- | -------------- | --------------------------------------------------------- |
    | gemini-2.5-flash          | 1M tokens      | Adaptive thinking, cost efficiency                        |
    | gemini-2.5-pro            | 1M tokens      | Enhanced thinking and reasoning, multimodal understanding |
    | gemini-2.0-flash          | 1M tokens      | Next generation features, speed, thinking                 |
    | gemini-2.0-flash-thinking | 32,768 tokens  | Advanced reasoning with thinking process                  |
    | gemini-2.0-flash-lite     | 1M tokens      | Cost efficiency and low latency                           |
    | gemini-1.5-pro            | 2M tokens      | Best performing, logical reasoning, coding                |
    | gemini-1.5-flash          | 1M tokens      | Balanced multimodal model, good for most tasks            |
    | gemini-1.5-flash-8b       | 1M tokens      | Fastest, most cost-efficient                              |
    | gemini-1.0-pro            | 32,768 tokens  | Earlier generation model                                  |

    **Gemma Models:**

    The Gemini API also supports [Gemma models](https://ai.google.dev/gemma/docs) hosted on Google infrastructure.

    | Model       | Context Window | Best For                            |
    | ----------- | -------------- | ----------------------------------- |
    | gemma-3-1b  | 32,000 tokens  | Ultra-lightweight tasks             |
    | gemma-3-4b  | 128,000 tokens | Efficient general-purpose tasks     |
    | gemma-3-12b | 128,000 tokens | Balanced performance and efficiency |
    | gemma-3-27b | 128,000 tokens | High-performance tasks              |

    **Note:** To use Google Gemini, install the required dependencies:

    ```bash theme={null}
    uv add "crewai[google-genai]"
    ```

    The full list of models is available in the [Gemini model docs](https://ai.google.dev/gemini-api/docs/models).
  </Accordion>

  <Accordion title="Google (Vertex AI)">
    Get credentials from your Google Cloud Console and save it to a JSON file, then load it with the following code:

    ```python Code theme={null}
    import json

    file_path = 'path/to/vertex_ai_service_account.json'

    # Load the JSON file
    with open(file_path, 'r') as file:
        vertex_credentials = json.load(file)

    # Convert the credentials to a JSON string
    vertex_credentials_json = json.dumps(vertex_credentials)
    ```

    Example usage in your CrewAI project:

    ```python Code theme={null}
    from crewai import LLM

    llm = LLM(
        model="gemini-1.5-pro-latest", # or vertex_ai/gemini-1.5-pro-latest
        temperature=0.7,
        vertex_credentials=vertex_credentials_json
    )
    ```

    Google offers a range of powerful models optimized for different use cases:

    | Model                          | Context Window | Best For                                                                                                         |
    | ------------------------------ | -------------- | ---------------------------------------------------------------------------------------------------------------- |
    | gemini-2.5-flash-preview-04-17 | 1M tokens      | Adaptive thinking, cost efficiency                                                                               |
    | gemini-2.5-pro-preview-05-06   | 1M tokens      | Enhanced thinking and reasoning, multimodal understanding, advanced coding, and more                             |
    | gemini-2.0-flash               | 1M tokens      | Next generation features, speed, thinking, and realtime streaming                                                |
    | gemini-2.0-flash-lite          | 1M tokens      | Cost efficiency and low latency                                                                                  |
    | gemini-1.5-flash               | 1M tokens      | Balanced multimodal model, good for most tasks                                                                   |
    | gemini-1.5-flash-8B            | 1M tokens      | Fastest, most cost-efficient, good for high-frequency tasks                                                      |
    | gemini-1.5-pro                 | 2M tokens      | Best performing, wide variety of reasoning tasks including logical reasoning, coding, and creative collaboration |

    **Note:** This provider uses LiteLLM. Add it as a dependency to your project:

    ```bash theme={null}
    uv add 'crewai[litellm]'
    ```
  </Accordion>

  <Accordion title="Azure">
    CrewAI provides native integration with Azure AI Inference and Azure OpenAI through the Azure AI Inference Python SDK.

    ```toml Code theme={null}
    # Required
    AZURE_API_KEY=<your-api-key>
    AZURE_ENDPOINT=<your-endpoint-url>

    # Optional
    AZURE_API_VERSION=<api-version>  # Defaults to 2024-06-01
    ```

    **Endpoint URL Formats:**

    For Azure OpenAI deployments:

    ```
    https://<resource-name>.openai.azure.com/openai/deployments/<deployment-name>
    ```

    For Azure AI Inference endpoints:

    ```
    https://<resource-name>.inference.azure.com
    ```

    **Basic Usage:**

    ```python Code theme={null}
    llm = LLM(
        model="azure/gpt-4",
        api_key="<your-api-key>",  # Or set AZURE_API_KEY
        endpoint="<your-endpoint-url>",
        api_version="2024-06-01"
    )
    ```

    **Advanced Configuration:**

    ```python Code theme={null}
    llm = LLM(
        model="azure/gpt-4o",
        temperature=0.7,
        max_tokens=4000,
        top_p=0.9,
        frequency_penalty=0.0,
        presence_penalty=0.0,
        stop=["END"],
        stream=True,
        timeout=60.0,
        max_retries=3
    )
    ```

    **Supported Environment Variables:**

    * `AZURE_API_KEY`: Your Azure API key (required)
    * `AZURE_ENDPOINT`: Your Azure endpoint URL (required, also checks `AZURE_OPENAI_ENDPOINT` and `AZURE_API_BASE`)
    * `AZURE_API_VERSION`: API version (optional, defaults to `2024-06-01`)

    **Features:**

    * Native function calling support for Azure OpenAI models (gpt-4, gpt-4o, gpt-3.5-turbo, etc.)
    * Streaming support for real-time responses
    * Automatic endpoint URL validation and correction
    * Comprehensive error handling with retry logic
    * Token usage tracking

    **Note:** To use Azure AI Inference, install the required dependencies:

    ```bash theme={null}
    uv add "crewai[azure-ai-inference]"
    ```
  </Accordion>

  <Accordion title="AWS Bedrock">
    CrewAI provides native integration with AWS Bedrock through the boto3 SDK using the Converse API.

    ```toml Code theme={null}
    # Required
    AWS_ACCESS_KEY_ID=<your-access-key>
    AWS_SECRET_ACCESS_KEY=<your-secret-key>

    # Optional
    AWS_SESSION_TOKEN=<your-session-token>  # For temporary credentials
    AWS_DEFAULT_REGION=<your-region>  # Defaults to us-east-1
    AWS_REGION_NAME=<your-region>  # Alternative configuration for backwards compatibility with LiteLLM. Defaults to us-east-1
    ```

    **Basic Usage:**

    ```python Code theme={null}
    from crewai import LLM

    llm = LLM(
        model="bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0",
        region_name="us-east-1"
    )
    ```

    **Advanced Configuration:**

    ```python Code theme={null}
    from crewai import LLM

    llm = LLM(
        model="bedrock/anthropic.claude-3-5-sonnet-20241022-v2:0",
        aws_access_key_id="your-access-key",  # Or set AWS_ACCESS_KEY_ID
        aws_secret_access_key="your-secret-key",  # Or set AWS_SECRET_ACCESS_KEY
        aws_session_token="your-session-token",  # For temporary credentials
        region_name="us-east-1",
        temperature=0.7,
        max_tokens=4096,
        top_p=0.9,
        top_k=250,  # For Claude models
        stop_sequences=["END", "STOP"],
        stream=True,  # Enable streaming
        guardrail_config={  # Optional content filtering
            "guardrailIdentifier": "your-guardrail-id",
            "guardrailVersion": "1"
        },
        additional_model_request_fields={  # Model-specific parameters
            "top_k": 250
        }
    )
    ```

    **Supported Environment Variables:**

    * `AWS_ACCESS_KEY_ID`: AWS access key (required)
    * `AWS_SECRET_ACCESS_KEY`: AWS secret key (required)
    * `AWS_SESSION_TOKEN`: AWS session token for temporary credentials (optional)
    * `AWS_DEFAULT_REGION`: AWS region (defaults to `us-east-1`)
    * `AWS_REGION_NAME`: AWS region (defaults to `us-east-1`). Alternative configuration for backwards compatibility with LiteLLM

    **Features:**

    * Native tool calling support via Converse API
    * Streaming and non-streaming responses
    * Comprehensive error handling with retry logic
    * Guardrail configuration for content filtering
    * Model-specific parameters via `additional_model_request_fields`
    * Token usage tracking and stop reason logging
    * Support for all Bedrock foundation models
    * Automatic conversation format handling

    **Important Notes:**

    * Uses the modern Converse API for unified model access
    * Automatic handling of model-specific conversation requirements
    * System messages are handled separately from conversation
    * First message must be from user (automatically handled)
    * Some models (like Cohere) require conversation to end with user message

    [Amazon Bedrock](https://docs.aws.amazon.com/bedrock/latest/userguide/models-regions.html) is a managed service that provides access to multiple foundation models from top AI companies through a unified API.

    | Model                   | Context Window     | Best For                                                                                                                              |
    | ----------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------- |
    | Amazon Nova Pro         | Up to 300k tokens  | High-performance, model balancing accuracy, speed, and cost-effectiveness across diverse tasks.                                       |
    | Amazon Nova Micro       | Up to 128k tokens  | High-performance, cost-effective text-only model optimized for lowest latency responses.                                              |
    | Amazon Nova Lite        | Up to 300k tokens  | High-performance, affordable multimodal processing for images, video, and text with real-time capabilities.                           |
    | Claude 3.7 Sonnet       | Up to 128k tokens  | High-performance, best for complex reasoning, coding & AI agents                                                                      |
    | Claude 3.5 Sonnet v2    | Up to 200k tokens  | State-of-the-art model specialized in software engineering, agentic capabilities, and computer interaction at optimized cost.         |
    | Claude 3.5 Sonnet       | Up to 200k tokens  | High-performance model delivering superior intelligence and reasoning across diverse tasks with optimal speed-cost balance.           |
    | Claude 3.5 Haiku        | Up to 200k tokens  | Fast, compact multimodal model optimized for quick responses and seamless human-like interactions                                     |
    | Claude 3 Sonnet         | Up to 200k tokens  | Multimodal model balancing intelligence and speed for high-volume deployments.                                                        |
    | Claude 3 Haiku          | Up to 200k tokens  | Compact, high-speed multimodal model optimized for quick responses and natural conversational interactions                            |
    | Claude 3 Opus           | Up to 200k tokens  | Most advanced multimodal model exceling at complex tasks with human-like reasoning and superior contextual understanding.             |
    | Claude 2.1              | Up to 200k tokens  | Enhanced version with expanded context window, improved reliability, and reduced hallucinations for long-form and RAG applications    |
    | Claude                  | Up to 100k tokens  | Versatile model excelling in sophisticated dialogue, creative content, and precise instruction following.                             |
    | Claude Instant          | Up to 100k tokens  | Fast, cost-effective model for everyday tasks like dialogue, analysis, summarization, and document Q\&A                               |
    | Llama 3.1 405B Instruct | Up to 128k tokens  | Advanced LLM for synthetic data generation, distillation, and inference for chatbots, coding, and domain-specific tasks.              |
    | Llama 3.1 70B Instruct  | Up to 128k tokens  | Powers complex conversations with superior contextual understanding, reasoning and text generation.                                   |
    | Llama 3.1 8B Instruct   | Up to 128k tokens  | Advanced state-of-the-art model with language understanding, superior reasoning, and text generation.                                 |
    | Llama 3 70B Instruct    | Up to 8k tokens    | Powers complex conversations with superior contextual understanding, reasoning and text generation.                                   |
    | Llama 3 8B Instruct     | Up to 8k tokens    | Advanced state-of-the-art LLM with language understanding, superior reasoning, and text generation.                                   |
    | Titan Text G1 - Lite    | Up to 4k tokens    | Lightweight, cost-effective model optimized for English tasks and fine-tuning with focus on summarization and content generation.     |
    | Titan Text G1 - Express | Up to 8k tokens    | Versatile model for general language tasks, chat, and RAG applications with support for English and 100+ languages.                   |
    | Cohere Command          | Up to 4k tokens    | Model specialized in following user commands and delivering practical enterprise solutions.                                           |
    | Jurassic-2 Mid          | Up to 8,191 tokens | Cost-effective model balancing quality and affordability for diverse language tasks like Q\&A, summarization, and content generation. |
    | Jurassic-2 Ultra        | Up to 8,191 tokens | Model for advanced text generation and comprehension, excelling in complex tasks like analysis and content creation.                  |
    | Jamba-Instruct          | Up to 256k tokens  | Model with extended context window optimized for cost-effective text generation, summarization, and Q\&A.                             |
    | Mistral 7B Instruct     | Up to 32k tokens   | This LLM follows instructions, completes requests, and generates creative text.                                                       |
    | Mistral 8x7B Instruct   | Up to 32k tokens   | An MOE LLM that follows instructions, completes requests, and generates creative text.                                                |
    | DeepSeek R1             | 32,768 tokens      | Advanced reasoning model                                                                                                              |

    **Note:** To use AWS Bedrock, install the required dependencies:

    ```bash theme={null}
    uv add "crewai[bedrock]"
    ```
  </Accordion>

  <Accordion title="Amazon SageMaker">
    ```toml Code theme={null}
    AWS_ACCESS_KEY_ID=<your-access-key>
    AWS_SECRET_ACCESS_KEY=<your-secret-key>
    AWS_DEFAULT_REGION=<your-region>
    ```

    Example usage in your CrewAI project:

    ```python Code theme={null}
    llm = LLM(
        model="sagemaker/<my-endpoint>"
    )
    ```

    **Note:** This provider uses LiteLLM. Add it as a dependency to your project:

    ```bash theme={null}
    uv add 'crewai[litellm]'
    ```
  </Accordion>

  <Accordion title="Mistral">
    Set the following environment variables in your `.env` file:

    ```toml Code theme={null}
    MISTRAL_API_KEY=<your-api-key>
    ```

    Example usage in your CrewAI project:

    ```python Code theme={null}
    llm = LLM(
        model="mistral/mistral-large-latest",
        temperature=0.7
    )
    ```

    **Note:** This provider uses LiteLLM. Add it as a dependency to your project:

    ```bash theme={null}
    uv add 'crewai[litellm]'
    ```
  </Accordion>

  <Accordion title="Nvidia NIM">
    Set the following environment variables in your `.env` file:

    ```toml Code theme={null}
    NVIDIA_API_KEY=<your-api-key>
    ```

    Example usage in your CrewAI project:

    ```python Code theme={null}
    llm = LLM(
        model="nvidia_nim/meta/llama3-70b-instruct",
        temperature=0.7
    )
    ```

    Nvidia NIM provides a comprehensive suite of models for various use cases, from general-purpose tasks to specialized applications.

    | Model                                       | Context Window | Best For                                                                                                                    |
    | ------------------------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------------------- |
    | nvidia/mistral-nemo-minitron-8b-8k-instruct | 8,192 tokens   | State-of-the-art small language model delivering superior accuracy for chatbot, virtual assistants, and content generation. |
    | nvidia/nemotron-4-mini-hindi-4b-instruct    | 4,096 tokens   | A bilingual Hindi-English SLM for on-device inference, tailored specifically for Hindi Language.                            |
    | nvidia/llama-3.1-nemotron-70b-instruct      | 128k tokens    | Customized for enhanced helpfulness in responses                                                                            |
    | nvidia/llama3-chatqa-1.5-8b                 | 128k tokens    | Advanced LLM to generate high-quality, context-aware responses for chatbots and search engines.                             |
    | nvidia/llama3-chatqa-1.5-70b                | 128k tokens    | Advanced LLM to generate high-quality, context-aware responses for chatbots and search engines.                             |
    | nvidia/vila                                 | 128k tokens    | Multi-modal vision-language model that understands text/img/video and creates informative responses                         |
    | nvidia/neva-22                              | 4,096 tokens   | Multi-modal vision-language model that understands text/images and generates informative responses                          |
    | nvidia/nemotron-mini-4b-instruct            | 8,192 tokens   | General-purpose tasks                                                                                                       |
    | nvidia/usdcode-llama3-70b-instruct          | 128k tokens    | State-of-the-art LLM that answers OpenUSD knowledge queries and generates USD-Python code.                                  |
    | nvidia/nemotron-4-340b-instruct             | 4,096 tokens   | Creates diverse synthetic data that mimics the characteristics of real-world data.                                          |
    | meta/codellama-70b                          | 100k tokens    | LLM capable of generating code from natural language and vice versa.                                                        |
    | meta/llama2-70b                             | 4,096 tokens   | Cutting-edge large language AI model capable of generating text and code in response to prompts.                            |
    | meta/llama3-8b-instruct                     | 8,192 tokens   | Advanced state-of-the-art LLM with language understanding, superior reasoning, and text generation.                         |
    | meta/llama3-70b-instruct                    | 8,192 tokens   | Powers complex conversations with superior contextual understanding, reasoning and text generation.                         |
    | meta/llama-3.1-8b-instruct                  | 128k tokens    | Advanced state-of-the-art model with language understanding, superior reasoning, and text generation.                       |
    | meta/llama-3.1-70b-instruct                 | 128k tokens    | Powers complex conversations with superior contextual understanding, reasoning and text generation.                         |
    | meta/llama-3.1-405b-instruct                | 128k tokens    | Advanced LLM for synthetic data generation, distillation, and inference for chatbots, coding, and domain-specific tasks.    |
    | meta/llama-3.2-1b-instruct                  | 128k tokens    | Advanced state-of-the-art small language model with language understanding, superior reasoning, and text generation.        |
    | meta/llama-3.2-3b-instruct                  | 128k tokens    | Advanced state-of-the-art small language model with language understanding, superior reasoning, and text generation.        |
    | meta/llama-3.2-11b-vision-instruct          | 128k tokens    | Advanced state-of-the-art small language model with language understanding, superior reasoning, and text generation.        |
    | meta/llama-3.2-90b-vision-instruct          | 128k tokens    | Advanced state-of-the-art small language model with language understanding, superior reasoning, and text generation.        |
    | google/gemma-7b                             | 8,192 tokens   | Cutting-edge text generation model text understanding, transformation, and code generation.                                 |
    | google/gemma-2b                             | 8,192 tokens   | Cutting-edge text generation model text understanding, transformation, and code generation.                                 |
    | google/codegemma-7b                         | 8,192 tokens   | Cutting-edge model built on Google's Gemma-7B specialized for code generation and code completion.                          |
    | google/codegemma-1.1-7b                     | 8,192 tokens   | Advanced programming model for code generation, completion, reasoning, and instruction following.                           |
    | google/recurrentgemma-2b                    | 8,192 tokens   | Novel recurrent architecture based language model for faster inference when generating long sequences.                      |
    | google/gemma-2-9b-it                        | 8,192 tokens   | Cutting-edge text generation model text understanding, transformation, and code generation.                                 |
    | google/gemma-2-27b-it                       | 8,192 tokens   | Cutting-edge text generation model text understanding, transformation, and code generation.                                 |
    | google/gemma-2-2b-it                        | 8,192 tokens   | Cutting-edge text generation model text understanding, transformation, and code generation.                                 |
    | google/deplot                               | 512 tokens     | One-shot visual language understanding model that translates images of plots into tables.                                   |
    | google/paligemma                            | 8,192 tokens   | Vision language model adept at comprehending text and visual inputs to produce informative responses.                       |
    | mistralai/mistral-7b-instruct-v0.2          | 32k tokens     | This LLM follows instructions, completes requests, and generates creative text.                                             |
    | mistralai/mixtral-8x7b-instruct-v0.1        | 8,192 tokens   | An MOE LLM that follows instructions, completes requests, and generates creative text.                                      |
    | mistralai/mistral-large                     | 4,096 tokens   | Creates diverse synthetic data that mimics the characteristics of real-world data.                                          |
    | mistralai/mixtral-8x22b-instruct-v0.1       | 8,192 tokens   | Creates diverse synthetic data that mimics the characteristics of real-world data.                                          |
    | mistralai/mistral-7b-instruct-v0.3          | 32k tokens     | This LLM follows instructions, completes requests, and generates creative text.                                             |
    | nv-mistralai/mistral-nemo-12b-instruct      | 128k tokens    | Most advanced language model for reasoning, code, multilingual tasks; runs on a single GPU.                                 |
    | mistralai/mamba-codestral-7b-v0.1           | 256k tokens    | Model for writing and interacting with code across a wide range of programming languages and tasks.                         |
    | microsoft/phi-3-mini-128k-instruct          | 128K tokens    | Lightweight, state-of-the-art open LLM with strong math and logical reasoning skills.                                       |
    | microsoft/phi-3-mini-4k-instruct            | 4,096 tokens   | Lightweight, state-of-the-art open LLM with strong math and logical reasoning skills.                                       |
    | microsoft/phi-3-small-8k-instruct           | 8,192 tokens   | Lightweight, state-of-the-art open LLM with strong math and logical reasoning skills.                                       |
    | microsoft/phi-3-small-128k-instruct         | 128K tokens    | Lightweight, state-of-the-art open LLM with strong math and logical reasoning skills.                                       |
    | microsoft/phi-3-medium-4k-instruct          | 4,096 tokens   | Lightweight, state-of-the-art open LLM with strong math and logical reasoning skills.                                       |
    | microsoft/phi-3-medium-128k-instruct        | 128K tokens    | Lightweight, state-of-the-art open LLM with strong math and logical reasoning skills.                                       |
    | microsoft/phi-3.5-mini-instruct             | 128K tokens    | Lightweight multilingual LLM powering AI applications in latency bound, memory/compute constrained environments             |
    | microsoft/phi-3.5-moe-instruct              | 128K tokens    | Advanced LLM based on Mixture of Experts architecture to deliver compute efficient content generation                       |
    | microsoft/kosmos-2                          | 1,024 tokens   | Groundbreaking multimodal model designed to understand and reason about visual elements in images.                          |
    | microsoft/phi-3-vision-128k-instruct        | 128k tokens    | Cutting-edge open multimodal model exceling in high-quality reasoning from images.                                          |
    | microsoft/phi-3.5-vision-instruct           | 128k tokens    | Cutting-edge open multimodal model exceling in high-quality reasoning from images.                                          |
    | databricks/dbrx-instruct                    | 12k tokens     | A general-purpose LLM with state-of-the-art performance in language understanding, coding, and RAG.                         |
    | snowflake/arctic                            | 1,024 tokens   | Delivers high efficiency inference for enterprise applications focused on SQL generation and coding.                        |
    | aisingapore/sea-lion-7b-instruct            | 4,096 tokens   | LLM to represent and serve the linguistic and cultural diversity of Southeast Asia                                          |
    | ibm/granite-8b-code-instruct                | 4,096 tokens   | Software programming LLM for code generation, completion, explanation, and multi-turn conversion.                           |
    | ibm/granite-34b-code-instruct               | 8,192 tokens   | Software programming LLM for code generation, completion, explanation, and multi-turn conversion.                           |
    | ibm/granite-3.0-8b-instruct                 | 4,096 tokens   | Advanced Small Language Model supporting RAG, summarization, classification, code, and agentic AI                           |
    | ibm/granite-3.0-3b-a800m-instruct           | 4,096 tokens   | Highly efficient Mixture of Experts model for RAG, summarization, entity extraction, and classification                     |
    | mediatek/breeze-7b-instruct                 | 4,096 tokens   | Creates diverse synthetic data that mimics the characteristics of real-world data.                                          |
    | upstage/solar-10.7b-instruct                | 4,096 tokens   | Excels in NLP tasks, particularly in instruction-following, reasoning, and mathematics.                                     |
    | writer/palmyra-med-70b-32k                  | 32k tokens     | Leading LLM for accurate, contextually relevant responses in the medical domain.                                            |
    | writer/palmyra-med-70b                      | 32k tokens     | Leading LLM for accurate, contextually relevant responses in the medical domain.                                            |
    | writer/palmyra-fin-70b-32k                  | 32k tokens     | Specialized LLM for financial analysis, reporting, and data processing                                                      |
    | 01-ai/yi-large                              | 32k tokens     | Powerful model trained on English and Chinese for diverse tasks including chatbot and creative writing.                     |
    | deepseek-ai/deepseek-coder-6.7b-instruct    | 2k tokens      | Powerful coding model offering advanced capabilities in code generation, completion, and infilling                          |
    | rakuten/rakutenai-7b-instruct               | 1,024 tokens   | Advanced state-of-the-art LLM with language understanding, superior reasoning, and text generation.                         |
    | rakuten/rakutenai-7b-chat                   | 1,024 tokens   | Advanced state-of-the-art LLM with language understanding, superior reasoning, and text generation.                         |
    | baichuan-inc/baichuan2-13b-chat             | 4,096 tokens   | Support Chinese and English chat, coding, math, instruction following, solving quizzes                                      |

    **Note:** This provider uses LiteLLM. Add it as a dependency to your project:

    ```bash theme={null}
    uv add 'crewai[litellm]'
    ```
  </Accordion>

  <Accordion title="Local NVIDIA NIM Deployed using WSL2">
    NVIDIA NIM enables you to run powerful LLMs locally on your Windows machine using WSL2 (Windows Subsystem for Linux).
    This approach allows you to leverage your NVIDIA GPU for private, secure, and cost-effective AI inference without relying on cloud services.
    Perfect for development, testing, or production scenarios where data privacy or offline capabilities are required.

    Here is a step-by-step guide to setting up a local NVIDIA NIM model:

    1. Follow installation instructions from [NVIDIA Website](https://docs.nvidia.com/nim/wsl2/latest/getting-started.html)

    2. Install the local model. For Llama 3.1-8b follow [instructions](https://build.nvidia.com/meta/llama-3_1-8b-instruct/deploy)

    3. Configure your crewai local models:

    ```python Code theme={null}
    from crewai.llm import LLM

    local_nvidia_nim_llm = LLM(
        model="openai/meta/llama-3.1-8b-instruct", # it's an openai-api compatible model
        base_url="http://localhost:8000/v1",
        api_key="<your_api_key|any text if you have not configured it>", # api_key is required, but you can use any text
    )

    # Then you can use it in your crew:

    @CrewBase
    class MyCrew():
        # ...

        @agent
        def researcher(self) -> Agent:
            return Agent(
                config=self.agents_config['researcher'], # type: ignore[index]
                llm=local_nvidia_nim_llm
            )

        # ...
    ```

    **Note:** This provider uses LiteLLM. Add it as a dependency to your project:

    ```bash theme={null}
    uv add 'crewai[litellm]'
    ```
  </Accordion>

  <Accordion title="Groq">
    Set the following environment variables in your `.env` file:

    ```toml Code theme={null}
    GROQ_API_KEY=<your-api-key>
    ```

    Example usage in your CrewAI project:

    ```python Code theme={null}
    llm = LLM(
        model="groq/llama-3.2-90b-text-preview",
        temperature=0.7
    )
    ```

    | Model            | Context Window | Best For                              |
    | ---------------- | -------------- | ------------------------------------- |
    | Llama 3.1 70B/8B | 131,072 tokens | High-performance, large context tasks |
    | Llama 3.2 Series | 8,192 tokens   | General-purpose tasks                 |
    | Mixtral 8x7B     | 32,768 tokens  | Balanced performance and context      |

    **Note:** This provider uses LiteLLM. Add it as a dependency to your project:

    ```bash theme={null}
    uv add 'crewai[litellm]'
    ```
  </Accordion>

  <Accordion title="IBM watsonx.ai">
    Set the following environment variables in your `.env` file:

    ```toml Code theme={null}
    # Required
    WATSONX_URL=<your-url>
    WATSONX_APIKEY=<your-apikey>
    WATSONX_PROJECT_ID=<your-project-id>

    # Optional
    WATSONX_TOKEN=<your-token>
    WATSONX_DEPLOYMENT_SPACE_ID=<your-space-id>
    ```

    Example usage in your CrewAI project:

    ```python Code theme={null}
    llm = LLM(
        model="watsonx/meta-llama/llama-3-1-70b-instruct",
        base_url="https://api.watsonx.ai/v1"
    )
    ```

    **Note:** This provider uses LiteLLM. Add it as a dependency to your project:

    ```bash theme={null}
    uv add 'crewai[litellm]'
    ```
  </Accordion>

  <Accordion title="Ollama (Local LLMs)">
    1. Install Ollama: [ollama.ai](https://ollama.ai/)
    2. Run a model: `ollama run llama3`
    3. Configure:

    ```python Code theme={null}
    llm = LLM(
        model="ollama/llama3:70b",
        base_url="http://localhost:11434"
    )
    ```

    **Note:** This provider uses LiteLLM. Add it as a dependency to your project:

    ```bash theme={null}
    uv add 'crewai[litellm]'
    ```
  </Accordion>

  <Accordion title="Fireworks AI">
    Set the following environment variables in your `.env` file:

    ```toml Code theme={null}
    FIREWORKS_API_KEY=<your-api-key>
    ```

    Example usage in your CrewAI project:

    ```python Code theme={null}
    llm = LLM(
        model="fireworks_ai/accounts/fireworks/models/llama-v3-70b-instruct",
        temperature=0.7
    )
    ```

    **Note:** This provider uses LiteLLM. Add it as a dependency to your project:

    ```bash theme={null}
    uv add 'crewai[litellm]'
    ```
  </Accordion>

  <Accordion title="Perplexity AI">
    Set the following environment variables in your `.env` file:

    ```toml Code theme={null}
    PERPLEXITY_API_KEY=<your-api-key>
    ```

    Example usage in your CrewAI project:

    ```python Code theme={null}
    llm = LLM(
        model="llama-3.1-sonar-large-128k-online",
        base_url="https://api.perplexity.ai/"
    )
    ```

    **Note:** This provider uses LiteLLM. Add it as a dependency to your project:

    ```bash theme={null}
    uv add 'crewai[litellm]'
    ```
  </Accordion>

  <Accordion title="Hugging Face">
    Set the following environment variables in your `.env` file:

    ```toml Code theme={null}
    HF_TOKEN=<your-api-key>
    ```

    Example usage in your CrewAI project:

    ```python Code theme={null}
    llm = LLM(
        model="huggingface/meta-llama/Meta-Llama-3.1-8B-Instruct"
    )
    ```

    **Note:** This provider uses LiteLLM. Add it as a dependency to your project:

    ```bash theme={null}
    uv add 'crewai[litellm]'
    ```
  </Accordion>

  <Accordion title="SambaNova">
    Set the following environment variables in your `.env` file:

    ```toml Code theme={null}
    SAMBANOVA_API_KEY=<your-api-key>
    ```

    Example usage in your CrewAI project:

    ```python Code theme={null}
    llm = LLM(
        model="sambanova/Meta-Llama-3.1-8B-Instruct",
        temperature=0.7
    )
    ```

    | Model            | Context Window       | Best For                              |
    | ---------------- | -------------------- | ------------------------------------- |
    | Llama 3.1 70B/8B | Up to 131,072 tokens | High-performance, large context tasks |
    | Llama 3.1 405B   | 8,192 tokens         | High-performance and output quality   |
    | Llama 3.2 Series | 8,192 tokens         | General-purpose, multimodal tasks     |
    | Llama 3.3 70B    | Up to 131,072 tokens | High-performance and output quality   |
    | Qwen2 familly    | 8,192 tokens         | High-performance and output quality   |

    **Note:** This provider uses LiteLLM. Add it as a dependency to your project:

    ```bash theme={null}
    uv add 'crewai[litellm]'
    ```
  </Accordion>

  <Accordion title="Cerebras">
    Set the following environment variables in your `.env` file:

    ```toml Code theme={null}
    # Required
    CEREBRAS_API_KEY=<your-api-key>
    ```

    Example usage in your CrewAI project:

    ```python Code theme={null}
    llm = LLM(
        model="cerebras/llama3.1-70b",
        temperature=0.7,
        max_tokens=8192
    )
    ```

    <Info>
      Cerebras features:

      * Fast inference speeds
      * Competitive pricing
      * Good balance of speed and quality
      * Support for long context windows
    </Info>

    **Note:** This provider uses LiteLLM. Add it as a dependency to your project:

    ```bash theme={null}
    uv add 'crewai[litellm]'
    ```
  </Accordion>

  <Accordion title="Open Router">
    Set the following environment variables in your `.env` file:

    ```toml Code theme={null}
    OPENROUTER_API_KEY=<your-api-key>
    ```

    Example usage in your CrewAI project:

    ```python Code theme={null}
    llm = LLM(
        model="openrouter/deepseek/deepseek-r1",
        base_url="https://openrouter.ai/api/v1",
        api_key=OPENROUTER_API_KEY
    )
    ```

    <Info>
      Open Router models:

      * openrouter/deepseek/deepseek-r1
      * openrouter/deepseek/deepseek-chat
    </Info>

    **Note:** This provider uses LiteLLM. Add it as a dependency to your project:

    ```bash theme={null}
    uv add 'crewai[litellm]'
    ```
  </Accordion>

  <Accordion title="Nebius AI Studio">
    Set the following environment variables in your `.env` file:

    ```toml Code theme={null}
    NEBIUS_API_KEY=<your-api-key>
    ```

    Example usage in your CrewAI project:

    ```python Code theme={null}
    llm = LLM(
        model="nebius/Qwen/Qwen3-30B-A3B"
    )
    ```

    <Info>
      Nebius AI Studio features:

      * Large collection of open source models
      * Higher rate limits
      * Competitive pricing
      * Good balance of speed and quality
    </Info>

    **Note:** This provider uses LiteLLM. Add it as a dependency to your project:

    ```bash theme={null}
    uv add 'crewai[litellm]'
    ```
  </Accordion>
</AccordionGroup>

## Streaming Responses

CrewAI supports streaming responses from LLMs, allowing your application to receive and process outputs in real-time as they're generated.

<Tabs>
  <Tab title="Basic Setup">
    Enable streaming by setting the `stream` parameter to `True` when initializing your LLM:

    ```python theme={null}
    from crewai import LLM

    # Create an LLM with streaming enabled
    llm = LLM(
        model="openai/gpt-4o",
        stream=True  # Enable streaming
    )
    ```

    When streaming is enabled, responses are delivered in chunks as they're generated, creating a more responsive user experience.
  </Tab>

  <Tab title="Event Handling">
    CrewAI emits events for each chunk received during streaming:

    ```python theme={null}
    from crewai.events import (
      LLMStreamChunkEvent
    )
    from crewai.events import BaseEventListener

    class MyCustomListener(BaseEventListener):
        def setup_listeners(self, crewai_event_bus):
            @crewai_event_bus.on(LLMStreamChunkEvent)
            def on_llm_stream_chunk(self, event: LLMStreamChunkEvent):
              # Process each chunk as it arrives
              print(f"Received chunk: {event.chunk}")

    my_listener = MyCustomListener()
    ```

    <Tip>
      [Click here](/en/concepts/event-listener#event-listeners) for more details
    </Tip>
  </Tab>

  <Tab title="Agent & Task Tracking">
    All LLM events in CrewAI include agent and task information, allowing you to track and filter LLM interactions by specific agents or tasks:

    ```python theme={null}
    from crewai import LLM, Agent, Task, Crew
    from crewai.events import LLMStreamChunkEvent
    from crewai.events import BaseEventListener

    class MyCustomListener(BaseEventListener):
        def setup_listeners(self, crewai_event_bus):
            @crewai_event_bus.on(LLMStreamChunkEvent)
            def on_llm_stream_chunk(source, event):
                if researcher.id == event.agent_id:
                    print("\n==============\n Got event:", event, "\n==============\n")


    my_listener = MyCustomListener()

    llm = LLM(model="gpt-4o-mini", temperature=0, stream=True)

    researcher = Agent(
        role="About User",
        goal="You know everything about the user.",
        backstory="""You are a master at understanding people and their preferences.""",
        llm=llm,
    )

    search = Task(
        description="Answer the following questions about the user: {question}",
        expected_output="An answer to the question.",
        agent=researcher,
    )

    crew = Crew(agents=[researcher], tasks=[search])

    result = crew.kickoff(
        inputs={"question": "..."}
    )
    ```

    <Info>
      This feature is particularly useful for:

      * Debugging specific agent behaviors
      * Logging LLM usage by task type
      * Auditing which agents are making what types of LLM calls
      * Performance monitoring of specific tasks
    </Info>
  </Tab>
</Tabs>

## Async LLM Calls

CrewAI supports asynchronous LLM calls for improved performance and concurrency in your AI workflows. Async calls allow you to run multiple LLM requests concurrently without blocking, making them ideal for high-throughput applications and parallel agent operations.

<Tabs>
  <Tab title="Basic Usage">
    Use the `acall` method for asynchronous LLM requests:

    ```python theme={null}
    import asyncio
    from crewai import LLM

    async def main():
        llm = LLM(model="openai/gpt-4o")

        # Single async call
        response = await llm.acall("What is the capital of France?")
        print(response)

    asyncio.run(main())
    ```

    The `acall` method supports all the same parameters as the synchronous `call` method, including messages, tools, and callbacks.
  </Tab>

  <Tab title="With Streaming">
    Combine async calls with streaming for real-time concurrent responses:

    ```python theme={null}
    import asyncio
    from crewai import LLM

    async def stream_async():
        llm = LLM(model="openai/gpt-4o", stream=True)

        response = await llm.acall("Write a short story about AI")

        print(response)

    asyncio.run(stream_async())
    ```
  </Tab>
</Tabs>

## Structured LLM Calls

CrewAI supports structured responses from LLM calls by allowing you to define a `response_format` using a Pydantic model. This enables the framework to automatically parse and validate the output, making it easier to integrate the response into your application without manual post-processing.

For example, you can define a Pydantic model to represent the expected response structure and pass it as the `response_format` when instantiating the LLM. The model will then be used to convert the LLM output into a structured Python object.

```python Code theme={null}
from crewai import LLM

class Dog(BaseModel):
    name: str
    age: int
    breed: str


llm = LLM(model="gpt-4o", response_format=Dog)

response = llm.call(
    "Analyze the following messages and return the name, age, and breed. "
    "Meet Kona! She is 3 years old and is a black german shepherd."
)
print(response)

# Output:
# Dog(name='Kona', age=3, breed='black german shepherd')
```

## Advanced Features and Optimization

Learn how to get the most out of your LLM configuration:

<AccordionGroup>
  <Accordion title="Context Window Management">
    CrewAI includes smart context management features:

    ```python theme={null}
    from crewai import LLM

    # CrewAI automatically handles:
    # 1. Token counting and tracking
    # 2. Content summarization when needed
    # 3. Task splitting for large contexts

    llm = LLM(
        model="gpt-4",
        max_tokens=4000,  # Limit response length
    )
    ```

    <Info>
      Best practices for context management:

      1. Choose models with appropriate context windows
      2. Pre-process long inputs when possible
      3. Use chunking for large documents
      4. Monitor token usage to optimize costs
    </Info>
  </Accordion>

  <Accordion title="Performance Optimization">
    <Steps>
      <Step title="Token Usage Optimization">
        Choose the right context window for your task:

        * Small tasks (up to 4K tokens): Standard models
        * Medium tasks (between 4K-32K): Enhanced models
        * Large tasks (over 32K): Large context models

        ```python theme={null}
        # Configure model with appropriate settings
        llm = LLM(
            model="openai/gpt-4-turbo-preview",
            temperature=0.7,    # Adjust based on task
            max_tokens=4096,    # Set based on output needs
            timeout=300        # Longer timeout for complex tasks
        )
        ```

        <Tip>
          * Lower temperature (0.1 to 0.3) for factual responses
          * Higher temperature (0.7 to 0.9) for creative tasks
        </Tip>
      </Step>

      <Step title="Best Practices">
        1. Monitor token usage
        2. Implement rate limiting
        3. Use caching when possible
        4. Set appropriate max\_tokens limits
      </Step>
    </Steps>

    <Info>
      Remember to regularly monitor your token usage and adjust your configuration as needed to optimize costs and performance.
    </Info>
  </Accordion>

  <Accordion title="Drop Additional Parameters">
    CrewAI internally uses native sdks for LLM calls, which allows you to drop additional parameters that are not needed for your specific use case. This can help simplify your code and reduce the complexity of your LLM configuration.
    For example, if you don't need to send the <code>stop</code> parameter, you can simply omit it from your LLM call:

    ```python theme={null}
    from crewai import LLM
    import os

    os.environ["OPENAI_API_KEY"] = "<api-key>"

    o3_llm = LLM(
        model="o3",
        drop_params=True,
        additional_drop_params=["stop"]
    )
    ```
  </Accordion>

  <Accordion title="Transport Interceptors">
    CrewAI provides message interceptors for several providers, allowing you to hook into request/response cycles at the transport layer.

    **Supported Providers:**

    * ✅ OpenAI
    * ✅ Anthropic

    **Basic Usage:**

    ```python theme={null}
    import httpx
    from crewai import LLM
    from crewai.llms.hooks import BaseInterceptor

    class CustomInterceptor(BaseInterceptor[httpx.Request, httpx.Response]):
    """Custom interceptor to modify requests and responses."""

    def on_outbound(self, request: httpx.Request) -> httpx.Request:
        """Print request before sending to the LLM provider."""
        print(request)
        return request

    def on_inbound(self, response: httpx.Response) -> httpx.Response:
        """Process response after receiving from the LLM provider."""
        print(f"Status: {response.status_code}")
        print(f"Response time: {response.elapsed}")
        return response

    # Use the interceptor with an LLM
    llm = LLM(
    model="openai/gpt-4o",
    interceptor=CustomInterceptor()
    )
    ```

    **Important Notes:**

    * Both methods must return the received object or type of object.
    * Modifying received objects may result in unexpected behavior or application crashes.
    * Not all providers support interceptors - check the supported providers list above

    <Info>
      Interceptors operate at the transport layer. This is particularly useful for:

      * Message transformation and filtering
      * Debugging API interactions
    </Info>
  </Accordion>
</AccordionGroup>

## Common Issues and Solutions

<Tabs>
  <Tab title="Authentication">
    <Warning>
      Most authentication issues can be resolved by checking API key format and environment variable names.
    </Warning>

    ```bash theme={null}
    # OpenAI
    OPENAI_API_KEY=sk-...

    # Anthropic
    ANTHROPIC_API_KEY=sk-ant-...
    ```
  </Tab>

  <Tab title="Model Names">
    <Check>
      Always include the provider prefix in model names
    </Check>

    ```python theme={null}
    # Correct
    llm = LLM(model="openai/gpt-4")

    # Incorrect
    llm = LLM(model="gpt-4")
    ```
  </Tab>

  <Tab title="Context Length">
    <Tip>
      Use larger context models for extensive tasks
    </Tip>

    ```python theme={null}
    # Large context model
    llm = LLM(model="openai/gpt-4o")  # 128K tokens
    ```
  </Tab>
</Tabs>


# Memory
Source: https://docs.crewai.com/en/concepts/memory

Leveraging the unified memory system in CrewAI to enhance agent capabilities.

## Overview

CrewAI provides a **unified memory system** -- a single `Memory` class that replaces separate short-term, long-term, entity, and external memory types with one intelligent API. Memory uses an LLM to analyze content when saving (inferring scope, categories, and importance) and supports adaptive-depth recall with composite scoring that blends semantic similarity, recency, and importance.

You can use memory four ways: **standalone** (scripts, notebooks), **with Crews**, **with Agents**, or **inside Flows**.

## Quick Start

```python theme={null}
from crewai import Memory

memory = Memory()

# Store -- the LLM infers scope, categories, and importance
memory.remember("We decided to use PostgreSQL for the user database.")

# Retrieve -- results ranked by composite score (semantic + recency + importance)
matches = memory.recall("What database did we choose?")
for m in matches:
    print(f"[{m.score:.2f}] {m.record.content}")

# Tune scoring for a fast-moving project
memory = Memory(recency_weight=0.5, recency_half_life_days=7)

# Forget
memory.forget(scope="/project/old")

# Explore the self-organized scope tree
print(memory.tree())
print(memory.info("/"))
```

## Four Ways to Use Memory

### Standalone

Use memory in scripts, notebooks, CLI tools, or as a standalone knowledge base -- no agents or crews required.

```python theme={null}
from crewai import Memory

memory = Memory()

# Build up knowledge
memory.remember("The API rate limit is 1000 requests per minute.")
memory.remember("Our staging environment uses port 8080.")
memory.remember("The team agreed to use feature flags for all new releases.")

# Later, recall what you need
matches = memory.recall("What are our API limits?", limit=5)
for m in matches:
    print(f"[{m.score:.2f}] {m.record.content}")

# Extract atomic facts from a longer text
raw = """Meeting notes: We decided to migrate from MySQL to PostgreSQL
next quarter. The budget is $50k. Sarah will lead the migration."""

facts = memory.extract_memories(raw)
# ["Migration from MySQL to PostgreSQL planned for next quarter",
#  "Database migration budget is $50k",
#  "Sarah will lead the database migration"]

for fact in facts:
    memory.remember(fact)
```

### With Crews

Pass `memory=True` for default settings, or pass a configured `Memory` instance for custom behavior.

```python theme={null}
from crewai import Crew, Agent, Task, Process, Memory

# Option 1: Default memory
crew = Crew(
    agents=[researcher, writer],
    tasks=[research_task, writing_task],
    process=Process.sequential,
    memory=True,
    verbose=True,
)

# Option 2: Custom memory with tuned scoring
memory = Memory(
    recency_weight=0.4,
    semantic_weight=0.4,
    importance_weight=0.2,
    recency_half_life_days=14,
)
crew = Crew(
    agents=[researcher, writer],
    tasks=[research_task, writing_task],
    memory=memory,
)
```

When `memory=True`, the crew creates a default `Memory()` and passes the crew's `embedder` configuration through automatically. All agents in the crew share the crew's memory unless an agent has its own.

After each task, the crew automatically extracts discrete facts from the task output and stores them. Before each task, the agent recalls relevant context from memory and injects it into the task prompt.

### With Agents

Agents can use the crew's shared memory (default) or receive a scoped view for private context.

```python theme={null}
from crewai import Agent, Memory

memory = Memory()

# Researcher gets a private scope -- only sees /agent/researcher
researcher = Agent(
    role="Researcher",
    goal="Find and analyze information",
    backstory="Expert researcher with attention to detail",
    memory=memory.scope("/agent/researcher"),
)

# Writer uses crew shared memory (no agent-level memory set)
writer = Agent(
    role="Writer",
    goal="Produce clear, well-structured content",
    backstory="Experienced technical writer",
    # memory not set -- uses crew._memory when crew has memory enabled
)
```

This pattern gives the researcher private findings while the writer reads from the shared crew memory.

### With Flows

Every Flow has built-in memory. Use `self.remember()`, `self.recall()`, and `self.extract_memories()` inside any flow method.

```python theme={null}
from crewai.flow.flow import Flow, listen, start

class ResearchFlow(Flow):
    @start()
    def gather_data(self):
        findings = "PostgreSQL handles 10k concurrent connections. MySQL caps at 5k."
        self.remember(findings, scope="/research/databases")
        return findings

    @listen(gather_data)
    def write_report(self, findings):
        # Recall past research to provide context
        past = self.recall("database performance benchmarks")
        context = "\n".join(f"- {m.record.content}" for m in past)
        return f"Report:\nNew findings: {findings}\nPrevious context:\n{context}"
```

See the [Flows documentation](/concepts/flows) for more on memory in Flows.

## Hierarchical Scopes

### What Scopes Are

Memories are organized into a hierarchical tree of scopes, similar to a filesystem. Each scope is a path like `/`, `/project/alpha`, or `/agent/researcher/findings`.

```
/
  /company
    /company/engineering
    /company/product
  /project
    /project/alpha
    /project/beta
  /agent
    /agent/researcher
    /agent/writer
```

Scopes provide **context-dependent memory** -- when you recall within a scope, you only search that branch of the tree, which improves both precision and performance.

### How Scope Inference Works

When you call `remember()` without specifying a scope, the LLM analyzes the content and the existing scope tree, then suggests the best placement. If no existing scope fits, it creates a new one. Over time, the scope tree grows organically from the content itself -- you don't need to design a schema upfront.

```python theme={null}
memory = Memory()

# LLM infers scope from content
memory.remember("We chose PostgreSQL for the user database.")
# -> might be placed under /project/decisions or /engineering/database

# You can also specify scope explicitly
memory.remember("Sprint velocity is 42 points", scope="/team/metrics")
```

### Visualizing the Scope Tree

```python theme={null}
print(memory.tree())
# / (15 records)
#   /project (8 records)
#     /project/alpha (5 records)
#     /project/beta (3 records)
#   /agent (7 records)
#     /agent/researcher (4 records)
#     /agent/writer (3 records)

print(memory.info("/project/alpha"))
# ScopeInfo(path='/project/alpha', record_count=5,
#           categories=['architecture', 'database'],
#           oldest_record=datetime(...), newest_record=datetime(...),
#           child_scopes=[])
```

### MemoryScope: Subtree Views

A `MemoryScope` restricts all operations to a branch of the tree. The agent or code using it can only see and write within that subtree.

```python theme={null}
memory = Memory()

# Create a scope for a specific agent
agent_memory = memory.scope("/agent/researcher")

# Everything is relative to /agent/researcher
agent_memory.remember("Found three relevant papers on LLM memory.")
# -> stored under /agent/researcher

agent_memory.recall("relevant papers")
# -> searches only under /agent/researcher

# Narrow further with subscope
project_memory = agent_memory.subscope("project-alpha")
# -> /agent/researcher/project-alpha
```

### Best Practices for Scope Design

* **Start flat, let the LLM organize.** Don't over-engineer your scope hierarchy upfront. Begin with `memory.remember(content)` and let the LLM's scope inference create structure as content accumulates.

* **Use `/{entity_type}/{identifier}` patterns.** Natural hierarchies emerge from patterns like `/project/alpha`, `/agent/researcher`, `/company/engineering`, `/customer/acme-corp`.

* **Scope by concern, not by data type.** Use `/project/alpha/decisions` rather than `/decisions/project/alpha`. This keeps related content together.

* **Keep depth shallow (2-3 levels).** Deeply nested scopes become too sparse. `/project/alpha/architecture` is good; `/project/alpha/architecture/decisions/databases/postgresql` is too deep.

* **Use explicit scopes when you know, let the LLM infer when you don't.** If you're storing a known project decision, pass `scope="/project/alpha/decisions"`. If you're storing freeform agent output, omit the scope and let the LLM figure it out.

### Use Case Examples

**Multi-project team:**

```python theme={null}
memory = Memory()
# Each project gets its own branch
memory.remember("Using microservices architecture", scope="/project/alpha/architecture")
memory.remember("GraphQL API for client apps", scope="/project/beta/api")

# Recall across all projects
memory.recall("API design decisions")

# Or within a specific project
memory.recall("API design", scope="/project/beta")
```

**Per-agent private context with shared knowledge:**

```python theme={null}
memory = Memory()

# Researcher has private findings
researcher_memory = memory.scope("/agent/researcher")

# Writer can read from both its own scope and shared company knowledge
writer_view = memory.slice(
    scopes=["/agent/writer", "/company/knowledge"],
    read_only=True,
)
```

**Customer support (per-customer context):**

```python theme={null}
memory = Memory()

# Each customer gets isolated context
memory.remember("Prefers email communication", scope="/customer/acme-corp")
memory.remember("On enterprise plan, 50 seats", scope="/customer/acme-corp")

# Shared product docs are accessible to all agents
memory.remember("Rate limit is 1000 req/min on enterprise plan", scope="/product/docs")
```

## Memory Slices

### What Slices Are

A `MemorySlice` is a view across multiple, possibly disjoint scopes. Unlike a scope (which restricts to one subtree), a slice lets you recall from several branches simultaneously.

### When to Use Slices vs Scopes

* **Scope**: Use when an agent or code block should be restricted to a single subtree. Example: an agent that only sees `/agent/researcher`.
* **Slice**: Use when you need to combine context from multiple branches. Example: an agent that reads from its own scope plus shared company knowledge.

### Read-Only Slices

The most common pattern: give an agent read access to multiple branches without letting it write to shared areas.

```python theme={null}
memory = Memory()

# Agent can recall from its own scope AND company knowledge,
# but cannot write to company knowledge
agent_view = memory.slice(
    scopes=["/agent/researcher", "/company/knowledge"],
    read_only=True,
)

matches = agent_view.recall("company security policies", limit=5)
# Searches both /agent/researcher and /company/knowledge, merges and ranks results

agent_view.remember("new finding")  # Raises PermissionError (read-only)
```

### Read-Write Slices

When read-only is disabled, you can write to any of the included scopes, but you must specify which scope explicitly.

```python theme={null}
view = memory.slice(scopes=["/team/alpha", "/team/beta"], read_only=False)

# Must specify scope when writing
view.remember("Cross-team decision", scope="/team/alpha", categories=["decisions"])
```

## Composite Scoring

Recall results are ranked by a weighted combination of three signals:

```
composite = semantic_weight * similarity + recency_weight * decay + importance_weight * importance
```

Where:

* **similarity** = `1 / (1 + distance)` from the vector index (0 to 1)
* **decay** = `0.5^(age_days / half_life_days)` -- exponential decay (1.0 for today, 0.5 at half-life)
* **importance** = the record's importance score (0 to 1), set at encoding time

Configure these directly on the `Memory` constructor:

```python theme={null}
# Sprint retrospective: favor recent memories, short half-life
memory = Memory(
    recency_weight=0.5,
    semantic_weight=0.3,
    importance_weight=0.2,
    recency_half_life_days=7,
)

# Architecture knowledge base: favor important memories, long half-life
memory = Memory(
    recency_weight=0.1,
    semantic_weight=0.5,
    importance_weight=0.4,
    recency_half_life_days=180,
)
```

Each `MemoryMatch` includes a `match_reasons` list so you can see why a result ranked where it did (e.g. `["semantic", "recency", "importance"]`).

## LLM Analysis Layer

Memory uses the LLM in three ways:

1. **On save** -- When you omit scope, categories, or importance, the LLM analyzes the content and suggests scope, categories, importance, and metadata (entities, dates, topics).
2. **On recall** -- For deep/auto recall, the LLM analyzes the query (keywords, time hints, suggested scopes, complexity) to guide retrieval.
3. **Extract memories** -- `extract_memories(content)` breaks raw text (e.g. task output) into discrete memory statements. Agents use this before calling `remember()` on each statement so that atomic facts are stored instead of one large blob.

All analysis degrades gracefully on LLM failure -- see [Failure Behavior](#failure-behavior).

## Memory Consolidation

When saving new content, the encoding pipeline automatically checks for similar existing records in storage. If the similarity is above `consolidation_threshold` (default 0.85), the LLM decides what to do:

* **keep** -- The existing record is still accurate and not redundant.
* **update** -- The existing record should be updated with new information (LLM provides the merged content).
* **delete** -- The existing record is outdated, superseded, or contradicted.
* **insert\_new** -- Whether the new content should also be inserted as a separate record.

This prevents duplicates from accumulating. For example, if you save "CrewAI ensures reliable operation" three times, consolidation recognizes the duplicates and keeps only one record.

### Intra-batch Dedup

When using `remember_many()`, items within the same batch are compared against each other before hitting storage. If two items have cosine similarity >= `batch_dedup_threshold` (default 0.98), the later one is silently dropped. This catches exact or near-exact duplicates within a single batch without any LLM calls (pure vector math).

```python theme={null}
# Only 2 records are stored (the third is a near-duplicate of the first)
memory.remember_many([
    "CrewAI supports complex workflows.",
    "Python is a great language.",
    "CrewAI supports complex workflows.",  # dropped by intra-batch dedup
])
```

## Non-blocking Saves

`remember_many()` is **non-blocking** -- it submits the encoding pipeline to a background thread and returns immediately. This means the agent can continue to the next task while memories are being saved.

```python theme={null}
# Returns immediately -- save happens in background
memory.remember_many(["Fact A.", "Fact B.", "Fact C."])

# recall() automatically waits for pending saves before searching
matches = memory.recall("facts")  # sees all 3 records
```

### Read Barrier

Every `recall()` call automatically calls `drain_writes()` before searching, ensuring the query always sees the latest persisted records. This is transparent -- you never need to think about it.

### Crew Shutdown

When a crew finishes, `kickoff()` drains all pending memory saves in its `finally` block, so no saves are lost even if the crew completes while background saves are in flight.

### Standalone Usage

For scripts or notebooks where there's no crew lifecycle, call `drain_writes()` or `close()` explicitly:

```python theme={null}
memory = Memory()
memory.remember_many(["Fact A.", "Fact B."])

# Option 1: Wait for pending saves
memory.drain_writes()

# Option 2: Drain and shut down the background pool
memory.close()
```

## Source and Privacy

Every memory record can carry a `source` tag for provenance tracking and a `private` flag for access control.

### Source Tracking

The `source` parameter identifies where a memory came from:

```python theme={null}
# Tag memories with their origin
memory.remember("User prefers dark mode", source="user:alice")
memory.remember("System config updated", source="admin")
memory.remember("Agent found a bug", source="agent:debugger")

# Recall only memories from a specific source
matches = memory.recall("user preferences", source="user:alice")
```

### Private Memories

Private memories are only visible to recall when the `source` matches:

```python theme={null}
# Store a private memory
memory.remember("Alice's API key is sk-...", source="user:alice", private=True)

# This recall sees the private memory (source matches)
matches = memory.recall("API key", source="user:alice")

# This recall does NOT see it (different source)
matches = memory.recall("API key", source="user:bob")

# Admin access: see all private records regardless of source
matches = memory.recall("API key", include_private=True)
```

This is particularly useful in multi-user or enterprise deployments where different users' memories should be isolated.

## RecallFlow (Deep Recall)

`recall()` supports two depths:

* **`depth="shallow"`** -- Direct vector search with composite scoring. Fast (\~200ms), no LLM calls.
* **`depth="deep"` (default)** -- Runs a multi-step RecallFlow: query analysis, scope selection, parallel vector search, confidence-based routing, and optional recursive exploration when confidence is low.

**Smart LLM skip**: Queries shorter than `query_analysis_threshold` (default 200 characters) skip the LLM query analysis entirely, even in deep mode. Short queries like "What database do we use?" are already good search phrases -- the LLM analysis adds little value. This saves \~1-3s per recall for typical short queries. Only longer queries (e.g. full task descriptions) go through LLM distillation into targeted sub-queries.

```python theme={null}
# Shallow: pure vector search, no LLM
matches = memory.recall("What did we decide?", limit=10, depth="shallow")

# Deep (default): intelligent retrieval with LLM analysis for long queries
matches = memory.recall(
    "Summarize all architecture decisions from this quarter",
    limit=10,
    depth="deep",
)
```

The confidence thresholds that control the RecallFlow router are configurable:

```python theme={null}
memory = Memory(
    confidence_threshold_high=0.9,   # Only synthesize when very confident
    confidence_threshold_low=0.4,    # Explore deeper more aggressively
    exploration_budget=2,            # Allow up to 2 exploration rounds
    query_analysis_threshold=200,    # Skip LLM for queries shorter than this
)
```

## Embedder Configuration

Memory needs an embedding model to convert text into vectors for semantic search. You can configure this in three ways.

### Passing to Memory Directly

```python theme={null}
from crewai import Memory

# As a config dict
memory = Memory(embedder={"provider": "openai", "config": {"model_name": "text-embedding-3-small"}})

# As a pre-built callable
from crewai.rag.embeddings.factory import build_embedder
embedder = build_embedder({"provider": "ollama", "config": {"model_name": "mxbai-embed-large"}})
memory = Memory(embedder=embedder)
```

### Via Crew Embedder Config

When using `memory=True`, the crew's `embedder` config is passed through:

```python theme={null}
from crewai import Crew

crew = Crew(
    agents=[...],
    tasks=[...],
    memory=True,
    embedder={"provider": "openai", "config": {"model_name": "text-embedding-3-small"}},
)
```

### Provider Examples

<AccordionGroup>
  <Accordion title="OpenAI (default)">
    ```python theme={null}
    memory = Memory(embedder={
        "provider": "openai",
        "config": {
            "model_name": "text-embedding-3-small",
            # "api_key": "sk-...",  # or set OPENAI_API_KEY env var
        },
    })
    ```
  </Accordion>

  <Accordion title="Ollama (local, private)">
    ```python theme={null}
    memory = Memory(embedder={
        "provider": "ollama",
        "config": {
            "model_name": "mxbai-embed-large",
            "url": "http://localhost:11434/api/embeddings",
        },
    })
    ```
  </Accordion>

  <Accordion title="Azure OpenAI">
    ```python theme={null}
    memory = Memory(embedder={
        "provider": "azure",
        "config": {
            "deployment_id": "your-embedding-deployment",
            "api_key": "your-azure-api-key",
            "api_base": "https://your-resource.openai.azure.com",
            "api_version": "2024-02-01",
        },
    })
    ```
  </Accordion>

  <Accordion title="Google AI">
    ```python theme={null}
    memory = Memory(embedder={
        "provider": "google-generativeai",
        "config": {
            "model_name": "gemini-embedding-001",
            # "api_key": "...",  # or set GOOGLE_API_KEY env var
        },
    })
    ```
  </Accordion>

  <Accordion title="Google Vertex AI">
    ```python theme={null}
    memory = Memory(embedder={
        "provider": "google-vertex",
        "config": {
            "model_name": "gemini-embedding-001",
            "project_id": "your-gcp-project-id",
            "location": "us-central1",
        },
    })
    ```
  </Accordion>

  <Accordion title="Cohere">
    ```python theme={null}
    memory = Memory(embedder={
        "provider": "cohere",
        "config": {
            "model_name": "embed-english-v3.0",
            # "api_key": "...",  # or set COHERE_API_KEY env var
        },
    })
    ```
  </Accordion>

  <Accordion title="VoyageAI">
    ```python theme={null}
    memory = Memory(embedder={
        "provider": "voyageai",
        "config": {
            "model": "voyage-3",
            # "api_key": "...",  # or set VOYAGE_API_KEY env var
        },
    })
    ```
  </Accordion>

  <Accordion title="AWS Bedrock">
    ```python theme={null}
    memory = Memory(embedder={
        "provider": "amazon-bedrock",
        "config": {
            "model_name": "amazon.titan-embed-text-v1",
            # Uses default AWS credentials (boto3 session)
        },
    })
    ```
  </Accordion>

  <Accordion title="Hugging Face">
    ```python theme={null}
    memory = Memory(embedder={
        "provider": "huggingface",
        "config": {
            "model_name": "sentence-transformers/all-MiniLM-L6-v2",
        },
    })
    ```
  </Accordion>

  <Accordion title="Jina">
    ```python theme={null}
    memory = Memory(embedder={
        "provider": "jina",
        "config": {
            "model_name": "jina-embeddings-v2-base-en",
            # "api_key": "...",  # or set JINA_API_KEY env var
        },
    })
    ```
  </Accordion>

  <Accordion title="IBM WatsonX">
    ```python theme={null}
    memory = Memory(embedder={
        "provider": "watsonx",
        "config": {
            "model_id": "ibm/slate-30m-english-rtrvr",
            "api_key": "your-watsonx-api-key",
            "project_id": "your-project-id",
            "url": "https://us-south.ml.cloud.ibm.com",
        },
    })
    ```
  </Accordion>

  <Accordion title="Custom Embedder">
    ```python theme={null}
    # Pass any callable that takes a list of strings and returns a list of vectors
    def my_embedder(texts: list[str]) -> list[list[float]]:
        # Your embedding logic here
        return [[0.1, 0.2, ...] for _ in texts]

    memory = Memory(embedder=my_embedder)
    ```
  </Accordion>
</AccordionGroup>

### Provider Reference

| Provider             | Key                    | Typical Model                 | Notes                          |
| :------------------- | :--------------------- | :---------------------------- | :----------------------------- |
| OpenAI               | `openai`               | `text-embedding-3-small`      | Default. Set `OPENAI_API_KEY`. |
| Ollama               | `ollama`               | `mxbai-embed-large`           | Local, no API key needed.      |
| Azure OpenAI         | `azure`                | `text-embedding-ada-002`      | Requires `deployment_id`.      |
| Google AI            | `google-generativeai`  | `gemini-embedding-001`        | Set `GOOGLE_API_KEY`.          |
| Google Vertex        | `google-vertex`        | `gemini-embedding-001`        | Requires `project_id`.         |
| Cohere               | `cohere`               | `embed-english-v3.0`          | Strong multilingual support.   |
| VoyageAI             | `voyageai`             | `voyage-3`                    | Optimized for retrieval.       |
| AWS Bedrock          | `amazon-bedrock`       | `amazon.titan-embed-text-v1`  | Uses boto3 credentials.        |
| Hugging Face         | `huggingface`          | `all-MiniLM-L6-v2`            | Local sentence-transformers.   |
| Jina                 | `jina`                 | `jina-embeddings-v2-base-en`  | Set `JINA_API_KEY`.            |
| IBM WatsonX          | `watsonx`              | `ibm/slate-30m-english-rtrvr` | Requires `project_id`.         |
| Sentence Transformer | `sentence-transformer` | `all-MiniLM-L6-v2`            | Local, no API key.             |
| Custom               | `custom`               | --                            | Requires `embedding_callable`. |

## LLM Configuration

Memory uses an LLM for save analysis (scope, categories, importance inference), consolidation decisions, and deep recall query analysis. You can configure which model to use.

```python theme={null}
from crewai import Memory, LLM

# Default: gpt-4o-mini
memory = Memory()

# Use a different OpenAI model
memory = Memory(llm="gpt-4o")

# Use Anthropic
memory = Memory(llm="anthropic/claude-3-haiku-20240307")

# Use Ollama for fully local/private analysis
memory = Memory(llm="ollama/llama3.2")

# Use Google Gemini
memory = Memory(llm="gemini/gemini-2.0-flash")

# Pass a pre-configured LLM instance with custom settings
llm = LLM(model="gpt-4o", temperature=0)
memory = Memory(llm=llm)
```

The LLM is initialized **lazily** -- it's only created when first needed. This means `Memory()` never fails at construction time, even if API keys aren't set. Errors only surface when the LLM is actually called (e.g. when saving without explicit scope/categories, or during deep recall).

For fully offline/private operation, use a local model for both the LLM and embedder:

```python theme={null}
memory = Memory(
    llm="ollama/llama3.2",
    embedder={"provider": "ollama", "config": {"model_name": "mxbai-embed-large"}},
)
```

## Storage Backend

* **Default**: LanceDB, stored under `./.crewai/memory` (or `$CREWAI_STORAGE_DIR/memory` if the env var is set, or the path you pass as `storage="path/to/dir"`).
* **Custom backend**: Implement the `StorageBackend` protocol (see `crewai.memory.storage.backend`) and pass an instance to `Memory(storage=your_backend)`.

## Discovery

Inspect the scope hierarchy, categories, and records:

```python theme={null}
memory.tree()                        # Formatted tree of scopes and record counts
memory.tree("/project", max_depth=2) # Subtree view
memory.info("/project")              # ScopeInfo: record_count, categories, oldest/newest
memory.list_scopes("/")              # Immediate child scopes
memory.list_categories()             # Category names and counts
memory.list_records(scope="/project/alpha", limit=20)  # Records in a scope, newest first
```

## Failure Behavior

If the LLM fails during analysis (network error, rate limit, invalid response), memory degrades gracefully:

* **Save analysis** -- A warning is logged and the memory is still stored with default scope `/`, empty categories, and importance `0.5`.
* **Extract memories** -- The full content is stored as a single memory so nothing is dropped.
* **Query analysis** -- Recall falls back to simple scope selection and vector search so you still get results.

No exception is raised for these analysis failures; only storage or embedder failures will raise.

## Privacy Note

Memory content is sent to the configured LLM for analysis (scope/categories/importance on save, query analysis and optional deep recall). For sensitive data, use a local LLM (e.g. Ollama) or ensure your provider meets your compliance requirements.

## Memory Events

All memory operations emit events with `source_type="unified_memory"`. You can listen for timing, errors, and content.

| Event                             | Description            | Key Properties                                   |
| :-------------------------------- | :--------------------- | :----------------------------------------------- |
| **MemoryQueryStartedEvent**       | Query begins           | `query`, `limit`                                 |
| **MemoryQueryCompletedEvent**     | Query succeeds         | `query`, `results`, `query_time_ms`              |
| **MemoryQueryFailedEvent**        | Query fails            | `query`, `error`                                 |
| **MemorySaveStartedEvent**        | Save begins            | `value`, `metadata`                              |
| **MemorySaveCompletedEvent**      | Save succeeds          | `value`, `save_time_ms`                          |
| **MemorySaveFailedEvent**         | Save fails             | `value`, `error`                                 |
| **MemoryRetrievalStartedEvent**   | Agent retrieval starts | `task_id`                                        |
| **MemoryRetrievalCompletedEvent** | Agent retrieval done   | `task_id`, `memory_content`, `retrieval_time_ms` |

Example: monitor query time:

```python theme={null}
from crewai.events import BaseEventListener, MemoryQueryCompletedEvent

class MemoryMonitor(BaseEventListener):
    def setup_listeners(self, crewai_event_bus):
        @crewai_event_bus.on(MemoryQueryCompletedEvent)
        def on_done(source, event):
            if getattr(event, "source_type", None) == "unified_memory":
                print(f"Query '{event.query}' completed in {event.query_time_ms:.0f}ms")
```

## Troubleshooting

**Memory not persisting?**

* Ensure the storage path is writable (default `./.crewai/memory`). Pass `storage="./your_path"` to use a different directory, or set the `CREWAI_STORAGE_DIR` environment variable.
* When using a crew, confirm `memory=True` or `memory=Memory(...)` is set.

**Slow recall?**

* Use `depth="shallow"` for routine agent context. Reserve `depth="deep"` for complex queries.
* Increase `query_analysis_threshold` to skip LLM analysis for more queries.

**LLM analysis errors in logs?**

* Memory still saves/recalls with safe defaults. Check API keys, rate limits, and model availability if you want full LLM analysis.

**Background save errors in logs?**

* Memory saves run in a background thread. Errors are emitted as `MemorySaveFailedEvent` but don't crash the agent. Check logs for the root cause (usually LLM or embedder connection issues).

**Concurrent write conflicts?**

* LanceDB operations are serialized with a shared lock and retried automatically on conflict. This handles multiple `Memory` instances pointing at the same database (e.g. agent memory + crew memory). No action needed.

**Browse memory from the terminal:**

```bash theme={null}
crewai memory                              # Opens the TUI browser
crewai memory --storage-path ./my_memory   # Point to a specific directory
```

**Reset memory (e.g. for tests):**

```python theme={null}
crew.reset_memories(command_type="memory")  # Resets unified memory
# Or on a Memory instance:
memory.reset()                    # All scopes
memory.reset(scope="/project/old")  # Only that subtree
```

## Configuration Reference

All configuration is passed as keyword arguments to `Memory(...)`. Every parameter has a sensible default.

| Parameter                   | Default                 | Description                                                                         |
| :-------------------------- | :---------------------- | :---------------------------------------------------------------------------------- |
| `llm`                       | `"gpt-4o-mini"`         | LLM for analysis (model name or `BaseLLM` instance).                                |
| `storage`                   | `"lancedb"`             | Storage backend (`"lancedb"`, a path string, or a `StorageBackend` instance).       |
| `embedder`                  | `None` (OpenAI default) | Embedder (config dict, callable, or `None` for default OpenAI).                     |
| `recency_weight`            | `0.3`                   | Weight for recency in composite score.                                              |
| `semantic_weight`           | `0.5`                   | Weight for semantic similarity in composite score.                                  |
| `importance_weight`         | `0.2`                   | Weight for importance in composite score.                                           |
| `recency_half_life_days`    | `30`                    | Days for recency score to halve (exponential decay).                                |
| `consolidation_threshold`   | `0.85`                  | Similarity above which consolidation is triggered on save. Set to `1.0` to disable. |
| `consolidation_limit`       | `5`                     | Max existing records to compare during consolidation.                               |
| `default_importance`        | `0.5`                   | Importance assigned when not provided and LLM analysis is skipped.                  |
| `batch_dedup_threshold`     | `0.98`                  | Cosine similarity for dropping near-duplicates within a `remember_many()` batch.    |
| `confidence_threshold_high` | `0.8`                   | Recall confidence above which results are returned directly.                        |
| `confidence_threshold_low`  | `0.5`                   | Recall confidence below which deeper exploration is triggered.                      |
| `complex_query_threshold`   | `0.7`                   | For complex queries, explore deeper below this confidence.                          |
| `exploration_budget`        | `1`                     | Number of LLM-driven exploration rounds during deep recall.                         |
| `query_analysis_threshold`  | `200`                   | Queries shorter than this (in characters) skip LLM analysis during deep recall.     |


# Planning
Source: https://docs.crewai.com/en/concepts/planning

Learn how to add planning to your CrewAI Crew and improve their performance.

## Overview

The planning feature in CrewAI allows you to add planning capability to your crew. When enabled, before each Crew iteration,
all Crew information is sent to an AgentPlanner that will plan the tasks step by step, and this plan will be added to each task description.

### Using the Planning Feature

Getting started with the planning feature is very easy, the only step required is to add `planning=True` to your Crew:

<CodeGroup>
  ```python Code theme={null}
  from crewai import Crew, Agent, Task, Process

  # Assemble your crew with planning capabilities
  my_crew = Crew(
      agents=self.agents,
      tasks=self.tasks,
      process=Process.sequential,
      planning=True,
  )
  ```
</CodeGroup>

From this point on, your crew will have planning enabled, and the tasks will be planned before each iteration.

<Warning>
  When planning is enabled, crewAI will use `gpt-4o-mini` as the default LLM for planning, which requires a valid OpenAI API key. Since your agents might be using different LLMs, this could cause confusion if you don't have an OpenAI API key configured or if you're experiencing unexpected behavior related to LLM API calls.
</Warning>

#### Planning LLM

Now you can define the LLM that will be used to plan the tasks.

When running the base case example, you will see something like the output below, which represents the output of the `AgentPlanner`
responsible for creating the step-by-step logic to add to the Agents' tasks.

<CodeGroup>
  ```python Code theme={null}
  from crewai import Crew, Agent, Task, Process

  # Assemble your crew with planning capabilities and custom LLM
  my_crew = Crew(
      agents=self.agents,
      tasks=self.tasks,
      process=Process.sequential,
      planning=True,
      planning_llm="gpt-4o"
  )

  # Run the crew
  my_crew.kickoff()
  ```

  ````markdown Result theme={null}
  [2024-07-15 16:49:11][INFO]: Planning the crew execution
  **Step-by-Step Plan for Task Execution**

  **Task Number 1: Conduct a thorough research about AI LLMs**

  **Agent:** AI LLMs Senior Data Researcher

  **Agent Goal:** Uncover cutting-edge developments in AI LLMs

  **Task Expected Output:** A list with 10 bullet points of the most relevant information about AI LLMs

  **Task Tools:** None specified

  **Agent Tools:** None specified

  **Step-by-Step Plan:**

  1. **Define Research Scope:**

     - Determine the specific areas of AI LLMs to focus on, such as advancements in architecture, use cases, ethical considerations, and performance metrics.

  2. **Identify Reliable Sources:**

     - List reputable sources for AI research, including academic journals, industry reports, conferences (e.g., NeurIPS, ACL), AI research labs (e.g., OpenAI, Google AI), and online databases (e.g., IEEE Xplore, arXiv).

  3. **Collect Data:**

     - Search for the latest papers, articles, and reports published in 2024 and early 2025.
     - Use keywords like "Large Language Models 2025", "AI LLM advancements", "AI ethics 2025", etc.

  4. **Analyze Findings:**

     - Read and summarize the key points from each source.
     - Highlight new techniques, models, and applications introduced in the past year.

  5. **Organize Information:**

     - Categorize the information into relevant topics (e.g., new architectures, ethical implications, real-world applications).
     - Ensure each bullet point is concise but informative.

  6. **Create the List:**

     - Compile the 10 most relevant pieces of information into a bullet point list.
     - Review the list to ensure clarity and relevance.

  **Expected Output:**

  A list with 10 bullet points of the most relevant information about AI LLMs.

  ---

  **Task Number 2: Review the context you got and expand each topic into a full section for a report**

  **Agent:** AI LLMs Reporting Analyst

  **Agent Goal:** Create detailed reports based on AI LLMs data analysis and research findings

  **Task Expected Output:** A fully fledged report with the main topics, each with a full section of information. Formatted as markdown without '```'

  **Task Tools:** None specified

  **Agent Tools:** None specified

  **Step-by-Step Plan:**

  1. **Review the Bullet Points:**
     - Carefully read through the list of 10 bullet points provided by the AI LLMs Senior Data Researcher.

  2. **Outline the Report:**
     - Create an outline with each bullet point as a main section heading.
     - Plan sub-sections under each main heading to cover different aspects of the topic.

  3. **Research Further Details:**
     - For each bullet point, conduct additional research if necessary to gather more detailed information.
     - Look for case studies, examples, and statistical data to support each section.

  4. **Write Detailed Sections:**
     - Expand each bullet point into a comprehensive section.
     - Ensure each section includes an introduction, detailed explanation, examples, and a conclusion.
     - Use markdown formatting for headings, subheadings, lists, and emphasis.

  5. **Review and Edit:**
     - Proofread the report for clarity, coherence, and correctness.
     - Make sure the report flows logically from one section to the next.
     - Format the report according to markdown standards.

  6. **Finalize the Report:**
     - Ensure the report is complete with all sections expanded and detailed.
     - Double-check formatting and make any necessary adjustments.

  **Expected Output:**
  A fully fledged report with the main topics, each with a full section of information. Formatted as markdown without '```'.
  ````
</CodeGroup>


# Processes
Source: https://docs.crewai.com/en/concepts/processes

Detailed guide on workflow management through processes in CrewAI, with updated implementation details.

## Overview

<Tip>
  Processes orchestrate the execution of tasks by agents, akin to project management in human teams.
  These processes ensure tasks are distributed and executed efficiently, in alignment with a predefined strategy.
</Tip>

## Process Implementations

* **Sequential**: Executes tasks sequentially, ensuring tasks are completed in an orderly progression.
* **Hierarchical**: Organizes tasks in a managerial hierarchy, where tasks are delegated and executed based on a structured chain of command. A manager language model (`manager_llm`) or a custom manager agent (`manager_agent`) must be specified in the crew to enable the hierarchical process, facilitating the creation and management of tasks by the manager.
* **Consensual Process (Planned)**: Aiming for collaborative decision-making among agents on task execution, this process type introduces a democratic approach to task management within CrewAI. It is planned for future development and is not currently implemented in the codebase.

## The Role of Processes in Teamwork

Processes enable individual agents to operate as a cohesive unit, streamlining their efforts to achieve common objectives with efficiency and coherence.

## Assigning Processes to a Crew

To assign a process to a crew, specify the process type upon crew creation to set the execution strategy. For a hierarchical process, ensure to define `manager_llm` or `manager_agent` for the manager agent.

```python theme={null}
from crewai import Crew, Process

# Example: Creating a crew with a sequential process
crew = Crew(
    agents=my_agents,
    tasks=my_tasks,
    process=Process.sequential
)

# Example: Creating a crew with a hierarchical process
# Ensure to provide a manager_llm or manager_agent
crew = Crew(
    agents=my_agents,
    tasks=my_tasks,
    process=Process.hierarchical,
    manager_llm="gpt-4o"
    # or
    # manager_agent=my_manager_agent
)
```

**Note:** Ensure `my_agents` and `my_tasks` are defined prior to creating a `Crew` object, and for the hierarchical process, either `manager_llm` or `manager_agent` is also required.

## Sequential Process

This method mirrors dynamic team workflows, progressing through tasks in a thoughtful and systematic manner. Task execution follows the predefined order in the task list, with the output of one task serving as context for the next.

To customize task context, utilize the `context` parameter in the `Task` class to specify outputs that should be used as context for subsequent tasks.

## Hierarchical Process

Emulates a corporate hierarchy, CrewAI allows specifying a custom manager agent or automatically creates one, requiring the specification of a manager language model (`manager_llm`). This agent oversees task execution, including planning, delegation, and validation. Tasks are not pre-assigned; the manager allocates tasks to agents based on their capabilities, reviews outputs, and assesses task completion.

## Process Class: Detailed Overview

The `Process` class is implemented as an enumeration (`Enum`), ensuring type safety and restricting process values to the defined types (`sequential`, `hierarchical`). The consensual process is planned for future inclusion, emphasizing our commitment to continuous development and innovation.

## Conclusion

The structured collaboration facilitated by processes within CrewAI is crucial for enabling systematic teamwork among agents.
This documentation has been updated to reflect the latest features, enhancements, and the planned integration of the Consensual Process, ensuring users have access to the most current and comprehensive information.


# Production Architecture
Source: https://docs.crewai.com/en/concepts/production-architecture

Best practices for building production-ready AI applications with CrewAI

# The Flow-First Mindset

When building production AI applications with CrewAI, **we recommend starting with a Flow**.

While it's possible to run individual Crews or Agents, wrapping them in a Flow provides the necessary structure for a robust, scalable application.

## Why Flows?

1. **State Management**: Flows provide a built-in way to manage state across different steps of your application. This is crucial for passing data between Crews, maintaining context, and handling user inputs.
2. **Control**: Flows allow you to define precise execution paths, including loops, conditionals, and branching logic. This is essential for handling edge cases and ensuring your application behaves predictably.
3. **Observability**: Flows provide a clear structure that makes it easier to trace execution, debug issues, and monitor performance. We recommend using [CrewAI Tracing](/en/observability/tracing) for detailed insights. Simply run `crewai login` to enable free observability features.

## The Architecture

A typical production CrewAI application looks like this:

```mermaid theme={null}
graph TD
    Start((Start)) --> Flow[Flow Orchestrator]
    Flow --> State{State Management}
    State --> Step1[Step 1: Data Gathering]
    Step1 --> Crew1[Research Crew]
    Crew1 --> State
    State --> Step2{Condition Check}
    Step2 -- "Valid" --> Step3[Step 3: Execution]
    Step3 --> Crew2[Action Crew]
    Step2 -- "Invalid" --> End((End))
    Crew2 --> End
```

### 1. The Flow Class

Your `Flow` class is the entry point. It defines the state schema and the methods that execute your logic.

```python theme={null}
from crewai.flow.flow import Flow, listen, start
from pydantic import BaseModel

class AppState(BaseModel):
    user_input: str = ""
    research_results: str = ""
    final_report: str = ""

class ProductionFlow(Flow[AppState]):
    @start()
    def gather_input(self):
        # ... logic to get input ...
        pass

    @listen(gather_input)
    def run_research_crew(self):
        # ... trigger a Crew ...
        pass
```

### 2. State Management

Use Pydantic models to define your state. This ensures type safety and makes it clear what data is available at each step.

* **Keep it minimal**: Store only what you need to persist between steps.
* **Use structured data**: Avoid unstructured dictionaries when possible.

### 3. Crews as Units of Work

Delegate complex tasks to Crews. A Crew should be focused on a specific goal (e.g., "Research a topic", "Write a blog post").

* **Don't over-engineer Crews**: Keep them focused.
* **Pass state explicitly**: Pass the necessary data from the Flow state to the Crew inputs.

```python theme={null}
    @listen(gather_input)
    def run_research_crew(self):
        crew = ResearchCrew()
        result = crew.kickoff(inputs={"topic": self.state.user_input})
        self.state.research_results = result.raw
```

## Control Primitives

Leverage CrewAI's control primitives to add robustness and control to your Crews.

### 1. Task Guardrails

Use [Task Guardrails](/en/concepts/tasks#task-guardrails) to validate task outputs before they are accepted. This ensures that your agents produce high-quality results.

```python theme={null}
def validate_content(result: TaskOutput) -> Tuple[bool, Any]:
    if len(result.raw) < 100:
        return (False, "Content is too short. Please expand.")
    return (True, result.raw)

task = Task(
    ...,
    guardrail=validate_content
)
```

### 2. Structured Outputs

Always use structured outputs (`output_pydantic` or `output_json`) when passing data between tasks or to your application. This prevents parsing errors and ensures type safety.

```python theme={null}
class ResearchResult(BaseModel):
    summary: str
    sources: List[str]

task = Task(
    ...,
    output_pydantic=ResearchResult
)
```

### 3. LLM Hooks

Use [LLM Hooks](/en/learn/llm-hooks) to inspect or modify messages before they are sent to the LLM, or to sanitize responses.

```python theme={null}
@before_llm_call
def log_request(context):
    print(f"Agent {context.agent.role} is calling the LLM...")
```

## Deployment Patterns

When deploying your Flow, consider the following:

### CrewAI Enterprise

The easiest way to deploy your Flow is using CrewAI Enterprise. It handles the infrastructure, authentication, and monitoring for you.

Check out the [Deployment Guide](/en/enterprise/guides/deploy-crew) to get started.

```bash theme={null}
crewai deploy create
```

### Async Execution

For long-running tasks, use `kickoff_async` to avoid blocking your API.

### Persistence

Use the `@persist` decorator to save the state of your Flow to a database. This allows you to resume execution if the process crashes or if you need to wait for human input.

```python theme={null}
@persist
class ProductionFlow(Flow[AppState]):
    # ...
```

## Summary

* **Start with a Flow.**
* **Define a clear State.**
* **Use Crews for complex tasks.**
* **Deploy with an API and persistence.**


# Reasoning
Source: https://docs.crewai.com/en/concepts/reasoning

Learn how to enable and use agent reasoning to improve task execution.

## Overview

Agent reasoning is a feature that allows agents to reflect on a task and create a plan before execution. This helps agents approach tasks more methodically and ensures they're ready to perform the assigned work.

## Usage

To enable reasoning for an agent, simply set `reasoning=True` when creating the agent:

```python theme={null}
from crewai import Agent

agent = Agent(
    role="Data Analyst",
    goal="Analyze complex datasets and provide insights",
    backstory="You are an experienced data analyst with expertise in finding patterns in complex data.",
    reasoning=True,  # Enable reasoning
    max_reasoning_attempts=3  # Optional: Set a maximum number of reasoning attempts
)
```

## How It Works

When reasoning is enabled, before executing a task, the agent will:

1. Reflect on the task and create a detailed plan
2. Evaluate whether it's ready to execute the task
3. Refine the plan as necessary until it's ready or max\_reasoning\_attempts is reached
4. Inject the reasoning plan into the task description before execution

This process helps the agent break down complex tasks into manageable steps and identify potential challenges before starting.

## Configuration Options

<ParamField type="bool">
  Enable or disable reasoning
</ParamField>

<ParamField type="int">
  Maximum number of attempts to refine the plan before proceeding with execution. If None (default), the agent will continue refining until it's ready.
</ParamField>

## Example

Here's a complete example:

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with reasoning enabled
analyst = Agent(
    role="Data Analyst",
    goal="Analyze data and provide insights",
    backstory="You are an expert data analyst.",
    reasoning=True,
    max_reasoning_attempts=3  # Optional: Set a limit on reasoning attempts
)

# Create a task
analysis_task = Task(
    description="Analyze the provided sales data and identify key trends.",
    expected_output="A report highlighting the top 3 sales trends.",
    agent=analyst
)

# Create a crew and run the task
crew = Crew(agents=[analyst], tasks=[analysis_task])
result = crew.kickoff()

print(result)
```

## Error Handling

The reasoning process is designed to be robust, with error handling built in. If an error occurs during reasoning, the agent will proceed with executing the task without the reasoning plan. This ensures that tasks can still be executed even if the reasoning process fails.

Here's how to handle potential errors in your code:

```python theme={null}
from crewai import Agent, Task
import logging

# Set up logging to capture any reasoning errors
logging.basicConfig(level=logging.INFO)

# Create an agent with reasoning enabled
agent = Agent(
    role="Data Analyst",
    goal="Analyze data and provide insights",
    reasoning=True,
    max_reasoning_attempts=3
)

# Create a task
task = Task(
    description="Analyze the provided sales data and identify key trends.",
    expected_output="A report highlighting the top 3 sales trends.",
    agent=agent
)

# Execute the task
# If an error occurs during reasoning, it will be logged and execution will continue
result = agent.execute_task(task)
```

## Example Reasoning Output

Here's an example of what a reasoning plan might look like for a data analysis task:

```
Task: Analyze the provided sales data and identify key trends.

Reasoning Plan:
I'll analyze the sales data to identify the top 3 trends.

1. Understanding of the task:
   I need to analyze sales data to identify key trends that would be valuable for business decision-making.

2. Key steps I'll take:
   - First, I'll examine the data structure to understand what fields are available
   - Then I'll perform exploratory data analysis to identify patterns
   - Next, I'll analyze sales by time periods to identify temporal trends
   - I'll also analyze sales by product categories and customer segments
   - Finally, I'll identify the top 3 most significant trends

3. Approach to challenges:
   - If the data has missing values, I'll decide whether to fill or filter them
   - If the data has outliers, I'll investigate whether they're valid data points or errors
   - If trends aren't immediately obvious, I'll apply statistical methods to uncover patterns

4. Use of available tools:
   - I'll use data analysis tools to explore and visualize the data
   - I'll use statistical tools to identify significant patterns
   - I'll use knowledge retrieval to access relevant information about sales analysis

5. Expected outcome:
   A concise report highlighting the top 3 sales trends with supporting evidence from the data.

READY: I am ready to execute the task.
```

This reasoning plan helps the agent organize its approach to the task, consider potential challenges, and ensure it delivers the expected output.


# Tasks
Source: https://docs.crewai.com/en/concepts/tasks

Detailed guide on managing and creating tasks within the CrewAI framework.

## Overview

In the CrewAI framework, a `Task` is a specific assignment completed by an `Agent`.

Tasks provide all necessary details for execution, such as a description, the agent responsible, required tools, and more, facilitating a wide range of action complexities.

Tasks within CrewAI can be collaborative, requiring multiple agents to work together. This is managed through the task properties and orchestrated by the Crew's process, enhancing teamwork and efficiency.

<Note type="info" title="Enterprise Enhancement: Visual Task Builder">
  CrewAI AMP includes a Visual Task Builder in Crew Studio that simplifies complex task creation and chaining. Design your task flows visually and test them in real-time without writing code.

  <img alt="Task Builder Screenshot" />

  The Visual Task Builder enables:

  * Drag-and-drop task creation
  * Visual task dependencies and flow
  * Real-time testing and validation
  * Easy sharing and collaboration
</Note>

### Task Execution Flow

Tasks can be executed in two ways:

* **Sequential**: Tasks are executed in the order they are defined
* **Hierarchical**: Tasks are assigned to agents based on their roles and expertise

The execution flow is defined when creating the crew:

```python Code theme={null}
crew = Crew(
    agents=[agent1, agent2],
    tasks=[task1, task2],
    process=Process.sequential  # or Process.hierarchical
)
```

## Task Attributes

| Attribute                              | Parameters              | Type                        | Description                                                                                                     |
| :------------------------------------- | :---------------------- | :-------------------------- | :-------------------------------------------------------------------------------------------------------------- |
| **Description**                        | `description`           | `str`                       | A clear, concise statement of what the task entails.                                                            |
| **Expected Output**                    | `expected_output`       | `str`                       | A detailed description of what the task's completion looks like.                                                |
| **Name** *(optional)*                  | `name`                  | `Optional[str]`             | A name identifier for the task.                                                                                 |
| **Agent** *(optional)*                 | `agent`                 | `Optional[BaseAgent]`       | The agent responsible for executing the task.                                                                   |
| **Tools** *(optional)*                 | `tools`                 | `List[BaseTool]`            | The tools/resources the agent is limited to use for this task.                                                  |
| **Context** *(optional)*               | `context`               | `Optional[List["Task"]]`    | Other tasks whose outputs will be used as context for this task.                                                |
| **Async Execution** *(optional)*       | `async_execution`       | `Optional[bool]`            | Whether the task should be executed asynchronously. Defaults to False.                                          |
| **Human Input** *(optional)*           | `human_input`           | `Optional[bool]`            | Whether the task should have a human review the final answer of the agent. Defaults to False.                   |
| **Markdown** *(optional)*              | `markdown`              | `Optional[bool]`            | Whether the task should instruct the agent to return the final answer formatted in Markdown. Defaults to False. |
| **Config** *(optional)*                | `config`                | `Optional[Dict[str, Any]]`  | Task-specific configuration parameters.                                                                         |
| **Output File** *(optional)*           | `output_file`           | `Optional[str]`             | File path for storing the task output.                                                                          |
| **Create Directory** *(optional)*      | `create_directory`      | `Optional[bool]`            | Whether to create the directory for output\_file if it doesn't exist. Defaults to True.                         |
| **Output JSON** *(optional)*           | `output_json`           | `Optional[Type[BaseModel]]` | A Pydantic model to structure the JSON output.                                                                  |
| **Output Pydantic** *(optional)*       | `output_pydantic`       | `Optional[Type[BaseModel]]` | A Pydantic model for task output.                                                                               |
| **Callback** *(optional)*              | `callback`              | `Optional[Any]`             | Function/object to be executed after task completion.                                                           |
| **Guardrail** *(optional)*             | `guardrail`             | `Optional[Callable]`        | Function to validate task output before proceeding to next task.                                                |
| **Guardrails** *(optional)*            | `guardrails`            | `Optional[List[Callable]]`  | List of guardrails to validate task output before proceeding to next task.                                      |
| **Guardrail Max Retries** *(optional)* | `guardrail_max_retries` | `Optional[int]`             | Maximum number of retries when guardrail validation fails. Defaults to 3.                                       |

<Note type="warning" title="Deprecated: max_retries">
  The task attribute `max_retries` is deprecated and will be removed in v1.0.0.
  Use `guardrail_max_retries` instead to control retry attempts when a guardrail
  fails.
</Note>

## Creating Tasks

There are two ways to create tasks in CrewAI: using **YAML configuration (recommended)** or defining them **directly in code**.

### YAML Configuration (Recommended)

Using YAML configuration provides a cleaner, more maintainable way to define tasks. We strongly recommend using this approach to define tasks in your CrewAI projects.

After creating your CrewAI project as outlined in the [Installation](/en/installation) section, navigate to the `src/latest_ai_development/config/tasks.yaml` file and modify the template to match your specific task requirements.

<Note>
  Variables in your YAML files (like `{topic}`) will be replaced with values from your inputs when running the crew:

  ```python Code theme={null}
  crew.kickoff(inputs={'topic': 'AI Agents'})
  ```
</Note>

Here's an example of how to configure tasks using YAML:

````yaml tasks.yaml theme={null}
research_task:
  description: >
    Conduct a thorough research about {topic}
    Make sure you find any interesting and relevant information given
    the current year is 2025.
  expected_output: >
    A list with 10 bullet points of the most relevant information about {topic}
  agent: researcher

reporting_task:
  description: >
    Review the context you got and expand each topic into a full section for a report.
    Make sure the report is detailed and contains any and all relevant information.
  expected_output: >
    A fully fledge reports with the mains topics, each with a full section of information.
    Formatted as markdown without '```'
  agent: reporting_analyst
  markdown: true
  output_file: report.md
````

To use this YAML configuration in your code, create a crew class that inherits from `CrewBase`:

```python crew.py theme={null}
# src/latest_ai_development/crew.py

from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from crewai_tools import SerperDevTool

@CrewBase
class LatestAiDevelopmentCrew():
  """LatestAiDevelopment crew"""

  @agent
  def researcher(self) -> Agent:
    return Agent(
      config=self.agents_config['researcher'], # type: ignore[index]
      verbose=True,
      tools=[SerperDevTool()]
    )

  @agent
  def reporting_analyst(self) -> Agent:
    return Agent(
      config=self.agents_config['reporting_analyst'], # type: ignore[index]
      verbose=True
    )

  @task
  def research_task(self) -> Task:
    return Task(
      config=self.tasks_config['research_task'] # type: ignore[index]
    )

  @task
  def reporting_task(self) -> Task:
    return Task(
      config=self.tasks_config['reporting_task'] # type: ignore[index]
    )

  @crew
  def crew(self) -> Crew:
    return Crew(
      agents=[
        self.researcher(),
        self.reporting_analyst()
      ],
      tasks=[
        self.research_task(),
        self.reporting_task()
      ],
      process=Process.sequential
    )
```

<Note>
  The names you use in your YAML files (`agents.yaml` and `tasks.yaml`) should
  match the method names in your Python code.
</Note>

### Direct Code Definition (Alternative)

Alternatively, you can define tasks directly in your code without using YAML configuration:

```python task.py theme={null}
from crewai import Task

research_task = Task(
    description="""
        Conduct a thorough research about AI Agents.
        Make sure you find any interesting and relevant information given
        the current year is 2025.
    """,
    expected_output="""
        A list with 10 bullet points of the most relevant information about AI Agents
    """,
    agent=researcher
)

reporting_task = Task(
    description="""
        Review the context you got and expand each topic into a full section for a report.
        Make sure the report is detailed and contains any and all relevant information.
    """,
    expected_output="""
        A fully fledge reports with the mains topics, each with a full section of information.
    """,
    agent=reporting_analyst,
    markdown=True,  # Enable markdown formatting for the final output
    output_file="report.md"
)
```

<Tip>
  Directly specify an `agent` for assignment or let the `hierarchical` CrewAI's
  process decide based on roles, availability, etc.
</Tip>

## Task Output

Understanding task outputs is crucial for building effective AI workflows. CrewAI provides a structured way to handle task results through the `TaskOutput` class, which supports multiple output formats and can be easily passed between tasks.

The output of a task in CrewAI framework is encapsulated within the `TaskOutput` class. This class provides a structured way to access results of a task, including various formats such as raw output, JSON, and Pydantic models.

By default, the `TaskOutput` will only include the `raw` output. A `TaskOutput` will only include the `pydantic` or `json_dict` output if the original `Task` object was configured with `output_pydantic` or `output_json`, respectively.

### Task Output Attributes

| Attribute         | Parameters      | Type                       | Description                                                                                        |
| :---------------- | :-------------- | :------------------------- | :------------------------------------------------------------------------------------------------- |
| **Description**   | `description`   | `str`                      | Description of the task.                                                                           |
| **Summary**       | `summary`       | `Optional[str]`            | Summary of the task, auto-generated from the first 10 words of the description.                    |
| **Raw**           | `raw`           | `str`                      | The raw output of the task. This is the default format for the output.                             |
| **Pydantic**      | `pydantic`      | `Optional[BaseModel]`      | A Pydantic model object representing the structured output of the task.                            |
| **JSON Dict**     | `json_dict`     | `Optional[Dict[str, Any]]` | A dictionary representing the JSON output of the task.                                             |
| **Agent**         | `agent`         | `str`                      | The agent that executed the task.                                                                  |
| **Output Format** | `output_format` | `OutputFormat`             | The format of the task output, with options including RAW, JSON, and Pydantic. The default is RAW. |
| **Messages**      | `messages`      | `list[LLMMessage]`         | The messages from the last task execution.                                                         |

### Task Methods and Properties

| Method/Property | Description                                                                                       |
| :-------------- | :------------------------------------------------------------------------------------------------ |
| **json**        | Returns the JSON string representation of the task output if the output format is JSON.           |
| **to\_dict**    | Converts the JSON and Pydantic outputs to a dictionary.                                           |
| **str**         | Returns the string representation of the task output, prioritizing Pydantic, then JSON, then raw. |

### Accessing Task Outputs

Once a task has been executed, its output can be accessed through the `output` attribute of the `Task` object. The `TaskOutput` class provides various ways to interact with and present this output.

#### Example

```python Code theme={null}
# Example task
task = Task(
    description='Find and summarize the latest AI news',
    expected_output='A bullet list summary of the top 5 most important AI news',
    agent=research_agent,
    tools=[search_tool]
)

# Execute the crew
crew = Crew(
    agents=[research_agent],
    tasks=[task],
    verbose=True
)

result = crew.kickoff()

# Accessing the task output
task_output = task.output

print(f"Task Description: {task_output.description}")
print(f"Task Summary: {task_output.summary}")
print(f"Raw Output: {task_output.raw}")
if task_output.json_dict:
    print(f"JSON Output: {json.dumps(task_output.json_dict, indent=2)}")
if task_output.pydantic:
    print(f"Pydantic Output: {task_output.pydantic}")
```

## Markdown Output Formatting

The `markdown` parameter enables automatic markdown formatting for task outputs. When set to `True`, the task will instruct the agent to format the final answer using proper Markdown syntax.

### Using Markdown Formatting

```python Code theme={null}
# Example task with markdown formatting enabled
formatted_task = Task(
    description="Create a comprehensive report on AI trends",
    expected_output="A well-structured report with headers, sections, and bullet points",
    agent=reporter_agent,
    markdown=True  # Enable automatic markdown formatting
)
```

When `markdown=True`, the agent will receive additional instructions to format the output using:

* `#` for headers
* `**text**` for bold text
* `*text*` for italic text
* `-` or `*` for bullet points
* `` `code` `` for inline code
* ` `language \`\`\` for code blocks

### YAML Configuration with Markdown

```yaml tasks.yaml theme={null}
analysis_task:
  description: >
    Analyze the market data and create a detailed report
  expected_output: >
    A comprehensive analysis with charts and key findings
  agent: analyst
  markdown: true # Enable markdown formatting
  output_file: analysis.md
```

### Benefits of Markdown Output

* **Consistent Formatting**: Ensures all outputs follow proper markdown conventions
* **Better Readability**: Structured content with headers, lists, and emphasis
* **Documentation Ready**: Output can be directly used in documentation systems
* **Cross-Platform Compatibility**: Markdown is universally supported

<Note>
  The markdown formatting instructions are automatically added to the task
  prompt when `markdown=True`, so you don't need to specify formatting
  requirements in your task description.
</Note>

## Task Dependencies and Context

Tasks can depend on the output of other tasks using the `context` attribute. For example:

```python Code theme={null}
research_task = Task(
    description="Research the latest developments in AI",
    expected_output="A list of recent AI developments",
    agent=researcher
)

analysis_task = Task(
    description="Analyze the research findings and identify key trends",
    expected_output="Analysis report of AI trends",
    agent=analyst,
    context=[research_task]  # This task will wait for research_task to complete
)
```

## Task Guardrails

Task guardrails provide a way to validate and transform task outputs before they
are passed to the next task. This feature helps ensure data quality and provides
feedback to agents when their output doesn't meet specific criteria.

CrewAI supports two types of guardrails:

1. **Function-based guardrails**: Python functions with custom validation logic, giving you complete control over the validation process and ensuring reliable, deterministic results.

2. **LLM-based guardrails**: String descriptions that use the agent's LLM to validate outputs based on natural language criteria. These are ideal for complex or subjective validation requirements.

### Function-Based Guardrails

To add a function-based guardrail to a task, provide a validation function through the `guardrail` parameter:

```python Code theme={null}
from typing import Tuple, Union, Dict, Any
from crewai import TaskOutput

def validate_blog_content(result: TaskOutput) -> Tuple[bool, Any]:
    """Validate blog content meets requirements."""
    try:
        # Check word count
        word_count = len(result.raw.split())
        if word_count > 200:
            return (False, "Blog content exceeds 200 words")

        # Additional validation logic here
        return (True, result.raw.strip())
    except Exception as e:
        return (False, "Unexpected error during validation")

blog_task = Task(
    description="Write a blog post about AI",
    expected_output="A blog post under 200 words",
    agent=blog_agent,
    guardrail=validate_blog_content  # Add the guardrail function
)
```

### LLM-Based Guardrails (String Descriptions)

Instead of writing custom validation functions, you can use string descriptions that leverage LLM-based validation. When you provide a string to the `guardrail` or `guardrails` parameter, CrewAI automatically creates an `LLMGuardrail` that uses the agent's LLM to validate the output based on your description.

**Requirements**:

* The task must have an `agent` assigned (the guardrail uses the agent's LLM)
* Provide a clear, descriptive string explaining the validation criteria

```python Code theme={null}
from crewai import Task

# Single LLM-based guardrail
blog_task = Task(
    description="Write a blog post about AI",
    expected_output="A blog post under 200 words",
    agent=blog_agent,
    guardrail="The blog post must be under 200 words and contain no technical jargon"
)
```

LLM-based guardrails are particularly useful for:

* **Complex validation logic** that's difficult to express programmatically
* **Subjective criteria** like tone, style, or quality assessments
* **Natural language requirements** that are easier to describe than code

The LLM guardrail will:

1. Analyze the task output against your description
2. Return `(True, output)` if the output complies with the criteria
3. Return `(False, feedback)` with specific feedback if validation fails

**Example with detailed validation criteria**:

```python Code theme={null}
research_task = Task(
    description="Research the latest developments in quantum computing",
    expected_output="A comprehensive research report",
    agent=researcher_agent,
    guardrail="""
    The research report must:
    - Be at least 1000 words long
    - Include at least 5 credible sources
    - Cover both technical and practical applications
    - Be written in a professional, academic tone
    - Avoid speculation or unverified claims
    """
)
```

### Multiple Guardrails

You can apply multiple guardrails to a task using the `guardrails` parameter. Multiple guardrails are executed sequentially, with each guardrail receiving the output from the previous one. This allows you to chain validation and transformation steps.

The `guardrails` parameter accepts:

* A list of guardrail functions or string descriptions
* A single guardrail function or string (same as `guardrail`)

**Note**: If `guardrails` is provided, it takes precedence over `guardrail`. The `guardrail` parameter will be ignored when `guardrails` is set.

```python Code theme={null}
from typing import Tuple, Any
from crewai import TaskOutput, Task

def validate_word_count(result: TaskOutput) -> Tuple[bool, Any]:
    """Validate word count is within limits."""
    word_count = len(result.raw.split())
    if word_count < 100:
        return (False, f"Content too short: {word_count} words. Need at least 100 words.")
    if word_count > 500:
        return (False, f"Content too long: {word_count} words. Maximum is 500 words.")
    return (True, result.raw)

def validate_no_profanity(result: TaskOutput) -> Tuple[bool, Any]:
    """Check for inappropriate language."""
    profanity_words = ["badword1", "badword2"]  # Example list
    content_lower = result.raw.lower()
    for word in profanity_words:
        if word in content_lower:
            return (False, f"Inappropriate language detected: {word}")
    return (True, result.raw)

def format_output(result: TaskOutput) -> Tuple[bool, Any]:
    """Format and clean the output."""
    formatted = result.raw.strip()
    # Capitalize first letter
    formatted = formatted[0].upper() + formatted[1:] if formatted else formatted
    return (True, formatted)

# Apply multiple guardrails sequentially
blog_task = Task(
    description="Write a blog post about AI",
    expected_output="A well-formatted blog post between 100-500 words",
    agent=blog_agent,
    guardrails=[
        validate_word_count,      # First: validate length
        validate_no_profanity,    # Second: check content
        format_output             # Third: format the result
    ],
    guardrail_max_retries=3
)
```

In this example, the guardrails execute in order:

1. `validate_word_count` checks the word count
2. `validate_no_profanity` checks for inappropriate language (using the output from step 1)
3. `format_output` formats the final result (using the output from step 2)

If any guardrail fails, the error is sent back to the agent, and the task is retried up to `guardrail_max_retries` times.

**Mixing function-based and LLM-based guardrails**:

You can combine both function-based and string-based guardrails in the same list:

```python Code theme={null}
from typing import Tuple, Any
from crewai import TaskOutput, Task

def validate_word_count(result: TaskOutput) -> Tuple[bool, Any]:
    """Validate word count is within limits."""
    word_count = len(result.raw.split())
    if word_count < 100:
        return (False, f"Content too short: {word_count} words. Need at least 100 words.")
    if word_count > 500:
        return (False, f"Content too long: {word_count} words. Maximum is 500 words.")
    return (True, result.raw)

# Mix function-based and LLM-based guardrails
blog_task = Task(
    description="Write a blog post about AI",
    expected_output="A well-formatted blog post between 100-500 words",
    agent=blog_agent,
    guardrails=[
        validate_word_count,  # Function-based: precise word count check
        "The content must be engaging and suitable for a general audience",  # LLM-based: subjective quality check
        "The writing style should be clear, concise, and free of technical jargon"  # LLM-based: style validation
    ],
    guardrail_max_retries=3
)
```

This approach combines the precision of programmatic validation with the flexibility of LLM-based assessment for subjective criteria.

### Guardrail Function Requirements

1. **Function Signature**:

   * Must accept exactly one parameter (the task output)
   * Should return a tuple of `(bool, Any)`
   * Type hints are recommended but optional

2. **Return Values**:
   * On success: it returns a tuple of `(bool, Any)`. For example: `(True, validated_result)`
   * On Failure: it returns a tuple of `(bool, str)`. For example: `(False, "Error message explain the failure")`

### Error Handling Best Practices

1. **Structured Error Responses**:

```python Code theme={null}
from crewai import TaskOutput, LLMGuardrail

def validate_with_context(result: TaskOutput) -> Tuple[bool, Any]:
    try:
        # Main validation logic
        validated_data = perform_validation(result)
        return (True, validated_data)
    except ValidationError as e:
        return (False, f"VALIDATION_ERROR: {str(e)}")
    except Exception as e:
        return (False, str(e))
```

2. **Error Categories**:

   * Use specific error codes
   * Include relevant context
   * Provide actionable feedback

3. **Validation Chain**:

```python Code theme={null}
from typing import Any, Dict, List, Tuple, Union
from crewai import TaskOutput

def complex_validation(result: TaskOutput) -> Tuple[bool, Any]:
    """Chain multiple validation steps."""
    # Step 1: Basic validation
    if not result:
        return (False, "Empty result")

    # Step 2: Content validation
    try:
        validated = validate_content(result)
        if not validated:
            return (False, "Invalid content")

        # Step 3: Format validation
        formatted = format_output(validated)
        return (True, formatted)
    except Exception as e:
        return (False, str(e))
```

### Handling Guardrail Results

When a guardrail returns `(False, error)`:

1. The error is sent back to the agent
2. The agent attempts to fix the issue
3. The process repeats until:
   * The guardrail returns `(True, result)`
   * Maximum retries are reached (`guardrail_max_retries`)

Example with retry handling:

```python Code theme={null}
from typing import Optional, Tuple, Union
from crewai import TaskOutput, Task

def validate_json_output(result: TaskOutput) -> Tuple[bool, Any]:
    """Validate and parse JSON output."""
    try:
        # Try to parse as JSON
        data = json.loads(result)
        return (True, data)
    except json.JSONDecodeError as e:
        return (False, "Invalid JSON format")

task = Task(
    description="Generate a JSON report",
    expected_output="A valid JSON object",
    agent=analyst,
    guardrail=validate_json_output,
    guardrail_max_retries=3  # Limit retry attempts
)
```

## Getting Structured Consistent Outputs from Tasks

<Note>
  It's also important to note that the output of the final task of a crew
  becomes the final output of the actual crew itself.
</Note>

### Using `output_pydantic`

The `output_pydantic` property allows you to define a Pydantic model that the task output should conform to. This ensures that the output is not only structured but also validated according to the Pydantic model.

Here's an example demonstrating how to use output\_pydantic:

```python Code theme={null}
import json

from crewai import Agent, Crew, Process, Task
from pydantic import BaseModel


class Blog(BaseModel):
    title: str
    content: str


blog_agent = Agent(
    role="Blog Content Generator Agent",
    goal="Generate a blog title and content",
    backstory="""You are an expert content creator, skilled in crafting engaging and informative blog posts.""",
    verbose=False,
    allow_delegation=False,
    llm="gpt-4o",
)

task1 = Task(
    description="""Create a blog title and content on a given topic. Make sure the content is under 200 words.""",
    expected_output="A compelling blog title and well-written content.",
    agent=blog_agent,
    output_pydantic=Blog,
)

# Instantiate your crew with a sequential process
crew = Crew(
    agents=[blog_agent],
    tasks=[task1],
    verbose=True,
    process=Process.sequential,
)

result = crew.kickoff()

# Option 1: Accessing Properties Using Dictionary-Style Indexing
print("Accessing Properties - Option 1")
title = result["title"]
content = result["content"]
print("Title:", title)
print("Content:", content)

# Option 2: Accessing Properties Directly from the Pydantic Model
print("Accessing Properties - Option 2")
title = result.pydantic.title
content = result.pydantic.content
print("Title:", title)
print("Content:", content)

# Option 3: Accessing Properties Using the to_dict() Method
print("Accessing Properties - Option 3")
output_dict = result.to_dict()
title = output_dict["title"]
content = output_dict["content"]
print("Title:", title)
print("Content:", content)

# Option 4: Printing the Entire Blog Object
print("Accessing Properties - Option 5")
print("Blog:", result)

```

In this example:

* A Pydantic model Blog is defined with title and content fields.
* The task task1 uses the output\_pydantic property to specify that its output should conform to the Blog model.
* After executing the crew, you can access the structured output in multiple ways as shown.

#### Explanation of Accessing the Output

1. Dictionary-Style Indexing: You can directly access the fields using result\["field\_name"]. This works because the CrewOutput class implements the **getitem** method.
2. Directly from Pydantic Model: Access the attributes directly from the result.pydantic object.
3. Using to\_dict() Method: Convert the output to a dictionary and access the fields.
4. Printing the Entire Object: Simply print the result object to see the structured output.

### Using `output_json`

The `output_json` property allows you to define the expected output in JSON format. This ensures that the task's output is a valid JSON structure that can be easily parsed and used in your application.

Here's an example demonstrating how to use `output_json`:

```python Code theme={null}
import json

from crewai import Agent, Crew, Process, Task
from pydantic import BaseModel


# Define the Pydantic model for the blog
class Blog(BaseModel):
    title: str
    content: str


# Define the agent
blog_agent = Agent(
    role="Blog Content Generator Agent",
    goal="Generate a blog title and content",
    backstory="""You are an expert content creator, skilled in crafting engaging and informative blog posts.""",
    verbose=False,
    allow_delegation=False,
    llm="gpt-4o",
)

# Define the task with output_json set to the Blog model
task1 = Task(
    description="""Create a blog title and content on a given topic. Make sure the content is under 200 words.""",
    expected_output="A JSON object with 'title' and 'content' fields.",
    agent=blog_agent,
    output_json=Blog,
)

# Instantiate the crew with a sequential process
crew = Crew(
    agents=[blog_agent],
    tasks=[task1],
    verbose=True,
    process=Process.sequential,
)

# Kickoff the crew to execute the task
result = crew.kickoff()

# Option 1: Accessing Properties Using Dictionary-Style Indexing
print("Accessing Properties - Option 1")
title = result["title"]
content = result["content"]
print("Title:", title)
print("Content:", content)

# Option 2: Printing the Entire Blog Object
print("Accessing Properties - Option 2")
print("Blog:", result)
```

In this example:

* A Pydantic model Blog is defined with title and content fields, which is used to specify the structure of the JSON output.
* The task task1 uses the output\_json property to indicate that it expects a JSON output conforming to the Blog model.
* After executing the crew, you can access the structured JSON output in two ways as shown.

#### Explanation of Accessing the Output

1. Accessing Properties Using Dictionary-Style Indexing: You can access the fields directly using result\["field\_name"]. This is possible because the CrewOutput class implements the **getitem** method, allowing you to treat the output like a dictionary. In this option, we're retrieving the title and content from the result.
2. Printing the Entire Blog Object: By printing result, you get the string representation of the CrewOutput object. Since the **str** method is implemented to return the JSON output, this will display the entire output as a formatted string representing the Blog object.

***

By using output\_pydantic or output\_json, you ensure that your tasks produce outputs in a consistent and structured format, making it easier to process and utilize the data within your application or across multiple tasks.

## Integrating Tools with Tasks

Leverage tools from the [CrewAI Toolkit](https://github.com/joaomdmoura/crewai-tools) and [LangChain Tools](https://python.langchain.com/docs/integrations/tools) for enhanced task performance and agent interaction.

## Creating a Task with Tools

```python Code theme={null}
import os
os.environ["OPENAI_API_KEY"] = "Your Key"
os.environ["SERPER_API_KEY"] = "Your Key" # serper.dev API key

from crewai import Agent, Task, Crew
from crewai_tools import SerperDevTool

research_agent = Agent(
  role='Researcher',
  goal='Find and summarize the latest AI news',
  backstory="""You're a researcher at a large company.
  You're responsible for analyzing data and providing insights
  to the business.""",
  verbose=True
)

# to perform a semantic search for a specified query from a text's content across the internet
search_tool = SerperDevTool()

task = Task(
  description='Find and summarize the latest AI news',
  expected_output='A bullet list summary of the top 5 most important AI news',
  agent=research_agent,
  tools=[search_tool]
)

crew = Crew(
    agents=[research_agent],
    tasks=[task],
    verbose=True
)

result = crew.kickoff()
print(result)
```

This demonstrates how tasks with specific tools can override an agent's default set for tailored task execution.

## Referring to Other Tasks

In CrewAI, the output of one task is automatically relayed into the next one, but you can specifically define what tasks' output, including multiple, should be used as context for another task.

This is useful when you have a task that depends on the output of another task that is not performed immediately after it. This is done through the `context` attribute of the task:

```python Code theme={null}
# ...

research_ai_task = Task(
    description="Research the latest developments in AI",
    expected_output="A list of recent AI developments",
    async_execution=True,
    agent=research_agent,
    tools=[search_tool]
)

research_ops_task = Task(
    description="Research the latest developments in AI Ops",
    expected_output="A list of recent AI Ops developments",
    async_execution=True,
    agent=research_agent,
    tools=[search_tool]
)

write_blog_task = Task(
    description="Write a full blog post about the importance of AI and its latest news",
    expected_output="Full blog post that is 4 paragraphs long",
    agent=writer_agent,
    context=[research_ai_task, research_ops_task]
)

#...
```

## Asynchronous Execution

You can define a task to be executed asynchronously. This means that the crew will not wait for it to be completed to continue with the next task. This is useful for tasks that take a long time to be completed, or that are not crucial for the next tasks to be performed.

You can then use the `context` attribute to define in a future task that it should wait for the output of the asynchronous task to be completed.

```python Code theme={null}
#...

list_ideas = Task(
    description="List of 5 interesting ideas to explore for an article about AI.",
    expected_output="Bullet point list of 5 ideas for an article.",
    agent=researcher,
    async_execution=True # Will be executed asynchronously
)

list_important_history = Task(
    description="Research the history of AI and give me the 5 most important events.",
    expected_output="Bullet point list of 5 important events.",
    agent=researcher,
    async_execution=True # Will be executed asynchronously
)

write_article = Task(
    description="Write an article about AI, its history, and interesting ideas.",
    expected_output="A 4 paragraph article about AI.",
    agent=writer,
    context=[list_ideas, list_important_history] # Will wait for the output of the two tasks to be completed
)

#...
```

## Callback Mechanism

The callback function is executed after the task is completed, allowing for actions or notifications to be triggered based on the task's outcome.

```python Code theme={null}
# ...

def callback_function(output: TaskOutput):
    # Do something after the task is completed
    # Example: Send an email to the manager
    print(f"""
        Task completed!
        Task: {output.description}
        Output: {output.raw}
    """)

research_task = Task(
    description='Find and summarize the latest AI news',
    expected_output='A bullet list summary of the top 5 most important AI news',
    agent=research_agent,
    tools=[search_tool],
    callback=callback_function
)

#...
```

## Accessing a Specific Task Output

Once a crew finishes running, you can access the output of a specific task by using the `output` attribute of the task object:

```python Code theme={null}
# ...
task1 = Task(
    description='Find and summarize the latest AI news',
    expected_output='A bullet list summary of the top 5 most important AI news',
    agent=research_agent,
    tools=[search_tool]
)

#...

crew = Crew(
    agents=[research_agent],
    tasks=[task1, task2, task3],
    verbose=True
)

result = crew.kickoff()

# Returns a TaskOutput object with the description and results of the task
print(f"""
    Task completed!
    Task: {task1.output.description}
    Output: {task1.output.raw}
""")
```

## Tool Override Mechanism

Specifying tools in a task allows for dynamic adaptation of agent capabilities, emphasizing CrewAI's flexibility.

## Error Handling and Validation Mechanisms

While creating and executing tasks, certain validation mechanisms are in place to ensure the robustness and reliability of task attributes. These include but are not limited to:

* Ensuring only one output type is set per task to maintain clear output expectations.
* Preventing the manual assignment of the `id` attribute to uphold the integrity of the unique identifier system.

These validations help in maintaining the consistency and reliability of task executions within the crewAI framework.

## Creating Directories when Saving Files

The `create_directory` parameter controls whether CrewAI should automatically create directories when saving task outputs to files. This feature is particularly useful for organizing outputs and ensuring that file paths are correctly structured, especially when working with complex project hierarchies.

### Default Behavior

By default, `create_directory=True`, which means CrewAI will automatically create any missing directories in the output file path:

```python Code theme={null}
# Default behavior - directories are created automatically
report_task = Task(
    description='Generate a comprehensive market analysis report',
    expected_output='A detailed market analysis with charts and insights',
    agent=analyst_agent,
    output_file='reports/2025/market_analysis.md',  # Creates 'reports/2025/' if it doesn't exist
    markdown=True
)
```

### Disabling Directory Creation

If you want to prevent automatic directory creation and ensure that the directory already exists, set `create_directory=False`:

```python Code theme={null}
# Strict mode - directory must already exist
strict_output_task = Task(
    description='Save critical data that requires existing infrastructure',
    expected_output='Data saved to pre-configured location',
    agent=data_agent,
    output_file='secure/vault/critical_data.json',
    create_directory=False  # Will raise RuntimeError if 'secure/vault/' doesn't exist
)
```

### YAML Configuration

You can also configure this behavior in your YAML task definitions:

```yaml tasks.yaml theme={null}
analysis_task:
  description: >
    Generate quarterly financial analysis
  expected_output: >
    A comprehensive financial report with quarterly insights
  agent: financial_analyst
  output_file: reports/quarterly/q4_2024_analysis.pdf
  create_directory: true # Automatically create 'reports/quarterly/' directory

audit_task:
  description: >
    Perform compliance audit and save to existing audit directory
  expected_output: >
    A compliance audit report
  agent: auditor
  output_file: audit/compliance_report.md
  create_directory: false # Directory must already exist
```

### Use Cases

**Automatic Directory Creation (`create_directory=True`):**

* Development and prototyping environments
* Dynamic report generation with date-based folders
* Automated workflows where directory structure may vary
* Multi-tenant applications with user-specific folders

**Manual Directory Management (`create_directory=False`):**

* Production environments with strict file system controls
* Security-sensitive applications where directories must be pre-configured
* Systems with specific permission requirements
* Compliance environments where directory creation is audited

### Error Handling

When `create_directory=False` and the directory doesn't exist, CrewAI will raise a `RuntimeError`:

```python Code theme={null}
try:
    result = crew.kickoff()
except RuntimeError as e:
    # Handle missing directory error
    print(f"Directory creation failed: {e}")
    # Create directory manually or use fallback location
```

Check out the video below to see how to use structured outputs in CrewAI:

<iframe title="Structured outputs in CrewAI" />

## Conclusion

Tasks are the driving force behind the actions of agents in CrewAI.
By properly defining tasks and their outcomes, you set the stage for your AI agents to work effectively, either independently or as a collaborative unit.
Equipping tasks with appropriate tools, understanding the execution process, and following robust validation practices are crucial for maximizing CrewAI's potential,
ensuring agents are effectively prepared for their assignments and that tasks are executed as intended.


# Testing
Source: https://docs.crewai.com/en/concepts/testing

Learn how to test your CrewAI Crew and evaluate their performance.

## Overview

Testing is a crucial part of the development process, and it is essential to ensure that your crew is performing as expected. With crewAI, you can easily test your crew and evaluate its performance using the built-in testing capabilities.

### Using the Testing Feature

We added the CLI command `crewai test` to make it easy to test your crew. This command will run your crew for a specified number of iterations and provide detailed performance metrics. The parameters are `n_iterations` and `model`, which are optional and default to 2 and `gpt-4o-mini` respectively. For now, the only provider available is OpenAI.

```bash theme={null}
crewai test
```

If you want to run more iterations or use a different model, you can specify the parameters like this:

```bash theme={null}
crewai test --n_iterations 5 --model gpt-4o
```

or using the short forms:

```bash theme={null}
crewai test -n 5 -m gpt-4o
```

When you run the `crewai test` command, the crew will be executed for the specified number of iterations, and the performance metrics will be displayed at the end of the run.

A table of scores at the end will show the performance of the crew in terms of the following metrics:

<center>**Tasks Scores (1-10 Higher is better)**</center>

| Tasks/Crew/Agents  | Run 1 | Run 2 | Avg. Total |            Agents            | Additional Info                |
| :----------------- | :---: | :---: | :--------: | :--------------------------: | :----------------------------- |
| Task 1             |  9.0  |  9.5  |   **9.2**  |     Professional Insights    |                                |
|                    |       |       |            |          Researcher          |                                |
| Task 2             |  9.0  |  10.0 |   **9.5**  | Company Profile Investigator |                                |
| Task 3             |  9.0  |  9.0  |   **9.0**  |      Automation Insights     |                                |
|                    |       |       |            |          Specialist          |                                |
| Task 4             |  9.0  |  9.0  |   **9.0**  |     Final Report Compiler    | Automation Insights Specialist |
| Crew               |  9.00 |  9.38 |   **9.2**  |                              |                                |
| Execution Time (s) |  126  |  145  |   **135**  |                              |                                |

The example above shows the test results for two runs of the crew with two tasks, with the average total score for each task and the crew as a whole.


# Tools
Source: https://docs.crewai.com/en/concepts/tools

Understanding and leveraging tools within the CrewAI framework for agent collaboration and task execution.

## Overview

CrewAI tools empower agents with capabilities ranging from web searching and data analysis to collaboration and delegating tasks among coworkers.
This documentation outlines how to create, integrate, and leverage these tools within the CrewAI framework, including a new focus on collaboration tools.

## What is a Tool?

A tool in CrewAI is a skill or function that agents can utilize to perform various actions.
This includes tools from the [CrewAI Toolkit](https://github.com/joaomdmoura/crewai-tools) and [LangChain Tools](https://python.langchain.com/docs/integrations/tools),
enabling everything from simple searches to complex interactions and effective teamwork among agents.

<Note type="info" title="Enterprise Enhancement: Tools Repository">
  CrewAI AMP provides a comprehensive Tools Repository with pre-built integrations for common business systems and APIs. Deploy agents with enterprise tools in minutes instead of days.

  The Enterprise Tools Repository includes:

  * Pre-built connectors for popular enterprise systems
  * Custom tool creation interface
  * Version control and sharing capabilities
  * Security and compliance features
</Note>

## Key Characteristics of Tools

* **Utility**: Crafted for tasks such as web searching, data analysis, content generation, and agent collaboration.
* **Integration**: Boosts agent capabilities by seamlessly integrating tools into their workflow.
* **Customizability**: Provides the flexibility to develop custom tools or utilize existing ones, catering to the specific needs of agents.
* **Error Handling**: Incorporates robust error handling mechanisms to ensure smooth operation.
* **Caching Mechanism**: Features intelligent caching to optimize performance and reduce redundant operations.
* **Asynchronous Support**: Handles both synchronous and asynchronous tools, enabling non-blocking operations.

## Using CrewAI Tools

To enhance your agents' capabilities with crewAI tools, begin by installing our extra tools package:

```bash theme={null}
pip install 'crewai[tools]'
```

Here's an example demonstrating their use:

```python Code theme={null}
import os
from crewai import Agent, Task, Crew
# Importing crewAI tools
from crewai_tools import (
    DirectoryReadTool,
    FileReadTool,
    SerperDevTool,
    WebsiteSearchTool
)

# Set up API keys
os.environ["SERPER_API_KEY"] = "Your Key" # serper.dev API key
os.environ["OPENAI_API_KEY"] = "Your Key"

# Instantiate tools
docs_tool = DirectoryReadTool(directory='./blog-posts')
file_tool = FileReadTool()
search_tool = SerperDevTool()
web_rag_tool = WebsiteSearchTool()

# Create agents
researcher = Agent(
    role='Market Research Analyst',
    goal='Provide up-to-date market analysis of the AI industry',
    backstory='An expert analyst with a keen eye for market trends.',
    tools=[search_tool, web_rag_tool],
    verbose=True
)

writer = Agent(
    role='Content Writer',
    goal='Craft engaging blog posts about the AI industry',
    backstory='A skilled writer with a passion for technology.',
    tools=[docs_tool, file_tool],
    verbose=True
)

# Define tasks
research = Task(
    description='Research the latest trends in the AI industry and provide a summary.',
    expected_output='A summary of the top 3 trending developments in the AI industry with a unique perspective on their significance.',
    agent=researcher
)

write = Task(
    description='Write an engaging blog post about the AI industry, based on the research analyst's summary. Draw inspiration from the latest blog posts in the directory.',
    expected_output='A 4-paragraph blog post formatted in markdown with engaging, informative, and accessible content, avoiding complex jargon.',
    agent=writer,
    output_file='blog-posts/new_post.md'  # The final blog post will be saved here
)

# Assemble a crew with planning enabled
crew = Crew(
    agents=[researcher, writer],
    tasks=[research, write],
    verbose=True,
    planning=True,  # Enable planning feature
)

# Execute tasks
crew.kickoff()
```

## Available CrewAI Tools

* **Error Handling**: All tools are built with error handling capabilities, allowing agents to gracefully manage exceptions and continue their tasks.
* **Caching Mechanism**: All tools support caching, enabling agents to efficiently reuse previously obtained results, reducing the load on external resources and speeding up the execution time. You can also define finer control over the caching mechanism using the `cache_function` attribute on the tool.

Here is a list of the available tools and their descriptions:

| Tool                             | Description                                                                                    |
| :------------------------------- | :--------------------------------------------------------------------------------------------- |
| **ApifyActorsTool**              | A tool that integrates Apify Actors with your workflows for web scraping and automation tasks. |
| **BrowserbaseLoadTool**          | A tool for interacting with and extracting data from web browsers.                             |
| **CodeDocsSearchTool**           | A RAG tool optimized for searching through code documentation and related technical documents. |
| **CodeInterpreterTool**          | A tool for interpreting python code.                                                           |
| **ComposioTool**                 | Enables use of Composio tools.                                                                 |
| **CSVSearchTool**                | A RAG tool designed for searching within CSV files, tailored to handle structured data.        |
| **DALL-E Tool**                  | A tool for generating images using the DALL-E API.                                             |
| **DirectorySearchTool**          | A RAG tool for searching within directories, useful for navigating through file systems.       |
| **DOCXSearchTool**               | A RAG tool aimed at searching within DOCX documents, ideal for processing Word files.          |
| **DirectoryReadTool**            | Facilitates reading and processing of directory structures and their contents.                 |
| **EXASearchTool**                | A tool designed for performing exhaustive searches across various data sources.                |
| **FileReadTool**                 | Enables reading and extracting data from files, supporting various file formats.               |
| **FirecrawlSearchTool**          | A tool to search webpages using Firecrawl and return the results.                              |
| **FirecrawlCrawlWebsiteTool**    | A tool for crawling webpages using Firecrawl.                                                  |
| **FirecrawlScrapeWebsiteTool**   | A tool for scraping webpages URL using Firecrawl and returning its contents.                   |
| **GithubSearchTool**             | A RAG tool for searching within GitHub repositories, useful for code and documentation search. |
| **SerperDevTool**                | A specialized tool for development purposes, with specific functionalities under development.  |
| **TXTSearchTool**                | A RAG tool focused on searching within text (.txt) files, suitable for unstructured data.      |
| **JSONSearchTool**               | A RAG tool designed for searching within JSON files, catering to structured data handling.     |
| **LlamaIndexTool**               | Enables the use of LlamaIndex tools.                                                           |
| **MDXSearchTool**                | A RAG tool tailored for searching within Markdown (MDX) files, useful for documentation.       |
| **PDFSearchTool**                | A RAG tool aimed at searching within PDF documents, ideal for processing scanned documents.    |
| **PGSearchTool**                 | A RAG tool optimized for searching within PostgreSQL databases, suitable for database queries. |
| **Vision Tool**                  | A tool for generating images using the DALL-E API.                                             |
| **RagTool**                      | A general-purpose RAG tool capable of handling various data sources and types.                 |
| **ScrapeElementFromWebsiteTool** | Enables scraping specific elements from websites, useful for targeted data extraction.         |
| **ScrapeWebsiteTool**            | Facilitates scraping entire websites, ideal for comprehensive data collection.                 |
| **WebsiteSearchTool**            | A RAG tool for searching website content, optimized for web data extraction.                   |
| **XMLSearchTool**                | A RAG tool designed for searching within XML files, suitable for structured data formats.      |
| **YoutubeChannelSearchTool**     | A RAG tool for searching within YouTube channels, useful for video content analysis.           |
| **YoutubeVideoSearchTool**       | A RAG tool aimed at searching within YouTube videos, ideal for video data extraction.          |

## Creating your own Tools

<Tip>
  Developers can craft `custom tools` tailored for their agent's needs or
  utilize pre-built options.
</Tip>

There are two main ways for one to create a CrewAI tool:

### Subclassing `BaseTool`

```python Code theme={null}
from crewai.tools import BaseTool
from pydantic import BaseModel, Field

class MyToolInput(BaseModel):
    """Input schema for MyCustomTool."""
    argument: str = Field(..., description="Description of the argument.")

class MyCustomTool(BaseTool):
    name: str = "Name of my tool"
    description: str = "What this tool does. It's vital for effective utilization."
    args_schema: Type[BaseModel] = MyToolInput

    def _run(self, argument: str) -> str:
        # Your tool's logic here
        return "Tool's result"
```

## Asynchronous Tool Support

CrewAI supports asynchronous tools, allowing you to implement tools that perform non-blocking operations like network requests, file I/O, or other async operations without blocking the main execution thread.

### Creating Async Tools

You can create async tools in two ways:

#### 1. Using the `tool` Decorator with Async Functions

```python Code theme={null}
from crewai.tools import tool

@tool("fetch_data_async")
async def fetch_data_async(query: str) -> str:
    """Asynchronously fetch data based on the query."""
    # Simulate async operation
    await asyncio.sleep(1)
    return f"Data retrieved for {query}"
```

#### 2. Implementing Async Methods in Custom Tool Classes

```python Code theme={null}
from crewai.tools import BaseTool

class AsyncCustomTool(BaseTool):
    name: str = "async_custom_tool"
    description: str = "An asynchronous custom tool"

    async def _run(self, query: str = "") -> str:
        """Asynchronously run the tool"""
        # Your async implementation here
        await asyncio.sleep(1)
        return f"Processed {query} asynchronously"
```

### Using Async Tools

Async tools work seamlessly in both standard Crew workflows and Flow-based workflows:

```python Code theme={null}
# In standard Crew
agent = Agent(role="researcher", tools=[async_custom_tool])

# In Flow
class MyFlow(Flow):
    @start()
    async def begin(self):
        crew = Crew(agents=[agent])
        result = await crew.kickoff_async()
        return result
```

The CrewAI framework automatically handles the execution of both synchronous and asynchronous tools, so you don't need to worry about how to call them differently.

### Utilizing the `tool` Decorator

```python Code theme={null}
from crewai.tools import tool
@tool("Name of my tool")
def my_tool(question: str) -> str:
    """Clear description for what this tool is useful for, your agent will need this information to use it."""
    # Function logic here
    return "Result from your custom tool"
```

### Custom Caching Mechanism

<Tip>
  Tools can optionally implement a `cache_function` to fine-tune caching
  behavior. This function determines when to cache results based on specific
  conditions, offering granular control over caching logic.
</Tip>

```python Code theme={null}
from crewai.tools import tool

@tool
def multiplication_tool(first_number: int, second_number: int) -> str:
    """Useful for when you need to multiply two numbers together."""
    return first_number * second_number

def cache_func(args, result):
    # In this case, we only cache the result if it's a multiple of 2
    cache = result % 2 == 0
    return cache

multiplication_tool.cache_function = cache_func

writer1 = Agent(
        role="Writer",
        goal="You write lessons of math for kids.",
        backstory="You're an expert in writing and you love to teach kids but you know nothing of math.",
        tools=[multiplication_tool],
        allow_delegation=False,
    )
    #...
```

## Conclusion

Tools are pivotal in extending the capabilities of CrewAI agents, enabling them to undertake a broad spectrum of tasks and collaborate effectively.
When building solutions with CrewAI, leverage both custom and existing tools to empower your agents and enhance the AI ecosystem. Consider utilizing error handling,
caching mechanisms, and the flexibility of tool arguments to optimize your agents' performance and capabilities.


# Training
Source: https://docs.crewai.com/en/concepts/training

Learn how to train your CrewAI agents by giving them feedback early on and get consistent results.

## Overview

The training feature in CrewAI allows you to train your AI agents using the command-line interface (CLI).
By running the command `crewai train -n <n_iterations>`, you can specify the number of iterations for the training process.

During training, CrewAI utilizes techniques to optimize the performance of your agents along with human feedback.
This helps the agents improve their understanding, decision-making, and problem-solving abilities.

### Training Your Crew Using the CLI

To use the training feature, follow these steps:

1. Open your terminal or command prompt.
2. Navigate to the directory where your CrewAI project is located.
3. Run the following command:

```shell theme={null}
crewai train -n <n_iterations> -f <filename.pkl>
```

<Tip>
  Replace `<n_iterations>` with the desired number of training iterations and `<filename>` with the appropriate filename ending with `.pkl`.
</Tip>

<Note>
  If you omit `-f`, the output defaults to `trained_agents_data.pkl` in the current working directory. You can pass an absolute path to control where the file is written.
</Note>

### Training your Crew programmatically

To train your crew programmatically, use the following steps:

1. Define the number of iterations for training.
2. Specify the input parameters for the training process.
3. Execute the training command within a try-except block to handle potential errors.

```python Code theme={null}
n_iterations = 2
inputs = {"topic": "CrewAI Training"}
filename = "your_model.pkl"

try:
    YourCrewName_Crew().crew().train(
      n_iterations=n_iterations,
      inputs=inputs,
      filename=filename
    )

except Exception as e:
    raise Exception(f"An error occurred while training the crew: {e}")
```

## How trained data is used by agents

CrewAI uses the training artifacts in two ways: during training to incorporate your human feedback, and after training to guide agents with consolidated suggestions.

### Training data flow

```mermaid theme={null}
flowchart TD
  A["Start training<br/>CLI: crewai train -n -f<br/>or Python: crew.train(...)"] --> B["Setup training mode<br/>- task.human_input = true<br/>- disable delegation<br/>- init training_data.pkl + trained file"]

  subgraph "Iterations"
    direction LR
    C["Iteration i<br/>initial_output"] --> D["User human_feedback"]
    D --> E["improved_output"]
    E --> F["Append to training_data.pkl<br/>by agent_id and iteration"]
  end

  B --> C
  F --> G{"More iterations?"}
  G -- "Yes" --> C
  G -- "No" --> H["Evaluate per agent<br/>aggregate iterations"]

  H --> I["Consolidate<br/>suggestions[] + quality + final_summary"]
  I --> J["Save by agent role to trained file<br/>(default: trained_agents_data.pkl)"]

  J --> K["Normal (non-training) runs"]
  K --> L["Auto-load suggestions<br/>from trained_agents_data.pkl"]
  L --> M["Append to prompt<br/>for consistent improvements"]
```

### During training runs

* On each iteration, the system records for every agent:
  * `initial_output`: the agent’s first answer
  * `human_feedback`: your inline feedback when prompted
  * `improved_output`: the agent’s follow-up answer after feedback
* This data is stored in a working file named `training_data.pkl` keyed by the agent’s internal ID and iteration.
* While training is active, the agent automatically appends your prior human feedback to its prompt to enforce those instructions on subsequent attempts within the training session.
  Training is interactive: tasks set `human_input = true`, so running in a non-interactive environment will block on user input.

### After training completes

* When `train(...)` finishes, CrewAI evaluates the collected training data per agent and produces a consolidated result containing:
  * `suggestions`: clear, actionable instructions distilled from your feedback and the difference between initial/improved outputs
  * `quality`: a 0–10 score capturing improvement
  * `final_summary`: a step-by-step set of action items for future tasks
* These consolidated results are saved to the filename you pass to `train(...)` (default via CLI is `trained_agents_data.pkl`). Entries are keyed by the agent’s `role` so they can be applied across sessions.
* During normal (non-training) execution, each agent automatically loads its consolidated `suggestions` and appends them to the task prompt as mandatory instructions. This gives you consistent improvements without changing your agent definitions.

### File summary

* `training_data.pkl` (ephemeral, per-session):
  * Structure: `agent_id -> { iteration_number: { initial_output, human_feedback, improved_output } }`
  * Purpose: capture raw data and human feedback during training
  * Location: saved in the current working directory (CWD)
* `trained_agents_data.pkl` (or your custom filename):
  * Structure: `agent_role -> { suggestions: string[], quality: number, final_summary: string }`
  * Purpose: persist consolidated guidance for future runs
  * Location: written to the CWD by default; use `-f` to set a custom (including absolute) path

## Small Language Model Considerations

<Warning>
  When using smaller language models (≤7B parameters) for training data evaluation, be aware that they may face challenges with generating structured outputs and following complex instructions.
</Warning>

### Limitations of Small Models in Training Evaluation

<CardGroup>
  <Card title="JSON Output Accuracy" icon="triangle-exclamation">
    Smaller models often struggle with producing valid JSON responses needed for structured training evaluations, leading to parsing errors and incomplete data.
  </Card>

  <Card title="Evaluation Quality" icon="chart-line">
    Models under 7B parameters may provide less nuanced evaluations with limited reasoning depth compared to larger models.
  </Card>

  <Card title="Instruction Following" icon="list-check">
    Complex training evaluation criteria may not be fully followed or considered by smaller models.
  </Card>

  <Card title="Consistency" icon="rotate">
    Evaluations across multiple training iterations may lack consistency with smaller models.
  </Card>
</CardGroup>

### Recommendations for Training

<Tabs>
  <Tab title="Best Practice">
    For optimal training quality and reliable evaluations, we strongly recommend using models with at least 7B parameters or larger:

    ```python theme={null}
    from crewai import Agent, Crew, Task, LLM

    # Recommended minimum for training evaluation
    llm = LLM(model="mistral/open-mistral-7b")

    # Better options for reliable training evaluation
    llm = LLM(model="anthropic/claude-3-sonnet-20240229-v1:0")
    llm = LLM(model="gpt-4o")

    # Use this LLM with your agents
    agent = Agent(
        role="Training Evaluator",
        goal="Provide accurate training feedback",
        llm=llm
    )
    ```

    <Tip>
      More powerful models provide higher quality feedback with better reasoning, leading to more effective training iterations.
    </Tip>
  </Tab>

  <Tab title="Small Model Usage">
    If you must use smaller models for training evaluation, be aware of these constraints:

    ```python theme={null}
    # Using a smaller model (expect some limitations)
    llm = LLM(model="huggingface/microsoft/Phi-3-mini-4k-instruct")
    ```

    <Warning>
      While CrewAI includes optimizations for small models, expect less reliable and less nuanced evaluation results that may require more human intervention during training.
    </Warning>
  </Tab>
</Tabs>

### Key Points to Note

* **Positive Integer Requirement:** Ensure that the number of iterations (`n_iterations`) is a positive integer. The code will raise a `ValueError` if this condition is not met.
* **Filename Requirement:** Ensure that the filename ends with `.pkl`. The code will raise a `ValueError` if this condition is not met.
* **Error Handling:** The code handles subprocess errors and unexpected exceptions, providing error messages to the user.
* Trained guidance is applied at prompt time; it does not modify your Python/YAML agent configuration.
* Agents automatically load trained suggestions from a file named `trained_agents_data.pkl` located in the current working directory. If you trained to a different filename, either rename it to `trained_agents_data.pkl` before running, or adjust the loader in code.
* You can change the output filename when calling `crewai train` with `-f/--filename`. Absolute paths are supported if you want to save outside the CWD.

It is important to note that the training process may take some time, depending on the complexity of your agents and will also require your feedback on each iteration.

Once the training is complete, your agents will be equipped with enhanced capabilities and knowledge, ready to tackle complex tasks and provide more consistent and valuable insights.

Remember to regularly update and retrain your agents to ensure they stay up-to-date with the latest information and advancements in the field.


# Customizing Prompts
Source: https://docs.crewai.com/en/guides/advanced/customizing-prompts

Dive deeper into low-level prompt customization for CrewAI, enabling super custom and complex use cases for different models and languages.

## Why Customize Prompts?

Although CrewAI's default prompts work well for many scenarios, low-level customization opens the door to significantly more flexible and powerful agent behavior. Here's why you might want to take advantage of this deeper control:

1. **Optimize for specific LLMs** – Different models (such as GPT-4, Claude, or Llama) thrive with prompt formats tailored to their unique architectures.
2. **Change the language** – Build agents that operate exclusively in languages beyond English, handling nuances with precision.
3. **Specialize for complex domains** – Adapt prompts for highly specialized industries like healthcare, finance, or legal.
4. **Adjust tone and style** – Make agents more formal, casual, creative, or analytical.
5. **Support super custom use cases** – Utilize advanced prompt structures and formatting to meet intricate, project-specific requirements.

This guide explores how to tap into CrewAI's prompts at a lower level, giving you fine-grained control over how agents think and interact.

## Understanding CrewAI's Prompt System

Under the hood, CrewAI employs a modular prompt system that you can customize extensively:

* **Agent templates** – Govern each agent's approach to their assigned role.
* **Prompt slices** – Control specialized behaviors such as tasks, tool usage, and output structure.
* **Error handling** – Direct how agents respond to failures, exceptions, or timeouts.
* **Tool-specific prompts** – Define detailed instructions for how tools are invoked or utilized.

Check out the [original prompt templates in CrewAI's repository](https://github.com/crewAIInc/crewAI/blob/main/src/crewai/translations/en.json) to see how these elements are organized. From there, you can override or adapt them as needed to unlock advanced behaviors.

## Understanding Default System Instructions

<Warning>
  **Production Transparency Issue**: CrewAI automatically injects default instructions into your prompts that you might not be aware of. This section explains what's happening under the hood and how to gain full control.
</Warning>

When you define an agent with `role`, `goal`, and `backstory`, CrewAI automatically adds additional system instructions that control formatting and behavior. Understanding these default injections is crucial for production systems where you need full prompt transparency.

### What CrewAI Automatically Injects

Based on your agent configuration, CrewAI adds different default instructions:

#### For Agents Without Tools

```text theme={null}
"I MUST use these formats, my job depends on it!"
```

#### For Agents With Tools

```text theme={null}
"IMPORTANT: Use the following format in your response:

Thought: you should always think about what to do
Action: the action to take, only one name of [tool_names]
Action Input: the input to the action, just a simple JSON object...
```

#### For Structured Outputs (JSON/Pydantic)

````text theme={null}
"Ensure your final answer contains only the content in the following format: {output_format}
Ensure the final output does not include any code block markers like ```json or ```python."
````

### Viewing the Complete System Prompt

To see exactly what prompt is being sent to your LLM, you can inspect the generated prompt:

```python theme={null}
from crewai import Agent, Crew, Task
from crewai.utilities.prompts import Prompts

# Create your agent
agent = Agent(
    role="Data Analyst",
    goal="Analyze data and provide insights",
    backstory="You are an expert data analyst with 10 years of experience.",
    verbose=True
)

# Create a sample task
task = Task(
    description="Analyze the sales data and identify trends",
    expected_output="A detailed analysis with key insights and trends",
    agent=agent
)

# Create the prompt generator
prompt_generator = Prompts(
    agent=agent,
    has_tools=len(agent.tools) > 0,
    use_system_prompt=agent.use_system_prompt
)

# Generate and inspect the actual prompt
generated_prompt = prompt_generator.task_execution()

# Print the complete system prompt that will be sent to the LLM
if "system" in generated_prompt:
    print("=== SYSTEM PROMPT ===")
    print(generated_prompt["system"])
    print("\n=== USER PROMPT ===")
    print(generated_prompt["user"])
else:
    print("=== COMPLETE PROMPT ===")
    print(generated_prompt["prompt"])

# You can also see how the task description gets formatted
print("\n=== TASK CONTEXT ===")
print(f"Task Description: {task.description}")
print(f"Expected Output: {task.expected_output}")
```

### Overriding Default Instructions

You have several options to gain full control over the prompts:

#### Option 1: Custom Templates (Recommended)

```python theme={null}
from crewai import Agent

# Define your own system template without default instructions
custom_system_template = """You are {role}. {backstory}
Your goal is: {goal}

Respond naturally and conversationally. Focus on providing helpful, accurate information."""

custom_prompt_template = """Task: {input}

Please complete this task thoughtfully."""

agent = Agent(
    role="Research Assistant",
    goal="Help users find accurate information",
    backstory="You are a helpful research assistant.",
    system_template=custom_system_template,
    prompt_template=custom_prompt_template,
    use_system_prompt=True  # Use separate system/user messages
)
```

#### Option 2: Custom Prompt File

Create a `custom_prompts.json` file to override specific prompt slices:

```json theme={null}
{
  "slices": {
    "no_tools": "\nProvide your best answer in a natural, conversational way.",
    "tools": "\nYou have access to these tools: {tools}\n\nUse them when helpful, but respond naturally.",
    "formatted_task_instructions": "Format your response as: {output_format}"
  }
}
```

Then use it in your crew:

```python theme={null}
crew = Crew(
    agents=[agent],
    tasks=[task],
    prompt_file="custom_prompts.json",
    verbose=True
)
```

#### Option 3: Disable System Prompts for o1 Models

```python theme={null}
agent = Agent(
    role="Analyst",
    goal="Analyze data",
    backstory="Expert analyst",
    use_system_prompt=False  # Disables system prompt separation
)
```

### Debugging with Observability Tools

For production transparency, integrate with observability platforms to monitor all prompts and LLM interactions. This allows you to see exactly what prompts (including default instructions) are being sent to your LLMs.

See our [Observability documentation](/en/observability/overview) for detailed integration guides with various platforms including Langfuse, MLflow, Weights & Biases, and custom logging solutions.

### Best Practices for Production

1. **Always inspect generated prompts** before deploying to production
2. **Use custom templates** when you need full control over prompt content
3. **Integrate observability tools** for ongoing prompt monitoring (see [Observability docs](/en/observability/overview))
4. **Test with different LLMs** as default instructions may work differently across models
5. **Document your prompt customizations** for team transparency

<Tip>
  The default instructions exist to ensure consistent agent behavior, but they can interfere with domain-specific requirements. Use the customization options above to maintain full control over your agent's behavior in production systems.
</Tip>

## Best Practices for Managing Prompt Files

When engaging in low-level prompt customization, follow these guidelines to keep things organized and maintainable:

1. **Keep files separate** – Store your customized prompts in dedicated JSON files outside your main codebase.
2. **Version control** – Track changes within your repository, ensuring clear documentation of prompt adjustments over time.
3. **Organize by model or language** – Use naming schemes like `prompts_llama.json` or `prompts_es.json` to quickly identify specialized configurations.
4. **Document changes** – Provide comments or maintain a README detailing the purpose and scope of your customizations.
5. **Minimize alterations** – Only override the specific slices you genuinely need to adjust, keeping default functionality intact for everything else.

## The Simplest Way to Customize Prompts

One straightforward approach is to create a JSON file for the prompts you want to override and then point your Crew at that file:

1. Craft a JSON file with your updated prompt slices.
2. Reference that file via the `prompt_file` parameter in your Crew.

CrewAI then merges your customizations with the defaults, so you don't have to redefine every prompt. Here's how:

### Example: Basic Prompt Customization

Create a `custom_prompts.json` file with the prompts you want to modify. Ensure you list all top-level prompts it should contain, not just your changes:

```json theme={null}
{
  "slices": {
    "format": "When responding, follow this structure:\n\nTHOUGHTS: Your step-by-step thinking\nACTION: Any tool you're using\nRESULT: Your final answer or conclusion"
  }
}
```

Then integrate it like so:

```python theme={null}
from crewai import Agent, Crew, Task, Process

# Create agents and tasks as normal
researcher = Agent(
    role="Research Specialist",
    goal="Find information on quantum computing",
    backstory="You are a quantum physics expert",
    verbose=True
)

research_task = Task(
    description="Research quantum computing applications",
    expected_output="A summary of practical applications",
    agent=researcher
)

# Create a crew with your custom prompt file
crew = Crew(
    agents=[researcher],
    tasks=[research_task],
    prompt_file="path/to/custom_prompts.json",
    verbose=True
)

# Run the crew
result = crew.kickoff()
```

With these few edits, you gain low-level control over how your agents communicate and solve tasks.

## Optimizing for Specific Models

Different models thrive on differently structured prompts. Making deeper adjustments can significantly boost performance by aligning your prompts with a model's nuances.

### Example: Llama 3.3 Prompting Template

For instance, when dealing with Meta's Llama 3.3, deeper-level customization may reflect the recommended structure described at:
[https://www.llama.com/docs/model-cards-and-prompt-formats/llama3\_1/#prompt-template](https://www.llama.com/docs/model-cards-and-prompt-formats/llama3_1/#prompt-template)

Here's an example to highlight how you might fine-tune an Agent to leverage Llama 3.3 in code:

```python theme={null}
from crewai import Agent, Crew, Task, Process
from crewai_tools import DirectoryReadTool, FileReadTool

# Define templates for system, user (prompt), and assistant (response) messages
system_template = """<|begin_of_text|><|start_header_id|>system<|end_header_id|>{{ .System }}<|eot_id|>"""
prompt_template = """<|start_header_id|>user<|end_header_id|>{{ .Prompt }}<|eot_id|>"""
response_template = """<|start_header_id|>assistant<|end_header_id|>{{ .Response }}<|eot_id|>"""

# Create an Agent using Llama-specific layouts
principal_engineer = Agent(
    role="Principal Engineer",
    goal="Oversee AI architecture and make high-level decisions",
    backstory="You are the lead engineer responsible for critical AI systems",
    verbose=True,
    llm="groq/llama-3.3-70b-versatile",  # Using the Llama 3 model
    system_template=system_template,
    prompt_template=prompt_template,
    response_template=response_template,
    tools=[DirectoryReadTool(), FileReadTool()]
)

# Define a sample task
engineering_task = Task(
    description="Review AI implementation files for potential improvements",
    expected_output="A summary of key findings and recommendations",
    agent=principal_engineer
)

# Create a Crew for the task
llama_crew = Crew(
    agents=[principal_engineer],
    tasks=[engineering_task],
    process=Process.sequential,
    verbose=True
)

# Execute the crew
result = llama_crew.kickoff()
print(result.raw)
```

Through this deeper configuration, you can exercise comprehensive, low-level control over your Llama-based workflows without needing a separate JSON file.

## Conclusion

Low-level prompt customization in CrewAI opens the door to super custom, complex use cases. By establishing well-organized prompt files (or direct inline templates), you can accommodate various models, languages, and specialized domains. This level of flexibility ensures you can craft precisely the AI behavior you need, all while knowing CrewAI still provides reliable defaults when you don't override them.

<Check>
  You now have the foundation for advanced prompt customizations in CrewAI. Whether you're adapting for model-specific structures or domain-specific constraints, this low-level approach lets you shape agent interactions in highly specialized ways.
</Check>


# Fingerprinting
Source: https://docs.crewai.com/en/guides/advanced/fingerprinting

Learn how to use CrewAI's fingerprinting system to uniquely identify and track components throughout their lifecycle.

## Overview

Fingerprints in CrewAI provide a way to uniquely identify and track components throughout their lifecycle. Each `Agent`, `Crew`, and `Task` automatically receives a unique fingerprint when created, which cannot be manually overridden.

These fingerprints can be used for:

* Auditing and tracking component usage
* Ensuring component identity integrity
* Attaching metadata to components
* Creating a traceable chain of operations

## How Fingerprints Work

A fingerprint is an instance of the `Fingerprint` class from the `crewai.security` module. Each fingerprint contains:

* A UUID string: A unique identifier for the component that is automatically generated and cannot be manually set
* A creation timestamp: When the fingerprint was generated, automatically set and cannot be manually modified
* Metadata: A dictionary of additional information that can be customized

Fingerprints are automatically generated and assigned when a component is created. Each component exposes its fingerprint through a read-only property.

## Basic Usage

### Accessing Fingerprints

```python theme={null}
from crewai import Agent, Crew, Task

# Create components - fingerprints are automatically generated
agent = Agent(
    role="Data Scientist",
    goal="Analyze data",
    backstory="Expert in data analysis"
)

crew = Crew(
    agents=[agent],
    tasks=[]
)

task = Task(
    description="Analyze customer data",
    expected_output="Insights from data analysis",
    agent=agent
)

# Access the fingerprints
agent_fingerprint = agent.fingerprint
crew_fingerprint = crew.fingerprint
task_fingerprint = task.fingerprint

# Print the UUID strings
print(f"Agent fingerprint: {agent_fingerprint.uuid_str}")
print(f"Crew fingerprint: {crew_fingerprint.uuid_str}")
print(f"Task fingerprint: {task_fingerprint.uuid_str}")
```

### Working with Fingerprint Metadata

You can add metadata to fingerprints for additional context:

```python theme={null}
# Add metadata to the agent's fingerprint
agent.security_config.fingerprint.metadata = {
    "version": "1.0",
    "department": "Data Science",
    "project": "Customer Analysis"
}

# Access the metadata
print(f"Agent metadata: {agent.fingerprint.metadata}")
```

## Fingerprint Persistence

Fingerprints are designed to persist and remain unchanged throughout a component's lifecycle. If you modify a component, the fingerprint remains the same:

```python theme={null}
original_fingerprint = agent.fingerprint.uuid_str

# Modify the agent
agent.goal = "New goal for analysis"

# The fingerprint remains unchanged
assert agent.fingerprint.uuid_str == original_fingerprint
```

## Deterministic Fingerprints

While you cannot directly set the UUID and creation timestamp, you can create deterministic fingerprints using the `generate` method with a seed:

```python theme={null}
from crewai.security import Fingerprint

# Create a deterministic fingerprint using a seed string
deterministic_fingerprint = Fingerprint.generate(seed="my-agent-id")

# The same seed always produces the same fingerprint
same_fingerprint = Fingerprint.generate(seed="my-agent-id")
assert deterministic_fingerprint.uuid_str == same_fingerprint.uuid_str

# You can also set metadata
custom_fingerprint = Fingerprint.generate(
    seed="my-agent-id",
    metadata={"version": "1.0"}
)
```

## Advanced Usage

### Fingerprint Structure

Each fingerprint has the following structure:

```python theme={null}
from crewai.security import Fingerprint

fingerprint = agent.fingerprint

# UUID string - the unique identifier (auto-generated)
uuid_str = fingerprint.uuid_str  # e.g., "123e4567-e89b-12d3-a456-426614174000"

# Creation timestamp (auto-generated)
created_at = fingerprint.created_at  # A datetime object

# Metadata - for additional information (can be customized)
metadata = fingerprint.metadata  # A dictionary, defaults to {}
```


# Crafting Effective Agents
Source: https://docs.crewai.com/en/guides/agents/crafting-effective-agents

Learn best practices for designing powerful, specialized AI agents that collaborate effectively to solve complex problems.

## The Art and Science of Agent Design

At the heart of CrewAI lies the agent - a specialized AI entity designed to perform specific roles within a collaborative framework. While creating basic agents is simple, crafting truly effective agents that produce exceptional results requires understanding key design principles and best practices.

This guide will help you master the art of agent design, enabling you to create specialized AI personas that collaborate effectively, think critically, and produce high-quality outputs tailored to your specific needs.

### Why Agent Design Matters

The way you define your agents significantly impacts:

1. **Output quality**: Well-designed agents produce more relevant, high-quality results
2. **Collaboration effectiveness**: Agents with complementary skills work together more efficiently
3. **Task performance**: Agents with clear roles and goals execute tasks more effectively
4. **System scalability**: Thoughtfully designed agents can be reused across multiple crews and contexts

Let's explore best practices for creating agents that excel in these dimensions.

## The 80/20 Rule: Focus on Tasks Over Agents

When building effective AI systems, remember this crucial principle: **80% of your effort should go into designing tasks, and only 20% into defining agents**.

Why? Because even the most perfectly defined agent will fail with poorly designed tasks, but well-designed tasks can elevate even a simple agent. This means:

* Spend most of your time writing clear task instructions
* Define detailed inputs and expected outputs
* Add examples and context to guide execution
* Dedicate the remaining time to agent role, goal, and backstory

This doesn't mean agent design isn't important - it absolutely is. But task design is where most execution failures occur, so prioritize accordingly.

## Core Principles of Effective Agent Design

### 1. The Role-Goal-Backstory Framework

The most powerful agents in CrewAI are built on a strong foundation of three key elements:

#### Role: The Agent's Specialized Function

The role defines what the agent does and their area of expertise. When crafting roles:

* **Be specific and specialized**: Instead of "Writer," use "Technical Documentation Specialist" or "Creative Storyteller"
* **Align with real-world professions**: Base roles on recognizable professional archetypes
* **Include domain expertise**: Specify the agent's field of knowledge (e.g., "Financial Analyst specializing in market trends")

**Examples of effective roles:**

```yaml theme={null}
role: "Senior UX Researcher specializing in user interview analysis"
role: "Full-Stack Software Architect with expertise in distributed systems"
role: "Corporate Communications Director specializing in crisis management"
```

#### Goal: The Agent's Purpose and Motivation

The goal directs the agent's efforts and shapes their decision-making process. Effective goals should:

* **Be clear and outcome-focused**: Define what the agent is trying to achieve
* **Emphasize quality standards**: Include expectations about the quality of work
* **Incorporate success criteria**: Help the agent understand what "good" looks like

**Examples of effective goals:**

```yaml theme={null}
goal: "Uncover actionable user insights by analyzing interview data and identifying recurring patterns, unmet needs, and improvement opportunities"
goal: "Design robust, scalable system architectures that balance performance, maintainability, and cost-effectiveness"
goal: "Craft clear, empathetic crisis communications that address stakeholder concerns while protecting organizational reputation"
```

#### Backstory: The Agent's Experience and Perspective

The backstory gives depth to the agent, influencing how they approach problems and interact with others. Good backstories:

* **Establish expertise and experience**: Explain how the agent gained their skills
* **Define working style and values**: Describe how the agent approaches their work
* **Create a cohesive persona**: Ensure all elements of the backstory align with the role and goal

**Examples of effective backstories:**

```yaml theme={null}
backstory: "You have spent 15 years conducting and analyzing user research for top tech companies. You have a talent for reading between the lines and identifying patterns that others miss. You believe that good UX is invisible and that the best insights come from listening to what users don't say as much as what they do say."

backstory: "With 20+ years of experience building distributed systems at scale, you've developed a pragmatic approach to software architecture. You've seen both successful and failed systems and have learned valuable lessons from each. You balance theoretical best practices with practical constraints and always consider the maintenance and operational aspects of your designs."

backstory: "As a seasoned communications professional who has guided multiple organizations through high-profile crises, you understand the importance of transparency, speed, and empathy in crisis response. You have a methodical approach to crafting messages that address concerns while maintaining organizational credibility."
```

### 2. Specialists Over Generalists

Agents perform significantly better when given specialized roles rather than general ones. A highly focused agent delivers more precise, relevant outputs:

**Generic (Less Effective):**

```yaml theme={null}
role: "Writer"
```

**Specialized (More Effective):**

```yaml theme={null}
role: "Technical Blog Writer specializing in explaining complex AI concepts to non-technical audiences"
```

**Specialist Benefits:**

* Clearer understanding of expected output
* More consistent performance
* Better alignment with specific tasks
* Improved ability to make domain-specific judgments

### 3. Balancing Specialization and Versatility

Effective agents strike the right balance between specialization (doing one thing extremely well) and versatility (being adaptable to various situations):

* **Specialize in role, versatile in application**: Create agents with specialized skills that can be applied across multiple contexts
* **Avoid overly narrow definitions**: Ensure agents can handle variations within their domain of expertise
* **Consider the collaborative context**: Design agents whose specializations complement the other agents they'll work with

### 4. Setting Appropriate Expertise Levels

The expertise level you assign to your agent shapes how they approach tasks:

* **Novice agents**: Good for straightforward tasks, brainstorming, or initial drafts
* **Intermediate agents**: Suitable for most standard tasks with reliable execution
* **Expert agents**: Best for complex, specialized tasks requiring depth and nuance
* **World-class agents**: Reserved for critical tasks where exceptional quality is needed

Choose the appropriate expertise level based on task complexity and quality requirements. For most collaborative crews, a mix of expertise levels often works best, with higher expertise assigned to core specialized functions.

## Practical Examples: Before and After

Let's look at some examples of agent definitions before and after applying these best practices:

### Example 1: Content Creation Agent

**Before:**

```yaml theme={null}
role: "Writer"
goal: "Write good content"
backstory: "You are a writer who creates content for websites."
```

**After:**

```yaml theme={null}
role: "B2B Technology Content Strategist"
goal: "Create compelling, technically accurate content that explains complex topics in accessible language while driving reader engagement and supporting business objectives"
backstory: "You have spent a decade creating content for leading technology companies, specializing in translating technical concepts for business audiences. You excel at research, interviewing subject matter experts, and structuring information for maximum clarity and impact. You believe that the best B2B content educates first and sells second, building trust through genuine expertise rather than marketing hype."
```

### Example 2: Research Agent

**Before:**

```yaml theme={null}
role: "Researcher"
goal: "Find information"
backstory: "You are good at finding information online."
```

**After:**

```yaml theme={null}
role: "Academic Research Specialist in Emerging Technologies"
goal: "Discover and synthesize cutting-edge research, identifying key trends, methodologies, and findings while evaluating the quality and reliability of sources"
backstory: "With a background in both computer science and library science, you've mastered the art of digital research. You've worked with research teams at prestigious universities and know how to navigate academic databases, evaluate research quality, and synthesize findings across disciplines. You're methodical in your approach, always cross-referencing information and tracing claims to primary sources before drawing conclusions."
```

## Crafting Effective Tasks for Your Agents

While agent design is important, task design is critical for successful execution. Here are best practices for designing tasks that set your agents up for success:

### The Anatomy of an Effective Task

A well-designed task has two key components that serve different purposes:

#### Task Description: The Process

The description should focus on what to do and how to do it, including:

* Detailed instructions for execution
* Context and background information
* Scope and constraints
* Process steps to follow

#### Expected Output: The Deliverable

The expected output should define what the final result should look like:

* Format specifications (markdown, JSON, etc.)
* Structure requirements
* Quality criteria
* Examples of good outputs (when possible)

### Task Design Best Practices

#### 1. Single Purpose, Single Output

Tasks perform best when focused on one clear objective:

**Bad Example (Too Broad):**

```yaml theme={null}
task_description: "Research market trends, analyze the data, and create a visualization."
```

**Good Example (Focused):**

```yaml theme={null}
# Task 1
research_task:
  description: "Research the top 5 market trends in the AI industry for 2024."
  expected_output: "A markdown list of the 5 trends with supporting evidence."

# Task 2
analysis_task:
  description: "Analyze the identified trends to determine potential business impacts."
  expected_output: "A structured analysis with impact ratings (High/Medium/Low)."

# Task 3
visualization_task:
  description: "Create a visual representation of the analyzed trends."
  expected_output: "A description of a chart showing trends and their impact ratings."
```

#### 2. Be Explicit About Inputs and Outputs

Always clearly specify what inputs the task will use and what the output should look like:

**Example:**

```yaml theme={null}
analysis_task:
  description: >
    Analyze the customer feedback data from the CSV file.
    Focus on identifying recurring themes related to product usability.
    Consider sentiment and frequency when determining importance.
  expected_output: >
    A markdown report with the following sections:
    1. Executive summary (3-5 bullet points)
    2. Top 3 usability issues with supporting data
    3. Recommendations for improvement
```

#### 3. Include Purpose and Context

Explain why the task matters and how it fits into the larger workflow:

**Example:**

```yaml theme={null}
competitor_analysis_task:
  description: >
    Analyze our three main competitors' pricing strategies.
    This analysis will inform our upcoming pricing model revision.
    Focus on identifying patterns in how they price premium features
    and how they structure their tiered offerings.
```

#### 4. Use Structured Output Tools

For machine-readable outputs, specify the format clearly:

**Example:**

```yaml theme={null}
data_extraction_task:
  description: "Extract key metrics from the quarterly report."
  expected_output: "JSON object with the following keys: revenue, growth_rate, customer_acquisition_cost, and retention_rate."
```

## Common Mistakes to Avoid

Based on lessons learned from real-world implementations, here are the most common pitfalls in agent and task design:

### 1. Unclear Task Instructions

**Problem:** Tasks lack sufficient detail, making it difficult for agents to execute effectively.

**Example of Poor Design:**

```yaml theme={null}
research_task:
  description: "Research AI trends."
  expected_output: "A report on AI trends."
```

**Improved Version:**

```yaml theme={null}
research_task:
  description: >
    Research the top emerging AI trends for 2024 with a focus on:
    1. Enterprise adoption patterns
    2. Technical breakthroughs in the past 6 months
    3. Regulatory developments affecting implementation

    For each trend, identify key companies, technologies, and potential business impacts.
  expected_output: >
    A comprehensive markdown report with:
    - Executive summary (5 bullet points)
    - 5-7 major trends with supporting evidence
    - For each trend: definition, examples, and business implications
    - References to authoritative sources
```

### 2. "God Tasks" That Try to Do Too Much

**Problem:** Tasks that combine multiple complex operations into one instruction set.

**Example of Poor Design:**

```yaml theme={null}
comprehensive_task:
  description: "Research market trends, analyze competitor strategies, create a marketing plan, and design a launch timeline."
```

**Improved Version:**
Break this into sequential, focused tasks:

```yaml theme={null}
# Task 1: Research
market_research_task:
  description: "Research current market trends in the SaaS project management space."
  expected_output: "A markdown summary of key market trends."

# Task 2: Competitive Analysis
competitor_analysis_task:
  description: "Analyze strategies of the top 3 competitors based on the market research."
  expected_output: "A comparison table of competitor strategies."
  context: [market_research_task]

# Continue with additional focused tasks...
```

### 3. Misaligned Description and Expected Output

**Problem:** The task description asks for one thing while the expected output specifies something different.

**Example of Poor Design:**

```yaml theme={null}
analysis_task:
  description: "Analyze customer feedback to find areas of improvement."
  expected_output: "A marketing plan for the next quarter."
```

**Improved Version:**

```yaml theme={null}
analysis_task:
  description: "Analyze customer feedback to identify the top 3 areas for product improvement."
  expected_output: "A report listing the 3 priority improvement areas with supporting customer quotes and data points."
```

### 4. Not Understanding the Process Yourself

**Problem:** Asking agents to execute tasks that you yourself don't fully understand.

**Solution:**

1. Try to perform the task manually first
2. Document your process, decision points, and information sources
3. Use this documentation as the basis for your task description

### 5. Premature Use of Hierarchical Structures

**Problem:** Creating unnecessarily complex agent hierarchies where sequential processes would work better.

**Solution:** Start with sequential processes and only move to hierarchical models when the workflow complexity truly requires it.

### 6. Vague or Generic Agent Definitions

**Problem:** Generic agent definitions lead to generic outputs.

**Example of Poor Design:**

```yaml theme={null}
agent:
  role: "Business Analyst"
  goal: "Analyze business data"
  backstory: "You are good at business analysis."
```

**Improved Version:**

```yaml theme={null}
agent:
  role: "SaaS Metrics Specialist focusing on growth-stage startups"
  goal: "Identify actionable insights from business data that can directly impact customer retention and revenue growth"
  backstory: "With 10+ years analyzing SaaS business models, you've developed a keen eye for the metrics that truly matter for sustainable growth. You've helped numerous companies identify the leverage points that turned around their business trajectory. You believe in connecting data to specific, actionable recommendations rather than general observations."
```

## Advanced Agent Design Strategies

### Designing for Collaboration

When creating agents that will work together in a crew, consider:

* **Complementary skills**: Design agents with distinct but complementary abilities
* **Handoff points**: Define clear interfaces for how work passes between agents
* **Constructive tension**: Sometimes, creating agents with slightly different perspectives can lead to better outcomes through productive dialogue

For example, a content creation crew might include:

```yaml theme={null}
# Research Agent
role: "Research Specialist for technical topics"
goal: "Gather comprehensive, accurate information from authoritative sources"
backstory: "You are a meticulous researcher with a background in library science..."

# Writer Agent
role: "Technical Content Writer"
goal: "Transform research into engaging, clear content that educates and informs"
backstory: "You are an experienced writer who excels at explaining complex concepts..."

# Editor Agent
role: "Content Quality Editor"
goal: "Ensure content is accurate, well-structured, and polished while maintaining consistency"
backstory: "With years of experience in publishing, you have a keen eye for detail..."
```

### Creating Specialized Tool Users

Some agents can be designed specifically to leverage certain tools effectively:

```yaml theme={null}
role: "Data Analysis Specialist"
goal: "Derive meaningful insights from complex datasets through statistical analysis"
backstory: "With a background in data science, you excel at working with structured and unstructured data..."
tools: [PythonREPLTool, DataVisualizationTool, CSVAnalysisTool]
```

### Tailoring Agents to LLM Capabilities

Different LLMs have different strengths. Design your agents with these capabilities in mind:

```yaml theme={null}
# For complex reasoning tasks
analyst:
  role: "Data Insights Analyst"
  goal: "..."
  backstory: "..."
  llm: openai/gpt-4o

# For creative content
writer:
  role: "Creative Content Writer"
  goal: "..."
  backstory: "..."
  llm: anthropic/claude-3-opus
```

## Testing and Iterating on Agent Design

Agent design is often an iterative process. Here's a practical approach:

1. **Start with a prototype**: Create an initial agent definition
2. **Test with sample tasks**: Evaluate performance on representative tasks
3. **Analyze outputs**: Identify strengths and weaknesses
4. **Refine the definition**: Adjust role, goal, and backstory based on observations
5. **Test in collaboration**: Evaluate how the agent performs in a crew setting

## Conclusion

Crafting effective agents is both an art and a science. By carefully defining roles, goals, and backstories that align with your specific needs, and combining them with well-designed tasks, you can create specialized AI collaborators that produce exceptional results.

Remember that agent and task design is an iterative process. Start with these best practices, observe your agents in action, and refine your approach based on what you learn. And always keep in mind the 80/20 rule - focus most of your effort on creating clear, focused tasks to get the best results from your agents.

<Check>
  Congratulations! You now understand the principles and practices of effective agent design. Apply these techniques to create powerful, specialized agents that work together seamlessly to accomplish complex tasks.
</Check>

## Next Steps

* Experiment with different agent configurations for your specific use case
* Learn about [building your first crew](/en/guides/crews/first-crew) to see how agents work together
* Explore [CrewAI Flows](/en/guides/flows/first-flow) for more advanced orchestration


# Coding Tools
Source: https://docs.crewai.com/en/guides/coding-tools/agents-md

Use AGENTS.md to guide coding agents and IDEs across your CrewAI projects.

## Why AGENTS.md

`AGENTS.md` is a lightweight, repo-local instruction file that gives coding agents consistent, project-specific guidance. Keep it in the project root and treat it as the source of truth for how you want assistants to work: conventions, commands, architecture notes, and guardrails.

## Create a Project with the CLI

Use the CrewAI CLI to scaffold a project, then `AGENTS.md` will be automatically added at the root.

```bash theme={null}
# Crew
crewai create crew my_crew

# Flow
crewai create flow my_flow

# Tool repository
crewai tool create my_tool
```

## Tool Setup: Point Assistants to AGENTS.md

### Codex

Codex can be guided by `AGENTS.md` files placed in your repository. Use them to supply persistent project context such as conventions, commands, and workflow expectations.

### Claude Code

Claude Code stores project memory in `CLAUDE.md`. You can bootstrap it with `/init` and edit it using `/memory`. Claude Code also supports imports inside `CLAUDE.md`, so you can add a single line like `@AGENTS.md` to pull in the shared instructions without duplicating them.

You can simply use:

```bash theme={null}
mv AGENTS.md CLAUDE.md
```

### Gemini CLI and Google Antigravity

Gemini CLI and Antigravity load a project context file (default: `GEMINI.md`) from the repo root and parent directories. You can configure it to read `AGENTS.md` instead (or in addition) by setting `context.fileName` in your Gemini CLI settings. For example, set it to `AGENTS.md` only, or include both `AGENTS.md` and `GEMINI.md` if you want to keep each tool’s format.

You can simply use:

```bash theme={null}
mv AGENTS.md GEMINI.md
```

### Cursor

Cursor supports `AGENTS.md` as a project instruction file. Place it at the project root to provide guidance for Cursor’s coding assistant.

### Windsurf

Claude Code provides an official integration with Windsurf. If you use Claude Code inside Windsurf, follow the Claude Code guidance above and import `AGENTS.md` from `CLAUDE.md`.

If you are using Windsurf’s native assistant, configure its project rules or instructions feature (if available) to read from `AGENTS.md` or paste the contents directly.


# Evaluating Use Cases for CrewAI
Source: https://docs.crewai.com/en/guides/concepts/evaluating-use-cases

Learn how to assess your AI application needs and choose the right approach between Crews and Flows based on complexity and precision requirements.

## Understanding the Decision Framework

When building AI applications with CrewAI, one of the most important decisions you'll make is choosing the right approach for your specific use case. Should you use a Crew? A Flow? A combination of both? This guide will help you evaluate your requirements and make informed architectural decisions.

At the heart of this decision is understanding the relationship between **complexity** and **precision** in your application:

<Frame>
  <img alt="Complexity vs. Precision Matrix" />
</Frame>

This matrix helps visualize how different approaches align with varying requirements for complexity and precision. Let's explore what each quadrant means and how it guides your architectural choices.

## The Complexity-Precision Matrix Explained

### What is Complexity?

In the context of CrewAI applications, **complexity** refers to:

* The number of distinct steps or operations required
* The diversity of tasks that need to be performed
* The interdependencies between different components
* The need for conditional logic and branching
* The sophistication of the overall workflow

### What is Precision?

**Precision** in this context refers to:

* The accuracy required in the final output
* The need for structured, predictable results
* The importance of reproducibility
* The level of control needed over each step
* The tolerance for variation in outputs

### The Four Quadrants

#### 1. Low Complexity, Low Precision

**Characteristics:**

* Simple, straightforward tasks
* Tolerance for some variation in outputs
* Limited number of steps
* Creative or exploratory applications

**Recommended Approach:** Simple Crews with minimal agents

**Example Use Cases:**

* Basic content generation
* Idea brainstorming
* Simple summarization tasks
* Creative writing assistance

#### 2. Low Complexity, High Precision

**Characteristics:**

* Simple workflows that require exact, structured outputs
* Need for reproducible results
* Limited steps but high accuracy requirements
* Often involves data processing or transformation

**Recommended Approach:** Flows with direct LLM calls or simple Crews with structured outputs

**Example Use Cases:**

* Data extraction and transformation
* Form filling and validation
* Structured content generation (JSON, XML)
* Simple classification tasks

#### 3. High Complexity, Low Precision

**Characteristics:**

* Multi-stage processes with many steps
* Creative or exploratory outputs
* Complex interactions between components
* Tolerance for variation in final results

**Recommended Approach:** Complex Crews with multiple specialized agents

**Example Use Cases:**

* Research and analysis
* Content creation pipelines
* Exploratory data analysis
* Creative problem-solving

#### 4. High Complexity, High Precision

**Characteristics:**

* Complex workflows requiring structured outputs
* Multiple interdependent steps with strict accuracy requirements
* Need for both sophisticated processing and precise results
* Often mission-critical applications

**Recommended Approach:** Flows orchestrating multiple Crews with validation steps

**Example Use Cases:**

* Enterprise decision support systems
* Complex data processing pipelines
* Multi-stage document processing
* Regulated industry applications

## Choosing Between Crews and Flows

### When to Choose Crews

Crews are ideal when:

1. **You need collaborative intelligence** - Multiple agents with different specializations need to work together
2. **The problem requires emergent thinking** - The solution benefits from different perspectives and approaches
3. **The task is primarily creative or analytical** - The work involves research, content creation, or analysis
4. **You value adaptability over strict structure** - The workflow can benefit from agent autonomy
5. **The output format can be somewhat flexible** - Some variation in output structure is acceptable

```python theme={null}
# Example: Research Crew for market analysis
from crewai import Agent, Crew, Process, Task

# Create specialized agents
researcher = Agent(
    role="Market Research Specialist",
    goal="Find comprehensive market data on emerging technologies",
    backstory="You are an expert at discovering market trends and gathering data."
)

analyst = Agent(
    role="Market Analyst",
    goal="Analyze market data and identify key opportunities",
    backstory="You excel at interpreting market data and spotting valuable insights."
)

# Define their tasks
research_task = Task(
    description="Research the current market landscape for AI-powered healthcare solutions",
    expected_output="Comprehensive market data including key players, market size, and growth trends",
    agent=researcher
)

analysis_task = Task(
    description="Analyze the market data and identify the top 3 investment opportunities",
    expected_output="Analysis report with 3 recommended investment opportunities and rationale",
    agent=analyst,
    context=[research_task]
)

# Create the crew
market_analysis_crew = Crew(
    agents=[researcher, analyst],
    tasks=[research_task, analysis_task],
    process=Process.sequential,
    verbose=True
)

# Run the crew
result = market_analysis_crew.kickoff()
```

### When to Choose Flows

Flows are ideal when:

1. **You need precise control over execution** - The workflow requires exact sequencing and state management
2. **The application has complex state requirements** - You need to maintain and transform state across multiple steps
3. **You need structured, predictable outputs** - The application requires consistent, formatted results
4. **The workflow involves conditional logic** - Different paths need to be taken based on intermediate results
5. **You need to combine AI with procedural code** - The solution requires both AI capabilities and traditional programming

```python theme={null}
# Example: Customer Support Flow with structured processing
from crewai.flow.flow import Flow, listen, router, start
from pydantic import BaseModel
from typing import List, Dict

# Define structured state
class SupportTicketState(BaseModel):
    ticket_id: str = ""
    customer_name: str = ""
    issue_description: str = ""
    category: str = ""
    priority: str = "medium"
    resolution: str = ""
    satisfaction_score: int = 0

class CustomerSupportFlow(Flow[SupportTicketState]):
    @start()
    def receive_ticket(self):
        # In a real app, this might come from an API
        self.state.ticket_id = "TKT-12345"
        self.state.customer_name = "Alex Johnson"
        self.state.issue_description = "Unable to access premium features after payment"
        return "Ticket received"

    @listen(receive_ticket)
    def categorize_ticket(self, _):
        # Use a direct LLM call for categorization
        from crewai import LLM
        llm = LLM(model="openai/gpt-4o-mini")

        prompt = f"""
        Categorize the following customer support issue into one of these categories:
        - Billing
        - Account Access
        - Technical Issue
        - Feature Request
        - Other

        Issue: {self.state.issue_description}

        Return only the category name.
        """

        self.state.category = llm.call(prompt).strip()
        return self.state.category

    @router(categorize_ticket)
    def route_by_category(self, category):
        # Route to different handlers based on category
        return category.lower().replace(" ", "_")

    @listen("billing")
    def handle_billing_issue(self):
        # Handle billing-specific logic
        self.state.priority = "high"
        # More billing-specific processing...
        return "Billing issue handled"

    @listen("account_access")
    def handle_access_issue(self):
        # Handle access-specific logic
        self.state.priority = "high"
        # More access-specific processing...
        return "Access issue handled"

    # Additional category handlers...

    @listen("billing", "account_access", "technical_issue", "feature_request", "other")
    def resolve_ticket(self, resolution_info):
        # Final resolution step
        self.state.resolution = f"Issue resolved: {resolution_info}"
        return self.state.resolution

# Run the flow
support_flow = CustomerSupportFlow()
result = support_flow.kickoff()
```

### When to Combine Crews and Flows

The most sophisticated applications often benefit from combining Crews and Flows:

1. **Complex multi-stage processes** - Use Flows to orchestrate the overall process and Crews for complex subtasks
2. **Applications requiring both creativity and structure** - Use Crews for creative tasks and Flows for structured processing
3. **Enterprise-grade AI applications** - Use Flows to manage state and process flow while leveraging Crews for specialized work

```python theme={null}
# Example: Content Production Pipeline combining Crews and Flows
from crewai.flow.flow import Flow, listen, start
from crewai import Agent, Crew, Process, Task
from pydantic import BaseModel
from typing import List, Dict

class ContentState(BaseModel):
    topic: str = ""
    target_audience: str = ""
    content_type: str = ""
    outline: Dict = {}
    draft_content: str = ""
    final_content: str = ""
    seo_score: int = 0

class ContentProductionFlow(Flow[ContentState]):
    @start()
    def initialize_project(self):
        # Set initial parameters
        self.state.topic = "Sustainable Investing"
        self.state.target_audience = "Millennial Investors"
        self.state.content_type = "Blog Post"
        return "Project initialized"

    @listen(initialize_project)
    def create_outline(self, _):
        # Use a research crew to create an outline
        researcher = Agent(
            role="Content Researcher",
            goal=f"Research {self.state.topic} for {self.state.target_audience}",
            backstory="You are an expert researcher with deep knowledge of content creation."
        )

        outliner = Agent(
            role="Content Strategist",
            goal=f"Create an engaging outline for a {self.state.content_type}",
            backstory="You excel at structuring content for maximum engagement."
        )

        research_task = Task(
            description=f"Research {self.state.topic} focusing on what would interest {self.state.target_audience}",
            expected_output="Comprehensive research notes with key points and statistics",
            agent=researcher
        )

        outline_task = Task(
            description=f"Create an outline for a {self.state.content_type} about {self.state.topic}",
            expected_output="Detailed content outline with sections and key points",
            agent=outliner,
            context=[research_task]
        )

        outline_crew = Crew(
            agents=[researcher, outliner],
            tasks=[research_task, outline_task],
            process=Process.sequential,
            verbose=True
        )

        # Run the crew and store the result
        result = outline_crew.kickoff()

        # Parse the outline (in a real app, you might use a more robust parsing approach)
        import json
        try:
            self.state.outline = json.loads(result.raw)
        except:
            # Fallback if not valid JSON
            self.state.outline = {"sections": result.raw}

        return "Outline created"

    @listen(create_outline)
    def write_content(self, _):
        # Use a writing crew to create the content
        writer = Agent(
            role="Content Writer",
            goal=f"Write engaging content for {self.state.target_audience}",
            backstory="You are a skilled writer who creates compelling content."
        )

        editor = Agent(
            role="Content Editor",
            goal="Ensure content is polished, accurate, and engaging",
            backstory="You have a keen eye for detail and a talent for improving content."
        )

        writing_task = Task(
            description=f"Write a {self.state.content_type} about {self.state.topic} following this outline: {self.state.outline}",
            expected_output="Complete draft content in markdown format",
            agent=writer
        )

        editing_task = Task(
            description="Edit and improve the draft content for clarity, engagement, and accuracy",
            expected_output="Polished final content in markdown format",
            agent=editor,
            context=[writing_task]
        )

        writing_crew = Crew(
            agents=[writer, editor],
            tasks=[writing_task, editing_task],
            process=Process.sequential,
            verbose=True
        )

        # Run the crew and store the result
        result = writing_crew.kickoff()
        self.state.final_content = result.raw

        return "Content created"

    @listen(write_content)
    def optimize_for_seo(self, _):
        # Use a direct LLM call for SEO optimization
        from crewai import LLM
        llm = LLM(model="openai/gpt-4o-mini")

        prompt = f"""
        Analyze this content for SEO effectiveness for the keyword "{self.state.topic}".
        Rate it on a scale of 1-100 and provide 3 specific recommendations for improvement.

        Content: {self.state.final_content[:1000]}... (truncated for brevity)

        Format your response as JSON with the following structure:
        {{
            "score": 85,
            "recommendations": [
                "Recommendation 1",
                "Recommendation 2",
                "Recommendation 3"
            ]
        }}
        """

        seo_analysis = llm.call(prompt)

        # Parse the SEO analysis
        import json
        try:
            analysis = json.loads(seo_analysis)
            self.state.seo_score = analysis.get("score", 0)
            return analysis
        except:
            self.state.seo_score = 50
            return {"score": 50, "recommendations": ["Unable to parse SEO analysis"]}

# Run the flow
content_flow = ContentProductionFlow()
result = content_flow.kickoff()
```

## Practical Evaluation Framework

To determine the right approach for your specific use case, follow this step-by-step evaluation framework:

### Step 1: Assess Complexity

Rate your application's complexity on a scale of 1-10 by considering:

1. **Number of steps**: How many distinct operations are required?
   * 1-3 steps: Low complexity (1-3)
   * 4-7 steps: Medium complexity (4-7)
   * 8+ steps: High complexity (8-10)

2. **Interdependencies**: How interconnected are the different parts?
   * Few dependencies: Low complexity (1-3)
   * Some dependencies: Medium complexity (4-7)
   * Many complex dependencies: High complexity (8-10)

3. **Conditional logic**: How much branching and decision-making is needed?
   * Linear process: Low complexity (1-3)
   * Some branching: Medium complexity (4-7)
   * Complex decision trees: High complexity (8-10)

4. **Domain knowledge**: How specialized is the knowledge required?
   * General knowledge: Low complexity (1-3)
   * Some specialized knowledge: Medium complexity (4-7)
   * Deep expertise in multiple domains: High complexity (8-10)

Calculate your average score to determine overall complexity.

### Step 2: Assess Precision Requirements

Rate your precision requirements on a scale of 1-10 by considering:

1. **Output structure**: How structured must the output be?
   * Free-form text: Low precision (1-3)
   * Semi-structured: Medium precision (4-7)
   * Strictly formatted (JSON, XML): High precision (8-10)

2. **Accuracy needs**: How important is factual accuracy?
   * Creative content: Low precision (1-3)
   * Informational content: Medium precision (4-7)
   * Critical information: High precision (8-10)

3. **Reproducibility**: How consistent must results be across runs?
   * Variation acceptable: Low precision (1-3)
   * Some consistency needed: Medium precision (4-7)
   * Exact reproducibility required: High precision (8-10)

4. **Error tolerance**: What is the impact of errors?
   * Low impact: Low precision (1-3)
   * Moderate impact: Medium precision (4-7)
   * High impact: High precision (8-10)

Calculate your average score to determine overall precision requirements.

### Step 3: Map to the Matrix

Plot your complexity and precision scores on the matrix:

* **Low Complexity (1-4), Low Precision (1-4)**: Simple Crews
* **Low Complexity (1-4), High Precision (5-10)**: Flows with direct LLM calls
* **High Complexity (5-10), Low Precision (1-4)**: Complex Crews
* **High Complexity (5-10), High Precision (5-10)**: Flows orchestrating Crews

### Step 4: Consider Additional Factors

Beyond complexity and precision, consider:

1. **Development time**: Crews are often faster to prototype
2. **Maintenance needs**: Flows provide better long-term maintainability
3. **Team expertise**: Consider your team's familiarity with different approaches
4. **Scalability requirements**: Flows typically scale better for complex applications
5. **Integration needs**: Consider how the solution will integrate with existing systems

## Conclusion

Choosing between Crews and Flows—or combining them—is a critical architectural decision that impacts the effectiveness, maintainability, and scalability of your CrewAI application. By evaluating your use case along the dimensions of complexity and precision, you can make informed decisions that align with your specific requirements.

Remember that the best approach often evolves as your application matures. Start with the simplest solution that meets your needs, and be prepared to refine your architecture as you gain experience and your requirements become clearer.

<Check>
  You now have a framework for evaluating CrewAI use cases and choosing the right approach based on complexity and precision requirements. This will help you build more effective, maintainable, and scalable AI applications.
</Check>

## Next Steps

* Learn more about [crafting effective agents](/en/guides/agents/crafting-effective-agents)
* Explore [building your first crew](/en/guides/crews/first-crew)
* Dive into [mastering flow state management](/en/guides/flows/mastering-flow-state)
* Check out the [core concepts](/en/concepts/agents) for deeper understanding


# Build Your First Crew
Source: https://docs.crewai.com/en/guides/crews/first-crew

Step-by-step tutorial to create a collaborative AI team that works together to solve complex problems.

## Unleashing the Power of Collaborative AI

Imagine having a team of specialized AI agents working together seamlessly to solve complex problems, each contributing their unique skills to achieve a common goal. This is the power of CrewAI - a framework that enables you to create collaborative AI systems that can accomplish tasks far beyond what a single AI could achieve alone.

In this guide, we'll walk through creating a research crew that will help us research and analyze a topic, then create a comprehensive report. This practical example demonstrates how AI agents can collaborate to accomplish complex tasks, but it's just the beginning of what's possible with CrewAI.

### What You'll Build and Learn

By the end of this guide, you'll have:

1. **Created a specialized AI research team** with distinct roles and responsibilities
2. **Orchestrated collaboration** between multiple AI agents
3. **Automated a complex workflow** that involves gathering information, analysis, and report generation
4. **Built foundational skills** that you can apply to more ambitious projects

While we're building a simple research crew in this guide, the same patterns and techniques can be applied to create much more sophisticated teams for tasks like:

* Multi-stage content creation with specialized writers, editors, and fact-checkers
* Complex customer service systems with tiered support agents
* Autonomous business analysts that gather data, create visualizations, and generate insights
* Product development teams that ideate, design, and plan implementation

Let's get started building your first crew!

### Prerequisites

Before starting, make sure you have:

1. Installed CrewAI following the [installation guide](/en/installation)
2. Set up your LLM API key in your environment, following the [LLM setup
   guide](/en/concepts/llms#setting-up-your-llm)
3. Basic understanding of Python

## Step 1: Create a New CrewAI Project

First, let's create a new CrewAI project using the CLI. This command will set up a complete project structure with all the necessary files, allowing you to focus on defining your agents and their tasks rather than setting up boilerplate code.

```bash theme={null}
crewai create crew research_crew
cd research_crew
```

This will generate a project with the basic structure needed for your crew. The CLI automatically creates:

* A project directory with the necessary files
* Configuration files for agents and tasks
* A basic crew implementation
* A main script to run the crew

<Frame>
  <img alt="CrewAI Framework Overview" />
</Frame>

## Step 2: Explore the Project Structure

Let's take a moment to understand the project structure created by the CLI. CrewAI follows best practices for Python projects, making it easy to maintain and extend your code as your crews become more complex.

```
research_crew/
├── .gitignore
├── pyproject.toml
├── README.md
├── .env
└── src/
    └── research_crew/
        ├── __init__.py
        ├── main.py
        ├── crew.py
        ├── tools/
        │   ├── custom_tool.py
        │   └── __init__.py
        └── config/
            ├── agents.yaml
            └── tasks.yaml
```

This structure follows best practices for Python projects and makes it easy to organize your code. The separation of configuration files (in YAML) from implementation code (in Python) makes it easy to modify your crew's behavior without changing the underlying code.

## Step 3: Configure Your Agents

Now comes the fun part - defining your AI agents! In CrewAI, agents are specialized entities with specific roles, goals, and backstories that shape their behavior. Think of them as characters in a play, each with their own personality and purpose.

For our research crew, we'll create two agents:

1. A **researcher** who excels at finding and organizing information
2. An **analyst** who can interpret research findings and create insightful reports

Let's modify the `agents.yaml` file to define these specialized agents. Be sure
to set `llm` to the provider you are using.

```yaml theme={null}
# src/research_crew/config/agents.yaml
researcher:
  role: >
    Senior Research Specialist for {topic}
  goal: >
    Find comprehensive and accurate information about {topic}
    with a focus on recent developments and key insights
  backstory: >
    You are an experienced research specialist with a talent for
    finding relevant information from various sources. You excel at
    organizing information in a clear and structured manner, making
    complex topics accessible to others.
  llm: provider/model-id  # e.g. openai/gpt-4o, google/gemini-2.0-flash, anthropic/claude...

analyst:
  role: >
    Data Analyst and Report Writer for {topic}
  goal: >
    Analyze research findings and create a comprehensive, well-structured
    report that presents insights in a clear and engaging way
  backstory: >
    You are a skilled analyst with a background in data interpretation
    and technical writing. You have a talent for identifying patterns
    and extracting meaningful insights from research data, then
    communicating those insights effectively through well-crafted reports.
  llm: provider/model-id  # e.g. openai/gpt-4o, google/gemini-2.0-flash, anthropic/claude...
```

Notice how each agent has a distinct role, goal, and backstory. These elements aren't just descriptive - they actively shape how the agent approaches its tasks. By crafting these carefully, you can create agents with specialized skills and perspectives that complement each other.

## Step 4: Define Your Tasks

With our agents defined, we now need to give them specific tasks to perform. Tasks in CrewAI represent the concrete work that agents will perform, with detailed instructions and expected outputs.

For our research crew, we'll define two main tasks:

1. A **research task** for gathering comprehensive information
2. An **analysis task** for creating an insightful report

Let's modify the `tasks.yaml` file:

```yaml theme={null}
# src/research_crew/config/tasks.yaml
research_task:
  description: >
    Conduct thorough research on {topic}. Focus on:
    1. Key concepts and definitions
    2. Historical development and recent trends
    3. Major challenges and opportunities
    4. Notable applications or case studies
    5. Future outlook and potential developments

    Make sure to organize your findings in a structured format with clear sections.
  expected_output: >
    A comprehensive research document with well-organized sections covering
    all the requested aspects of {topic}. Include specific facts, figures,
    and examples where relevant.
  agent: researcher

analysis_task:
  description: >
    Analyze the research findings and create a comprehensive report on {topic}.
    Your report should:
    1. Begin with an executive summary
    2. Include all key information from the research
    3. Provide insightful analysis of trends and patterns
    4. Offer recommendations or future considerations
    5. Be formatted in a professional, easy-to-read style with clear headings
  expected_output: >
    A polished, professional report on {topic} that presents the research
    findings with added analysis and insights. The report should be well-structured
    with an executive summary, main sections, and conclusion.
  agent: analyst
  context:
    - research_task
  output_file: output/report.md
```

Note the `context` field in the analysis task - this is a powerful feature that allows the analyst to access the output of the research task. This creates a workflow where information flows naturally between agents, just as it would in a human team.

## Step 5: Configure Your Crew

Now it's time to bring everything together by configuring our crew. The crew is the container that orchestrates how agents work together to complete tasks.

Let's modify the `crew.py` file:

```python theme={null}
# src/research_crew/crew.py
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from crewai_tools import SerperDevTool
from crewai.agents.agent_builder.base_agent import BaseAgent
from typing import List

@CrewBase
class ResearchCrew():
    """Research crew for comprehensive topic analysis and reporting"""

    agents: List[BaseAgent]
    tasks: List[Task]

    @agent
    def researcher(self) -> Agent:
        return Agent(
            config=self.agents_config['researcher'], # type: ignore[index]
            verbose=True,
            tools=[SerperDevTool()]
        )

    @agent
    def analyst(self) -> Agent:
        return Agent(
            config=self.agents_config['analyst'], # type: ignore[index]
            verbose=True
        )

    @task
    def research_task(self) -> Task:
        return Task(
            config=self.tasks_config['research_task'] # type: ignore[index]
        )

    @task
    def analysis_task(self) -> Task:
        return Task(
            config=self.tasks_config['analysis_task'], # type: ignore[index]
            output_file='output/report.md'
        )

    @crew
    def crew(self) -> Crew:
        """Creates the research crew"""
        return Crew(
            agents=self.agents,
            tasks=self.tasks,
            process=Process.sequential,
            verbose=True,
        )
```

In this code, we're:

1. Creating the researcher agent and equipping it with the SerperDevTool to search the web
2. Creating the analyst agent
3. Setting up the research and analysis tasks
4. Configuring the crew to run tasks sequentially (the analyst will wait for the researcher to finish)

This is where the magic happens - with just a few lines of code, we've defined a collaborative AI system where specialized agents work together in a coordinated process.

## Step 6: Set Up Your Main Script

Now, let's set up the main script that will run our crew. This is where we provide the specific topic we want our crew to research.

```python theme={null}
#!/usr/bin/env python
# src/research_crew/main.py
import os
from research_crew.crew import ResearchCrew

# Create output directory if it doesn't exist
os.makedirs('output', exist_ok=True)

def run():
    """
    Run the research crew.
    """
    inputs = {
        'topic': 'Artificial Intelligence in Healthcare'
    }

    # Create and run the crew
    result = ResearchCrew().crew().kickoff(inputs=inputs)

    # Print the result
    print("\n\n=== FINAL REPORT ===\n\n")
    print(result.raw)

    print("\n\nReport has been saved to output/report.md")

if __name__ == "__main__":
    run()
```

This script prepares the environment, specifies our research topic, and kicks off the crew's work. The power of CrewAI is evident in how simple this code is - all the complexity of managing multiple AI agents is handled by the framework.

## Step 7: Set Up Your Environment Variables

Create a `.env` file in your project root with your API keys:

```sh theme={null}
SERPER_API_KEY=your_serper_api_key
# Add your provider's API key here too.
```

See the [LLM Setup guide](/en/concepts/llms#setting-up-your-llm) for details on configuring your provider of choice. You can get a Serper API key from [Serper.dev](https://serper.dev/).

## Step 8: Install Dependencies

Install the required dependencies using the CrewAI CLI:

```bash theme={null}
crewai install
```

This command will:

1. Read the dependencies from your project configuration
2. Create a virtual environment if needed
3. Install all required packages

## Step 9: Run Your Crew

Now for the exciting moment - it's time to run your crew and see AI collaboration in action!

```bash theme={null}
crewai run
```

When you run this command, you'll see your crew spring to life. The researcher will gather information about the specified topic, and the analyst will then create a comprehensive report based on that research. You'll see the agents' thought processes, actions, and outputs in real-time as they work together to complete their tasks.

## Step 10: Review the Output

Once the crew completes its work, you'll find the final report in the `output/report.md` file. The report will include:

1. An executive summary
2. Detailed information about the topic
3. Analysis and insights
4. Recommendations or future considerations

Take a moment to appreciate what you've accomplished - you've created a system where multiple AI agents collaborated on a complex task, each contributing their specialized skills to produce a result that's greater than what any single agent could achieve alone.

## Exploring Other CLI Commands

CrewAI offers several other useful CLI commands for working with crews:

```bash theme={null}
# View all available commands
crewai --help

# Run the crew
crewai run

# Test the crew
crewai test

# Reset crew memories
crewai reset-memories

# Replay from a specific task
crewai replay -t <task_id>
```

## The Art of the Possible: Beyond Your First Crew

What you've built in this guide is just the beginning. The skills and patterns you've learned can be applied to create increasingly sophisticated AI systems. Here are some ways you could extend this basic research crew:

### Expanding Your Crew

You could add more specialized agents to your crew:

* A **fact-checker** to verify research findings
* A **data visualizer** to create charts and graphs
* A **domain expert** with specialized knowledge in a particular area
* A **critic** to identify weaknesses in the analysis

### Adding Tools and Capabilities

You could enhance your agents with additional tools:

* Web browsing tools for real-time research
* CSV/database tools for data analysis
* Code execution tools for data processing
* API connections to external services

### Creating More Complex Workflows

You could implement more sophisticated processes:

* Hierarchical processes where manager agents delegate to worker agents
* Iterative processes with feedback loops for refinement
* Parallel processes where multiple agents work simultaneously
* Dynamic processes that adapt based on intermediate results

### Applying to Different Domains

The same patterns can be applied to create crews for:

* **Content creation**: Writers, editors, fact-checkers, and designers working together
* **Customer service**: Triage agents, specialists, and quality control working together
* **Product development**: Researchers, designers, and planners collaborating
* **Data analysis**: Data collectors, analysts, and visualization specialists

## Next Steps

Now that you've built your first crew, you can:

1. Experiment with different agent configurations and personalities
2. Try more complex task structures and workflows
3. Implement custom tools to give your agents new capabilities
4. Apply your crew to different topics or problem domains
5. Explore [CrewAI Flows](/en/guides/flows/first-flow) for more advanced workflows with procedural programming

<Check>
  Congratulations! You've successfully built your first CrewAI crew that can research and analyze any topic you provide. This foundational experience has equipped you with the skills to create increasingly sophisticated AI systems that can tackle complex, multi-stage problems through collaborative intelligence.
</Check>


# Build Your First Flow
Source: https://docs.crewai.com/en/guides/flows/first-flow

Learn how to create structured, event-driven workflows with precise control over execution.

## Taking Control of AI Workflows with Flows

CrewAI Flows represent the next level in AI orchestration - combining the collaborative power of AI agent crews with the precision and flexibility of procedural programming. While crews excel at agent collaboration, flows give you fine-grained control over exactly how and when different components of your AI system interact.

In this guide, we'll walk through creating a powerful CrewAI Flow that generates a comprehensive learning guide on any topic. This tutorial will demonstrate how Flows provide structured, event-driven control over your AI workflows by combining regular code, direct LLM calls, and crew-based processing.

### What Makes Flows Powerful

Flows enable you to:

1. **Combine different AI interaction patterns** - Use crews for complex collaborative tasks, direct LLM calls for simpler operations, and regular code for procedural logic
2. **Build event-driven systems** - Define how components respond to specific events and data changes
3. **Maintain state across components** - Share and transform data between different parts of your application
4. **Integrate with external systems** - Seamlessly connect your AI workflow with databases, APIs, and user interfaces
5. **Create complex execution paths** - Design conditional branches, parallel processing, and dynamic workflows

### What You'll Build and Learn

By the end of this guide, you'll have:

1. **Created a sophisticated content generation system** that combines user input, AI planning, and multi-agent content creation
2. **Orchestrated the flow of information** between different components of your system
3. **Implemented event-driven architecture** where each step responds to the completion of previous steps
4. **Built a foundation for more complex AI applications** that you can expand and customize

This guide creator flow demonstrates fundamental patterns that can be applied to create much more advanced applications, such as:

* Interactive AI assistants that combine multiple specialized subsystems
* Complex data processing pipelines with AI-enhanced transformations
* Autonomous agents that integrate with external services and APIs
* Multi-stage decision-making systems with human-in-the-loop processes

Let's dive in and build your first flow!

## Prerequisites

Before starting, make sure you have:

1. Installed CrewAI following the [installation guide](/en/installation)
2. Set up your LLM API key in your environment, following the [LLM setup
   guide](/en/concepts/llms#setting-up-your-llm)
3. Basic understanding of Python

## Step 1: Create a New CrewAI Flow Project

First, let's create a new CrewAI Flow project using the CLI. This command sets up a scaffolded project with all the necessary directories and template files for your flow.

```bash theme={null}
crewai create flow guide_creator_flow
cd guide_creator_flow
```

This will generate a project with the basic structure needed for your flow.

<Frame>
  <img alt="CrewAI Framework Overview" />
</Frame>

## Step 2: Understanding the Project Structure

The generated project has the following structure. Take a moment to familiarize yourself with it, as understanding this structure will help you create more complex flows in the future.

```
guide_creator_flow/
├── .gitignore
├── pyproject.toml
├── README.md
├── .env
├── main.py
├── crews/
│   └── poem_crew/
│       ├── config/
│       │   ├── agents.yaml
│       │   └── tasks.yaml
│       └── poem_crew.py
└── tools/
    └── custom_tool.py
```

This structure provides a clear separation between different components of your flow:

* The main flow logic in the `main.py` file
* Specialized crews in the `crews` directory
* Custom tools in the `tools` directory

We'll modify this structure to create our guide creator flow, which will orchestrate the process of generating comprehensive learning guides.

## Step 3: Add a Content Writer Crew

Our flow will need a specialized crew to handle the content creation process. Let's use the CrewAI CLI to add a content writer crew:

```bash theme={null}
crewai flow add-crew content-crew
```

This command automatically creates the necessary directories and template files for your crew. The content writer crew will be responsible for writing and reviewing sections of our guide, working within the overall flow orchestrated by our main application.

## Step 4: Configure the Content Writer Crew

Now, let's modify the generated files for the content writer crew. We'll set up two specialized agents - a writer and a reviewer - that will collaborate to create high-quality content for our guide.

1. First, update the agents configuration file to define our content creation team:

   Remember to set `llm` to the provider you are using.

```yaml theme={null}
# src/guide_creator_flow/crews/content_crew/config/agents.yaml
content_writer:
  role: >
    Educational Content Writer
  goal: >
    Create engaging, informative content that thoroughly explains the assigned topic
    and provides valuable insights to the reader
  backstory: >
    You are a talented educational writer with expertise in creating clear, engaging
    content. You have a gift for explaining complex concepts in accessible language
    and organizing information in a way that helps readers build their understanding.
  llm: provider/model-id  # e.g. openai/gpt-4o, google/gemini-2.0-flash, anthropic/claude...

content_reviewer:
  role: >
    Educational Content Reviewer and Editor
  goal: >
    Ensure content is accurate, comprehensive, well-structured, and maintains
    consistency with previously written sections
  backstory: >
    You are a meticulous editor with years of experience reviewing educational
    content. You have an eye for detail, clarity, and coherence. You excel at
    improving content while maintaining the original author's voice and ensuring
    consistent quality across multiple sections.
  llm: provider/model-id  # e.g. openai/gpt-4o, google/gemini-2.0-flash, anthropic/claude...
```

These agent definitions establish the specialized roles and perspectives that will shape how our AI agents approach content creation. Notice how each agent has a distinct purpose and expertise.

2. Next, update the tasks configuration file to define the specific writing and reviewing tasks:

```yaml theme={null}
# src/guide_creator_flow/crews/content_crew/config/tasks.yaml
write_section_task:
  description: >
    Write a comprehensive section on the topic: "{section_title}"

    Section description: {section_description}
    Target audience: {audience_level} level learners

    Your content should:
    1. Begin with a brief introduction to the section topic
    2. Explain all key concepts clearly with examples
    3. Include practical applications or exercises where appropriate
    4. End with a summary of key points
    5. Be approximately 500-800 words in length

    Format your content in Markdown with appropriate headings, lists, and emphasis.

    Previously written sections:
    {previous_sections}

    Make sure your content maintains consistency with previously written sections
    and builds upon concepts that have already been explained.
  expected_output: >
    A well-structured, comprehensive section in Markdown format that thoroughly
    explains the topic and is appropriate for the target audience.
  agent: content_writer

review_section_task:
  description: >
    Review and improve the following section on "{section_title}":

    {draft_content}

    Target audience: {audience_level} level learners

    Previously written sections:
    {previous_sections}

    Your review should:
    1. Fix any grammatical or spelling errors
    2. Improve clarity and readability
    3. Ensure content is comprehensive and accurate
    4. Verify consistency with previously written sections
    5. Enhance the structure and flow
    6. Add any missing key information

    Provide the improved version of the section in Markdown format.
  expected_output: >
    An improved, polished version of the section that maintains the original
    structure but enhances clarity, accuracy, and consistency.
  agent: content_reviewer
  context:
    - write_section_task
```

These task definitions provide detailed instructions to our agents, ensuring they produce content that meets our quality standards. Note how the `context` parameter in the review task creates a workflow where the reviewer has access to the writer's output.

3. Now, update the crew implementation file to define how our agents and tasks work together:

```python theme={null}
# src/guide_creator_flow/crews/content_crew/content_crew.py
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from crewai.agents.agent_builder.base_agent import BaseAgent
from typing import List

@CrewBase
class ContentCrew():
    """Content writing crew"""

    agents: List[BaseAgent]
    tasks: List[Task]

    @agent
    def content_writer(self) -> Agent:
        return Agent(
            config=self.agents_config['content_writer'], # type: ignore[index]
            verbose=True
        )

    @agent
    def content_reviewer(self) -> Agent:
        return Agent(
            config=self.agents_config['content_reviewer'], # type: ignore[index]
            verbose=True
        )

    @task
    def write_section_task(self) -> Task:
        return Task(
            config=self.tasks_config['write_section_task'] # type: ignore[index]
        )

    @task
    def review_section_task(self) -> Task:
        return Task(
            config=self.tasks_config['review_section_task'], # type: ignore[index]
            context=[self.write_section_task()]
        )

    @crew
    def crew(self) -> Crew:
        """Creates the content writing crew"""
        return Crew(
            agents=self.agents,
            tasks=self.tasks,
            process=Process.sequential,
            verbose=True,
        )
```

This crew definition establishes the relationship between our agents and tasks, setting up a sequential process where the content writer creates a draft and then the reviewer improves it. While this crew can function independently, in our flow it will be orchestrated as part of a larger system.

## Step 5: Create the Flow

Now comes the exciting part - creating the flow that will orchestrate the entire guide creation process. This is where we'll combine regular Python code, direct LLM calls, and our content creation crew into a cohesive system.

Our flow will:

1. Get user input for a topic and audience level
2. Make a direct LLM call to create a structured guide outline
3. Process each section sequentially using the content writer crew
4. Combine everything into a final comprehensive document

Let's create our flow in the `main.py` file:

```python theme={null}
#!/usr/bin/env python
import json
import os
from typing import List, Dict
from pydantic import BaseModel, Field
from crewai import LLM
from crewai.flow.flow import Flow, listen, start
from guide_creator_flow.crews.content_crew.content_crew import ContentCrew

# Define our models for structured data
class Section(BaseModel):
    title: str = Field(description="Title of the section")
    description: str = Field(description="Brief description of what the section should cover")

class GuideOutline(BaseModel):
    title: str = Field(description="Title of the guide")
    introduction: str = Field(description="Introduction to the topic")
    target_audience: str = Field(description="Description of the target audience")
    sections: List[Section] = Field(description="List of sections in the guide")
    conclusion: str = Field(description="Conclusion or summary of the guide")

# Define our flow state
class GuideCreatorState(BaseModel):
    topic: str = ""
    audience_level: str = ""
    guide_outline: GuideOutline = None
    sections_content: Dict[str, str] = {}

class GuideCreatorFlow(Flow[GuideCreatorState]):
    """Flow for creating a comprehensive guide on any topic"""

    @start()
    def get_user_input(self):
        """Get input from the user about the guide topic and audience"""
        print("\n=== Create Your Comprehensive Guide ===\n")

        # Get user input
        self.state.topic = input("What topic would you like to create a guide for? ")

        # Get audience level with validation
        while True:
            audience = input("Who is your target audience? (beginner/intermediate/advanced) ").lower()
            if audience in ["beginner", "intermediate", "advanced"]:
                self.state.audience_level = audience
                break
            print("Please enter 'beginner', 'intermediate', or 'advanced'")

        print(f"\nCreating a guide on {self.state.topic} for {self.state.audience_level} audience...\n")
        return self.state

    @listen(get_user_input)
    def create_guide_outline(self, state):
        """Create a structured outline for the guide using a direct LLM call"""
        print("Creating guide outline...")

        # Initialize the LLM
        llm = LLM(model="openai/gpt-4o-mini", response_format=GuideOutline)

        # Create the messages for the outline
        messages = [
            {"role": "system", "content": "You are a helpful assistant designed to output JSON."},
            {"role": "user", "content": f"""
            Create a detailed outline for a comprehensive guide on "{state.topic}" for {state.audience_level} level learners.

            The outline should include:
            1. A compelling title for the guide
            2. An introduction to the topic
            3. 4-6 main sections that cover the most important aspects of the topic
            4. A conclusion or summary

            For each section, provide a clear title and a brief description of what it should cover.
            """}
        ]

        # Make the LLM call with JSON response format
        response = llm.call(messages=messages)

        # Parse the JSON response
        outline_dict = json.loads(response)
        self.state.guide_outline = GuideOutline(**outline_dict)

        # Ensure output directory exists before saving
        os.makedirs("output", exist_ok=True)

        # Save the outline to a file
        with open("output/guide_outline.json", "w") as f:
            json.dump(outline_dict, f, indent=2)

        print(f"Guide outline created with {len(self.state.guide_outline.sections)} sections")
        return self.state.guide_outline

    @listen(create_guide_outline)
    def write_and_compile_guide(self, outline):
        """Write all sections and compile the guide"""
        print("Writing guide sections and compiling...")
        completed_sections = []

        # Process sections one by one to maintain context flow
        for section in outline.sections:
            print(f"Processing section: {section.title}")

            # Build context from previous sections
            previous_sections_text = ""
            if completed_sections:
                previous_sections_text = "# Previously Written Sections\n\n"
                for title in completed_sections:
                    previous_sections_text += f"## {title}\n\n"
                    previous_sections_text += self.state.sections_content.get(title, "") + "\n\n"
            else:
                previous_sections_text = "No previous sections written yet."

            # Run the content crew for this section
            result = ContentCrew().crew().kickoff(inputs={
                "section_title": section.title,
                "section_description": section.description,
                "audience_level": self.state.audience_level,
                "previous_sections": previous_sections_text,
                "draft_content": ""
            })

            # Store the content
            self.state.sections_content[section.title] = result.raw
            completed_sections.append(section.title)
            print(f"Section completed: {section.title}")

        # Compile the final guide
        guide_content = f"# {outline.title}\n\n"
        guide_content += f"## Introduction\n\n{outline.introduction}\n\n"

        # Add each section in order
        for section in outline.sections:
            section_content = self.state.sections_content.get(section.title, "")
            guide_content += f"\n\n{section_content}\n\n"

        # Add conclusion
        guide_content += f"## Conclusion\n\n{outline.conclusion}\n\n"

        # Save the guide
        with open("output/complete_guide.md", "w") as f:
            f.write(guide_content)

        print("\nComplete guide compiled and saved to output/complete_guide.md")
        return "Guide creation completed successfully"

def kickoff():
    """Run the guide creator flow"""
    GuideCreatorFlow().kickoff()
    print("\n=== Flow Complete ===")
    print("Your comprehensive guide is ready in the output directory.")
    print("Open output/complete_guide.md to view it.")

def plot():
    """Generate a visualization of the flow"""
    flow = GuideCreatorFlow()
    flow.plot("guide_creator_flow")
    print("Flow visualization saved to guide_creator_flow.html")

if __name__ == "__main__":
    kickoff()
```

Let's analyze what's happening in this flow:

1. We define Pydantic models for structured data, ensuring type safety and clear data representation
2. We create a state class to maintain data across different steps of the flow
3. We implement three main flow steps:
   * Getting user input with the `@start()` decorator
   * Creating a guide outline with a direct LLM call
   * Processing sections with our content crew
4. We use the `@listen()` decorator to establish event-driven relationships between steps

This is the power of flows - combining different types of processing (user interaction, direct LLM calls, crew-based tasks) into a coherent, event-driven system.

## Step 6: Set Up Your Environment Variables

Create a `.env` file in your project root with your API keys. See the [LLM setup
guide](/en/concepts/llms#setting-up-your-llm) for details on configuring a provider.

```sh .env theme={null}
OPENAI_API_KEY=your_openai_api_key
# or
GEMINI_API_KEY=your_gemini_api_key
# or
ANTHROPIC_API_KEY=your_anthropic_api_key
```

## Step 7: Install Dependencies

Install the required dependencies:

```bash theme={null}
crewai install
```

## Step 8: Run Your Flow

Now it's time to see your flow in action! Run it using the CrewAI CLI:

```bash theme={null}
crewai flow kickoff
```

When you run this command, you'll see your flow spring to life:

1. It will prompt you for a topic and audience level
2. It will create a structured outline for your guide
3. It will process each section, with the content writer and reviewer collaborating on each
4. Finally, it will compile everything into a comprehensive guide

This demonstrates the power of flows to orchestrate complex processes involving multiple components, both AI and non-AI.

## Step 9: Visualize Your Flow

One of the powerful features of flows is the ability to visualize their structure:

```bash theme={null}
crewai flow plot
```

This will create an HTML file that shows the structure of your flow, including the relationships between different steps and the data that flows between them. This visualization can be invaluable for understanding and debugging complex flows.

## Step 10: Review the Output

Once the flow completes, you'll find two files in the `output` directory:

1. `guide_outline.json`: Contains the structured outline of the guide
2. `complete_guide.md`: The comprehensive guide with all sections

Take a moment to review these files and appreciate what you've built - a system that combines user input, direct AI interactions, and collaborative agent work to produce a complex, high-quality output.

## The Art of the Possible: Beyond Your First Flow

What you've learned in this guide provides a foundation for creating much more sophisticated AI systems. Here are some ways you could extend this basic flow:

### Enhancing User Interaction

You could create more interactive flows with:

* Web interfaces for input and output
* Real-time progress updates
* Interactive feedback and refinement loops
* Multi-stage user interactions

### Adding More Processing Steps

You could expand your flow with additional steps for:

* Research before outline creation
* Image generation for illustrations
* Code snippet generation for technical guides
* Final quality assurance and fact-checking

### Creating More Complex Flows

You could implement more sophisticated flow patterns:

* Conditional branching based on user preferences or content type
* Parallel processing of independent sections
* Iterative refinement loops with feedback
* Integration with external APIs and services

### Applying to Different Domains

The same patterns can be applied to create flows for:

* **Interactive storytelling**: Create personalized stories based on user input
* **Business intelligence**: Process data, generate insights, and create reports
* **Product development**: Facilitate ideation, design, and planning
* **Educational systems**: Create personalized learning experiences

## Key Features Demonstrated

This guide creator flow demonstrates several powerful features of CrewAI:

1. **User interaction**: The flow collects input directly from the user
2. **Direct LLM calls**: Uses the LLM class for efficient, single-purpose AI interactions
3. **Structured data with Pydantic**: Uses Pydantic models to ensure type safety
4. **Sequential processing with context**: Writes sections in order, providing previous sections for context
5. **Multi-agent crews**: Leverages specialized agents (writer and reviewer) for content creation
6. **State management**: Maintains state across different steps of the process
7. **Event-driven architecture**: Uses the `@listen` decorator to respond to events

## Understanding the Flow Structure

Let's break down the key components of flows to help you understand how to build your own:

### 1. Direct LLM Calls

Flows allow you to make direct calls to language models when you need simple, structured responses:

```python theme={null}
llm = LLM(
    model="model-id-here",  # gpt-4o, gemini-2.0-flash, anthropic/claude...
    response_format=GuideOutline
)
response = llm.call(messages=messages)
```

This is more efficient than using a crew when you need a specific, structured output.

### 2. Event-Driven Architecture

Flows use decorators to establish relationships between components:

```python theme={null}
@start()
def get_user_input(self):
    # First step in the flow
    # ...

@listen(get_user_input)
def create_guide_outline(self, state):
    # This runs when get_user_input completes
    # ...
```

This creates a clear, declarative structure for your application.

### 3. State Management

Flows maintain state across steps, making it easy to share data:

```python theme={null}
class GuideCreatorState(BaseModel):
    topic: str = ""
    audience_level: str = ""
    guide_outline: GuideOutline = None
    sections_content: Dict[str, str] = {}
```

This provides a type-safe way to track and transform data throughout your flow.

### 4. Crew Integration

Flows can seamlessly integrate with crews for complex collaborative tasks:

```python theme={null}
result = ContentCrew().crew().kickoff(inputs={
    "section_title": section.title,
    # ...
})
```

This allows you to use the right tool for each part of your application - direct LLM calls for simple tasks and crews for complex collaboration.

## Next Steps

Now that you've built your first flow, you can:

1. Experiment with more complex flow structures and patterns
2. Try using `@router()` to create conditional branches in your flows
3. Explore the `and_` and `or_` functions for more complex parallel execution
4. Connect your flow to external APIs, databases, or user interfaces
5. Combine multiple specialized crews in a single flow

<Check>
  Congratulations! You've successfully built your first CrewAI Flow that combines regular code, direct LLM calls, and crew-based processing to create a comprehensive guide. These foundational skills enable you to create increasingly sophisticated AI applications that can tackle complex, multi-stage problems through a combination of procedural control and collaborative intelligence.
</Check>


# Mastering Flow State Management
Source: https://docs.crewai.com/en/guides/flows/mastering-flow-state

A comprehensive guide to managing, persisting, and leveraging state in CrewAI Flows for building robust AI applications.

## Understanding the Power of State in Flows

State management is the backbone of any sophisticated AI workflow. In CrewAI Flows, the state system allows you to maintain context, share data between steps, and build complex application logic. Mastering state management is essential for creating reliable, maintainable, and powerful AI applications.

This guide will walk you through everything you need to know about managing state in CrewAI Flows, from basic concepts to advanced techniques, with practical code examples along the way.

### Why State Management Matters

Effective state management enables you to:

1. **Maintain context across execution steps** - Pass information seamlessly between different stages of your workflow
2. **Build complex conditional logic** - Make decisions based on accumulated data
3. **Create persistent applications** - Save and restore workflow progress
4. **Handle errors gracefully** - Implement recovery patterns for more robust applications
5. **Scale your applications** - Support complex workflows with proper data organization
6. **Enable conversational applications** - Store and access conversation history for context-aware AI interactions

Let's explore how to leverage these capabilities effectively.

## State Management Fundamentals

### The Flow State Lifecycle

In CrewAI Flows, the state follows a predictable lifecycle:

1. **Initialization** - When a flow is created, its state is initialized (either as an empty dictionary or a Pydantic model instance)
2. **Modification** - Flow methods access and modify the state as they execute
3. **Transmission** - State is passed automatically between flow methods
4. **Persistence** (optional) - State can be saved to storage and later retrieved
5. **Completion** - The final state reflects the cumulative changes from all executed methods

Understanding this lifecycle is crucial for designing effective flows.

### Two Approaches to State Management

CrewAI offers two ways to manage state in your flows:

1. **Unstructured State** - Using dictionary-like objects for flexibility
2. **Structured State** - Using Pydantic models for type safety and validation

Let's examine each approach in detail.

## Unstructured State Management

Unstructured state uses a dictionary-like approach, offering flexibility and simplicity for straightforward applications.

### How It Works

With unstructured state:

* You access state via `self.state` which behaves like a dictionary
* You can freely add, modify, or remove keys at any point
* All state is automatically available to all flow methods

### Basic Example

Here's a simple example of unstructured state management:

```python theme={null}
from crewai.flow.flow import Flow, listen, start

class UnstructuredStateFlow(Flow):
    @start()
    def initialize_data(self):
        print("Initializing flow data")
        # Add key-value pairs to state
        self.state["user_name"] = "Alex"
        self.state["preferences"] = {
            "theme": "dark",
            "language": "English"
        }
        self.state["items"] = []

        # The flow state automatically gets a unique ID
        print(f"Flow ID: {self.state['id']}")

        return "Initialized"

    @listen(initialize_data)
    def process_data(self, previous_result):
        print(f"Previous step returned: {previous_result}")

        # Access and modify state
        user = self.state["user_name"]
        print(f"Processing data for {user}")

        # Add items to a list in state
        self.state["items"].append("item1")
        self.state["items"].append("item2")

        # Add a new key-value pair
        self.state["processed"] = True

        return "Processed"

    @listen(process_data)
    def generate_summary(self, previous_result):
        # Access multiple state values
        user = self.state["user_name"]
        theme = self.state["preferences"]["theme"]
        items = self.state["items"]
        processed = self.state.get("processed", False)

        summary = f"User {user} has {len(items)} items with {theme} theme. "
        summary += "Data is processed." if processed else "Data is not processed."

        return summary

# Run the flow
flow = UnstructuredStateFlow()
result = flow.kickoff()
print(f"Final result: {result}")
print(f"Final state: {flow.state}")
```

### When to Use Unstructured State

Unstructured state is ideal for:

* Quick prototyping and simple flows
* Dynamically evolving state needs
* Cases where the structure may not be known in advance
* Flows with simple state requirements

While flexible, unstructured state lacks type checking and schema validation, which can lead to errors in complex applications.

## Structured State Management

Structured state uses Pydantic models to define a schema for your flow's state, providing type safety, validation, and better developer experience.

### How It Works

With structured state:

* You define a Pydantic model that represents your state structure
* You pass this model type to your Flow class as a type parameter
* You access state via `self.state`, which behaves like a Pydantic model instance
* All fields are validated according to their defined types
* You get IDE autocompletion and type checking support

### Basic Example

Here's how to implement structured state management:

```python theme={null}
from crewai.flow.flow import Flow, listen, start
from pydantic import BaseModel, Field
from typing import List, Dict, Optional

# Define your state model
class UserPreferences(BaseModel):
    theme: str = "light"
    language: str = "English"

class AppState(BaseModel):
    user_name: str = ""
    preferences: UserPreferences = UserPreferences()
    items: List[str] = []
    processed: bool = False
    completion_percentage: float = 0.0

# Create a flow with typed state
class StructuredStateFlow(Flow[AppState]):
    @start()
    def initialize_data(self):
        print("Initializing flow data")
        # Set state values (type-checked)
        self.state.user_name = "Taylor"
        self.state.preferences.theme = "dark"

        # The ID field is automatically available
        print(f"Flow ID: {self.state.id}")

        return "Initialized"

    @listen(initialize_data)
    def process_data(self, previous_result):
        print(f"Processing data for {self.state.user_name}")

        # Modify state (with type checking)
        self.state.items.append("item1")
        self.state.items.append("item2")
        self.state.processed = True
        self.state.completion_percentage = 50.0

        return "Processed"

    @listen(process_data)
    def generate_summary(self, previous_result):
        # Access state (with autocompletion)
        summary = f"User {self.state.user_name} has {len(self.state.items)} items "
        summary += f"with {self.state.preferences.theme} theme. "
        summary += "Data is processed." if self.state.processed else "Data is not processed."
        summary += f" Completion: {self.state.completion_percentage}%"

        return summary

# Run the flow
flow = StructuredStateFlow()
result = flow.kickoff()
print(f"Final result: {result}")
print(f"Final state: {flow.state}")
```

### Benefits of Structured State

Using structured state provides several advantages:

1. **Type Safety** - Catch type errors at development time
2. **Self-Documentation** - The state model clearly documents what data is available
3. **Validation** - Automatic validation of data types and constraints
4. **IDE Support** - Get autocomplete and inline documentation
5. **Default Values** - Easily define fallbacks for missing data

### When to Use Structured State

Structured state is recommended for:

* Complex flows with well-defined data schemas
* Team projects where multiple developers work on the same code
* Applications where data validation is important
* Flows that need to enforce specific data types and constraints

## The Automatic State ID

Both unstructured and structured states automatically receive a unique identifier (UUID) to help track and manage state instances.

### How It Works

* For unstructured state, the ID is accessible as `self.state["id"]`
* For structured state, the ID is accessible as `self.state.id`
* This ID is generated automatically when the flow is created
* The ID remains the same throughout the flow's lifecycle
* The ID can be used for tracking, logging, and retrieving persisted states

This UUID is particularly valuable when implementing persistence or tracking multiple flow executions.

## Dynamic State Updates

Regardless of whether you're using structured or unstructured state, you can update state dynamically throughout your flow's execution.

### Passing Data Between Steps

Flow methods can return values that are then passed as arguments to listening methods:

```python theme={null}
from crewai.flow.flow import Flow, listen, start

class DataPassingFlow(Flow):
    @start()
    def generate_data(self):
        # This return value will be passed to listening methods
        return "Generated data"

    @listen(generate_data)
    def process_data(self, data_from_previous_step):
        print(f"Received: {data_from_previous_step}")
        # You can modify the data and pass it along
        processed_data = f"{data_from_previous_step} - processed"
        # Also update state
        self.state["last_processed"] = processed_data
        return processed_data

    @listen(process_data)
    def finalize_data(self, processed_data):
        print(f"Received processed data: {processed_data}")
        # Access both the passed data and state
        last_processed = self.state.get("last_processed", "")
        return f"Final: {processed_data} (from state: {last_processed})"
```

This pattern allows you to combine direct data passing with state updates for maximum flexibility.

## Persisting Flow State

One of CrewAI's most powerful features is the ability to persist flow state across executions. This enables workflows that can be paused, resumed, and even recovered after failures.

### The @persist() Decorator

The `@persist()` decorator automates state persistence, saving your flow's state at key points in execution.

#### Class-Level Persistence

When applied at the class level, `@persist()` saves state after every method execution:

```python theme={null}
from crewai.flow.flow import Flow, listen, start
from crewai.flow.persistence import persist
from pydantic import BaseModel

class CounterState(BaseModel):
    value: int = 0

@persist()  # Apply to the entire flow class
class PersistentCounterFlow(Flow[CounterState]):
    @start()
    def increment(self):
        self.state.value += 1
        print(f"Incremented to {self.state.value}")
        return self.state.value

    @listen(increment)
    def double(self, value):
        self.state.value = value * 2
        print(f"Doubled to {self.state.value}")
        return self.state.value

# First run
flow1 = PersistentCounterFlow()
result1 = flow1.kickoff()
print(f"First run result: {result1}")

# Second run - state is automatically loaded
flow2 = PersistentCounterFlow()
result2 = flow2.kickoff()
print(f"Second run result: {result2}")  # Will be higher due to persisted state
```

#### Method-Level Persistence

For more granular control, you can apply `@persist()` to specific methods:

```python theme={null}
from crewai.flow.flow import Flow, listen, start
from crewai.flow.persistence import persist

class SelectivePersistFlow(Flow):
    @start()
    def first_step(self):
        self.state["count"] = 1
        return "First step"

    @persist()  # Only persist after this method
    @listen(first_step)
    def important_step(self, prev_result):
        self.state["count"] += 1
        self.state["important_data"] = "This will be persisted"
        return "Important step completed"

    @listen(important_step)
    def final_step(self, prev_result):
        self.state["count"] += 1
        return f"Complete with count {self.state['count']}"
```

## Advanced State Patterns

### Conditional starts and resumable execution

Flows support conditional `@start()` and resumable execution for HITL/cyclic scenarios:

```python theme={null}
from crewai.flow.flow import Flow, start, listen, and_, or_

class ResumableFlow(Flow):
    @start()  # unconditional start
    def init(self):
        ...

    # Conditional start: run after "init" or external trigger name
    @start("init")
    def maybe_begin(self):
        ...

    @listen(and_(init, maybe_begin))
    def proceed(self):
        ...
```

* Conditional `@start()` accepts a method name, a router label, or a callable condition.
* During resume, listeners continue from prior checkpoints; cycle/router branches honor resumption flags.

### State-Based Conditional Logic

You can use state to implement complex conditional logic in your flows:

```python theme={null}
from crewai.flow.flow import Flow, listen, router, start
from pydantic import BaseModel

class PaymentState(BaseModel):
    amount: float = 0.0
    is_approved: bool = False
    retry_count: int = 0

class PaymentFlow(Flow[PaymentState]):
    @start()
    def process_payment(self):
        # Simulate payment processing
        self.state.amount = 100.0
        self.state.is_approved = self.state.amount < 1000
        return "Payment processed"

    @router(process_payment)
    def check_approval(self, previous_result):
        if self.state.is_approved:
            return "approved"
        elif self.state.retry_count < 3:
            return "retry"
        else:
            return "rejected"

    @listen("approved")
    def handle_approval(self):
        return f"Payment of ${self.state.amount} approved!"

    @listen("retry")
    def handle_retry(self):
        self.state.retry_count += 1
        print(f"Retrying payment (attempt {self.state.retry_count})...")
        # Could implement retry logic here
        return "Retry initiated"

    @listen("rejected")
    def handle_rejection(self):
        return f"Payment of ${self.state.amount} rejected after {self.state.retry_count} retries."
```

### Handling Complex State Transformations

For complex state transformations, you can create dedicated methods:

```python theme={null}
from crewai.flow.flow import Flow, listen, start
from pydantic import BaseModel
from typing import List, Dict

class UserData(BaseModel):
    name: str
    active: bool = True
    login_count: int = 0

class ComplexState(BaseModel):
    users: Dict[str, UserData] = {}
    active_user_count: int = 0

class TransformationFlow(Flow[ComplexState]):
    @start()
    def initialize(self):
        # Add some users
        self.add_user("alice", "Alice")
        self.add_user("bob", "Bob")
        self.add_user("charlie", "Charlie")
        return "Initialized"

    @listen(initialize)
    def process_users(self, _):
        # Increment login counts
        for user_id in self.state.users:
            self.increment_login(user_id)

        # Deactivate one user
        self.deactivate_user("bob")

        # Update active count
        self.update_active_count()

        return f"Processed {len(self.state.users)} users"

    # Helper methods for state transformations
    def add_user(self, user_id: str, name: str):
        self.state.users[user_id] = UserData(name=name)
        self.update_active_count()

    def increment_login(self, user_id: str):
        if user_id in self.state.users:
            self.state.users[user_id].login_count += 1

    def deactivate_user(self, user_id: str):
        if user_id in self.state.users:
            self.state.users[user_id].active = False
            self.update_active_count()

    def update_active_count(self):
        self.state.active_user_count = sum(
            1 for user in self.state.users.values() if user.active
        )
```

This pattern of creating helper methods keeps your flow methods clean while enabling complex state manipulations.

## State Management with Crews

One of the most powerful patterns in CrewAI is combining flow state management with crew execution.

### Passing State to Crews

You can use flow state to parameterize crews:

```python theme={null}
from crewai.flow.flow import Flow, listen, start
from crewai import Agent, Crew, Process, Task
from pydantic import BaseModel

class ResearchState(BaseModel):
    topic: str = ""
    depth: str = "medium"
    results: str = ""

class ResearchFlow(Flow[ResearchState]):
    @start()
    def get_parameters(self):
        # In a real app, this might come from user input
        self.state.topic = "Artificial Intelligence Ethics"
        self.state.depth = "deep"
        return "Parameters set"

    @listen(get_parameters)
    def execute_research(self, _):
        # Create agents
        researcher = Agent(
            role="Research Specialist",
            goal=f"Research {self.state.topic} in {self.state.depth} detail",
            backstory="You are an expert researcher with a talent for finding accurate information."
        )

        writer = Agent(
            role="Content Writer",
            goal="Transform research into clear, engaging content",
            backstory="You excel at communicating complex ideas clearly and concisely."
        )

        # Create tasks
        research_task = Task(
            description=f"Research {self.state.topic} with {self.state.depth} analysis",
            expected_output="Comprehensive research notes in markdown format",
            agent=researcher
        )

        writing_task = Task(
            description=f"Create a summary on {self.state.topic} based on the research",
            expected_output="Well-written article in markdown format",
            agent=writer,
            context=[research_task]
        )

        # Create and run crew
        research_crew = Crew(
            agents=[researcher, writer],
            tasks=[research_task, writing_task],
            process=Process.sequential,
            verbose=True
        )

        # Run crew and store result in state
        result = research_crew.kickoff()
        self.state.results = result.raw

        return "Research completed"

    @listen(execute_research)
    def summarize_results(self, _):
        # Access the stored results
        result_length = len(self.state.results)
        return f"Research on {self.state.topic} completed with {result_length} characters of results."
```

### Handling Crew Outputs in State

When a crew completes, you can process its output and store it in your flow state:

```python theme={null}
@listen(execute_crew)
def process_crew_results(self, _):
    # Parse the raw results (assuming JSON output)
    import json
    try:
        results_dict = json.loads(self.state.raw_results)
        self.state.processed_results = {
            "title": results_dict.get("title", ""),
            "main_points": results_dict.get("main_points", []),
            "conclusion": results_dict.get("conclusion", "")
        }
        return "Results processed successfully"
    except json.JSONDecodeError:
        self.state.error = "Failed to parse crew results as JSON"
        return "Error processing results"
```

## Best Practices for State Management

### 1. Keep State Focused

Design your state to contain only what's necessary:

```python theme={null}
# Too broad
class BloatedState(BaseModel):
    user_data: Dict = {}
    system_settings: Dict = {}
    temporary_calculations: List = []
    debug_info: Dict = {}
    # ...many more fields

# Better: Focused state
class FocusedState(BaseModel):
    user_id: str
    preferences: Dict[str, str]
    completion_status: Dict[str, bool]
```

### 2. Use Structured State for Complex Flows

As your flows grow in complexity, structured state becomes increasingly valuable:

```python theme={null}
# Simple flow can use unstructured state
class SimpleGreetingFlow(Flow):
    @start()
    def greet(self):
        self.state["name"] = "World"
        return f"Hello, {self.state['name']}!"

# Complex flow benefits from structured state
class UserRegistrationState(BaseModel):
    username: str
    email: str
    verification_status: bool = False
    registration_date: datetime = Field(default_factory=datetime.now)
    last_login: Optional[datetime] = None

class RegistrationFlow(Flow[UserRegistrationState]):
    # Methods with strongly-typed state access
```

### 3. Document State Transitions

For complex flows, document how state changes throughout the execution:

```python theme={null}
@start()
def initialize_order(self):
    """
    Initialize order state with empty values.

    State before: {}
    State after: {order_id: str, items: [], status: 'new'}
    """
    self.state.order_id = str(uuid.uuid4())
    self.state.items = []
    self.state.status = "new"
    return "Order initialized"
```

### 4. Handle State Errors Gracefully

Implement error handling for state access:

```python theme={null}
@listen(previous_step)
def process_data(self, _):
    try:
        # Try to access a value that might not exist
        user_preference = self.state.preferences.get("theme", "default")
    except (AttributeError, KeyError):
        # Handle the error gracefully
        self.state.errors = self.state.get("errors", [])
        self.state.errors.append("Failed to access preferences")
        user_preference = "default"

    return f"Used preference: {user_preference}"
```

### 5. Use State for Progress Tracking

Leverage state to track progress in long-running flows:

```python theme={null}
class ProgressTrackingFlow(Flow):
    @start()
    def initialize(self):
        self.state["total_steps"] = 3
        self.state["current_step"] = 0
        self.state["progress"] = 0.0
        self.update_progress()
        return "Initialized"

    def update_progress(self):
        """Helper method to calculate and update progress"""
        if self.state.get("total_steps", 0) > 0:
            self.state["progress"] = (self.state.get("current_step", 0) /
                                    self.state["total_steps"]) * 100
            print(f"Progress: {self.state['progress']:.1f}%")

    @listen(initialize)
    def step_one(self, _):
        # Do work...
        self.state["current_step"] = 1
        self.update_progress()
        return "Step 1 complete"

    # Additional steps...
```

### 6. Use Immutable Operations When Possible

Especially with structured state, prefer immutable operations for clarity:

```python theme={null}
# Instead of modifying lists in place:
self.state.items.append(new_item)  # Mutable operation

# Consider creating new state:
from pydantic import BaseModel
from typing import List

class ItemState(BaseModel):
    items: List[str] = []

class ImmutableFlow(Flow[ItemState]):
    @start()
    def add_item(self):
        # Create new list with the added item
        self.state.items = [*self.state.items, "new item"]
        return "Item added"
```

## Debugging Flow State

### Logging State Changes

When developing, add logging to track state changes:

```python theme={null}
import logging
logging.basicConfig(level=logging.INFO)

class LoggingFlow(Flow):
    def log_state(self, step_name):
        logging.info(f"State after {step_name}: {self.state}")

    @start()
    def initialize(self):
        self.state["counter"] = 0
        self.log_state("initialize")
        return "Initialized"

    @listen(initialize)
    def increment(self, _):
        self.state["counter"] += 1
        self.log_state("increment")
        return f"Incremented to {self.state['counter']}"
```

### State Visualization

You can add methods to visualize your state for debugging:

```python theme={null}
def visualize_state(self):
    """Create a simple visualization of the current state"""
    import json
    from rich.console import Console
    from rich.panel import Panel

    console = Console()

    if hasattr(self.state, "model_dump"):
        # Pydantic v2
        state_dict = self.state.model_dump()
    elif hasattr(self.state, "dict"):
        # Pydantic v1
        state_dict = self.state.dict()
    else:
        # Unstructured state
        state_dict = dict(self.state)

    # Remove id for cleaner output
    if "id" in state_dict:
        state_dict.pop("id")

    state_json = json.dumps(state_dict, indent=2, default=str)
    console.print(Panel(state_json, title="Current Flow State"))
```

## Conclusion

Mastering state management in CrewAI Flows gives you the power to build sophisticated, robust AI applications that maintain context, make complex decisions, and deliver consistent results.

Whether you choose unstructured or structured state, implementing proper state management practices will help you create flows that are maintainable, extensible, and effective at solving real-world problems.

As you develop more complex flows, remember that good state management is about finding the right balance between flexibility and structure, making your code both powerful and easy to understand.

<Check>
  You've now mastered the concepts and practices of state management in CrewAI Flows! With this knowledge, you can create robust AI workflows that effectively maintain context, share data between steps, and build sophisticated application logic.
</Check>

## Next Steps

* Experiment with both structured and unstructured state in your flows
* Try implementing state persistence for long-running workflows
* Explore [building your first crew](/en/guides/crews/first-crew) to see how crews and flows can work together
* Check out the [Flow reference documentation](/en/concepts/flows) for more advanced features


# Installation
Source: https://docs.crewai.com/en/installation

Get started with CrewAI - Install, configure, and build your first AI crew

## Video Tutorial

Watch this video tutorial for a step-by-step demonstration of the installation process:

<iframe title="CrewAI Installation Guide" />

## Text Tutorial

<Note>
  **Python Version Requirements**

  CrewAI requires `Python >=3.10 and <3.14`. Here's how to check your version:

  ```bash theme={null}
  python3 --version
  ```

  If you need to update Python, visit [python.org/downloads](https://python.org/downloads)
</Note>

<Note>
  **OpenAI SDK Requirement**

  CrewAI 0.175.0 requires `openai >= 1.13.3`. If you manage dependencies yourself, ensure your environment satisfies this constraint to avoid import/runtime issues.
</Note>

CrewAI uses the `uv` as its dependency management and package handling tool. It simplifies project setup and execution, offering a seamless experience.

If you haven't installed `uv` yet, follow **step 1** to quickly get it set up on your system, else you can skip to **step 2**.

<Steps>
  <Step title="Install uv">
    * **On macOS/Linux:**

      Use `curl` to download the script and execute it with `sh`:

      ```shell theme={null}
      curl -LsSf https://astral.sh/uv/install.sh | sh
      ```

      If your system doesn't have `curl`, you can use `wget`:

      ```shell theme={null}
      wget -qO- https://astral.sh/uv/install.sh | sh
      ```

    * **On Windows:**

      Use `irm` to download the script and `iex` to execute it:

      ```shell theme={null}
      powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
      ```

      If you run into any issues, refer to [UV's installation guide](https://docs.astral.sh/uv/getting-started/installation/) for more information.
  </Step>

  <Step title="Install CrewAI 🚀">
    * Run the following command to install `crewai` CLI:

      ```shell theme={null}
      uv tool install crewai
      ```

      <Warning>
        If you encounter a `PATH` warning, run this command to update your shell:

        ```shell theme={null}
        uv tool update-shell
        ```
      </Warning>

      <Warning>
        If you encounter the `chroma-hnswlib==0.7.6` build error (`fatal error C1083: Cannot open include file: 'float.h'`) on Windows, install [Visual Studio Build Tools](https://visualstudio.microsoft.com/downloads/) with *Desktop development with C++*.
      </Warning>

    * To verify that `crewai` is installed, run:
      ```shell theme={null}
      uv tool list
      ```

    * You should see something like:
      ```shell theme={null}
      crewai v0.102.0
      - crewai
      ```

    * If you need to update `crewai`, run:
      ```shell theme={null}
      uv tool install crewai --upgrade
      ```

    <Check>Installation successful! You're ready to create your first crew! 🎉</Check>
  </Step>
</Steps>

# Creating a CrewAI Project

We recommend using the `YAML` template scaffolding for a structured approach to defining agents and tasks. Here's how to get started:

<Steps>
  <Step title="Generate Project Scaffolding">
    * Run the `crewai` CLI command:
      ```shell theme={null}
      crewai create crew <your_project_name>
      ```

    * This creates a new project with the following structure:
      ```
      my_project/
      ├── .gitignore
      ├── knowledge/
      ├── pyproject.toml
      ├── README.md
      ├── .env
      └── src/
          └── my_project/
              ├── __init__.py
              ├── main.py
              ├── crew.py
              ├── tools/
              │   ├── custom_tool.py
              │   └── __init__.py
              └── config/
                  ├── agents.yaml
                  └── tasks.yaml
      ```
  </Step>

  <Step title="Customize Your Project">
    * Your project will contain these essential files:
      | File          | Purpose                                  |
      | ------------- | ---------------------------------------- |
      | `agents.yaml` | Define your AI agents and their roles    |
      | `tasks.yaml`  | Set up agent tasks and workflows         |
      | `.env`        | Store API keys and environment variables |
      | `main.py`     | Project entry point and execution flow   |
      | `crew.py`     | Crew orchestration and coordination      |
      | `tools/`      | Directory for custom agent tools         |
      | `knowledge/`  | Directory for knowledge base             |

    * Start by editing `agents.yaml` and `tasks.yaml` to define your crew's behavior.

    * Keep sensitive information like API keys in `.env`.
  </Step>

  <Step title="Run your Crew">
    * Before you run your crew, make sure to run:
      ```bash theme={null}
      crewai install
      ```
    * If you need to install additional packages, use:
      ```shell theme={null}
      uv add <package-name>
      ```
    * To run your crew, execute the following command in the root of your project:
      ```bash theme={null}
      crewai run
      ```
  </Step>
</Steps>

## Enterprise Installation Options

<Note type="info">
  For teams and organizations, CrewAI offers enterprise deployment options that eliminate setup complexity:

  ### CrewAI AMP (SaaS)

  * Zero installation required - just sign up for free at [app.crewai.com](https://app.crewai.com)
  * Automatic updates and maintenance
  * Managed infrastructure and scaling
  * Build Crews with no Code

  ### CrewAI Factory (Self-hosted)

  * Containerized deployment for your infrastructure
  * Supports any hyperscaler including on prem deployments
  * Integration with your existing security systems

  <Card title="Explore Enterprise Options" icon="building" href="https://crewai.com/enterprise">
    Learn about CrewAI's enterprise offerings and schedule a demo
  </Card>
</Note>

## Next Steps

<CardGroup>
  <Card title="Build Your First Agent" icon="code" href="/en/quickstart">
    Follow our quickstart guide to create your first CrewAI agent and get
    hands-on experience.
  </Card>

  <Card title="Join the Community" icon="comments" href="https://community.crewai.com">
    Connect with other developers, get help, and share your CrewAI experiences.
  </Card>
</CardGroup>


# Introduction
Source: https://docs.crewai.com/en/introduction

Build AI agent teams that work together to tackle complex tasks

# What is CrewAI?

**CrewAI is the leading open-source framework for orchestrating autonomous AI agents and building complex workflows.**

It empowers developers to build production-ready multi-agent systems by combining the collaborative intelligence of **Crews** with the precise control of **Flows**.

* **[CrewAI Flows](/en/guides/flows/first-flow)**: The backbone of your AI application. Flows allow you to create structured, event-driven workflows that manage state and control execution. They provide the scaffolding for your AI agents to work within.
* **[CrewAI Crews](/en/guides/crews/first-crew)**: The units of work within your Flow. Crews are teams of autonomous agents that collaborate to solve specific tasks delegated to them by the Flow.

With over 100,000 developers certified through our community courses, CrewAI is the standard for enterprise-ready AI automation.

## The CrewAI Architecture

CrewAI's architecture is designed to balance autonomy with control.

### 1. Flows: The Backbone

<Note>
  Think of a Flow as the "manager" or the "process definition" of your application. It defines the steps, the logic, and how data moves through your system.
</Note>

<Frame>
  <img alt="CrewAI Framework Overview" />
</Frame>

Flows provide:

* **State Management**: Persist data across steps and executions.
* **Event-Driven Execution**: Trigger actions based on events or external inputs.
* **Control Flow**: Use conditional logic, loops, and branching.

### 2. Crews: The Intelligence

<Note>
  Crews are the "teams" that do the heavy lifting. Within a Flow, you can trigger a Crew to tackle a complex problem requiring creativity and collaboration.
</Note>

<Frame>
  <img alt="CrewAI Framework Overview" />
</Frame>

Crews provide:

* **Role-Playing Agents**: Specialized agents with specific goals and tools.
* **Autonomous Collaboration**: Agents work together to solve tasks.
* **Task Delegation**: Tasks are assigned and executed based on agent capabilities.

## How It All Works Together

1. **The Flow** triggers an event or starts a process.
2. **The Flow** manages the state and decides what to do next.
3. **The Flow** delegates a complex task to a **Crew**.
4. **The Crew**'s agents collaborate to complete the task.
5. **The Crew** returns the result to the **Flow**.
6. **The Flow** continues execution based on the result.

## Key Features

<CardGroup>
  <Card title="Production-Grade Flows" icon="arrow-progress">
    Build reliable, stateful workflows that can handle long-running processes and complex logic.
  </Card>

  <Card title="Autonomous Crews" icon="users">
    Deploy teams of agents that can plan, execute, and collaborate to achieve high-level goals.
  </Card>

  <Card title="Flexible Tools" icon="screwdriver-wrench">
    Connect your agents to any API, database, or local tool.
  </Card>

  <Card title="Enterprise Security" icon="lock">
    Designed with security and compliance in mind for enterprise deployments.
  </Card>
</CardGroup>

## When to Use Crews vs. Flows

**The short answer: Use both.**

For any production-ready application, **start with a Flow**.

* **Use a Flow** to define the overall structure, state, and logic of your application.
* **Use a Crew** within a Flow step when you need a team of agents to perform a specific, complex task that requires autonomy.

| Use Case                | Architecture                                                               |
| :---------------------- | :------------------------------------------------------------------------- |
| **Simple Automation**   | Single Flow with Python tasks                                              |
| **Complex Research**    | Flow managing state -> Crew performing research                            |
| **Application Backend** | Flow handling API requests -> Crew generating content -> Flow saving to DB |

## Why Choose CrewAI?

* 🧠 **Autonomous Operation**: Agents make intelligent decisions based on their roles and available tools
* 📝 **Natural Interaction**: Agents communicate and collaborate like human team members
* 🛠️ **Extensible Design**: Easy to add new tools, roles, and capabilities
* 🚀 **Production Ready**: Built for reliability and scalability in real-world applications
* 🔒 **Security-Focused**: Designed with enterprise security requirements in mind
* 💰 **Cost-Efficient**: Optimized to minimize token usage and API calls

## Ready to Start Building?

<CardGroup>
  <Card title="Build Your First Flow" icon="diagram-project" href="/en/guides/flows/first-flow">
    Learn how to create structured, event-driven workflows with precise control over execution.
  </Card>

  <Card title="Build Your First Crew" icon="users-gear" href="/en/guides/crews/first-crew">
    Step-by-step tutorial to create a collaborative AI team that works together to solve complex problems.
  </Card>
</CardGroup>

<CardGroup>
  <Card title="Install CrewAI" icon="wrench" href="/en/installation">
    Get started with CrewAI in your development environment.
  </Card>

  <Card title="Quick Start" icon="bolt" href="en/quickstart">
    Follow our quickstart guide to create your first CrewAI agent and get hands-on experience.
  </Card>

  <Card title="Join the Community" icon="comments" href="https://community.crewai.com">
    Connect with other developers, get help, and share your CrewAI experiences.
  </Card>
</CardGroup>


# MCP DSL Integration
Source: https://docs.crewai.com/en/mcp/dsl-integration

Learn how to use CrewAI's simple DSL syntax to integrate MCP servers directly with your agents using the mcps field.

## Overview

CrewAI's MCP DSL (Domain Specific Language) integration provides the **simplest way** to connect your agents to MCP (Model Context Protocol) servers. Just add an `mcps` field to your agent and CrewAI handles all the complexity automatically.

<Info>
  This is the **recommended approach** for most MCP use cases. For advanced
  scenarios requiring manual connection management, see
  [MCPServerAdapter](/en/mcp/overview#advanced-mcpserveradapter).
</Info>

## Basic Usage

Add MCP servers to your agent using the `mcps` field:

```python theme={null}
from crewai import Agent

agent = Agent(
    role="Research Assistant",
    goal="Help with research and analysis tasks",
    backstory="Expert assistant with access to advanced research tools",
    mcps=[
        "https://mcp.exa.ai/mcp?api_key=your_key&profile=research"
    ]
)

# MCP tools are now automatically available!
# No need for manual connection management or tool configuration
```

## Supported Reference Formats

### External MCP Remote Servers

```python theme={null}
# Basic HTTPS server
"https://api.example.com/mcp"

# Server with authentication
"https://mcp.exa.ai/mcp?api_key=your_key&profile=your_profile"

# Server with custom path
"https://services.company.com/api/v1/mcp"
```

### Specific Tool Selection

Use the `#` syntax to select specific tools from a server:

```python theme={null}
# Get only the forecast tool from weather server
"https://weather.api.com/mcp#get_forecast"

# Get only the search tool from Exa
"https://mcp.exa.ai/mcp?api_key=your_key#web_search_exa"
```

### CrewAI AMP Marketplace

Access tools from the CrewAI AMP marketplace:

```python theme={null}
# Full service with all tools
"crewai-amp:financial-data"

# Specific tool from AMP service
"crewai-amp:research-tools#pubmed_search"

# Multiple AMP services
mcps=[
    "crewai-amp:weather-insights",
    "crewai-amp:market-analysis",
    "crewai-amp:social-media-monitoring"
]
```

## Complete Example

Here's a complete example using multiple MCP servers:

```python theme={null}
from crewai import Agent, Task, Crew, Process

# Create agent with multiple MCP sources
multi_source_agent = Agent(
    role="Multi-Source Research Analyst",
    goal="Conduct comprehensive research using multiple data sources",
    backstory="""Expert researcher with access to web search, weather data,
    financial information, and academic research tools""",
    mcps=[
        # External MCP servers
        "https://mcp.exa.ai/mcp?api_key=your_exa_key&profile=research",
        "https://weather.api.com/mcp#get_current_conditions",

        # CrewAI AMP marketplace
        "crewai-amp:financial-insights",
        "crewai-amp:academic-research#pubmed_search",
        "crewai-amp:market-intelligence#competitor_analysis"
    ]
)

# Create comprehensive research task
research_task = Task(
    description="""Research the impact of AI agents on business productivity.
    Include current weather impacts on remote work, financial market trends,
    and recent academic publications on AI agent frameworks.""",
    expected_output="""Comprehensive report covering:
    1. AI agent business impact analysis
    2. Weather considerations for remote work
    3. Financial market trends related to AI
    4. Academic research citations and insights
    5. Competitive landscape analysis""",
    agent=multi_source_agent
)

# Create and execute crew
research_crew = Crew(
    agents=[multi_source_agent],
    tasks=[research_task],
    process=Process.sequential,
    verbose=True
)

result = research_crew.kickoff()
print(f"Research completed with {len(multi_source_agent.mcps)} MCP data sources")
```

## Tool Naming and Organization

CrewAI automatically handles tool naming to prevent conflicts:

```python theme={null}
# Original MCP server has tools: "search", "analyze"
# CrewAI creates tools: "mcp_exa_ai_search", "mcp_exa_ai_analyze"

agent = Agent(
    role="Tool Organization Demo",
    goal="Show how tool naming works",
    backstory="Demonstrates automatic tool organization",
    mcps=[
        "https://mcp.exa.ai/mcp?api_key=key",      # Tools: mcp_exa_ai_*
        "https://weather.service.com/mcp",         # Tools: weather_service_com_*
        "crewai-amp:financial-data"                # Tools: financial_data_*
    ]
)

# Each server's tools get unique prefixes based on the server name
# This prevents naming conflicts between different MCP servers
```

## Error Handling and Resilience

The MCP DSL is designed to be robust and user-friendly:

### Graceful Server Failures

```python theme={null}
agent = Agent(
    role="Resilient Researcher",
    goal="Research despite server issues",
    backstory="Experienced researcher who adapts to available tools",
    mcps=[
        "https://primary-server.com/mcp",         # Primary data source
        "https://backup-server.com/mcp",          # Backup if primary fails
        "https://unreachable-server.com/mcp",     # Will be skipped with warning
        "crewai-amp:reliable-service"             # Reliable AMP service
    ]
)

# Agent will:
# 1. Successfully connect to working servers
# 2. Log warnings for failing servers
# 3. Continue with available tools
# 4. Not crash or hang on server failures
```

### Timeout Protection

All MCP operations have built-in timeouts:

* **Connection timeout**: 10 seconds
* **Tool execution timeout**: 30 seconds
* **Discovery timeout**: 15 seconds

```python theme={null}
# These servers will timeout gracefully if unresponsive
mcps=[
    "https://slow-server.com/mcp",        # Will timeout after 10s if unresponsive
    "https://overloaded-api.com/mcp"      # Will timeout if discovery takes > 15s
]
```

## Performance Features

### Automatic Caching

Tool schemas are cached for 5 minutes to improve performance:

```python theme={null}
# First agent creation - discovers tools from server
agent1 = Agent(role="First", goal="Test", backstory="Test",
               mcps=["https://api.example.com/mcp"])

# Second agent creation (within 5 minutes) - uses cached tool schemas
agent2 = Agent(role="Second", goal="Test", backstory="Test",
               mcps=["https://api.example.com/mcp"])  # Much faster!
```

### On-Demand Connections

Tool connections are established only when tools are actually used:

```python theme={null}
# Agent creation is fast - no MCP connections made yet
agent = Agent(
    role="On-Demand Agent",
    goal="Use tools efficiently",
    backstory="Efficient agent that connects only when needed",
    mcps=["https://api.example.com/mcp"]
)

# MCP connection is made only when a tool is actually executed
# This minimizes connection overhead and improves startup performance
```

## Integration with Existing Features

MCP tools work seamlessly with other CrewAI features:

```python theme={null}
from crewai.tools import BaseTool

class CustomTool(BaseTool):
    name: str = "custom_analysis"
    description: str = "Custom analysis tool"

    def _run(self, **kwargs):
        return "Custom analysis result"

agent = Agent(
    role="Full-Featured Agent",
    goal="Use all available tool types",
    backstory="Agent with comprehensive tool access",

    # All tool types work together
    tools=[CustomTool()],                          # Custom tools
    apps=["gmail", "slack"],                       # Platform integrations
    mcps=[                                         # MCP servers
        "https://mcp.exa.ai/mcp?api_key=key",
        "crewai-amp:research-tools"
    ],

    verbose=True,
    max_iter=15
)
```

## Best Practices

### 1. Use Specific Tools When Possible

```python theme={null}
# Good - only get the tools you need
mcps=["https://weather.api.com/mcp#get_forecast"]

# Less efficient - gets all tools from server
mcps=["https://weather.api.com/mcp"]
```

### 2. Handle Authentication Securely

```python theme={null}
import os

# Store API keys in environment variables
exa_key = os.getenv("EXA_API_KEY")
exa_profile = os.getenv("EXA_PROFILE")

agent = Agent(
    role="Secure Agent",
    goal="Use MCP tools securely",
    backstory="Security-conscious agent",
    mcps=[f"https://mcp.exa.ai/mcp?api_key={exa_key}&profile={exa_profile}"]
)
```

### 3. Plan for Server Failures

```python theme={null}
# Always include backup options
mcps=[
    "https://primary-api.com/mcp",       # Primary choice
    "https://backup-api.com/mcp",        # Backup option
    "crewai-amp:reliable-service"        # AMP fallback
]
```

### 4. Use Descriptive Agent Roles

```python theme={null}
agent = Agent(
    role="Weather-Enhanced Market Analyst",
    goal="Analyze markets considering weather impacts",
    backstory="Financial analyst with access to weather data for agricultural market insights",
    mcps=[
        "https://weather.service.com/mcp#get_forecast",
        "crewai-amp:financial-data#stock_analysis"
    ]
)
```

## Troubleshooting

### Common Issues

**No tools discovered:**

```python theme={null}
# Check your MCP server URL and authentication
# Verify the server is running and accessible
mcps=["https://mcp.example.com/mcp?api_key=valid_key"]
```

**Connection timeouts:**

```python theme={null}
# Server may be slow or overloaded
# CrewAI will log warnings and continue with other servers
# Check server status or try backup servers
```

**Authentication failures:**

```python theme={null}
# Verify API keys and credentials
# Check server documentation for required parameters
# Ensure query parameters are properly URL encoded
```

## Advanced: MCPServerAdapter

For complex scenarios requiring manual connection management, use the `MCPServerAdapter` class from `crewai-tools`. Using a Python context manager (`with` statement) is the recommended approach as it automatically handles starting and stopping the connection to the MCP server.


# Connecting to Multiple MCP Servers
Source: https://docs.crewai.com/en/mcp/multiple-servers

Learn how to use MCPServerAdapter in CrewAI to connect to multiple MCP servers simultaneously and aggregate their tools.

## Overview

`MCPServerAdapter` in `crewai-tools` allows you to connect to multiple MCP servers concurrently. This is useful when your agents need to access tools distributed across different services or environments. The adapter aggregates tools from all specified servers, making them available to your CrewAI agents.

## Configuration

To connect to multiple servers, you provide a list of server parameter dictionaries to `MCPServerAdapter`. Each dictionary in the list should define the parameters for one MCP server.

Supported transport types for each server in the list include `stdio`, `sse`, and `streamable-http`.

```python theme={null}
from crewai import Agent, Task, Crew, Process
from crewai_tools import MCPServerAdapter
from mcp import StdioServerParameters # Needed for Stdio example

# Define parameters for multiple MCP servers
server_params_list = [
    # Streamable HTTP Server
    {
        "url": "http://localhost:8001/mcp", 
        "transport": "streamable-http"
    },
    # SSE Server
    {
        "url": "http://localhost:8000/sse",
        "transport": "sse"
    },
    # StdIO Server
    StdioServerParameters(
        command="python3",
        args=["servers/your_stdio_server.py"],
        env={"UV_PYTHON": "3.12", **os.environ},
    )
]

try:
    with MCPServerAdapter(server_params_list) as aggregated_tools:
        print(f"Available aggregated tools: {[tool.name for tool in aggregated_tools]}")

        multi_server_agent = Agent(
            role="Versatile Assistant",
            goal="Utilize tools from local Stdio, remote SSE, and remote HTTP MCP servers.",
            backstory="An AI agent capable of leveraging a diverse set of tools from multiple sources.",
            tools=aggregated_tools, # All tools are available here
            verbose=True,
        )

        ... # Your other agent, tasks, and crew code here

except Exception as e:
    print(f"Error connecting to or using multiple MCP servers (Managed): {e}")
    print("Ensure all MCP servers are running and accessible with correct configurations.")

```

## Connection Management

When using the context manager (`with` statement), `MCPServerAdapter` handles the lifecycle (start and stop) of all connections to the configured MCP servers. This simplifies resource management and ensures that all connections are properly closed when the context is exited.


# MCP Servers as Tools in CrewAI
Source: https://docs.crewai.com/en/mcp/overview

Learn how to integrate MCP servers as tools in your CrewAI agents using the `crewai-tools` library.

## Overview

The [Model Context Protocol](https://modelcontextprotocol.io/introduction) (MCP) provides a standardized way for AI agents to provide context to LLMs by communicating with external services, known as MCP Servers.

CrewAI offers **two approaches** for MCP integration:

### 🚀 **Simple DSL Integration** (Recommended)

Use the `mcps` field directly on agents for seamless MCP tool integration. The DSL supports both **string references** (for quick setup) and **structured configurations** (for full control).

#### String-Based References (Quick Setup)

Perfect for remote HTTPS servers and CrewAI AMP marketplace:

```python theme={null}
from crewai import Agent

agent = Agent(
    role="Research Analyst",
    goal="Research and analyze information",
    backstory="Expert researcher with access to external tools",
    mcps=[
        "https://mcp.exa.ai/mcp?api_key=your_key",           # External MCP server
        "https://api.weather.com/mcp#get_forecast",          # Specific tool from server
        "crewai-amp:financial-data",                         # CrewAI AMP marketplace
        "crewai-amp:research-tools#pubmed_search"            # Specific AMP tool
    ]
)
# MCP tools are now automatically available to your agent!
```

#### Structured Configurations (Full Control)

For complete control over connection settings, tool filtering, and all transport types:

```python theme={null}
from crewai import Agent
from crewai.mcp import MCPServerStdio, MCPServerHTTP, MCPServerSSE
from crewai.mcp.filters import create_static_tool_filter

agent = Agent(
    role="Advanced Research Analyst",
    goal="Research with full control over MCP connections",
    backstory="Expert researcher with advanced tool access",
    mcps=[
        # Stdio transport for local servers
        MCPServerStdio(
            command="npx",
            args=["-y", "@modelcontextprotocol/server-filesystem"],
            env={"API_KEY": "your_key"},
            tool_filter=create_static_tool_filter(
                allowed_tool_names=["read_file", "list_directory"]
            ),
            cache_tools_list=True,
        ),
        # HTTP/Streamable HTTP transport for remote servers
        MCPServerHTTP(
            url="https://api.example.com/mcp",
            headers={"Authorization": "Bearer your_token"},
            streamable=True,
            cache_tools_list=True,
        ),
        # SSE transport for real-time streaming
        MCPServerSSE(
            url="https://stream.example.com/mcp/sse",
            headers={"Authorization": "Bearer your_token"},
        ),
    ]
)
```

### 🔧 **Advanced: MCPServerAdapter** (For Complex Scenarios)

For advanced use cases requiring manual connection management, the `crewai-tools` library provides the `MCPServerAdapter` class.

We currently support the following transport mechanisms:

* **Stdio**: for local servers (communication via standard input/output between processes on the same machine)
* **Server-Sent Events (SSE)**: for remote servers (unidirectional, real-time data streaming from server to client over HTTP)
* **Streamable HTTPS**: for remote servers (flexible, potentially bi-directional communication over HTTPS, often utilizing SSE for server-to-client streams)

## Video Tutorial

Watch this video tutorial for a comprehensive guide on MCP integration with CrewAI:

<iframe title="CrewAI MCP Integration Guide" />

## Installation

CrewAI MCP integration requires the `mcp` library:

```shell theme={null}
# For Simple DSL Integration (Recommended)
uv add mcp

# For Advanced MCPServerAdapter usage
uv pip install 'crewai-tools[mcp]'
```

## Quick Start: Simple DSL Integration

The easiest way to integrate MCP servers is using the `mcps` field on your agents. You can use either string references or structured configurations.

### Quick Start with String References

```python theme={null}
from crewai import Agent, Task, Crew

# Create agent with MCP tools using string references
research_agent = Agent(
    role="Research Analyst",
    goal="Find and analyze information using advanced search tools",
    backstory="Expert researcher with access to multiple data sources",
    mcps=[
        "https://mcp.exa.ai/mcp?api_key=your_key&profile=your_profile",
        "crewai-amp:weather-service#current_conditions"
    ]
)

# Create task
research_task = Task(
    description="Research the latest developments in AI agent frameworks",
    expected_output="Comprehensive research report with citations",
    agent=research_agent
)

# Create and run crew
crew = Crew(agents=[research_agent], tasks=[research_task])
result = crew.kickoff()
```

### Quick Start with Structured Configurations

```python theme={null}
from crewai import Agent, Task, Crew
from crewai.mcp import MCPServerStdio, MCPServerHTTP, MCPServerSSE

# Create agent with structured MCP configurations
research_agent = Agent(
    role="Research Analyst",
    goal="Find and analyze information using advanced search tools",
    backstory="Expert researcher with access to multiple data sources",
    mcps=[
        # Local stdio server
        MCPServerStdio(
            command="python",
            args=["local_server.py"],
            env={"API_KEY": "your_key"},
        ),
        # Remote HTTP server
        MCPServerHTTP(
            url="https://api.research.com/mcp",
            headers={"Authorization": "Bearer your_token"},
        ),
    ]
)

# Create task
research_task = Task(
    description="Research the latest developments in AI agent frameworks",
    expected_output="Comprehensive research report with citations",
    agent=research_agent
)

# Create and run crew
crew = Crew(agents=[research_agent], tasks=[research_task])
result = crew.kickoff()
```

That's it! The MCP tools are automatically discovered and available to your agent.

## MCP Reference Formats

The `mcps` field supports both **string references** (for quick setup) and **structured configurations** (for full control). You can mix both formats in the same list.

### String-Based References

#### External MCP Servers

```python theme={null}
mcps=[
    # Full server - get all available tools
    "https://mcp.example.com/api",

    # Specific tool from server using # syntax
    "https://api.weather.com/mcp#get_current_weather",

    # Server with authentication parameters
    "https://mcp.exa.ai/mcp?api_key=your_key&profile=your_profile"
]
```

#### CrewAI AMP Marketplace

```python theme={null}
mcps=[
    # Full AMP MCP service - get all available tools
    "crewai-amp:financial-data",

    # Specific tool from AMP service using # syntax
    "crewai-amp:research-tools#pubmed_search",

    # Multiple AMP services
    "crewai-amp:weather-service",
    "crewai-amp:market-analysis"
]
```

### Structured Configurations

#### Stdio Transport (Local Servers)

Perfect for local MCP servers that run as processes:

```python theme={null}
from crewai.mcp import MCPServerStdio
from crewai.mcp.filters import create_static_tool_filter

mcps=[
    MCPServerStdio(
        command="npx",
        args=["-y", "@modelcontextprotocol/server-filesystem"],
        env={"API_KEY": "your_key"},
        tool_filter=create_static_tool_filter(
            allowed_tool_names=["read_file", "write_file"]
        ),
        cache_tools_list=True,
    ),
    # Python-based server
    MCPServerStdio(
        command="python",
        args=["path/to/server.py"],
        env={"UV_PYTHON": "3.12", "API_KEY": "your_key"},
    ),
]
```

#### HTTP/Streamable HTTP Transport (Remote Servers)

For remote MCP servers over HTTP/HTTPS:

```python theme={null}
from crewai.mcp import MCPServerHTTP

mcps=[
    # Streamable HTTP (default)
    MCPServerHTTP(
        url="https://api.example.com/mcp",
        headers={"Authorization": "Bearer your_token"},
        streamable=True,
        cache_tools_list=True,
    ),
    # Standard HTTP
    MCPServerHTTP(
        url="https://api.example.com/mcp",
        headers={"Authorization": "Bearer your_token"},
        streamable=False,
    ),
]
```

#### SSE Transport (Real-Time Streaming)

For remote servers using Server-Sent Events:

```python theme={null}
from crewai.mcp import MCPServerSSE

mcps=[
    MCPServerSSE(
        url="https://stream.example.com/mcp/sse",
        headers={"Authorization": "Bearer your_token"},
        cache_tools_list=True,
    ),
]
```

### Mixed References

You can combine string references and structured configurations:

```python theme={null}
from crewai.mcp import MCPServerStdio, MCPServerHTTP

mcps=[
    # String references
    "https://external-api.com/mcp",              # External server
    "crewai-amp:financial-insights",             # AMP service

    # Structured configurations
    MCPServerStdio(
        command="npx",
        args=["-y", "@modelcontextprotocol/server-filesystem"],
    ),
    MCPServerHTTP(
        url="https://api.example.com/mcp",
        headers={"Authorization": "Bearer token"},
    ),
]
```

### Tool Filtering

Structured configurations support advanced tool filtering:

```python theme={null}
from crewai.mcp import MCPServerStdio
from crewai.mcp.filters import create_static_tool_filter, create_dynamic_tool_filter, ToolFilterContext

# Static filtering (allow/block lists)
static_filter = create_static_tool_filter(
    allowed_tool_names=["read_file", "write_file"],
    blocked_tool_names=["delete_file"],
)

# Dynamic filtering (context-aware)
def dynamic_filter(context: ToolFilterContext, tool: dict) -> bool:
    # Block dangerous tools for certain agent roles
    if context.agent.role == "Code Reviewer":
        if "delete" in tool.get("name", "").lower():
            return False
    return True

mcps=[
    MCPServerStdio(
        command="npx",
        args=["-y", "@modelcontextprotocol/server-filesystem"],
        tool_filter=static_filter,  # or dynamic_filter
    ),
]
```

## Configuration Parameters

Each transport type supports specific configuration options:

### MCPServerStdio Parameters

* **`command`** (required): Command to execute (e.g., `"python"`, `"node"`, `"npx"`, `"uvx"`)
* **`args`** (optional): List of command arguments (e.g., `["server.py"]` or `["-y", "@mcp/server"]`)
* **`env`** (optional): Dictionary of environment variables to pass to the process
* **`tool_filter`** (optional): Tool filter function for filtering available tools
* **`cache_tools_list`** (optional): Whether to cache the tool list for faster subsequent access (default: `False`)

### MCPServerHTTP Parameters

* **`url`** (required): Server URL (e.g., `"https://api.example.com/mcp"`)
* **`headers`** (optional): Dictionary of HTTP headers for authentication or other purposes
* **`streamable`** (optional): Whether to use streamable HTTP transport (default: `True`)
* **`tool_filter`** (optional): Tool filter function for filtering available tools
* **`cache_tools_list`** (optional): Whether to cache the tool list for faster subsequent access (default: `False`)

### MCPServerSSE Parameters

* **`url`** (required): Server URL (e.g., `"https://api.example.com/mcp/sse"`)
* **`headers`** (optional): Dictionary of HTTP headers for authentication or other purposes
* **`tool_filter`** (optional): Tool filter function for filtering available tools
* **`cache_tools_list`** (optional): Whether to cache the tool list for faster subsequent access (default: `False`)

### Common Parameters

All transport types support:

* **`tool_filter`**: Filter function to control which tools are available. Can be:
  * `None` (default): All tools are available
  * Static filter: Created with `create_static_tool_filter()` for allow/block lists
  * Dynamic filter: Created with `create_dynamic_tool_filter()` for context-aware filtering
* **`cache_tools_list`**: When `True`, caches the tool list after first discovery to improve performance on subsequent connections

## Key Features

* 🔄 **Automatic Tool Discovery**: Tools are automatically discovered and integrated
* 🏷️ **Name Collision Prevention**: Server names are prefixed to tool names
* ⚡ **Performance Optimized**: On-demand connections with schema caching
* 🛡️ **Error Resilience**: Graceful handling of unavailable servers
* ⏱️ **Timeout Protection**: Built-in timeouts prevent hanging connections
* 📊 **Transparent Integration**: Works seamlessly with existing CrewAI features
* 🔧 **Full Transport Support**: Stdio, HTTP/Streamable HTTP, and SSE transports
* 🎯 **Advanced Filtering**: Static and dynamic tool filtering capabilities
* 🔐 **Flexible Authentication**: Support for headers, environment variables, and query parameters

## Error Handling

The MCP DSL integration is designed to be resilient and handles failures gracefully:

```python theme={null}
from crewai import Agent
from crewai.mcp import MCPServerStdio, MCPServerHTTP

agent = Agent(
    role="Resilient Agent",
    goal="Continue working despite server issues",
    backstory="Agent that handles failures gracefully",
    mcps=[
        # String references
        "https://reliable-server.com/mcp",        # Will work
        "https://unreachable-server.com/mcp",     # Will be skipped gracefully
        "crewai-amp:working-service",             # Will work

        # Structured configs
        MCPServerStdio(
            command="python",
            args=["reliable_server.py"],          # Will work
        ),
        MCPServerHTTP(
            url="https://slow-server.com/mcp",     # Will timeout gracefully
        ),
    ]
)
# Agent will use tools from working servers and log warnings for failing ones
```

All connection errors are handled gracefully:

* **Connection failures**: Logged as warnings, agent continues with available tools
* **Timeout errors**: Connections timeout after 30 seconds (configurable)
* **Authentication errors**: Logged clearly for debugging
* **Invalid configurations**: Validation errors are raised at agent creation time

## Advanced: MCPServerAdapter

For complex scenarios requiring manual connection management, use the `MCPServerAdapter` class from `crewai-tools`. Using a Python context manager (`with` statement) is the recommended approach as it automatically handles starting and stopping the connection to the MCP server.

## Connection Configuration

The `MCPServerAdapter` supports several configuration options to customize the connection behavior:

* **`connect_timeout`** (optional): Maximum time in seconds to wait for establishing a connection to the MCP server. Defaults to 30 seconds if not specified. This is particularly useful for remote servers that may have variable response times.

```python theme={null}
# Example with custom connection timeout
with MCPServerAdapter(server_params, connect_timeout=60) as tools:
    # Connection will timeout after 60 seconds if not established
    pass
```

```python theme={null}
from crewai import Agent
from crewai_tools import MCPServerAdapter
from mcp import StdioServerParameters # For Stdio Server

# Example server_params (choose one based on your server type):
# 1. Stdio Server:
server_params=StdioServerParameters(
    command="python3",
    args=["servers/your_server.py"],
    env={"UV_PYTHON": "3.12", **os.environ},
)

# 2. SSE Server:
server_params = {
    "url": "http://localhost:8000/sse",
    "transport": "sse"
}

# 3. Streamable HTTP Server:
server_params = {
    "url": "http://localhost:8001/mcp",
    "transport": "streamable-http"
}

# Example usage (uncomment and adapt once server_params is set):
with MCPServerAdapter(server_params, connect_timeout=60) as mcp_tools:
    print(f"Available tools: {[tool.name for tool in mcp_tools]}")

    my_agent = Agent(
        role="MCP Tool User",
        goal="Utilize tools from an MCP server.",
        backstory="I can connect to MCP servers and use their tools.",
        tools=mcp_tools, # Pass the loaded tools to your agent
        reasoning=True,
        verbose=True
    )
    # ... rest of your crew setup ...
```

This general pattern shows how to integrate tools. For specific examples tailored to each transport, refer to the detailed guides below.

## Filtering Tools

There are two ways to filter tools:

1. Accessing a specific tool using dictionary-style indexing.
2. Pass a list of tool names to the `MCPServerAdapter` constructor.

### Accessing a specific tool using dictionary-style indexing.

```python theme={null}
with MCPServerAdapter(server_params, connect_timeout=60) as mcp_tools:
    print(f"Available tools: {[tool.name for tool in mcp_tools]}")

    my_agent = Agent(
        role="MCP Tool User",
        goal="Utilize tools from an MCP server.",
        backstory="I can connect to MCP servers and use their tools.",
        tools=[mcp_tools["tool_name"]], # Pass the loaded tools to your agent
        reasoning=True,
        verbose=True
    )
    # ... rest of your crew setup ...
```

### Pass a list of tool names to the `MCPServerAdapter` constructor.

```python theme={null}
with MCPServerAdapter(server_params, "tool_name", connect_timeout=60) as mcp_tools:
    print(f"Available tools: {[tool.name for tool in mcp_tools]}")

    my_agent = Agent(
        role="MCP Tool User",
        goal="Utilize tools from an MCP server.",
        backstory="I can connect to MCP servers and use their tools.",
        tools=mcp_tools, # Pass the loaded tools to your agent
        reasoning=True,
        verbose=True
    )
    # ... rest of your crew setup ...
```

## Using with CrewBase

To use MCPServer tools within a CrewBase class, use the `get_mcp_tools` method. Server configurations should be provided via the `mcp_server_params` attribute. You can pass either a single configuration or a list of multiple server configurations.

```python theme={null}
@CrewBase
class CrewWithMCP:
  # ... define your agents and tasks config file ...

  mcp_server_params = [
    # Streamable HTTP Server
    {
        "url": "http://localhost:8001/mcp",
        "transport": "streamable-http"
    },
    # SSE Server
    {
        "url": "http://localhost:8000/sse",
        "transport": "sse"
    },
    # StdIO Server
    StdioServerParameters(
        command="python3",
        args=["servers/your_stdio_server.py"],
        env={"UV_PYTHON": "3.12", **os.environ},
    )
  ]

  @agent
  def your_agent(self):
      return Agent(config=self.agents_config["your_agent"], tools=self.get_mcp_tools()) # get all available tools

    # ... rest of your crew setup ...
```

<Tip>
  When a crew class is decorated with `@CrewBase`, the adapter lifecycle is managed for you:

  * The first call to `get_mcp_tools()` lazily creates a shared `MCPServerAdapter` that is reused by every agent in the crew.
  * The adapter automatically shuts down after `.kickoff()` completes thanks to an implicit after-kickoff hook injected by `@CrewBase`, so no manual cleanup is required.
  * If `mcp_server_params` is not defined, `get_mcp_tools()` simply returns an empty list, allowing the same code paths to run with or without MCP configured.

  This makes it safe to call `get_mcp_tools()` from multiple agent methods or selectively enable MCP per environment.
</Tip>

### Connection Timeout Configuration

You can configure the connection timeout for MCP servers by setting the `mcp_connect_timeout` class attribute. If no timeout is specified, it defaults to 30 seconds.

```python theme={null}
@CrewBase
class CrewWithMCP:
  mcp_server_params = [...]
  mcp_connect_timeout = 60  # 60 seconds timeout for all MCP connections

  @agent
  def your_agent(self):
      return Agent(config=self.agents_config["your_agent"], tools=self.get_mcp_tools())
```

```python theme={null}
@CrewBase
class CrewWithDefaultTimeout:
  mcp_server_params = [...]
  # No mcp_connect_timeout specified - uses default 30 seconds

  @agent
  def your_agent(self):
      return Agent(config=self.agents_config["your_agent"], tools=self.get_mcp_tools())
```

### Filtering Tools

You can filter which tools are available to your agent by passing a list of tool names to the `get_mcp_tools` method.

```python theme={null}
@agent
def another_agent(self):
    return Agent(
      config=self.agents_config["your_agent"],
      tools=self.get_mcp_tools("tool_1", "tool_2") # get specific tools
    )
```

The timeout configuration applies to all MCP tool calls within the crew:

```python theme={null}
@CrewBase
class CrewWithCustomTimeout:
  mcp_server_params = [...]
  mcp_connect_timeout = 90  # 90 seconds timeout for all MCP connections

  @agent
  def filtered_agent(self):
      return Agent(
        config=self.agents_config["your_agent"],
        tools=self.get_mcp_tools("tool_1", "tool_2") # specific tools with custom timeout
      )
```

## Explore MCP Integrations

<CardGroup>
  <Card title="Simple DSL Integration" icon="code" href="/en/mcp/dsl-integration">
    **Recommended**: Use the simple `mcps=[]` field syntax for effortless MCP
    integration.
  </Card>

  <Card title="Stdio Transport" icon="server" href="/en/mcp/stdio">
    Connect to local MCP servers via standard input/output. Ideal for scripts
    and local executables.
  </Card>

  <Card title="SSE Transport" icon="wifi" href="/en/mcp/sse">
    Integrate with remote MCP servers using Server-Sent Events for real-time
    data streaming.
  </Card>

  <Card title="Streamable HTTP Transport" icon="globe" href="/en/mcp/streamable-http">
    Utilize flexible Streamable HTTP for robust communication with remote MCP
    servers.
  </Card>

  <Card title="Connecting to Multiple Servers" icon="layer-group" href="/en/mcp/multiple-servers">
    Aggregate tools from several MCP servers simultaneously using a single
    adapter.
  </Card>

  <Card title="Security Considerations" icon="lock" href="/en/mcp/security">
    Review important security best practices for MCP integration to keep your
    agents safe.
  </Card>
</CardGroup>

Checkout this repository for full demos and examples of MCP integration with CrewAI! 👇

<Card title="GitHub Repository" icon="github" href="https://github.com/tonykipkemboi/crewai-mcp-demo">
  CrewAI MCP Demo
</Card>

## Staying Safe with MCP

<Warning>Always ensure that you trust an MCP Server before using it.</Warning>

#### Security Warning: DNS Rebinding Attacks

SSE transports can be vulnerable to DNS rebinding attacks if not properly secured.
To prevent this:

1. **Always validate Origin headers** on incoming SSE connections to ensure they come from expected sources
2. **Avoid binding servers to all network interfaces** (0.0.0.0) when running locally - bind only to localhost (127.0.0.1) instead
3. **Implement proper authentication** for all SSE connections

Without these protections, attackers could use DNS rebinding to interact with local MCP servers from remote websites.

For more details, see the [Anthropic's MCP Transport Security docs](https://modelcontextprotocol.io/docs/concepts/transports#security-considerations).

### Limitations

* **Supported Primitives**: Currently, `MCPServerAdapter` primarily supports adapting MCP `tools`.
  Other MCP primitives like `prompts` or `resources` are not directly integrated as CrewAI components through this adapter at this time.
* **Output Handling**: The adapter typically processes the primary text output from an MCP tool (e.g., `.content[0].text`). Complex or multi-modal outputs might require custom handling if not fitting this pattern.


# MCP Security Considerations
Source: https://docs.crewai.com/en/mcp/security

Learn about important security best practices when integrating MCP servers with your CrewAI agents.

## Overview

<Warning>
  The most critical aspect of MCP security is **trust**. You should **only** connect your CrewAI agents to MCP servers that you fully trust.
</Warning>

When integrating external services like MCP (Model Context Protocol) servers into your CrewAI agents, security is paramount.
MCP servers can execute code, access data, or interact with other systems based on the tools they expose.
It's crucial to understand the implications and follow best practices to protect your applications and data.

### Risks

* Execute arbitrary code on the machine where the agent is running (especially with `Stdio` transport if the server can control the command executed).
* Expose sensitive data from your agent or its environment.
* Manipulate your agent's behavior in unintended ways, including making unauthorized API calls on your behalf.
* Hijack your agent's reasoning process through sophisticated prompt injection techniques (see below).

### 1. Trusting MCP Servers

<Warning>
  **Only connect to MCP servers that you trust.**
</Warning>

Before configuring `MCPServerAdapter` to connect to an MCP server, ensure you know:

* **Who operates the server?** Is it a known, reputable service, or an internal server under your control?
* **What tools does it expose?** Understand the capabilities of the tools. Could they be misused if an attacker gained control or if the server itself is malicious?
* **What data does it access or process?** Be aware of any sensitive information that might be sent to or handled by the MCP server.

Avoid connecting to unknown or unverified MCP servers, especially if your agents handle sensitive tasks or data.

### 2. Secure Prompt Injection via Tool Metadata: The "Model Control Protocol" Risk

A significant and subtle risk is the potential for prompt injection through tool metadata. Here's how it works:

1. When your CrewAI agent connects to an MCP server, it typically requests a list of available tools.
2. The MCP server responds with metadata for each tool, including its name, description, and parameter descriptions.
3. Your agent's underlying Language Model (LLM) uses this metadata to understand how and when to use the tools. This metadata is often incorporated into the LLM's system prompt or context.
4. A malicious MCP server can craft its tool metadata (names, descriptions) to include hidden or overt instructions. These instructions can act as a prompt injection, effectively telling your LLM to behave in a certain way, reveal sensitive information, or perform malicious actions.

**Crucially, this attack can occur simply by connecting to a malicious server and listing its tools, even if your agent never explicitly decides to *use* any of those tools.** The mere exposure to the malicious metadata can be enough to compromise the agent's behavior.

**Mitigation:**

* **Extreme Caution with Untrusted Servers:** Reiterate: *Do not connect to MCP servers you do not fully trust.* The risk of metadata injection makes this paramount.

### Stdio Transport Security

Stdio (Standard Input/Output) transport is typically used for local MCP servers running on the same machine as your CrewAI application.

* **Process Isolation**: While generally safer as it doesn't involve network exposure by default, ensure the script or command run by `StdioServerParameters` is from a trusted source and has appropriate file system permissions. A malicious Stdio server script could still harm your local system.
* **Input Sanitization**: If your Stdio server script takes complex inputs derived from agent interactions, ensure the script itself sanitizes these inputs to prevent command injection or other vulnerabilities within the script's logic.
* **Resource Limits**: Be mindful that a local Stdio server process consumes local resources (CPU, memory). Ensure it's well-behaved and won't exhaust system resources.

### Confused Deputy Attacks

The [Confused Deputy Problem](https://en.wikipedia.org/wiki/Confused_deputy_problem) is a classic security vulnerability that can manifest in MCP integrations, especially when an MCP server acts as a proxy to other third-party services (e.g., Google Calendar, GitHub) that use OAuth 2.0 for authorization.

**Scenario:**

1. An MCP server (let's call it `MCP-Proxy`) allows your agent to interact with `ThirdPartyAPI`.
2. `MCP-Proxy` uses its own single, static `client_id` when talking to `ThirdPartyAPI`'s authorization server.
3. You, as the user, legitimately authorize `MCP-Proxy` to access `ThirdPartyAPI` on your behalf. During this, `ThirdPartyAPI`'s auth server might set a cookie in your browser indicating your consent for `MCP-Proxy`'s `client_id`.
4. An attacker crafts a malicious link. This link initiates an OAuth flow with `MCP-Proxy`, but is designed to trick `ThirdPartyAPI`'s auth server.
5. If you click this link, and `ThirdPartyAPI`'s auth server sees your existing consent cookie for `MCP-Proxy`'s `client_id`, it might *skip* asking for your consent again.
6. `MCP-Proxy` might then be tricked into forwarding an authorization code (for `ThirdPartyAPI`) to the attacker, or an MCP authorization code that the attacker can use to impersonate you to `MCP-Proxy`.

**Mitigation (Primarily for MCP Server Developers):**

* MCP proxy servers using static client IDs for downstream services **must** obtain explicit user consent for *each client application or agent* connecting to them *before* initiating an OAuth flow with the third-party service. This means `MCP-Proxy` itself should show a consent screen.

**CrewAI User Implication:**

* Be cautious if an MCP server redirects you for multiple OAuth authentications, especially if it seems unexpected or if the permissions requested are overly broad.
* Prefer MCP servers that clearly delineate their own identity versus the third-party services they might proxy.

### Remote Transport Security (SSE & Streamable HTTP)

When connecting to remote MCP servers via Server-Sent Events (SSE) or Streamable HTTP, standard web security practices are essential.

### SSE Security Considerations

### a. DNS Rebinding Attacks (Especially for SSE)

<Critical>
  **Protect against DNS Rebinding Attacks.**
</Critical>

DNS rebinding allows an attacker-controlled website to bypass the same-origin policy and make requests to servers on the user's local network (e.g., `localhost`) or intranet. This is particularly risky if you run an MCP server locally (e.g., for development) and an agent in a browser-like environment (though less common for typical CrewAI backend setups) or if the MCP server is on an internal network.

**Mitigation Strategies for MCP Server Implementers:**

* **Validate `Origin` and `Host` Headers**: MCP servers (especially SSE ones) should validate the `Origin` and/or `Host` HTTP headers to ensure requests are coming from expected domains/clients.
* **Bind to `localhost` (127.0.0.1)**: When running MCP servers locally for development, bind them to `127.0.0.1` instead of `0.0.0.0`. This prevents them from being accessible from other machines on the network.
* **Authentication**: Require authentication for all connections to your MCP server if it's not intended for public anonymous access.

### b. Use HTTPS

* **Encrypt Data in Transit**: Always use HTTPS (HTTP Secure) for the URLs of remote MCP servers. This encrypts the communication between your CrewAI application and the MCP server, protecting against eavesdropping and man-in-the-middle attacks. `MCPServerAdapter` will respect the scheme (`http` or `https`) provided in the URL.

### c. Token Passthrough (Anti-Pattern)

This is primarily a concern for MCP server developers but understanding it helps in choosing secure servers.

"Token passthrough" is when an MCP server accepts an access token from your CrewAI agent (which might be a token for a *different* service, say `ServiceA`) and simply passes it through to another downstream API (`ServiceB`) without proper validation. Specifically, `ServiceB` (or the MCP server itself) should only accept tokens that were explicitly issued *for them* (i.e., the 'audience' claim in the token matches the server/service).

**Risks:**

* Bypasses security controls (like rate limiting or fine-grained permissions) on the MCP server or the downstream API.
* Breaks audit trails and accountability.
* Allows misuse of stolen tokens.

**Mitigation (For MCP Server Developers):**

* MCP servers **MUST NOT** accept tokens that were not explicitly issued for them. They must validate the token's audience claim.

**CrewAI User Implication:**

* While not directly controllable by the user, this highlights the importance of connecting to well-designed MCP servers that adhere to security best practices.

#### Authentication and Authorization

* **Verify Identity**: If the MCP server provides sensitive tools or access to private data, it MUST implement strong authentication mechanisms to verify the identity of the client (your CrewAI application). This could involve API keys, OAuth tokens, or other standard methods.
* **Principle of Least Privilege**: Ensure the credentials used by `MCPServerAdapter` (if any) have only the necessary permissions to access the required tools.

### d. Input Validation and Sanitization

* **Input Validation is Critical**: MCP servers **must** rigorously validate all inputs received from agents *before* processing them or passing them to tools. This is a primary defense against many common vulnerabilities:
  * **Command Injection:** If a tool constructs shell commands, SQL queries, or other interpreted language statements based on input, the server must meticulously sanitize this input to prevent malicious commands from being injected and executed.
  * **Path Traversal:** If a tool accesses files based on input parameters, the server must validate and sanitize these paths to prevent access to unauthorized files or directories (e.g., by blocking `../` sequences).
  * **Data Type & Range Checks:** Servers must ensure that input data conforms to the expected data types (e.g., string, number, boolean) and falls within acceptable ranges or adheres to defined formats (e.g., regex for URLs).
  * **JSON Schema Validation:** All tool parameters should be strictly validated against their defined JSON schema. This helps catch malformed requests early.
* **Client-Side Awareness**: While server-side validation is paramount, as a CrewAI user, be mindful of the data your agents are constructed to send to MCP tools, especially if interacting with less-trusted or new MCP servers.

### e. Rate Limiting and Resource Management

* **Prevent Abuse**: MCP servers should implement rate limiting to prevent abuse, whether intentional (Denial of Service attacks) or unintentional (e.g., a misconfigured agent making too many requests).
* **Client-Side Retries**: Implement sensible retry logic in your CrewAI tasks if transient network issues or server rate limits are expected, but avoid aggressive retries that could exacerbate server load.

## 4. Secure MCP Server Implementation Advice (For Developers)

If you are developing an MCP server that CrewAI agents might connect to, consider these best practices in addition to the points above:

* **Follow Secure Coding Practices**: Adhere to standard secure coding principles for your chosen language and framework (e.g., OWASP Top 10).
* **Principle of Least Privilege**: Ensure the process running the MCP server (especially for `Stdio`) has only the minimum necessary permissions. Tools themselves should also operate with the least privilege required to perform their function.
* **Dependency Management**: Keep all server-side dependencies, including operating system packages, language runtimes, and third-party libraries, up-to-date to patch known vulnerabilities. Use tools to scan for vulnerable dependencies.
* **Secure Defaults**: Design your server and its tools to be secure by default. For example, features that could be risky should be off by default or require explicit opt-in with clear warnings.
* **Access Control for Tools**: Implement robust mechanisms to control which authenticated and authorized agents or users can access specific tools, especially those that are powerful, sensitive, or incur costs.
* **Secure Error Handling**: Servers should not expose detailed internal error messages, stack traces, or debugging information to the client, as these can reveal internal workings or potential vulnerabilities. Log errors comprehensively on the server-side for diagnostics.
* **Comprehensive Logging and Monitoring**: Implement detailed logging of security-relevant events (e.g., authentication attempts, tool invocations, errors, authorization changes). Monitor these logs for suspicious activity or abuse patterns.
* **Adherence to MCP Authorization Spec**: If implementing authentication and authorization, strictly follow the [MCP Authorization specification](https://modelcontextprotocol.io/specification/draft/basic/authorization) and relevant [OAuth 2.0 security best practices](https://datatracker.ietf.org/doc/html/rfc9700).
* **Regular Security Audits**: If your MCP server handles sensitive data, performs critical operations, or is publicly exposed, consider periodic security audits by qualified professionals.

## 5. Further Reading

For more detailed information on MCP security, refer to the official documentation:

* **[MCP Transport Security](https://modelcontextprotocol.io/docs/concepts/transports#security-considerations)**

By understanding these security considerations and implementing best practices, you can safely leverage the power of MCP servers in your CrewAI projects.
These are by no means exhaustive, but they cover the most common and critical security concerns.
The threats will continue to evolve, so it's important to stay informed and adapt your security measures accordingly.


# SSE Transport
Source: https://docs.crewai.com/en/mcp/sse

Learn how to connect CrewAI to remote MCP servers using Server-Sent Events (SSE) for real-time communication.

## Overview

Server-Sent Events (SSE) provide a standard way for a web server to send updates to a client over a single, long-lived HTTP connection. In the context of MCP, SSE is used for remote servers to stream data (like tool responses) to your CrewAI application in real-time.

## Key Concepts

* **Remote Servers**: SSE is suitable for MCP servers hosted remotely.
* **Unidirectional Stream**: Typically, SSE is a one-way communication channel from server to client.
* **`MCPServerAdapter` Configuration**: For SSE, you'll provide the server's URL and specify the transport type.

## Connecting via SSE

You can connect to an SSE-based MCP server using two main approaches for managing the connection lifecycle:

### 1. Fully Managed Connection (Recommended)

Using a Python context manager (`with` statement) is the recommended approach. It automatically handles establishing and closing the connection to the SSE MCP server.

```python theme={null}
from crewai import Agent, Task, Crew, Process
from crewai_tools import MCPServerAdapter

server_params = {
    "url": "http://localhost:8000/sse", # Replace with your actual SSE server URL
    "transport": "sse" 
}

# Using MCPServerAdapter with a context manager
try:
    with MCPServerAdapter(server_params) as tools:
        print(f"Available tools from SSE MCP server: {[tool.name for tool in tools]}")

        # Example: Using a tool from the SSE MCP server
        sse_agent = Agent(
            role="Remote Service User",
            goal="Utilize a tool provided by a remote SSE MCP server.",
            backstory="An AI agent that connects to external services via SSE.",
            tools=tools,
            reasoning=True,
            verbose=True,
        )

        sse_task = Task(
            description="Fetch real-time stock updates for 'AAPL' using an SSE tool.",
            expected_output="The latest stock price for AAPL.",
            agent=sse_agent,
            markdown=True
        )

        sse_crew = Crew(
            agents=[sse_agent],
            tasks=[sse_task],
            verbose=True,
            process=Process.sequential
        )
        
        if tools: # Only kickoff if tools were loaded
            result = sse_crew.kickoff() # Add inputs={'stock_symbol': 'AAPL'} if tool requires it
            print("\nCrew Task Result (SSE - Managed):\n", result)
        else:
            print("Skipping crew kickoff as tools were not loaded (check server connection).")

except Exception as e:
    print(f"Error connecting to or using SSE MCP server (Managed): {e}")
    print("Ensure the SSE MCP server is running and accessible at the specified URL.")

```

<Note>
  Replace `"http://localhost:8000/sse"` with the actual URL of your SSE MCP server.
</Note>

### 2. Manual Connection Lifecycle

If you need finer-grained control, you can manage the `MCPServerAdapter` connection lifecycle manually.

<Info>
  You **MUST** call `mcp_server_adapter.stop()` to ensure the connection is closed and resources are released. Using a `try...finally` block is highly recommended.
</Info>

```python theme={null}
from crewai import Agent, Task, Crew, Process
from crewai_tools import MCPServerAdapter

server_params = {
    "url": "http://localhost:8000/sse", # Replace with your actual SSE server URL
    "transport": "sse"
}

mcp_server_adapter = None 
try:
    mcp_server_adapter = MCPServerAdapter(server_params)
    mcp_server_adapter.start()
    tools = mcp_server_adapter.tools
    print(f"Available tools (manual SSE): {[tool.name for tool in tools]}")

    manual_sse_agent = Agent(
        role="Remote Data Analyst",
        goal="Analyze data fetched from a remote SSE MCP server using manual connection management.",
        backstory="An AI skilled in handling SSE connections explicitly.",
        tools=tools,
        verbose=True
    )
    
    analysis_task = Task(
        description="Fetch and analyze the latest user activity trends from the SSE server.",
        expected_output="A summary report of user activity trends.",
        agent=manual_sse_agent
    )
    
    analysis_crew = Crew(
        agents=[manual_sse_agent],
        tasks=[analysis_task],
        verbose=True,
        process=Process.sequential
    )
    
    result = analysis_crew.kickoff()
    print("\nCrew Task Result (SSE - Manual):\n", result)

except Exception as e:
    print(f"An error occurred during manual SSE MCP integration: {e}")
    print("Ensure the SSE MCP server is running and accessible.")
finally:
    if mcp_server_adapter and mcp_server_adapter.is_connected:
        print("Stopping SSE MCP server connection (manual)...")
        mcp_server_adapter.stop()  # **Crucial: Ensure stop is called**
    elif mcp_server_adapter:
        print("SSE MCP server adapter was not connected. No stop needed or start failed.")

```

## Security Considerations for SSE

<Warning>
  **DNS Rebinding Attacks**: SSE transports can be vulnerable to DNS rebinding attacks if the MCP server is not properly secured. This could allow malicious websites to interact with local or intranet-based MCP servers.
</Warning>

To mitigate this risk:

* MCP server implementations should **validate `Origin` headers** on incoming SSE connections.
* When running local SSE MCP servers for development, **bind only to `localhost` (`127.0.0.1`)** rather than all network interfaces (`0.0.0.0`).
* Implement **proper authentication** for all SSE connections if they expose sensitive tools or data.

For a comprehensive overview of security best practices, please refer to our [Security Considerations](./security.mdx) page and the official [MCP Transport Security documentation](https://modelcontextprotocol.io/docs/concepts/transports#security-considerations).


# Stdio Transport
Source: https://docs.crewai.com/en/mcp/stdio

Learn how to connect CrewAI to local MCP servers using the Stdio (Standard Input/Output) transport mechanism.

## Overview

The Stdio (Standard Input/Output) transport is designed for connecting `MCPServerAdapter` to local MCP servers that communicate over their standard input and output streams. This is typically used when the MCP server is a script or executable running on the same machine as your CrewAI application.

## Key Concepts

* **Local Execution**: Stdio transport manages a locally running process for the MCP server.
* **`StdioServerParameters`**: This class from the `mcp` library is used to configure the command, arguments, and environment variables for launching the Stdio server.

## Connecting via Stdio

You can connect to an Stdio-based MCP server using two main approaches for managing the connection lifecycle:

### 1. Fully Managed Connection (Recommended)

Using a Python context manager (`with` statement) is the recommended approach. It automatically handles starting the MCP server process and stopping it when the context is exited.

```python theme={null}
from crewai import Agent, Task, Crew, Process
from crewai_tools import MCPServerAdapter
from mcp import StdioServerParameters
import os

# Create a StdioServerParameters object
server_params=StdioServerParameters(
    command="python3", 
    args=["servers/your_stdio_server.py"],
    env={"UV_PYTHON": "3.12", **os.environ},
)

with MCPServerAdapter(server_params) as tools:
    print(f"Available tools from Stdio MCP server: {[tool.name for tool in tools]}")

    # Example: Using the tools from the Stdio MCP server in a CrewAI Agent
    research_agent = Agent(
        role="Local Data Processor",
        goal="Process data using a local Stdio-based tool.",
        backstory="An AI that leverages local scripts via MCP for specialized tasks.",
        tools=tools,
        reasoning=True,
        verbose=True,
    )
    
    processing_task = Task(
        description="Process the input data file 'data.txt' and summarize its contents.",
        expected_output="A summary of the processed data.",
        agent=research_agent,
        markdown=True
    )
    
    data_crew = Crew(
        agents=[research_agent],
        tasks=[processing_task],
        verbose=True,
        process=Process.sequential 
    )
   
    result = data_crew.kickoff()
    print("\nCrew Task Result (Stdio - Managed):\n", result)

```

### 2. Manual Connection Lifecycle

If you need finer-grained control over when the Stdio MCP server process is started and stopped, you can manage the `MCPServerAdapter` lifecycle manually.

<Info>
  You **MUST** call `mcp_server_adapter.stop()` to ensure the server process is terminated and resources are released. Using a `try...finally` block is highly recommended.
</Info>

```python theme={null}
from crewai import Agent, Task, Crew, Process
from crewai_tools import MCPServerAdapter
from mcp import StdioServerParameters
import os

# Create a StdioServerParameters object
stdio_params=StdioServerParameters(
    command="python3", 
    args=["servers/your_stdio_server.py"],
    env={"UV_PYTHON": "3.12", **os.environ},
)

mcp_server_adapter = MCPServerAdapter(server_params=stdio_params)
try:
    mcp_server_adapter.start()  # Manually start the connection and server process
    tools = mcp_server_adapter.tools
    print(f"Available tools (manual Stdio): {[tool.name for tool in tools]}")

    # Example: Using the tools with your Agent, Task, Crew setup
    manual_agent = Agent(
        role="Local Task Executor",
        goal="Execute a specific local task using a manually managed Stdio tool.",
        backstory="An AI proficient in controlling local processes via MCP.",
        tools=tools,
        verbose=True
    )
    
    manual_task = Task(
        description="Execute the 'perform_analysis' command via the Stdio tool.",
        expected_output="Results of the analysis.",
        agent=manual_agent
    )
    
    manual_crew = Crew(
        agents=[manual_agent],
        tasks=[manual_task],
        verbose=True,
        process=Process.sequential
    )
        
       
    result = manual_crew.kickoff() # Actual inputs depend on your tool
    print("\nCrew Task Result (Stdio - Manual):\n", result)
            
except Exception as e:
    print(f"An error occurred during manual Stdio MCP integration: {e}")
finally:
    if mcp_server_adapter and mcp_server_adapter.is_connected: # Check if connected before stopping
        print("Stopping Stdio MCP server connection (manual)...")
        mcp_server_adapter.stop()  # **Crucial: Ensure stop is called**
    elif mcp_server_adapter: # If adapter exists but not connected (e.g. start failed)
        print("Stdio MCP server adapter was not connected. No stop needed or start failed.")

```

Remember to replace placeholder paths and commands with your actual Stdio server details. The `env` parameter in `StdioServerParameters` can
be used to set environment variables for the server process, which can be useful for configuring its behavior or providing necessary paths (like `PYTHONPATH`).


# Streamable HTTP Transport
Source: https://docs.crewai.com/en/mcp/streamable-http

Learn how to connect CrewAI to remote MCP servers using the flexible Streamable HTTP transport.

## Overview

Streamable HTTP transport provides a flexible way to connect to remote MCP servers. It's often built upon HTTP and can support various communication patterns, including request-response and streaming, sometimes utilizing Server-Sent Events (SSE) for server-to-client streams within a broader HTTP interaction.

## Key Concepts

* **Remote Servers**: Designed for MCP servers hosted remotely.
* **Flexibility**: Can support more complex interaction patterns than plain SSE, potentially including bi-directional communication if the server implements it.
* **`MCPServerAdapter` Configuration**: You'll need to provide the server's base URL for MCP communication and specify `"streamable-http"` as the transport type.

## Connecting via Streamable HTTP

You have two primary methods for managing the connection lifecycle with a Streamable HTTP MCP server:

### 1. Fully Managed Connection (Recommended)

The recommended approach is to use a Python context manager (`with` statement), which handles the connection's setup and teardown automatically.

```python theme={null}
from crewai import Agent, Task, Crew, Process
from crewai_tools import MCPServerAdapter

server_params = {
    "url": "http://localhost:8001/mcp", # Replace with your actual Streamable HTTP server URL
    "transport": "streamable-http"
}

try:
    with MCPServerAdapter(server_params) as tools:
        print(f"Available tools from Streamable HTTP MCP server: {[tool.name for tool in tools]}")

        http_agent = Agent(
            role="HTTP Service Integrator",
            goal="Utilize tools from a remote MCP server via Streamable HTTP.",
            backstory="An AI agent adept at interacting with complex web services.",
            tools=tools,
            verbose=True,
        )

        http_task = Task(
            description="Perform a complex data query using a tool from the Streamable HTTP server.",
            expected_output="The result of the complex data query.",
            agent=http_agent,
        )

        http_crew = Crew(
            agents=[http_agent],
            tasks=[http_task],
            verbose=True,
            process=Process.sequential
        )
        
        result = http_crew.kickoff() 
        print("\nCrew Task Result (Streamable HTTP - Managed):\n", result)

except Exception as e:
    print(f"Error connecting to or using Streamable HTTP MCP server (Managed): {e}")
    print("Ensure the Streamable HTTP MCP server is running and accessible at the specified URL.")

```

**Note:** Replace `"http://localhost:8001/mcp"` with the actual URL of your Streamable HTTP MCP server.

### 2. Manual Connection Lifecycle

For scenarios requiring more explicit control, you can manage the `MCPServerAdapter` connection manually.

<Info>
  It is **critical** to call `mcp_server_adapter.stop()` when you are done to close the connection and free up resources. A `try...finally` block is the safest way to ensure this.
</Info>

```python theme={null}
from crewai import Agent, Task, Crew, Process
from crewai_tools import MCPServerAdapter

server_params = {
    "url": "http://localhost:8001/mcp", # Replace with your actual Streamable HTTP server URL
    "transport": "streamable-http"
}

mcp_server_adapter = None 
try:
    mcp_server_adapter = MCPServerAdapter(server_params)
    mcp_server_adapter.start()
    tools = mcp_server_adapter.tools
    print(f"Available tools (manual Streamable HTTP): {[tool.name for tool in tools]}")

    manual_http_agent = Agent(
        role="Advanced Web Service User",
        goal="Interact with an MCP server using manually managed Streamable HTTP connections.",
        backstory="An AI specialist in fine-tuning HTTP-based service integrations.",
        tools=tools,
        verbose=True
    )
    
    data_processing_task = Task(
        description="Submit data for processing and retrieve results via Streamable HTTP.",
        expected_output="Processed data or confirmation.",
        agent=manual_http_agent
    )
    
    data_crew = Crew(
        agents=[manual_http_agent],
        tasks=[data_processing_task],
        verbose=True,
        process=Process.sequential
    )
    
    result = data_crew.kickoff()
    print("\nCrew Task Result (Streamable HTTP - Manual):\n", result)

except Exception as e:
    print(f"An error occurred during manual Streamable HTTP MCP integration: {e}")
    print("Ensure the Streamable HTTP MCP server is running and accessible.")
finally:
    if mcp_server_adapter and mcp_server_adapter.is_connected:
        print("Stopping Streamable HTTP MCP server connection (manual)...")
        mcp_server_adapter.stop()  # **Crucial: Ensure stop is called**
    elif mcp_server_adapter:
        print("Streamable HTTP MCP server adapter was not connected. No stop needed or start failed.")
```

## Security Considerations

When using Streamable HTTP transport, general web security best practices are paramount:

* **Use HTTPS**: Always prefer HTTPS (HTTP Secure) for your MCP server URLs to encrypt data in transit.
* **Authentication**: Implement robust authentication mechanisms if your MCP server exposes sensitive tools or data.
* **Input Validation**: Ensure your MCP server validates all incoming requests and parameters.

For a comprehensive guide on securing your MCP integrations, please refer to our [Security Considerations](./security.mdx) page and the official [MCP Transport Security documentation](https://modelcontextprotocol.io/docs/concepts/transports#security-considerations).


# Quickstart
Source: https://docs.crewai.com/en/quickstart

Build your first AI agent with CrewAI in under 5 minutes.

## Build your first CrewAI Agent

Let's create a simple crew that will help us `research` and `report` on the `latest AI developments` for a given topic or subject.

Before we proceed, make sure you have finished installing CrewAI.
If you haven't installed them yet, you can do so by following the [installation guide](/en/installation).

Follow the steps below to get Crewing! 🚣‍♂️

<Steps>
  <Step title="Create your crew">
    Create a new crew project by running the following command in your terminal.
    This will create a new directory called `latest-ai-development` with the basic structure for your crew.

    <CodeGroup>
      ```shell Terminal theme={null}
      crewai create crew latest-ai-development
      ```
    </CodeGroup>
  </Step>

  <Step title="Navigate to your new crew project">
    <CodeGroup>
      ```shell Terminal theme={null}
      cd latest_ai_development
      ```
    </CodeGroup>
  </Step>

  <Step title="Modify your `agents.yaml` file">
    <Tip>
      You can also modify the agents as needed to fit your use case or copy and paste as is to your project.
      Any variable interpolated in your `agents.yaml` and `tasks.yaml` files like `{topic}` will be replaced by the value of the variable in the `main.py` file.
    </Tip>

    ```yaml agents.yaml theme={null}
    # src/latest_ai_development/config/agents.yaml
    researcher:
      role: >
        {topic} Senior Data Researcher
      goal: >
        Uncover cutting-edge developments in {topic}
      backstory: >
        You're a seasoned researcher with a knack for uncovering the latest
        developments in {topic}. Known for your ability to find the most relevant
        information and present it in a clear and concise manner.

    reporting_analyst:
      role: >
        {topic} Reporting Analyst
      goal: >
        Create detailed reports based on {topic} data analysis and research findings
      backstory: >
        You're a meticulous analyst with a keen eye for detail. You're known for
        your ability to turn complex data into clear and concise reports, making
        it easy for others to understand and act on the information you provide.
    ```
  </Step>

  <Step title="Modify your `tasks.yaml` file">
    ````yaml tasks.yaml theme={null}
    # src/latest_ai_development/config/tasks.yaml
    research_task:
      description: >
        Conduct a thorough research about {topic}
        Make sure you find any interesting and relevant information given
        the current year is 2025.
      expected_output: >
        A list with 10 bullet points of the most relevant information about {topic}
      agent: researcher

    reporting_task:
      description: >
        Review the context you got and expand each topic into a full section for a report.
        Make sure the report is detailed and contains any and all relevant information.
      expected_output: >
        A fully fledge reports with the mains topics, each with a full section of information.
        Formatted as markdown without '```'
      agent: reporting_analyst
      output_file: report.md
    ````
  </Step>

  <Step title="Modify your `crew.py` file">
    ```python crew.py theme={null}
    # src/latest_ai_development/crew.py
    from crewai import Agent, Crew, Process, Task
    from crewai.project import CrewBase, agent, crew, task
    from crewai_tools import SerperDevTool
    from crewai.agents.agent_builder.base_agent import BaseAgent
    from typing import List

    @CrewBase
    class LatestAiDevelopmentCrew():
      """LatestAiDevelopment crew"""

      agents: List[BaseAgent]
      tasks: List[Task]

      @agent
      def researcher(self) -> Agent:
        return Agent(
          config=self.agents_config['researcher'], # type: ignore[index]
          verbose=True,
          tools=[SerperDevTool()]
        )

      @agent
      def reporting_analyst(self) -> Agent:
        return Agent(
          config=self.agents_config['reporting_analyst'], # type: ignore[index]
          verbose=True
        )

      @task
      def research_task(self) -> Task:
        return Task(
          config=self.tasks_config['research_task'], # type: ignore[index]
        )

      @task
      def reporting_task(self) -> Task:
        return Task(
          config=self.tasks_config['reporting_task'], # type: ignore[index]
          output_file='output/report.md' # This is the file that will be contain the final report.
        )

      @crew
      def crew(self) -> Crew:
        """Creates the LatestAiDevelopment crew"""
        return Crew(
          agents=self.agents, # Automatically created by the @agent decorator
          tasks=self.tasks, # Automatically created by the @task decorator
          process=Process.sequential,
          verbose=True,
        )
    ```
  </Step>

  <Step title="[Optional] Add before and after crew functions">
    ```python crew.py theme={null}
    # src/latest_ai_development/crew.py
    from crewai import Agent, Crew, Process, Task
    from crewai.project import CrewBase, agent, crew, task, before_kickoff, after_kickoff
    from crewai_tools import SerperDevTool

    @CrewBase
    class LatestAiDevelopmentCrew():
      """LatestAiDevelopment crew"""

      @before_kickoff
      def before_kickoff_function(self, inputs):
        print(f"Before kickoff function with inputs: {inputs}")
        return inputs # You can return the inputs or modify them as needed

      @after_kickoff
      def after_kickoff_function(self, result):
        print(f"After kickoff function with result: {result}")
        return result # You can return the result or modify it as needed

      # ... remaining code
    ```
  </Step>

  <Step title="Feel free to pass custom inputs to your crew">
    For example, you can pass the `topic` input to your crew to customize the research and reporting.

    ```python main.py theme={null}
    #!/usr/bin/env python
    # src/latest_ai_development/main.py
    import sys
    from latest_ai_development.crew import LatestAiDevelopmentCrew

    def run():
      """
      Run the crew.
      """
      inputs = {
        'topic': 'AI Agents'
      }
      LatestAiDevelopmentCrew().crew().kickoff(inputs=inputs)
    ```
  </Step>

  <Step title="Set your environment variables">
    Before running your crew, make sure you have the following keys set as environment variables in your `.env` file:

    * A [Serper.dev](https://serper.dev/) API key: `SERPER_API_KEY=YOUR_KEY_HERE`
    * The configuration for your choice of model, such as an API key. See the
      [LLM setup guide](/en/concepts/llms#setting-up-your-llm) to learn how to configure models from any provider.
  </Step>

  <Step title="Lock and install the dependencies">
    * Lock the dependencies and install them by using the CLI command:
      <CodeGroup>
        ```shell Terminal theme={null}
        crewai install
        ```
      </CodeGroup>
    * If you have additional packages that you want to install, you can do so by running:
      <CodeGroup>
        ```shell Terminal theme={null}
        uv add <package-name>
        ```
      </CodeGroup>
  </Step>

  <Step title="Run your crew">
    * To run your crew, execute the following command in the root of your project:
      <CodeGroup>
        ```bash Terminal theme={null}
        crewai run
        ```
      </CodeGroup>
  </Step>

  <Step title="Enterprise Alternative: Create in Crew Studio">
    For CrewAI AMP users, you can create the same crew without writing code:

    1. Log in to your CrewAI AMP account (create a free account at [app.crewai.com](https://app.crewai.com))
    2. Open Crew Studio
    3. Type what is the automation you're trying to build
    4. Create your tasks visually and connect them in sequence
    5. Configure your inputs and click "Download Code" or "Deploy"

       <img alt="Crew Studio Quickstart" />

    <Card title="Try CrewAI AMP" icon="rocket" href="https://app.crewai.com">
      Start your free account at CrewAI AMP
    </Card>
  </Step>

  <Step title="View your final report">
    You should see the output in the console and the `report.md` file should be created in the root of your project with the final report.

    Here's an example of what the report should look like:

    <CodeGroup>
      ```markdown output/report.md theme={null}
      # Comprehensive Report on the Rise and Impact of AI Agents in 2025

      ## 1. Introduction to AI Agents
      In 2025, Artificial Intelligence (AI) agents are at the forefront of innovation across various industries. As intelligent systems that can perform tasks typically requiring human cognition, AI agents are paving the way for significant advancements in operational efficiency, decision-making, and overall productivity within sectors like Human Resources (HR) and Finance. This report aims to detail the rise of AI agents, their frameworks, applications, and potential implications on the workforce.

      ## 2. Benefits of AI Agents
      AI agents bring numerous advantages that are transforming traditional work environments. Key benefits include:

      - **Task Automation**: AI agents can carry out repetitive tasks such as data entry, scheduling, and payroll processing without human intervention, greatly reducing the time and resources spent on these activities.
      - **Improved Efficiency**: By quickly processing large datasets and performing analyses that would take humans significantly longer, AI agents enhance operational efficiency. This allows teams to focus on strategic tasks that require higher-level thinking.
      - **Enhanced Decision-Making**: AI agents can analyze trends and patterns in data, provide insights, and even suggest actions, helping stakeholders make informed decisions based on factual data rather than intuition alone.

      ## 3. Popular AI Agent Frameworks
      Several frameworks have emerged to facilitate the development of AI agents, each with its own unique features and capabilities. Some of the most popular frameworks include:

      - **Autogen**: A framework designed to streamline the development of AI agents through automation of code generation.
      - **Semantic Kernel**: Focuses on natural language processing and understanding, enabling agents to comprehend user intentions better.
      - **Promptflow**: Provides tools for developers to create conversational agents that can navigate complex interactions seamlessly.
      - **Langchain**: Specializes in leveraging various APIs to ensure agents can access and utilize external data effectively.
      - **CrewAI**: Aimed at collaborative environments, CrewAI strengthens teamwork by facilitating communication through AI-driven insights.
      - **MemGPT**: Combines memory-optimized architectures with generative capabilities, allowing for more personalized interactions with users.

      These frameworks empower developers to build versatile and intelligent agents that can engage users, perform advanced analytics, and execute various tasks aligned with organizational goals.

      ## 4. AI Agents in Human Resources
      AI agents are revolutionizing HR practices by automating and optimizing key functions:

      - **Recruiting**: AI agents can screen resumes, schedule interviews, and even conduct initial assessments, thus accelerating the hiring process while minimizing biases.
      - **Succession Planning**: AI systems analyze employee performance data and potential, helping organizations identify future leaders and plan appropriate training.
      - **Employee Engagement**: Chatbots powered by AI can facilitate feedback loops between employees and management, promoting an open culture and addressing concerns promptly.

      As AI continues to evolve, HR departments leveraging these agents can realize substantial improvements in both efficiency and employee satisfaction.

      ## 5. AI Agents in Finance
      The finance sector is seeing extensive integration of AI agents that enhance financial practices:

      - **Expense Tracking**: Automated systems manage and monitor expenses, flagging anomalies and offering recommendations based on spending patterns.
      - **Risk Assessment**: AI models assess credit risk and uncover potential fraud by analyzing transaction data and behavioral patterns.
      - **Investment Decisions**: AI agents provide stock predictions and analytics based on historical data and current market conditions, empowering investors with informative insights.

      The incorporation of AI agents into finance is fostering a more responsive and risk-aware financial landscape.

      ## 6. Market Trends and Investments
      The growth of AI agents has attracted significant investment, especially amidst the rising popularity of chatbots and generative AI technologies. Companies and entrepreneurs are eager to explore the potential of these systems, recognizing their ability to streamline operations and improve customer engagement.

      Conversely, corporations like Microsoft are taking strides to integrate AI agents into their product offerings, with enhancements to their Copilot 365 applications. This strategic move emphasizes the importance of AI literacy in the modern workplace and indicates the stabilizing of AI agents as essential business tools.

      ## 7. Future Predictions and Implications
      Experts predict that AI agents will transform essential aspects of work life. As we look toward the future, several anticipated changes include:

      - Enhanced integration of AI agents across all business functions, creating interconnected systems that leverage data from various departmental silos for comprehensive decision-making.
      - Continued advancement of AI technologies, resulting in smarter, more adaptable agents capable of learning and evolving from user interactions.
      - Increased regulatory scrutiny to ensure ethical use, especially concerning data privacy and employee surveillance as AI agents become more prevalent.

      To stay competitive and harness the full potential of AI agents, organizations must remain vigilant about latest developments in AI technology and consider continuous learning and adaptation in their strategic planning.

      ## 8. Conclusion
      The emergence of AI agents is undeniably reshaping the workplace landscape in 5. With their ability to automate tasks, enhance efficiency, and improve decision-making, AI agents are critical in driving operational success. Organizations must embrace and adapt to AI developments to thrive in an increasingly digital business environment.
      ```
    </CodeGroup>
  </Step>
</Steps>

<Check>
  Congratulations!

  You have successfully set up your crew project and are ready to start building your own agentic workflows!
</Check>

### Note on Consistency in Naming

The names you use in your YAML files (`agents.yaml` and `tasks.yaml`) should match the method names in your Python code.
For example, you can reference the agent for specific tasks from `tasks.yaml` file.
This naming consistency allows CrewAI to automatically link your configurations with your code; otherwise, your task won't recognize the reference properly.

#### Example References

<Tip>
  Note how we use the same name for the agent in the `agents.yaml`
  (`email_summarizer`) file as the method name in the `crew.py`
  (`email_summarizer`) file.
</Tip>

```yaml agents.yaml theme={null}
email_summarizer:
  role: >
    Email Summarizer
  goal: >
    Summarize emails into a concise and clear summary
  backstory: >
    You will create a 5 bullet point summary of the report
  llm: provider/model-id # Add your choice of model here
```

<Tip>
  Note how we use the same name for the task in the `tasks.yaml`
  (`email_summarizer_task`) file as the method name in the `crew.py`
  (`email_summarizer_task`) file.
</Tip>

```yaml tasks.yaml theme={null}
email_summarizer_task:
  description: >
    Summarize the email into a 5 bullet point summary
  expected_output: >
    A 5 bullet point summary of the email
  agent: email_summarizer
  context:
    - reporting_task
    - research_task
```

## Deploying Your Crew

The easiest way to deploy your crew to production is through [CrewAI AMP](http://app.crewai.com).

Watch this video tutorial for a step-by-step demonstration of deploying your crew to [CrewAI AMP](http://app.crewai.com) using the CLI.

<iframe title="CrewAI Deployment Guide" />

<CardGroup>
  <Card title="Deploy on Enterprise" icon="rocket" href="http://app.crewai.com">
    Get started with CrewAI AMP and deploy your crew in a production environment
    with just a few clicks.
  </Card>

  <Card title="Join the Community" icon="comments" href="https://community.crewai.com">
    Join our open source community to discuss ideas, share your projects, and
    connect with other CrewAI developers.
  </Card>
</CardGroup>


# AI Mind Tool
Source: https://docs.crewai.com/en/tools/ai-ml/aimindtool

The `AIMindTool` is designed to query data sources in natural language.

# `AIMindTool`

## Description

The `AIMindTool` is a wrapper around [AI-Minds](https://mindsdb.com/minds) provided by [MindsDB](https://mindsdb.com/). It allows you to query data sources in natural language by simply configuring their connection parameters. This tool is useful when you need answers to questions from your data stored in various data sources including PostgreSQL, MySQL, MariaDB, ClickHouse, Snowflake, and Google BigQuery.

Minds are AI systems that work similarly to large language models (LLMs) but go beyond by answering any question from any data. This is accomplished by:

* Selecting the most relevant data for an answer using parametric search
* Understanding the meaning and providing responses within the correct context through semantic search
* Delivering precise answers by analyzing data and using machine learning (ML) models

## Installation

To incorporate this tool into your project, you need to install the Minds SDK:

```shell theme={null}
uv add minds-sdk
```

## Steps to Get Started

To effectively use the `AIMindTool`, follow these steps:

1. **Package Installation**: Confirm that the `crewai[tools]` and `minds-sdk` packages are installed in your Python environment.
2. **API Key Acquisition**: Sign up for a Minds account [here](https://mdb.ai/register), and obtain an API key.
3. **Environment Configuration**: Store your obtained API key in an environment variable named `MINDS_API_KEY` to facilitate its use by the tool.

## Example

The following example demonstrates how to initialize the tool and execute a query:

```python Code theme={null}
from crewai_tools import AIMindTool

# Initialize the AIMindTool
aimind_tool = AIMindTool(
    datasources=[
        {
            "description": "house sales data",
            "engine": "postgres",
            "connection_data": {
                "user": "demo_user",
                "password": "demo_password",
                "host": "samples.mindsdb.com",
                "port": 5432,
                "database": "demo",
                "schema": "demo_data"
            },
            "tables": ["house_sales"]
        }
    ]
)

# Run a natural language query
result = aimind_tool.run("How many 3 bedroom houses were sold in 2008?")
print(result)
```

## Parameters

The `AIMindTool` accepts the following parameters:

* **api\_key**: Optional. Your Minds API key. If not provided, it will be read from the `MINDS_API_KEY` environment variable.
* **datasources**: A list of dictionaries, each containing the following keys:
  * **description**: A description of the data contained in the datasource.
  * **engine**: The engine (or type) of the datasource.
  * **connection\_data**: A dictionary containing the connection parameters for the datasource.
  * **tables**: A list of tables that the data source will use. This is optional and can be omitted if all tables in the data source are to be used.

A list of supported data sources and their connection parameters can be found [here](https://docs.mdb.ai/docs/data_sources).

## Agent Integration Example

Here's how to integrate the `AIMindTool` with a CrewAI agent:

```python Code theme={null}
from crewai import Agent
from crewai.project import agent
from crewai_tools import AIMindTool

# Initialize the tool
aimind_tool = AIMindTool(
    datasources=[
        {
            "description": "sales data",
            "engine": "postgres",
            "connection_data": {
                "user": "your_user",
                "password": "your_password",
                "host": "your_host",
                "port": 5432,
                "database": "your_db",
                "schema": "your_schema"
            },
            "tables": ["sales"]
        }
    ]
)

# Define an agent with the AIMindTool
@agent
def data_analyst(self) -> Agent:
    return Agent(
        config=self.agents_config["data_analyst"],
        allow_delegation=False,
        tools=[aimind_tool]
    )
```

## Conclusion

The `AIMindTool` provides a powerful way to query your data sources using natural language, making it easier to extract insights without writing complex SQL queries. By connecting to various data sources and leveraging AI-Minds technology, this tool enables agents to access and analyze data efficiently.


# Code Interpreter
Source: https://docs.crewai.com/en/tools/ai-ml/codeinterpretertool

The `CodeInterpreterTool` is a powerful tool designed for executing Python 3 code within a secure, isolated environment.

# `CodeInterpreterTool`

## Description

The `CodeInterpreterTool` enables CrewAI agents to execute Python 3 code that they generate autonomously. This functionality is particularly valuable as it allows agents to create code, execute it, obtain the results, and utilize that information to inform subsequent decisions and actions.

There are several ways to use this tool:

### Docker Container (Recommended)

This is the primary option. The code runs in a secure, isolated Docker container, ensuring safety regardless of its content.
Make sure Docker is installed and running on your system. If you don’t have it, you can install it from [here](https://docs.docker.com/get-docker/).

### Sandbox environment

If Docker is unavailable — either not installed or not accessible for any reason — the code will be executed in a restricted Python environment - called sandbox.
This environment is very limited, with strict restrictions on many modules and built-in functions.

### Unsafe Execution

**NOT RECOMMENDED FOR PRODUCTION**
This mode allows execution of any Python code, including dangerous calls to `sys, os..` and similar modules. [Check out](/en/tools/ai-ml/codeinterpretertool#enabling-unsafe-mode) how to enable this mode

## Logging

The `CodeInterpreterTool` logs the selected execution strategy to STDOUT

## Installation

To use this tool, you need to install the CrewAI tools package:

```shell theme={null}
pip install 'crewai[tools]'
```

## Example

The following example demonstrates how to use the `CodeInterpreterTool` with a CrewAI agent:

```python Code theme={null}
from crewai import Agent, Task, Crew, Process
from crewai_tools import CodeInterpreterTool

# Initialize the tool
code_interpreter = CodeInterpreterTool()

# Define an agent that uses the tool
programmer_agent = Agent(
    role="Python Programmer",
    goal="Write and execute Python code to solve problems",
    backstory="An expert Python programmer who can write efficient code to solve complex problems.",
    tools=[code_interpreter],
    verbose=True,
)

# Example task to generate and execute code
coding_task = Task(
    description="Write a Python function to calculate the Fibonacci sequence up to the 10th number and print the result.",
    expected_output="The Fibonacci sequence up to the 10th number.",
    agent=programmer_agent,
)

# Create and run the crew
crew = Crew(
    agents=[programmer_agent],
    tasks=[coding_task],
    verbose=True,
    process=Process.sequential,
)
result = crew.kickoff()
```

You can also enable code execution directly when creating an agent:

```python Code theme={null}
from crewai import Agent

# Create an agent with code execution enabled
programmer_agent = Agent(
    role="Python Programmer",
    goal="Write and execute Python code to solve problems",
    backstory="An expert Python programmer who can write efficient code to solve complex problems.",
    allow_code_execution=True,  # This automatically adds the CodeInterpreterTool
    verbose=True,
)
```

### Enabling `unsafe_mode`

```python Code theme={null}
from crewai_tools import CodeInterpreterTool

code = """
import os
os.system("ls -la")
"""

CodeInterpreterTool(unsafe_mode=True).run(code=code)
```

## Parameters

The `CodeInterpreterTool` accepts the following parameters during initialization:

* **user\_dockerfile\_path**: Optional. Path to a custom Dockerfile to use for the code interpreter container.
* **user\_docker\_base\_url**: Optional. URL to the Docker daemon to use for running the container.
* **unsafe\_mode**: Optional. Whether to run code directly on the host machine instead of in a Docker container or sandbox. Default is `False`. Use with caution!
* **default\_image\_tag**: Optional. Default Docker image tag. Default is `code-interpreter:latest`

When using the tool with an agent, the agent will need to provide:

* **code**: Required. The Python 3 code to execute.
* **libraries\_used**: Optional. A list of libraries used in the code that need to be installed. Default is `[]`

## Agent Integration Example

Here's a more detailed example of how to integrate the `CodeInterpreterTool` with a CrewAI agent:

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import CodeInterpreterTool

# Initialize the tool
code_interpreter = CodeInterpreterTool()

# Define an agent that uses the tool
data_analyst = Agent(
    role="Data Analyst",
    goal="Analyze data using Python code",
    backstory="""You are an expert data analyst who specializes in using Python
    to analyze and visualize data. You can write efficient code to process
    large datasets and extract meaningful insights.""",
    tools=[code_interpreter],
    verbose=True,
)

# Create a task for the agent
analysis_task = Task(
    description="""
    Write Python code to:
    1. Generate a random dataset of 100 points with x and y coordinates
    2. Calculate the correlation coefficient between x and y
    3. Create a scatter plot of the data
    4. Print the correlation coefficient and save the plot as 'scatter.png'

    Make sure to handle any necessary imports and print the results.
    """,
    expected_output="The correlation coefficient and confirmation that the scatter plot has been saved.",
    agent=data_analyst,
)

# Run the task
crew = Crew(
    agents=[data_analyst],
    tasks=[analysis_task],
    verbose=True,
    process=Process.sequential,
)
result = crew.kickoff()
```

## Implementation Details

The `CodeInterpreterTool` uses Docker to create a secure environment for code execution:

```python Code theme={null}
class CodeInterpreterTool(BaseTool):
    name: str = "Code Interpreter"
    description: str = "Interprets Python3 code strings with a final print statement."
    args_schema: Type[BaseModel] = CodeInterpreterSchema
    default_image_tag: str = "code-interpreter:latest"

    def _run(self, **kwargs) -> str:
        code = kwargs.get("code", self.code)
        libraries_used = kwargs.get("libraries_used", [])

        if self.unsafe_mode:
            return self.run_code_unsafe(code, libraries_used)
        else:
            return self.run_code_safety(code, libraries_used)
```

The tool performs the following steps:

1. Verifies that the Docker image exists or builds it if necessary
2. Creates a Docker container with the current working directory mounted
3. Installs any required libraries specified by the agent
4. Executes the Python code in the container
5. Returns the output of the code execution
6. Cleans up by stopping and removing the container

## Security Considerations

By default, the `CodeInterpreterTool` runs code in an isolated Docker container, which provides a layer of security. However, there are still some security considerations to keep in mind:

1. The Docker container has access to the current working directory, so sensitive files could potentially be accessed.
2. If the Docker container is unavailable and the code needs to run safely, it will be executed in a sandbox environment. For security reasons, installing arbitrary libraries is not allowed
3. The `unsafe_mode` parameter allows code to be executed directly on the host machine, which should only be used in trusted environments.
4. Be cautious when allowing agents to install arbitrary libraries, as they could potentially include malicious code.

## Conclusion

The `CodeInterpreterTool` provides a powerful way for CrewAI agents to execute Python code in a relatively secure environment. By enabling agents to write and run code, it significantly expands their problem-solving capabilities, especially for tasks involving data analysis, calculations, or other computational work. This tool is particularly useful for agents that need to perform complex operations that are more efficiently expressed in code than in natural language.


# DALL-E Tool
Source: https://docs.crewai.com/en/tools/ai-ml/dalletool

The `DallETool` is a powerful tool designed for generating images from textual descriptions.

# `DallETool`

## Description

This tool is used to give the Agent the ability to generate images using the DALL-E model. It is a transformer-based model that generates images from textual descriptions.
This tool allows the Agent to generate images based on the text input provided by the user.

## Installation

Install the crewai\_tools package

```shell theme={null}
pip install 'crewai[tools]'
```

## Example

Remember that when using this tool, the text must be generated by the Agent itself. The text must be a description of the image you want to generate.

```python Code theme={null}
from crewai_tools import DallETool

Agent(
    ...
    tools=[DallETool()],
)
```

If needed you can also tweak the parameters of the DALL-E model by passing them as arguments to the `DallETool` class. For example:

```python Code theme={null}
from crewai_tools import DallETool

dalle_tool = DallETool(model="dall-e-3",
                       size="1024x1024",
                       quality="standard",
                       n=1)

Agent(
    ...
    tools=[dalle_tool]
)
```

The parameters are based on the `client.images.generate` method from the OpenAI API. For more information on the parameters,
please refer to the [OpenAI API documentation](https://platform.openai.com/docs/guides/images/introduction?lang=python).


# LangChain Tool
Source: https://docs.crewai.com/en/tools/ai-ml/langchaintool

The `LangChainTool` is a wrapper for LangChain tools and query engines.

## `LangChainTool`

<Info>
  CrewAI seamlessly integrates with LangChain's comprehensive [list of tools](https://python.langchain.com/docs/integrations/tools/), all of which can be used with CrewAI.
</Info>

```python Code theme={null}
import os
from dotenv import load_dotenv
from crewai import Agent, Task, Crew
from crewai.tools import BaseTool
from pydantic import Field
from langchain_community.utilities import GoogleSerperAPIWrapper

# Set up your SERPER_API_KEY key in an .env file, eg:
# SERPER_API_KEY=<your api key>
load_dotenv()

search = GoogleSerperAPIWrapper()

class SearchTool(BaseTool):
    name: str = "Search"
    description: str = "Useful for search-based queries. Use this to find current information about markets, companies, and trends."
    search: GoogleSerperAPIWrapper = Field(default_factory=GoogleSerperAPIWrapper)

    def _run(self, query: str) -> str:
        """Execute the search query and return results"""
        try:
            return self.search.run(query)
        except Exception as e:
            return f"Error performing search: {str(e)}"

# Create Agents
researcher = Agent(
    role='Research Analyst',
    goal='Gather current market data and trends',
    backstory="""You are an expert research analyst with years of experience in
    gathering market intelligence. You're known for your ability to find
    relevant and up-to-date market information and present it in a clear,
    actionable format.""",
    tools=[SearchTool()],
    verbose=True
)

# rest of the code ...
```

## Conclusion

Tools are pivotal in extending the capabilities of CrewAI agents, enabling them to undertake a broad spectrum of tasks and collaborate effectively.
When building solutions with CrewAI, leverage both custom and existing tools to empower your agents and enhance the AI ecosystem. Consider utilizing error handling, caching mechanisms,
and the flexibility of tool arguments to optimize your agents' performance and capabilities.


# LlamaIndex Tool
Source: https://docs.crewai.com/en/tools/ai-ml/llamaindextool

The `LlamaIndexTool` is a wrapper for LlamaIndex tools and query engines.

# `LlamaIndexTool`

## Description

The `LlamaIndexTool` is designed to be a general wrapper around LlamaIndex tools and query engines, enabling you to leverage LlamaIndex resources in terms of RAG/agentic pipelines as tools to plug into CrewAI agents. This tool allows you to seamlessly integrate LlamaIndex's powerful data processing and retrieval capabilities into your CrewAI workflows.

## Installation

To use this tool, you need to install LlamaIndex:

```shell theme={null}
uv add llama-index
```

## Steps to Get Started

To effectively use the `LlamaIndexTool`, follow these steps:

1. **Install LlamaIndex**: Install the LlamaIndex package using the command above.
2. **Set Up LlamaIndex**: Follow the [LlamaIndex documentation](https://docs.llamaindex.ai/) to set up a RAG/agent pipeline.
3. **Create a Tool or Query Engine**: Create a LlamaIndex tool or query engine that you want to use with CrewAI.

## Example

The following examples demonstrate how to initialize the tool from different LlamaIndex components:

### From a LlamaIndex Tool

```python Code theme={null}
from crewai_tools import LlamaIndexTool
from crewai import Agent
from llama_index.core.tools import FunctionTool

# Example 1: Initialize from FunctionTool
def search_data(query: str) -> str:
    """Search for information in the data."""
    # Your implementation here
    return f"Results for: {query}"

# Create a LlamaIndex FunctionTool
og_tool = FunctionTool.from_defaults(
    search_data, 
    name="DataSearchTool",
    description="Search for information in the data"
)

# Wrap it with LlamaIndexTool
tool = LlamaIndexTool.from_tool(og_tool)

# Define an agent that uses the tool
@agent
def researcher(self) -> Agent:
    '''
    This agent uses the LlamaIndexTool to search for information.
    '''
    return Agent(
        config=self.agents_config["researcher"],
        tools=[tool]
    )
```

### From LlamaHub Tools

```python Code theme={null}
from crewai_tools import LlamaIndexTool
from llama_index.tools.wolfram_alpha import WolframAlphaToolSpec

# Initialize from LlamaHub Tools
wolfram_spec = WolframAlphaToolSpec(app_id="your_app_id")
wolfram_tools = wolfram_spec.to_tool_list()
tools = [LlamaIndexTool.from_tool(t) for t in wolfram_tools]
```

### From a LlamaIndex Query Engine

```python Code theme={null}
from crewai_tools import LlamaIndexTool
from llama_index.core import VectorStoreIndex
from llama_index.core.readers import SimpleDirectoryReader

# Load documents
documents = SimpleDirectoryReader("./data").load_data()

# Create an index
index = VectorStoreIndex.from_documents(documents)

# Create a query engine
query_engine = index.as_query_engine()

# Create a LlamaIndexTool from the query engine
query_tool = LlamaIndexTool.from_query_engine(
    query_engine,
    name="Company Data Query Tool",
    description="Use this tool to lookup information in company documents"
)
```

## Class Methods

The `LlamaIndexTool` provides two main class methods for creating instances:

### from\_tool

Creates a `LlamaIndexTool` from a LlamaIndex tool.

```python Code theme={null}
@classmethod
def from_tool(cls, tool: Any, **kwargs: Any) -> "LlamaIndexTool":
    # Implementation details
```

### from\_query\_engine

Creates a `LlamaIndexTool` from a LlamaIndex query engine.

```python Code theme={null}
@classmethod
def from_query_engine(
    cls,
    query_engine: Any,
    name: Optional[str] = None,
    description: Optional[str] = None,
    return_direct: bool = False,
    **kwargs: Any,
) -> "LlamaIndexTool":
    # Implementation details
```

## Parameters

The `from_query_engine` method accepts the following parameters:

* **query\_engine**: Required. The LlamaIndex query engine to wrap.
* **name**: Optional. The name of the tool.
* **description**: Optional. The description of the tool.
* **return\_direct**: Optional. Whether to return the response directly. Default is `False`.

## Conclusion

The `LlamaIndexTool` provides a powerful way to integrate LlamaIndex's capabilities into CrewAI agents. By wrapping LlamaIndex tools and query engines, it enables agents to leverage sophisticated data retrieval and processing functionalities, enhancing their ability to work with complex information sources.


# Overview
Source: https://docs.crewai.com/en/tools/ai-ml/overview

Leverage AI services, generate images, process vision, and build intelligent systems

These tools integrate with AI and machine learning services to enhance your agents with advanced capabilities like image generation, vision processing, and intelligent code execution.

## **Available Tools**

<CardGroup>
  <Card title="DALL-E Tool" icon="image" href="/en/tools/ai-ml/dalletool">
    Generate AI images using OpenAI's DALL-E model.
  </Card>

  <Card title="Vision Tool" icon="eye" href="/en/tools/ai-ml/visiontool">
    Process and analyze images with computer vision capabilities.
  </Card>

  <Card title="AI Mind Tool" icon="brain" href="/en/tools/ai-ml/aimindtool">
    Advanced AI reasoning and decision-making capabilities.
  </Card>

  <Card title="LlamaIndex Tool" icon="llama" href="/en/tools/ai-ml/llamaindextool">
    Build knowledge bases and retrieval systems with LlamaIndex.
  </Card>

  <Card title="LangChain Tool" icon="link" href="/en/tools/ai-ml/langchaintool">
    Integrate with LangChain for complex AI workflows.
  </Card>

  <Card title="RAG Tool" icon="database" href="/en/tools/ai-ml/ragtool">
    Implement Retrieval-Augmented Generation systems.
  </Card>

  <Card title="Code Interpreter Tool" icon="code" href="/en/tools/ai-ml/codeinterpretertool">
    Execute Python code and perform data analysis.
  </Card>
</CardGroup>

## **Common Use Cases**

* **Content Generation**: Create images, text, and multimedia content
* **Data Analysis**: Execute code and analyze complex datasets
* **Knowledge Systems**: Build RAG systems and intelligent databases
* **Computer Vision**: Process and understand visual content
* **AI Safety**: Implement content moderation and safety checks

```python theme={null}
from crewai_tools import DallETool, VisionTool, CodeInterpreterTool

# Create AI tools
image_generator = DallETool()
vision_processor = VisionTool()
code_executor = CodeInterpreterTool()

# Add to your agent
agent = Agent(
    role="AI Specialist",
    tools=[image_generator, vision_processor, code_executor],
    goal="Create and analyze content using AI capabilities"
)
```


# RAG Tool
Source: https://docs.crewai.com/en/tools/ai-ml/ragtool

The `RagTool` is a dynamic knowledge base tool for answering questions using Retrieval-Augmented Generation.

# `RagTool`

## Description

The `RagTool` is designed to answer questions by leveraging the power of Retrieval-Augmented Generation (RAG) through CrewAI's native RAG system.
It provides a dynamic knowledge base that can be queried to retrieve relevant information from various data sources.
This tool is particularly useful for applications that require access to a vast array of information and need to provide contextually relevant answers.

## Example

The following example demonstrates how to initialize the tool and use it with different data sources:

```python Code theme={null}
from crewai_tools import RagTool

# Create a RAG tool with default settings
rag_tool = RagTool()

# Add content from a file
rag_tool.add(data_type="file", path="path/to/your/document.pdf")

# Add content from a web page
rag_tool.add(data_type="web_page", url="https://example.com")

# Define an agent with the RagTool
@agent
def knowledge_expert(self) -> Agent:
    '''
    This agent uses the RagTool to answer questions about the knowledge base.
    '''
    return Agent(
        config=self.agents_config["knowledge_expert"],
        allow_delegation=False,
        tools=[rag_tool]
    )
```

## Supported Data Sources

The `RagTool` can be used with a wide variety of data sources, including:

* 📰 PDF files
* 📊 CSV files
* 📃 JSON files
* 📝 Text
* 📁 Directories/Folders
* 🌐 HTML Web pages
* 📽️ YouTube Channels
* 📺 YouTube Videos
* 📚 Documentation websites
* 📝 MDX files
* 📄 DOCX files
* 🧾 XML files
* 📬 Gmail
* 📝 GitHub repositories
* 🐘 PostgreSQL databases
* 🐬 MySQL databases
* 🤖 Slack conversations
* 💬 Discord messages
* 🗨️ Discourse forums
* 📝 Substack newsletters
* 🐝 Beehiiv content
* 💾 Dropbox files
* 🖼️ Images
* ⚙️ Custom data sources

## Parameters

The `RagTool` accepts the following parameters:

* **summarize**: Optional. Whether to summarize the retrieved content. Default is `False`.
* **adapter**: Optional. A custom adapter for the knowledge base. If not provided, a CrewAIRagAdapter will be used.
* **config**: Optional. Configuration for the underlying CrewAI RAG system. Accepts a `RagToolConfig` TypedDict with optional `embedding_model` (ProviderSpec) and `vectordb` (VectorDbConfig) keys. All configuration values provided programmatically take precedence over environment variables.

## Adding Content

You can add content to the knowledge base using the `add` method:

```python Code theme={null}
# Add a PDF file
rag_tool.add(data_type="file", path="path/to/your/document.pdf")

# Add a web page
rag_tool.add(data_type="web_page", url="https://example.com")

# Add a YouTube video
rag_tool.add(data_type="youtube_video", url="https://www.youtube.com/watch?v=VIDEO_ID")

# Add a directory of files
rag_tool.add(data_type="directory", path="path/to/your/directory")
```

## Agent Integration Example

Here's how to integrate the `RagTool` with a CrewAI agent:

```python Code theme={null}
from crewai import Agent
from crewai.project import agent
from crewai_tools import RagTool

# Initialize the tool and add content
rag_tool = RagTool()
rag_tool.add(data_type="web_page", url="https://docs.crewai.com")
rag_tool.add(data_type="file", path="company_data.pdf")

# Define an agent with the RagTool
@agent
def knowledge_expert(self) -> Agent:
    return Agent(
        config=self.agents_config["knowledge_expert"],
        allow_delegation=False,
        tools=[rag_tool]
    )
```

## Advanced Configuration

You can customize the behavior of the `RagTool` by providing a configuration dictionary:

```python Code theme={null}
from crewai_tools import RagTool
from crewai_tools.tools.rag import RagToolConfig, VectorDbConfig, ProviderSpec

# Create a RAG tool with custom configuration

vectordb: VectorDbConfig = {
    "provider": "qdrant",
    "config": {
        "collection_name": "my-collection"
    }
}

embedding_model: ProviderSpec = {
    "provider": "openai",
    "config": {
        "model_name": "text-embedding-3-small"
    }
}

config: RagToolConfig = {
    "vectordb": vectordb,
    "embedding_model": embedding_model
}

rag_tool = RagTool(config=config, summarize=True)
```

## Embedding Model Configuration

The `embedding_model` parameter accepts a `crewai.rag.embeddings.types.ProviderSpec` dictionary with the structure:

```python theme={null}
{
    "provider": "provider-name",  # Required
    "config": {                    # Optional
        # Provider-specific configuration
    }
}
```

### Supported Providers

<AccordionGroup>
  <Accordion title="OpenAI">
    ```python main.py theme={null}
    from crewai.rag.embeddings.providers.openai.types import OpenAIProviderSpec

    embedding_model: OpenAIProviderSpec = {
        "provider": "openai",
        "config": {
            "api_key": "your-api-key",
            "model_name": "text-embedding-ada-002",
            "dimensions": 1536,
            "organization_id": "your-org-id",
            "api_base": "https://api.openai.com/v1",
            "api_version": "v1",
            "default_headers": {"Custom-Header": "value"}
        }
    }
    ```

    **Config Options:**

    * `api_key` (str): OpenAI API key
    * `model_name` (str): Model to use. Default: `text-embedding-ada-002`. Options: `text-embedding-3-small`, `text-embedding-3-large`, `text-embedding-ada-002`
    * `dimensions` (int): Number of dimensions for the embedding
    * `organization_id` (str): OpenAI organization ID
    * `api_base` (str): Custom API base URL
    * `api_version` (str): API version
    * `default_headers` (dict): Custom headers for API requests

    **Environment Variables:**

    * `OPENAI_API_KEY` or `EMBEDDINGS_OPENAI_API_KEY`: `api_key`
    * `OPENAI_ORGANIZATION_ID` or `EMBEDDINGS_OPENAI_ORGANIZATION_ID`: `organization_id`
    * `OPENAI_MODEL_NAME` or `EMBEDDINGS_OPENAI_MODEL_NAME`: `model_name`
    * `OPENAI_API_BASE` or `EMBEDDINGS_OPENAI_API_BASE`: `api_base`
    * `OPENAI_API_VERSION` or `EMBEDDINGS_OPENAI_API_VERSION`: `api_version`
    * `OPENAI_DIMENSIONS` or `EMBEDDINGS_OPENAI_DIMENSIONS`: `dimensions`
  </Accordion>

  <Accordion title="Cohere">
    ```python main.py theme={null}
    from crewai.rag.embeddings.providers.cohere.types import CohereProviderSpec

    embedding_model: CohereProviderSpec = {
        "provider": "cohere",
        "config": {
            "api_key": "your-api-key",
            "model_name": "embed-english-v3.0"
        }
    }
    ```

    **Config Options:**

    * `api_key` (str): Cohere API key
    * `model_name` (str): Model to use. Default: `large`. Options: `embed-english-v3.0`, `embed-multilingual-v3.0`, `large`, `small`

    **Environment Variables:**

    * `COHERE_API_KEY` or `EMBEDDINGS_COHERE_API_KEY`: `api_key`
    * `EMBEDDINGS_COHERE_MODEL_NAME`: `model_name`
  </Accordion>

  <Accordion title="VoyageAI">
    ```python main.py theme={null}
    from crewai.rag.embeddings.providers.voyageai.types import VoyageAIProviderSpec

    embedding_model: VoyageAIProviderSpec = {
        "provider": "voyageai",
        "config": {
            "api_key": "your-api-key",
            "model": "voyage-3",
            "input_type": "document",
            "truncation": True,
            "output_dtype": "float32",
            "output_dimension": 1024,
            "max_retries": 3,
            "timeout": 60.0
        }
    }
    ```

    **Config Options:**

    * `api_key` (str): VoyageAI API key
    * `model` (str): Model to use. Default: `voyage-2`. Options: `voyage-3`, `voyage-3-lite`, `voyage-code-3`, `voyage-large-2`
    * `input_type` (str): Type of input. Options: `document` (for storage), `query` (for search)
    * `truncation` (bool): Whether to truncate inputs that exceed max length. Default: `True`
    * `output_dtype` (str): Output data type
    * `output_dimension` (int): Dimension of output embeddings
    * `max_retries` (int): Maximum number of retry attempts. Default: `0`
    * `timeout` (float): Request timeout in seconds

    **Environment Variables:**

    * `VOYAGEAI_API_KEY` or `EMBEDDINGS_VOYAGEAI_API_KEY`: `api_key`
    * `VOYAGEAI_MODEL` or `EMBEDDINGS_VOYAGEAI_MODEL`: `model`
    * `VOYAGEAI_INPUT_TYPE` or `EMBEDDINGS_VOYAGEAI_INPUT_TYPE`: `input_type`
    * `VOYAGEAI_TRUNCATION` or `EMBEDDINGS_VOYAGEAI_TRUNCATION`: `truncation`
    * `VOYAGEAI_OUTPUT_DTYPE` or `EMBEDDINGS_VOYAGEAI_OUTPUT_DTYPE`: `output_dtype`
    * `VOYAGEAI_OUTPUT_DIMENSION` or `EMBEDDINGS_VOYAGEAI_OUTPUT_DIMENSION`: `output_dimension`
    * `VOYAGEAI_MAX_RETRIES` or `EMBEDDINGS_VOYAGEAI_MAX_RETRIES`: `max_retries`
    * `VOYAGEAI_TIMEOUT` or `EMBEDDINGS_VOYAGEAI_TIMEOUT`: `timeout`
  </Accordion>

  <Accordion title="Ollama">
    ```python main.py theme={null}
    from crewai.rag.embeddings.providers.ollama.types import OllamaProviderSpec

    embedding_model: OllamaProviderSpec = {
        "provider": "ollama",
        "config": {
            "model_name": "llama2",
            "url": "http://localhost:11434/api/embeddings"
        }
    }
    ```

    **Config Options:**

    * `model_name` (str): Ollama model name (e.g., `llama2`, `mistral`, `nomic-embed-text`)
    * `url` (str): Ollama API endpoint URL. Default: `http://localhost:11434/api/embeddings`

    **Environment Variables:**

    * `OLLAMA_MODEL` or `EMBEDDINGS_OLLAMA_MODEL`: `model_name`
    * `OLLAMA_URL` or `EMBEDDINGS_OLLAMA_URL`: `url`
  </Accordion>

  <Accordion title="Amazon Bedrock">
    ```python main.py theme={null}
    from crewai.rag.embeddings.providers.aws.types import BedrockProviderSpec

    embedding_model: BedrockProviderSpec = {
        "provider": "amazon-bedrock",
        "config": {
            "model_name": "amazon.titan-embed-text-v2:0",
            "session": boto3_session
        }
    }
    ```

    **Config Options:**

    * `model_name` (str): Bedrock model ID. Default: `amazon.titan-embed-text-v1`. Options: `amazon.titan-embed-text-v1`, `amazon.titan-embed-text-v2:0`, `cohere.embed-english-v3`, `cohere.embed-multilingual-v3`
    * `session` (Any): Boto3 session object for AWS authentication

    **Environment Variables:**

    * `AWS_ACCESS_KEY_ID`: AWS access key
    * `AWS_SECRET_ACCESS_KEY`: AWS secret key
    * `AWS_REGION`: AWS region (e.g., `us-east-1`)
  </Accordion>

  <Accordion title="Azure OpenAI">
    ```python main.py theme={null}
    from crewai.rag.embeddings.providers.microsoft.types import AzureProviderSpec

    embedding_model: AzureProviderSpec = {
        "provider": "azure",
        "config": {
            "deployment_id": "your-deployment-id",
            "api_key": "your-api-key",
            "api_base": "https://your-resource.openai.azure.com",
            "api_version": "2024-02-01",
            "model_name": "text-embedding-ada-002",
            "api_type": "azure"
        }
    }
    ```

    **Config Options:**

    * `deployment_id` (str): **Required** - Azure OpenAI deployment ID
    * `api_key` (str): Azure OpenAI API key
    * `api_base` (str): Azure OpenAI resource endpoint
    * `api_version` (str): API version. Example: `2024-02-01`
    * `model_name` (str): Model name. Default: `text-embedding-ada-002`
    * `api_type` (str): API type. Default: `azure`
    * `dimensions` (int): Output dimensions
    * `default_headers` (dict): Custom headers

    **Environment Variables:**

    * `AZURE_OPENAI_API_KEY` or `EMBEDDINGS_AZURE_API_KEY`: `api_key`
    * `AZURE_OPENAI_ENDPOINT` or `EMBEDDINGS_AZURE_API_BASE`: `api_base`
    * `EMBEDDINGS_AZURE_DEPLOYMENT_ID`: `deployment_id`
    * `EMBEDDINGS_AZURE_API_VERSION`: `api_version`
    * `EMBEDDINGS_AZURE_MODEL_NAME`: `model_name`
    * `EMBEDDINGS_AZURE_API_TYPE`: `api_type`
    * `EMBEDDINGS_AZURE_DIMENSIONS`: `dimensions`
  </Accordion>

  <Accordion title="Google Generative AI">
    ```python main.py theme={null}
    from crewai.rag.embeddings.providers.google.types import GenerativeAiProviderSpec

    embedding_model: GenerativeAiProviderSpec = {
        "provider": "google-generativeai",
        "config": {
            "api_key": "your-api-key",
            "model_name": "gemini-embedding-001",
            "task_type": "RETRIEVAL_DOCUMENT"
        }
    }
    ```

    **Config Options:**

    * `api_key` (str): Google AI API key
    * `model_name` (str): Model name. Default: `gemini-embedding-001`. Options: `gemini-embedding-001`, `text-embedding-005`, `text-multilingual-embedding-002`
    * `task_type` (str): Task type for embeddings. Default: `RETRIEVAL_DOCUMENT`. Options: `RETRIEVAL_DOCUMENT`, `RETRIEVAL_QUERY`

    **Environment Variables:**

    * `GOOGLE_API_KEY`, `GEMINI_API_KEY`, or `EMBEDDINGS_GOOGLE_API_KEY`: `api_key`
    * `EMBEDDINGS_GOOGLE_GENERATIVE_AI_MODEL_NAME`: `model_name`
    * `EMBEDDINGS_GOOGLE_GENERATIVE_AI_TASK_TYPE`: `task_type`
  </Accordion>

  <Accordion title="Google Vertex AI">
    ```python main.py theme={null}
    from crewai.rag.embeddings.providers.google.types import VertexAIProviderSpec

    embedding_model: VertexAIProviderSpec = {
        "provider": "google-vertex",
        "config": {
            "model_name": "text-embedding-004",
            "project_id": "your-project-id",
            "region": "us-central1",
            "api_key": "your-api-key"
        }
    }
    ```

    **Config Options:**

    * `model_name` (str): Model name. Default: `textembedding-gecko`. Options: `text-embedding-004`, `textembedding-gecko`, `textembedding-gecko-multilingual`
    * `project_id` (str): Google Cloud project ID. Default: `cloud-large-language-models`
    * `region` (str): Google Cloud region. Default: `us-central1`
    * `api_key` (str): API key for authentication

    **Environment Variables:**

    * `GOOGLE_APPLICATION_CREDENTIALS`: Path to service account JSON file
    * `GOOGLE_CLOUD_PROJECT` or `EMBEDDINGS_GOOGLE_VERTEX_PROJECT_ID`: `project_id`
    * `EMBEDDINGS_GOOGLE_VERTEX_MODEL_NAME`: `model_name`
    * `EMBEDDINGS_GOOGLE_VERTEX_REGION`: `region`
    * `EMBEDDINGS_GOOGLE_VERTEX_API_KEY`: `api_key`
  </Accordion>

  <Accordion title="Jina AI">
    ```python main.py theme={null}
    from crewai.rag.embeddings.providers.jina.types import JinaProviderSpec

    embedding_model: JinaProviderSpec = {
        "provider": "jina",
        "config": {
            "api_key": "your-api-key",
            "model_name": "jina-embeddings-v3"
        }
    }
    ```

    **Config Options:**

    * `api_key` (str): Jina AI API key
    * `model_name` (str): Model name. Default: `jina-embeddings-v2-base-en`. Options: `jina-embeddings-v3`, `jina-embeddings-v2-base-en`, `jina-embeddings-v2-small-en`

    **Environment Variables:**

    * `JINA_API_KEY` or `EMBEDDINGS_JINA_API_KEY`: `api_key`
    * `EMBEDDINGS_JINA_MODEL_NAME`: `model_name`
  </Accordion>

  <Accordion title="HuggingFace">
    ```python main.py theme={null}
    from crewai.rag.embeddings.providers.huggingface.types import HuggingFaceProviderSpec

    embedding_model: HuggingFaceProviderSpec = {
        "provider": "huggingface",
        "config": {
            "url": "https://api-inference.huggingface.co/models/sentence-transformers/all-MiniLM-L6-v2"
        }
    }
    ```

    **Config Options:**

    * `url` (str): Full URL to HuggingFace inference API endpoint

    **Environment Variables:**

    * `HUGGINGFACE_URL` or `EMBEDDINGS_HUGGINGFACE_URL`: `url`
  </Accordion>

  <Accordion title="Instructor">
    ```python main.py theme={null}
    from crewai.rag.embeddings.providers.instructor.types import InstructorProviderSpec

    embedding_model: InstructorProviderSpec = {
        "provider": "instructor",
        "config": {
            "model_name": "hkunlp/instructor-xl",
            "device": "cuda",
            "instruction": "Represent the document"
        }
    }
    ```

    **Config Options:**

    * `model_name` (str): HuggingFace model ID. Default: `hkunlp/instructor-base`. Options: `hkunlp/instructor-xl`, `hkunlp/instructor-large`, `hkunlp/instructor-base`
    * `device` (str): Device to run on. Default: `cpu`. Options: `cpu`, `cuda`, `mps`
    * `instruction` (str): Instruction prefix for embeddings

    **Environment Variables:**

    * `EMBEDDINGS_INSTRUCTOR_MODEL_NAME`: `model_name`
    * `EMBEDDINGS_INSTRUCTOR_DEVICE`: `device`
    * `EMBEDDINGS_INSTRUCTOR_INSTRUCTION`: `instruction`
  </Accordion>

  <Accordion title="Sentence Transformer">
    ```python main.py theme={null}
    from crewai.rag.embeddings.providers.sentence_transformer.types import SentenceTransformerProviderSpec

    embedding_model: SentenceTransformerProviderSpec = {
        "provider": "sentence-transformer",
        "config": {
            "model_name": "all-mpnet-base-v2",
            "device": "cuda",
            "normalize_embeddings": True
        }
    }
    ```

    **Config Options:**

    * `model_name` (str): Sentence Transformers model name. Default: `all-MiniLM-L6-v2`. Options: `all-mpnet-base-v2`, `all-MiniLM-L6-v2`, `paraphrase-multilingual-MiniLM-L12-v2`
    * `device` (str): Device to run on. Default: `cpu`. Options: `cpu`, `cuda`, `mps`
    * `normalize_embeddings` (bool): Whether to normalize embeddings. Default: `False`

    **Environment Variables:**

    * `EMBEDDINGS_SENTENCE_TRANSFORMER_MODEL_NAME`: `model_name`
    * `EMBEDDINGS_SENTENCE_TRANSFORMER_DEVICE`: `device`
    * `EMBEDDINGS_SENTENCE_TRANSFORMER_NORMALIZE_EMBEDDINGS`: `normalize_embeddings`
  </Accordion>

  <Accordion title="ONNX">
    ```python main.py theme={null}
    from crewai.rag.embeddings.providers.onnx.types import ONNXProviderSpec

    embedding_model: ONNXProviderSpec = {
        "provider": "onnx",
        "config": {
            "preferred_providers": ["CUDAExecutionProvider", "CPUExecutionProvider"]
        }
    }
    ```

    **Config Options:**

    * `preferred_providers` (list\[str]): List of ONNX execution providers in order of preference

    **Environment Variables:**

    * `EMBEDDINGS_ONNX_PREFERRED_PROVIDERS`: `preferred_providers` (comma-separated list)
  </Accordion>

  <Accordion title="OpenCLIP">
    ```python main.py theme={null}
    from crewai.rag.embeddings.providers.openclip.types import OpenCLIPProviderSpec

    embedding_model: OpenCLIPProviderSpec = {
        "provider": "openclip",
        "config": {
            "model_name": "ViT-B-32",
            "checkpoint": "laion2b_s34b_b79k",
            "device": "cuda"
        }
    }
    ```

    **Config Options:**

    * `model_name` (str): OpenCLIP model architecture. Default: `ViT-B-32`. Options: `ViT-B-32`, `ViT-B-16`, `ViT-L-14`
    * `checkpoint` (str): Pretrained checkpoint name. Default: `laion2b_s34b_b79k`. Options: `laion2b_s34b_b79k`, `laion400m_e32`, `openai`
    * `device` (str): Device to run on. Default: `cpu`. Options: `cpu`, `cuda`

    **Environment Variables:**

    * `EMBEDDINGS_OPENCLIP_MODEL_NAME`: `model_name`
    * `EMBEDDINGS_OPENCLIP_CHECKPOINT`: `checkpoint`
    * `EMBEDDINGS_OPENCLIP_DEVICE`: `device`
  </Accordion>

  <Accordion title="Text2Vec">
    ```python main.py theme={null}
    from crewai.rag.embeddings.providers.text2vec.types import Text2VecProviderSpec

    embedding_model: Text2VecProviderSpec = {
        "provider": "text2vec",
        "config": {
            "model_name": "shibing624/text2vec-base-multilingual"
        }
    }
    ```

    **Config Options:**

    * `model_name` (str): Text2Vec model name from HuggingFace. Default: `shibing624/text2vec-base-chinese`. Options: `shibing624/text2vec-base-multilingual`, `shibing624/text2vec-base-chinese`

    **Environment Variables:**

    * `EMBEDDINGS_TEXT2VEC_MODEL_NAME`: `model_name`
  </Accordion>

  <Accordion title="Roboflow">
    ```python main.py theme={null}
    from crewai.rag.embeddings.providers.roboflow.types import RoboflowProviderSpec

    embedding_model: RoboflowProviderSpec = {
        "provider": "roboflow",
        "config": {
            "api_key": "your-api-key",
            "api_url": "https://infer.roboflow.com"
        }
    }
    ```

    **Config Options:**

    * `api_key` (str): Roboflow API key. Default: `""` (empty string)
    * `api_url` (str): Roboflow inference API URL. Default: `https://infer.roboflow.com`

    **Environment Variables:**

    * `ROBOFLOW_API_KEY` or `EMBEDDINGS_ROBOFLOW_API_KEY`: `api_key`
    * `ROBOFLOW_API_URL` or `EMBEDDINGS_ROBOFLOW_API_URL`: `api_url`
  </Accordion>

  <Accordion title="WatsonX (IBM)">
    ```python main.py theme={null}
    from crewai.rag.embeddings.providers.ibm.types import WatsonXProviderSpec

    embedding_model: WatsonXProviderSpec = {
        "provider": "watsonx",
        "config": {
            "model_id": "ibm/slate-125m-english-rtrvr",
            "url": "https://us-south.ml.cloud.ibm.com",
            "api_key": "your-api-key",
            "project_id": "your-project-id",
            "batch_size": 100,
            "concurrency_limit": 10,
            "persistent_connection": True
        }
    }
    ```

    **Config Options:**

    * `model_id` (str): WatsonX model identifier
    * `url` (str): WatsonX API endpoint
    * `api_key` (str): IBM Cloud API key
    * `project_id` (str): WatsonX project ID
    * `space_id` (str): WatsonX space ID (alternative to project\_id)
    * `batch_size` (int): Batch size for embeddings. Default: `100`
    * `concurrency_limit` (int): Maximum concurrent requests. Default: `10`
    * `persistent_connection` (bool): Use persistent connections. Default: `True`
    * Plus 20+ additional authentication and configuration options

    **Environment Variables:**

    * `WATSONX_API_KEY` or `EMBEDDINGS_WATSONX_API_KEY`: `api_key`
    * `WATSONX_URL` or `EMBEDDINGS_WATSONX_URL`: `url`
    * `WATSONX_PROJECT_ID` or `EMBEDDINGS_WATSONX_PROJECT_ID`: `project_id`
    * `EMBEDDINGS_WATSONX_MODEL_ID`: `model_id`
    * `EMBEDDINGS_WATSONX_SPACE_ID`: `space_id`
    * `EMBEDDINGS_WATSONX_BATCH_SIZE`: `batch_size`
    * `EMBEDDINGS_WATSONX_CONCURRENCY_LIMIT`: `concurrency_limit`
    * `EMBEDDINGS_WATSONX_PERSISTENT_CONNECTION`: `persistent_connection`
  </Accordion>

  <Accordion title="Custom">
    ```python main.py theme={null}
    from crewai.rag.core.base_embeddings_callable import EmbeddingFunction
    from crewai.rag.embeddings.providers.custom.types import CustomProviderSpec

    class MyEmbeddingFunction(EmbeddingFunction):
        def __call__(self, input):
            # Your custom embedding logic
            return embeddings

    embedding_model: CustomProviderSpec = {
        "provider": "custom",
        "config": {
            "embedding_callable": MyEmbeddingFunction
        }
    }
    ```

    **Config Options:**

    * `embedding_callable` (type\[EmbeddingFunction]): Custom embedding function class

    **Note:** Custom embedding functions must implement the `EmbeddingFunction` protocol defined in `crewai.rag.core.base_embeddings_callable`. The `__call__` method should accept input data and return embeddings as a list of numpy arrays (or compatible format that will be normalized). The returned embeddings are automatically normalized and validated.
  </Accordion>
</AccordionGroup>

### Notes

* All config fields are optional unless marked as **Required**
* API keys can typically be provided via environment variables instead of config
* Default values are shown where applicable

## Conclusion

The `RagTool` provides a powerful way to create and query knowledge bases from various data sources. By leveraging Retrieval-Augmented Generation, it enables agents to access and retrieve relevant information efficiently, enhancing their ability to provide accurate and contextually appropriate responses.


# Vision Tool
Source: https://docs.crewai.com/en/tools/ai-ml/visiontool

The `VisionTool` is designed to extract text from images.

# `VisionTool`

## Description

This tool is used to extract text from images. When passed to the agent it will extract the text from the image and then use it to generate a response, report or any other output.
The URL or the PATH of the image should be passed to the Agent.

## Installation

Install the crewai\_tools package

```shell theme={null}
pip install 'crewai[tools]'
```

## Usage

In order to use the VisionTool, the OpenAI API key should be set in the environment variable `OPENAI_API_KEY`.

```python Code theme={null}
from crewai_tools import VisionTool

vision_tool = VisionTool()

@agent
def researcher(self) -> Agent:
    '''
    This agent uses the VisionTool to extract text from images.
    '''
    return Agent(
        config=self.agents_config["researcher"],
        allow_delegation=False,
        tools=[vision_tool]
    )
```

## Arguments

The VisionTool requires the following arguments:

| Argument             | Type     | Description                                                                      |
| :------------------- | :------- | :------------------------------------------------------------------------------- |
| **image\_path\_url** | `string` | **Mandatory**. The path to the image file from which text needs to be extracted. |


# Overview
Source: https://docs.crewai.com/en/tools/cloud-storage/overview

Interact with cloud services, storage systems, and cloud-based AI platforms

These tools enable your agents to interact with cloud services, access cloud storage, and leverage cloud-based AI platforms for scalable operations.

## **Available Tools**

<CardGroup>
  <Card title="S3 Reader Tool" icon="cloud" href="/en/tools/cloud-storage/s3readertool">
    Read files and data from Amazon S3 buckets.
  </Card>

  <Card title="S3 Writer Tool" icon="cloud-arrow-up" href="/en/tools/cloud-storage/s3writertool">
    Write and upload files to Amazon S3 storage.
  </Card>

  <Card title="Bedrock Invoke Agent" icon="aws" href="/en/tools/integration/bedrockinvokeagenttool">
    Invoke Amazon Bedrock agents for AI-powered tasks.
  </Card>

  <Card title="Bedrock KB Retriever" icon="database" href="/en/tools/cloud-storage/bedrockkbretriever">
    Retrieve information from Amazon Bedrock knowledge bases.
  </Card>
</CardGroup>

## **Common Use Cases**

* **File Storage**: Store and retrieve files from cloud storage systems
* **Data Backup**: Backup important data to cloud storage
* **AI Services**: Access cloud-based AI models and services
* **Knowledge Retrieval**: Query cloud-hosted knowledge bases
* **Scalable Operations**: Leverage cloud infrastructure for processing

```python theme={null}
from crewai_tools import S3ReaderTool, S3WriterTool, BedrockInvokeAgentTool

# Create cloud tools
s3_reader = S3ReaderTool()
s3_writer = S3WriterTool()
bedrock_agent = BedrockInvokeAgentTool()

# Add to your agent
agent = Agent(
    role="Cloud Operations Specialist",
    tools=[s3_reader, s3_writer, bedrock_agent],
    goal="Manage cloud resources and AI services"
)
```


# MongoDB Vector Search Tool
Source: https://docs.crewai.com/en/tools/database-data/mongodbvectorsearchtool

The `MongoDBVectorSearchTool` performs vector search on MongoDB Atlas with optional indexing helpers.

# `MongoDBVectorSearchTool`

## Description

Perform vector similarity queries on MongoDB Atlas collections. Supports index creation helpers and bulk insert of embedded texts.

MongoDB Atlas supports native vector search. Learn more:
[https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-overview/](https://www.mongodb.com/docs/atlas/atlas-vector-search/vector-search-overview/)

## Installation

Install with the MongoDB extra:

```shell theme={null}
pip install crewai-tools[mongodb]
```

or

```shell theme={null}
uv add crewai-tools --extra mongodb
```

## Parameters

### Initialization

* `connection_string` (str, required)
* `database_name` (str, required)
* `collection_name` (str, required)
* `vector_index_name` (str, default `vector_index`)
* `text_key` (str, default `text`)
* `embedding_key` (str, default `embedding`)
* `dimensions` (int, default `1536`)

### Run Parameters

* `query` (str, required): Natural language query to embed and search.

## Quick start

```python Code theme={null}
from crewai_tools import MongoDBVectorSearchTool

tool = MongoDBVectorSearchTool(
  connection_string="mongodb+srv://...",
  database_name="mydb",
  collection_name="docs",
)

print(tool.run(query="how to create vector index"))
```

## Index creation helpers

Use `create_vector_search_index(...)` to provision an Atlas Vector Search index with the correct dimensions and similarity.

## Common issues

* Authentication failures: ensure your Atlas IP Access List allows your runner and the connection string includes credentials.
* Index not found: create the vector index first; name must match `vector_index_name`.
* Dimensions mismatch: align embedding model dimensions with `dimensions`.

## More examples

### Basic initialization

```python Code theme={null}
from crewai_tools import MongoDBVectorSearchTool

tool = MongoDBVectorSearchTool(
    database_name="example_database",
    collection_name="example_collection",
    connection_string="<your_mongodb_connection_string>",
)
```

### Custom query configuration

```python Code theme={null}
from crewai_tools import MongoDBVectorSearchConfig, MongoDBVectorSearchTool

query_config = MongoDBVectorSearchConfig(limit=10, oversampling_factor=2)
tool = MongoDBVectorSearchTool(
    database_name="example_database",
    collection_name="example_collection",
    connection_string="<your_mongodb_connection_string>",
    query_config=query_config,
    vector_index_name="my_vector_index",
)

rag_agent = Agent(
    name="rag_agent",
    role="You are a helpful assistant that can answer questions with the help of the MongoDBVectorSearchTool.",
    goal="...",
    backstory="...",
    tools=[tool],
)
```

### Preloading the database and creating the index

```python Code theme={null}
import os
from crewai_tools import MongoDBVectorSearchTool

tool = MongoDBVectorSearchTool(
    database_name="example_database",
    collection_name="example_collection",
    connection_string="<your_mongodb_connection_string>",
)

# Load text content from a local folder and add to MongoDB
texts = []
for fname in os.listdir("knowledge"):
    path = os.path.join("knowledge", fname)
    if os.path.isfile(path):
        with open(path, "r", encoding="utf-8") as f:
            texts.append(f.read())

tool.add_texts(texts)

# Create the Atlas Vector Search index (e.g., 3072 dims for text-embedding-3-large)
tool.create_vector_search_index(dimensions=3072)
```

## Example

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import MongoDBVectorSearchTool

tool = MongoDBVectorSearchTool(
    connection_string="mongodb+srv://...",
    database_name="mydb",
    collection_name="docs",
)

agent = Agent(
    role="RAG Agent",
    goal="Answer using MongoDB vector search",
    backstory="Knowledge retrieval specialist",
    tools=[tool],
    verbose=True,
)

task = Task(
    description="Find relevant content for 'indexing guidance'",
    expected_output="A concise answer citing the most relevant matches",
    agent=agent,
)

crew = Crew(
    agents=[agent], 
    tasks=[task],
    verbose=True,
)

result = crew.kickoff()
```


# MySQL RAG Search
Source: https://docs.crewai.com/en/tools/database-data/mysqltool

The `MySQLSearchTool` is designed to search MySQL databases and return the most relevant results.

## Overview

This tool is designed to facilitate semantic searches within MySQL database tables. Leveraging the RAG (Retrieve and Generate) technology,
the MySQLSearchTool provides users with an efficient means of querying database table content, specifically tailored for MySQL databases.
It simplifies the process of finding relevant data through semantic search queries, making it an invaluable resource for users needing
to perform advanced queries on extensive datasets within a MySQL database.

## Installation

To install the `crewai_tools` package and utilize the MySQLSearchTool, execute the following command in your terminal:

```shell theme={null}
pip install 'crewai[tools]'
```

## Example

Below is an example showcasing how to use the MySQLSearchTool to conduct a semantic search on a table within a MySQL database:

```python Code theme={null}
from crewai_tools import MySQLSearchTool

# Initialize the tool with the database URI and the target table name
tool = MySQLSearchTool(
    db_uri='mysql://user:password@localhost:3306/mydatabase',
    table_name='employees'
)
```

## Arguments

The MySQLSearchTool requires the following arguments for its operation:

* `db_uri`: A string representing the URI of the MySQL database to be queried. This argument is mandatory and must include the necessary authentication details and the location of the database.
* `table_name`: A string specifying the name of the table within the database on which the semantic search will be performed. This argument is mandatory.

## Custom model and embeddings

By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows:

```python Code theme={null}
tool = MySQLSearchTool(
    config=dict(
        llm=dict(
            provider="ollama", # or google, openai, anthropic, llama2, ...
            config=dict(
                model="llama2",
                # temperature=0.5,
                # top_p=1,
                # stream=true,
            ),
        ),
        embedder=dict(
            provider="google-generativeai",
            config=dict(
                model_name="gemini-embedding-001",
                task_type="RETRIEVAL_DOCUMENT",
                # title="Embeddings",
            ),
        ),
    )
)
```


# NL2SQL Tool
Source: https://docs.crewai.com/en/tools/database-data/nl2sqltool

The `NL2SQLTool` is designed to convert natural language to SQL queries.

## Overview

This tool is used to convert natural language to SQL queries. When passed to the agent it will generate queries and then use them to interact with the database.

This enables multiple workflows like having an Agent to access the database fetch information based on the goal and then use the information to generate a response, report or any other output.
Along with that provides the ability for the Agent to update the database based on its goal.

**Attention**: Make sure that the Agent has access to a Read-Replica or that is okay for the Agent to run insert/update queries on the database.

## Security Model

`NL2SQLTool` is an execution-capable tool. It runs model-generated SQL directly against the configured database connection.

This means risk depends on your deployment choices:

* Which credentials you provide in `db_uri`
* Whether untrusted input can influence prompts
* Whether you add tool-call guardrails before execution

If you route untrusted input to agents using this tool, treat it as a high-risk integration.

## Hardening Recommendations

Use all of the following in production:

* Use a read-only database user whenever possible
* Prefer a read replica for analytics/retrieval workloads
* Grant least privilege (no superuser/admin roles, no file/system-level capabilities)
* Apply database-side resource limits (statement timeout, lock timeout, cost/row limits)
* Add `before_tool_call` hooks to enforce allowed query patterns
* Enable query logging and alerting for destructive statements

## Requirements

* SqlAlchemy
* Any DB compatible library (e.g. psycopg2, mysql-connector-python)

## Installation

Install the crewai\_tools package

```shell theme={null}
pip install 'crewai[tools]'
```

## Usage

In order to use the NL2SQLTool, you need to pass the database URI to the tool. The URI should be in the format `dialect+driver://username:password@host:port/database`.

```python Code theme={null}
from crewai_tools import NL2SQLTool

# psycopg2 was installed to run this example with PostgreSQL
nl2sql = NL2SQLTool(db_uri="postgresql://example@localhost:5432/test_db")

@agent
def researcher(self) -> Agent:
    return Agent(
        config=self.agents_config["researcher"],
        allow_delegation=False,
        tools=[nl2sql]
    )
```

## Example

The primary task goal was:

"Retrieve the average, maximum, and minimum monthly revenue for each city, but only include cities that have more than one user. Also, count the number of user in each city and
sort the results by the average monthly revenue in descending order"

So the Agent tried to get information from the DB, the first one is wrong so the Agent tries again and gets the correct information and passes to the next agent.

![alt text](https://github.com/crewAIInc/crewAI-tools/blob/main/crewai_tools/tools/nl2sql/images/image-2.png?raw=true)
![alt text](https://github.com/crewAIInc/crewAI-tools/raw/main/crewai_tools/tools/nl2sql/images/image-3.png)

The second task goal was:

"Review the data and create a detailed report, and then create the table on the database with the fields based on the data provided.
Include information on the average, maximum, and minimum monthly revenue for each city, but only include cities that have more than one user. Also, count the number of users in each city and sort the results by the average monthly revenue in descending order."

Now things start to get interesting, the Agent generates the SQL query to not only create the table but also insert the data into the table. And in the end the Agent still returns the final report which is exactly what was in the database.

![alt text](https://github.com/crewAIInc/crewAI-tools/raw/main/crewai_tools/tools/nl2sql/images/image-4.png)
![alt text](https://github.com/crewAIInc/crewAI-tools/raw/main/crewai_tools/tools/nl2sql/images/image-5.png)

![alt text](https://github.com/crewAIInc/crewAI-tools/raw/main/crewai_tools/tools/nl2sql/images/image-9.png)
![alt text](https://github.com/crewAIInc/crewAI-tools/raw/main/crewai_tools/tools/nl2sql/images/image-7.png)

This is a simple example of how the NL2SQLTool can be used to interact with the database and generate reports based on the data in the database.

The Tool provides endless possibilities on the logic of the Agent and how it can interact with the database.

```md theme={null}
 DB -> Agent -> ... -> Agent -> DB
```


# Overview
Source: https://docs.crewai.com/en/tools/database-data/overview

Connect to databases, vector stores, and data warehouses for comprehensive data access

These tools enable your agents to interact with various database systems, from traditional SQL databases to modern vector stores and data warehouses.

## **Available Tools**

<CardGroup>
  <Card title="MySQL Tool" icon="database" href="/en/tools/database-data/mysqltool">
    Connect to and query MySQL databases with SQL operations.
  </Card>

  <Card title="PostgreSQL Search" icon="elephant" href="/en/tools/database-data/pgsearchtool">
    Search and query PostgreSQL databases efficiently.
  </Card>

  <Card title="Snowflake Search" icon="snowflake" href="/en/tools/database-data/snowflakesearchtool">
    Access Snowflake data warehouse for analytics and reporting.
  </Card>

  <Card title="NL2SQL Tool" icon="language" href="/en/tools/database-data/nl2sqltool">
    Convert natural language queries to SQL statements automatically.
  </Card>

  <Card title="Qdrant Vector Search" icon="vector-square" href="/en/tools/database-data/qdrantvectorsearchtool">
    Search vector embeddings using Qdrant vector database.
  </Card>

  <Card title="Weaviate Vector Search" icon="network-wired" href="/en/tools/database-data/weaviatevectorsearchtool">
    Perform semantic search with Weaviate vector database.
  </Card>

  <Card title="MongoDB Vector Search" icon="leaf" href="/en/tools/database-data/mongodbvectorsearchtool">
    Vector similarity search on MongoDB Atlas with indexing helpers.
  </Card>

  <Card title="SingleStore Search" icon="database" href="/en/tools/database-data/singlestoresearchtool">
    Safe SELECT/SHOW queries on SingleStore with pooling and validation.
  </Card>
</CardGroup>

## **Common Use Cases**

* **Data Analysis**: Query databases for business intelligence and reporting
* **Vector Search**: Find similar content using semantic embeddings
* **ETL Operations**: Extract, transform, and load data between systems
* **Real-time Analytics**: Access live data for decision making

```python theme={null}
from crewai_tools import MySQLTool, QdrantVectorSearchTool, NL2SQLTool

# Create database tools
mysql_db = MySQLTool()
vector_search = QdrantVectorSearchTool()
nl_to_sql = NL2SQLTool()

# Add to your agent
agent = Agent(
    role="Data Analyst",
    tools=[mysql_db, vector_search, nl_to_sql],
    goal="Extract insights from various data sources"
)
```


# PG RAG Search
Source: https://docs.crewai.com/en/tools/database-data/pgsearchtool

The `PGSearchTool` is designed to search PostgreSQL databases and return the most relevant results.

## Overview

<Note>
  The PGSearchTool is currently under development. This document outlines the intended functionality and interface.
  As development progresses, please be aware that some features may not be available or could change.
</Note>

## Description

The PGSearchTool is envisioned as a powerful tool for facilitating semantic searches within PostgreSQL database tables. By leveraging advanced Retrieve and Generate (RAG) technology,
it aims to provide an efficient means for querying database table content, specifically tailored for PostgreSQL databases.
The tool's goal is to simplify the process of finding relevant data through semantic search queries, offering a valuable resource for users needing to conduct advanced queries on
extensive datasets within a PostgreSQL environment.

## Installation

The `crewai_tools` package, which will include the PGSearchTool upon its release, can be installed using the following command:

```shell theme={null}
pip install 'crewai[tools]'
```

<Note>
  The PGSearchTool is not yet available in the current version of the `crewai_tools` package. This installation command will be updated once the tool is released.
</Note>

## Example Usage

Below is a proposed example showcasing how to use the PGSearchTool for conducting a semantic search on a table within a PostgreSQL database:

```python Code theme={null}
from crewai_tools import PGSearchTool

# Initialize the tool with the database URI and the target table name
tool = PGSearchTool(
    db_uri='postgresql://user:password@localhost:5432/mydatabase', 
    table_name='employees'
)
```

## Arguments

The PGSearchTool is designed to require the following arguments for its operation:

| Argument        | Type     | Description                                                                                                                                                                                                    |
| :-------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **db\_uri**     | `string` | **Mandatory**. A string representing the URI of the PostgreSQL database to be queried. This argument will be mandatory and must include the necessary authentication details and the location of the database. |
| **table\_name** | `string` | **Mandatory**. A string specifying the name of the table within the database on which the semantic search will be performed. This argument will also be mandatory.                                             |

## Custom Model and Embeddings

The tool intends to use OpenAI for both embeddings and summarization by default. Users will have the option to customize the model using a config dictionary as follows:

```python Code theme={null}
tool = PGSearchTool(
    config=dict(
        llm=dict(
            provider="ollama", # or google, openai, anthropic, llama2, ...
            config=dict(
                model="llama2",
                # temperature=0.5,
                # top_p=1,
                # stream=true,
            ),
        ),
        embedder=dict(
            provider="google-generativeai", # or openai, ollama, ...
            config=dict(
                model_name="gemini-embedding-001",
                task_type="RETRIEVAL_DOCUMENT",
                # title="Embeddings",
            ),
        ),
    )
)
```


# Qdrant Vector Search Tool
Source: https://docs.crewai.com/en/tools/database-data/qdrantvectorsearchtool

Semantic search capabilities for CrewAI agents using Qdrant vector database

## Overview

The Qdrant Vector Search Tool enables semantic search capabilities in your CrewAI agents by leveraging [Qdrant](https://qdrant.tech/), a vector similarity search engine. This tool allows your agents to search through documents stored in a Qdrant collection using semantic similarity.

## Installation

Install the required packages:

```bash theme={null}
uv add qdrant-client
```

## Basic Usage

Here's a minimal example of how to use the tool:

```python theme={null}
from crewai import Agent
from crewai_tools import QdrantVectorSearchTool, QdrantConfig

# Initialize the tool with QdrantConfig
qdrant_tool = QdrantVectorSearchTool(
    qdrant_config=QdrantConfig(
        qdrant_url="your_qdrant_url",
        qdrant_api_key="your_qdrant_api_key",
        collection_name="your_collection"
    )
)

# Create an agent that uses the tool
agent = Agent(
    role="Research Assistant",
    goal="Find relevant information in documents",
    tools=[qdrant_tool]
)

# The tool will automatically use OpenAI embeddings
# and return the 3 most relevant results with scores > 0.35
```

## Complete Working Example

Here's a complete example showing how to:

1. Extract text from a PDF
2. Generate embeddings using OpenAI
3. Store in Qdrant
4. Create a CrewAI agentic RAG workflow for semantic search

```python theme={null}
import os
import uuid
import pdfplumber
from openai import OpenAI
from dotenv import load_dotenv
from crewai import Agent, Task, Crew, Process, LLM
from crewai_tools import QdrantVectorSearchTool
from qdrant_client import QdrantClient
from qdrant_client.models import PointStruct, Distance, VectorParams

# Load environment variables
load_dotenv()

# Initialize OpenAI client
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

# Extract text from PDF
def extract_text_from_pdf(pdf_path):
    text = []
    with pdfplumber.open(pdf_path) as pdf:
        for page in pdf.pages:
            page_text = page.extract_text()
            if page_text:
                text.append(page_text.strip())
    return text

# Generate OpenAI embeddings
def get_openai_embedding(text):
    response = client.embeddings.create(
        input=text,
        model="text-embedding-3-large"
    )
    return response.data[0].embedding

# Store text and embeddings in Qdrant
def load_pdf_to_qdrant(pdf_path, qdrant, collection_name):
    # Extract text from PDF
    text_chunks = extract_text_from_pdf(pdf_path)

    # Create Qdrant collection
    if qdrant.collection_exists(collection_name):
        qdrant.delete_collection(collection_name)
    qdrant.create_collection(
        collection_name=collection_name,
        vectors_config=VectorParams(size=3072, distance=Distance.COSINE)
    )

    # Store embeddings
    points = []
    for chunk in text_chunks:
        embedding = get_openai_embedding(chunk)
        points.append(PointStruct(
            id=str(uuid.uuid4()),
            vector=embedding,
            payload={"text": chunk}
        ))
    qdrant.upsert(collection_name=collection_name, points=points)

# Initialize Qdrant client and load data
qdrant = QdrantClient(
    url=os.getenv("QDRANT_URL"),
    api_key=os.getenv("QDRANT_API_KEY")
)
collection_name = "example_collection"
pdf_path = "path/to/your/document.pdf"
load_pdf_to_qdrant(pdf_path, qdrant, collection_name)

# Initialize Qdrant search tool
from crewai_tools import QdrantConfig

qdrant_tool = QdrantVectorSearchTool(
    qdrant_config=QdrantConfig(
        qdrant_url=os.getenv("QDRANT_URL"),
        qdrant_api_key=os.getenv("QDRANT_API_KEY"),
        collection_name=collection_name,
        limit=3,
        score_threshold=0.35
    )
)

# Create CrewAI agents
search_agent = Agent(
    role="Senior Semantic Search Agent",
    goal="Find and analyze documents based on semantic search",
    backstory="""You are an expert research assistant who can find relevant
    information using semantic search in a Qdrant database.""",
    tools=[qdrant_tool],
    verbose=True
)

answer_agent = Agent(
    role="Senior Answer Assistant",
    goal="Generate answers to questions based on the context provided",
    backstory="""You are an expert answer assistant who can generate
    answers to questions based on the context provided.""",
    tools=[qdrant_tool],
    verbose=True
)

# Define tasks
search_task = Task(
    description="""Search for relevant documents about the {query}.
    Your final answer should include:
    - The relevant information found
    - The similarity scores of the results
    - The metadata of the relevant documents""",
    agent=search_agent
)

answer_task = Task(
    description="""Given the context and metadata of relevant documents,
    generate a final answer based on the context.""",
    agent=answer_agent
)

# Run CrewAI workflow
crew = Crew(
    agents=[search_agent, answer_agent],
    tasks=[search_task, answer_task],
    process=Process.sequential,
    verbose=True
)

result = crew.kickoff(
    inputs={"query": "What is the role of X in the document?"}
)
print(result)
```

## Tool Parameters

### Required Parameters

* `qdrant_config` (QdrantConfig): Configuration object containing all Qdrant settings

### QdrantConfig Parameters

* `qdrant_url` (str): The URL of your Qdrant server
* `qdrant_api_key` (str, optional): API key for authentication with Qdrant
* `collection_name` (str): Name of the Qdrant collection to search
* `limit` (int): Maximum number of results to return (default: 3)
* `score_threshold` (float): Minimum similarity score threshold (default: 0.35)
* `filter` (Any, optional): Qdrant Filter instance for advanced filtering (default: None)

### Optional Tool Parameters

* `custom_embedding_fn` (Callable\[\[str], list\[float]]): Custom function for text vectorization
* `qdrant_package` (str): Base package path for Qdrant (default: "qdrant\_client")
* `client` (Any): Pre-initialized Qdrant client (optional)

## Advanced Filtering

The QdrantVectorSearchTool supports powerful filtering capabilities to refine your search results:

### Dynamic Filtering

Use `filter_by` and `filter_value` parameters in your search to filter results on-the-fly:

```python theme={null}
# Agent will use these parameters when calling the tool
# The tool schema accepts filter_by and filter_value
# Example: search with category filter
# Results will be filtered where category == "technology"
```

### Preset Filters with QdrantConfig

For complex filtering, use Qdrant Filter instances in your configuration:

```python theme={null}
from qdrant_client.http import models as qmodels
from crewai_tools import QdrantVectorSearchTool, QdrantConfig

# Create a filter for specific conditions
preset_filter = qmodels.Filter(
    must=[
        qmodels.FieldCondition(
            key="category",
            match=qmodels.MatchValue(value="research")
        ),
        qmodels.FieldCondition(
            key="year",
            match=qmodels.MatchValue(value=2024)
        )
    ]
)

# Initialize tool with preset filter
qdrant_tool = QdrantVectorSearchTool(
    qdrant_config=QdrantConfig(
        qdrant_url="your_url",
        qdrant_api_key="your_key",
        collection_name="your_collection",
        filter=preset_filter  # Preset filter applied to all searches
    )
)
```

### Combining Filters

The tool automatically combines preset filters from `QdrantConfig` with dynamic filters from `filter_by` and `filter_value`:

```python theme={null}
# If QdrantConfig has a preset filter for category="research"
# And the search uses filter_by="year", filter_value=2024
# Both filters will be combined (AND logic)
```

## Search Parameters

The tool accepts these parameters in its schema:

* `query` (str): The search query to find similar documents
* `filter_by` (str, optional): Metadata field to filter on
* `filter_value` (Any, optional): Value to filter by

## Return Format

The tool returns results in JSON format:

```json theme={null}
[
  {
    "metadata": {
      // Any metadata stored with the document
    },
    "context": "The actual text content of the document",
    "distance": 0.95  // Similarity score
  }
]
```

## Default Embedding

By default, the tool uses OpenAI's `text-embedding-3-large` model for vectorization. This requires:

* OpenAI API key set in environment: `OPENAI_API_KEY`

## Custom Embeddings

Instead of using the default embedding model, you might want to use your own embedding function in cases where you:

1. Want to use a different embedding model (e.g., Cohere, HuggingFace, Ollama models)
2. Need to reduce costs by using open-source embedding models
3. Have specific requirements for vector dimensions or embedding quality
4. Want to use domain-specific embeddings (e.g., for medical or legal text)

Here's an example using a HuggingFace model:

```python theme={null}
from transformers import AutoTokenizer, AutoModel
import torch

# Load model and tokenizer
tokenizer = AutoTokenizer.from_pretrained('sentence-transformers/all-MiniLM-L6-v2')
model = AutoModel.from_pretrained('sentence-transformers/all-MiniLM-L6-v2')

def custom_embeddings(text: str) -> list[float]:
    # Tokenize and get model outputs
    inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True)
    outputs = model(**inputs)

    # Use mean pooling to get text embedding
    embeddings = outputs.last_hidden_state.mean(dim=1)

    # Convert to list of floats and return
    return embeddings[0].tolist()

# Use custom embeddings with the tool
from crewai_tools import QdrantConfig

tool = QdrantVectorSearchTool(
    qdrant_config=QdrantConfig(
        qdrant_url="your_url",
        qdrant_api_key="your_key",
        collection_name="your_collection"
    ),
    custom_embedding_fn=custom_embeddings  # Pass your custom function
)
```

## Error Handling

The tool handles these specific errors:

* Raises ImportError if `qdrant-client` is not installed (with option to auto-install)
* Raises ValueError if `QDRANT_URL` is not set
* Prompts to install `qdrant-client` if missing using `uv add qdrant-client`

## Environment Variables

Required environment variables:

```bash theme={null}
export QDRANT_URL="your_qdrant_url"  # If not provided in constructor
export QDRANT_API_KEY="your_api_key"  # If not provided in constructor
export OPENAI_API_KEY="your_openai_key"  # If using default embeddings
```


# SingleStore Search Tool
Source: https://docs.crewai.com/en/tools/database-data/singlestoresearchtool

The `SingleStoreSearchTool` safely executes SELECT/SHOW queries on SingleStore with pooling.

# `SingleStoreSearchTool`

## Description

Execute read‑only queries (`SELECT`/`SHOW`) against SingleStore with connection pooling and input validation.

## Installation

```shell theme={null}
uv add crewai-tools[singlestore]
```

## Environment Variables

Variables like `SINGLESTOREDB_HOST`, `SINGLESTOREDB_USER`, `SINGLESTOREDB_PASSWORD`, etc., can be used, or `SINGLESTOREDB_URL` as a single DSN.

Generate the API key from the SingleStore dashboard, [docs here](https://docs.singlestore.com/cloud/reference/management-api/#generate-an-api-key).

## Example

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import SingleStoreSearchTool

tool = SingleStoreSearchTool(
    tables=["products"], 
    host="host", 
    user="user", 
    password="pass", 
    database="db",
)

agent = Agent(
    role="Analyst", 
    goal="Query SingleStore", 
    tools=[tool], 
    verbose=True,
)

task = Task(
    description="List 5 products", 
    expected_output="5 rows as JSON/text", 
    agent=agent,
)

crew = Crew(
    agents=[agent], 
    tasks=[task],
    verbose=True,
)

result = crew.kickoff()
```


# Snowflake Search Tool
Source: https://docs.crewai.com/en/tools/database-data/snowflakesearchtool

The `SnowflakeSearchTool` enables CrewAI agents to execute SQL queries and perform semantic search on Snowflake data warehouses.

# `SnowflakeSearchTool`

## Description

The `SnowflakeSearchTool` is designed to connect to Snowflake data warehouses and execute SQL queries with advanced features like connection pooling, retry logic, and asynchronous execution. This tool allows CrewAI agents to interact with Snowflake databases, making it ideal for data analysis, reporting, and business intelligence tasks that require access to enterprise data stored in Snowflake.

## Installation

To use this tool, you need to install the required dependencies:

```shell theme={null}
uv add cryptography snowflake-connector-python snowflake-sqlalchemy
```

Or alternatively:

```shell theme={null}
uv sync --extra snowflake
```

## Steps to Get Started

To effectively use the `SnowflakeSearchTool`, follow these steps:

1. **Install Dependencies**: Install the required packages using one of the commands above.
2. **Configure Snowflake Connection**: Create a `SnowflakeConfig` object with your Snowflake credentials.
3. **Initialize the Tool**: Create an instance of the tool with the necessary configuration.
4. **Execute Queries**: Use the tool to run SQL queries against your Snowflake database.

## Example

The following example demonstrates how to use the `SnowflakeSearchTool` to query data from a Snowflake database:

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import SnowflakeSearchTool, SnowflakeConfig

# Create Snowflake configuration
config = SnowflakeConfig(
    account="your_account",
    user="your_username",
    password="your_password",
    warehouse="COMPUTE_WH",
    database="your_database",
    snowflake_schema="your_schema"
)

# Initialize the tool
snowflake_tool = SnowflakeSearchTool(config=config)

# Define an agent that uses the tool
data_analyst_agent = Agent(
    role="Data Analyst",
    goal="Analyze data from Snowflake database",
    backstory="An expert data analyst who can extract insights from enterprise data.",
    tools=[snowflake_tool],
    verbose=True,
)

# Example task to query sales data
query_task = Task(
    description="Query the sales data for the last quarter and summarize the top 5 products by revenue.",
    expected_output="A summary of the top 5 products by revenue for the last quarter.",
    agent=data_analyst_agent,
)

# Create and run the crew
crew = Crew(agents=[data_analyst_agent], 
            tasks=[query_task])
result = crew.kickoff()
```

You can also customize the tool with additional parameters:

```python Code theme={null}
# Initialize the tool with custom parameters
snowflake_tool = SnowflakeSearchTool(
    config=config,
    pool_size=10,
    max_retries=5,
    retry_delay=2.0,
    enable_caching=True
)
```

## Parameters

### SnowflakeConfig Parameters

The `SnowflakeConfig` class accepts the following parameters:

* **account**: Required. Snowflake account identifier.
* **user**: Required. Snowflake username.
* **password**: Optional\*. Snowflake password.
* **private\_key\_path**: Optional\*. Path to private key file (alternative to password).
* **warehouse**: Required. Snowflake warehouse name.
* **database**: Required. Default database.
* **snowflake\_schema**: Required. Default schema.
* **role**: Optional. Snowflake role.
* **session\_parameters**: Optional. Custom session parameters as a dictionary.

\*Either `password` or `private_key_path` must be provided.

### SnowflakeSearchTool Parameters

The `SnowflakeSearchTool` accepts the following parameters during initialization:

* **config**: Required. A `SnowflakeConfig` object containing connection details.
* **pool\_size**: Optional. Number of connections in the pool. Default is 5.
* **max\_retries**: Optional. Maximum retry attempts for failed queries. Default is 3.
* **retry\_delay**: Optional. Delay between retries in seconds. Default is 1.0.
* **enable\_caching**: Optional. Whether to enable query result caching. Default is True.

## Usage

When using the `SnowflakeSearchTool`, you need to provide the following parameters:

* **query**: Required. The SQL query to execute.
* **database**: Optional. Override the default database specified in the config.
* **snowflake\_schema**: Optional. Override the default schema specified in the config.
* **timeout**: Optional. Query timeout in seconds. Default is 300.

The tool will return the query results as a list of dictionaries, where each dictionary represents a row with column names as keys.

```python Code theme={null}
# Example of using the tool with an agent
data_analyst = Agent(
    role="Data Analyst",
    goal="Analyze sales data from Snowflake",
    backstory="An expert data analyst with experience in SQL and data visualization.",
    tools=[snowflake_tool],
    verbose=True
)

# The agent will use the tool with parameters like:
# query="SELECT product_name, SUM(revenue) as total_revenue FROM sales GROUP BY product_name ORDER BY total_revenue DESC LIMIT 5"
# timeout=600

# Create a task for the agent
analysis_task = Task(
    description="Query the sales database and identify the top 5 products by revenue for the last quarter.",
    expected_output="A detailed analysis of the top 5 products by revenue.",
    agent=data_analyst
)

# Run the task
crew = Crew(
    agents=[data_analyst], 
    tasks=[analysis_task]
)
result = crew.kickoff()
```

## Advanced Features

### Connection Pooling

The `SnowflakeSearchTool` implements connection pooling to improve performance by reusing database connections. You can control the pool size with the `pool_size` parameter.

### Automatic Retries

The tool automatically retries failed queries with exponential backoff. You can configure the retry behavior with the `max_retries` and `retry_delay` parameters.

### Query Result Caching

To improve performance for repeated queries, the tool can cache query results. This feature is enabled by default but can be disabled by setting `enable_caching=False`.

### Key-Pair Authentication

In addition to password authentication, the tool supports key-pair authentication for enhanced security:

```python Code theme={null}
config = SnowflakeConfig(
    account="your_account",
    user="your_username",
    private_key_path="/path/to/your/private/key.p8",
    warehouse="COMPUTE_WH",
    database="your_database",
    snowflake_schema="your_schema"
)
```

## Error Handling

The `SnowflakeSearchTool` includes comprehensive error handling for common Snowflake issues:

* Connection failures
* Query timeouts
* Authentication errors
* Database and schema errors

When an error occurs, the tool will attempt to retry the operation (if configured) and provide detailed error information.

## Conclusion

The `SnowflakeSearchTool` provides a powerful way to integrate Snowflake data warehouses with CrewAI agents. With features like connection pooling, automatic retries, and query caching, it enables efficient and reliable access to enterprise data. This tool is particularly useful for data analysis, reporting, and business intelligence tasks that require access to structured data stored in Snowflake.


# Weaviate Vector Search
Source: https://docs.crewai.com/en/tools/database-data/weaviatevectorsearchtool

The `WeaviateVectorSearchTool` is designed to search a Weaviate vector database for semantically similar documents using hybrid search.

## Overview

The `WeaviateVectorSearchTool` is specifically crafted for conducting semantic searches within documents stored in a Weaviate vector database. This tool allows you to find semantically similar documents to a given query, leveraging the power of vector and keyword search for more accurate and contextually relevant search results.

[Weaviate](https://weaviate.io/) is a vector database that stores and queries vector embeddings, enabling semantic search capabilities.

## Installation

To incorporate this tool into your project, you need to install the Weaviate client:

```shell theme={null}
uv add weaviate-client
```

## Steps to Get Started

To effectively use the `WeaviateVectorSearchTool`, follow these steps:

1. **Package Installation**: Confirm that the `crewai[tools]` and `weaviate-client` packages are installed in your Python environment.
2. **Weaviate Setup**: Set up a Weaviate cluster. You can follow the [Weaviate documentation](https://weaviate.io/developers/wcs/manage-clusters/connect) for instructions.
3. **API Keys**: Obtain your Weaviate cluster URL and API key.
4. **OpenAI API Key**: Ensure you have an OpenAI API key set in your environment variables as `OPENAI_API_KEY`.

## Example

The following example demonstrates how to initialize the tool and execute a search:

```python Code theme={null}
from crewai_tools import WeaviateVectorSearchTool

# Initialize the tool
tool = WeaviateVectorSearchTool(
    collection_name='example_collections',
    limit=3,
    alpha=0.75,
    weaviate_cluster_url="https://your-weaviate-cluster-url.com",
    weaviate_api_key="your-weaviate-api-key",
)

@agent
def search_agent(self) -> Agent:
    '''
    This agent uses the WeaviateVectorSearchTool to search for 
    semantically similar documents in a Weaviate vector database.
    '''
    return Agent(
        config=self.agents_config["search_agent"],
        tools=[tool]
    )
```

## Parameters

The `WeaviateVectorSearchTool` accepts the following parameters:

* **collection\_name**: Required. The name of the collection to search within.
* **weaviate\_cluster\_url**: Required. The URL of the Weaviate cluster.
* **weaviate\_api\_key**: Required. The API key for the Weaviate cluster.
* **limit**: Optional. The number of results to return. Default is `3`.
* **alpha**: Optional. Controls the weighting between vector and keyword (BM25) search. alpha = 0 -> BM25 only, alpha = 1 -> vector search only. Default is `0.75`.
* **vectorizer**: Optional. The vectorizer to use. If not provided, it will use `text2vec_openai` with the `nomic-embed-text` model.
* **generative\_model**: Optional. The generative model to use. If not provided, it will use OpenAI's `gpt-4o`.

## Advanced Configuration

You can customize the vectorizer and generative model used by the tool:

```python Code theme={null}
from crewai_tools import WeaviateVectorSearchTool
from weaviate.classes.config import Configure

# Setup custom model for vectorizer and generative model
tool = WeaviateVectorSearchTool(
    collection_name='example_collections',
    limit=3,
    alpha=0.75,
    vectorizer=Configure.Vectorizer.text2vec_openai(model="nomic-embed-text"),
    generative_model=Configure.Generative.openai(model="gpt-4o-mini"),
    weaviate_cluster_url="https://your-weaviate-cluster-url.com",
    weaviate_api_key="your-weaviate-api-key",
)
```

## Preloading Documents

You can preload your Weaviate database with documents before using the tool:

```python Code theme={null}
import os
from crewai_tools import WeaviateVectorSearchTool
import weaviate
from weaviate.classes.init import Auth

# Connect to Weaviate
client = weaviate.connect_to_weaviate_cloud(
    cluster_url="https://your-weaviate-cluster-url.com",
    auth_credentials=Auth.api_key("your-weaviate-api-key"),
    headers={"X-OpenAI-Api-Key": "your-openai-api-key"}
)

# Get or create collection
test_docs = client.collections.get("example_collections")
if not test_docs:
    test_docs = client.collections.create(
        name="example_collections",
        vectorizer_config=Configure.Vectorizer.text2vec_openai(model="nomic-embed-text"),
        generative_config=Configure.Generative.openai(model="gpt-4o"),
    )

# Load documents
docs_to_load = os.listdir("knowledge")
with test_docs.batch.dynamic() as batch:
    for d in docs_to_load:
        with open(os.path.join("knowledge", d), "r") as f:
            content = f.read()
        batch.add_object(
            {
                "content": content,
                "year": d.split("_")[0],
            }
        )

# Initialize the tool
tool = WeaviateVectorSearchTool(
    collection_name='example_collections', 
    limit=3,
    alpha=0.75,
    weaviate_cluster_url="https://your-weaviate-cluster-url.com",
    weaviate_api_key="your-weaviate-api-key",
)
```

## Agent Integration Example

Here's how to integrate the `WeaviateVectorSearchTool` with a CrewAI agent:

```python Code theme={null}
from crewai import Agent
from crewai_tools import WeaviateVectorSearchTool

# Initialize the tool
weaviate_tool = WeaviateVectorSearchTool(
    collection_name='example_collections',
    limit=3,
    alpha=0.75,
    weaviate_cluster_url="https://your-weaviate-cluster-url.com",
    weaviate_api_key="your-weaviate-api-key",
)

# Create an agent with the tool
rag_agent = Agent(
    name="rag_agent",
    role="You are a helpful assistant that can answer questions with the help of the WeaviateVectorSearchTool.",
    llm="gpt-4o-mini",
    tools=[weaviate_tool],
)
```

## Conclusion

The `WeaviateVectorSearchTool` provides a powerful way to search for semantically similar documents in a Weaviate vector database. By leveraging vector embeddings, it enables more accurate and contextually relevant search results compared to traditional keyword-based searches. This tool is particularly useful for applications that require finding information based on meaning rather than exact matches.


# CSV RAG Search
Source: https://docs.crewai.com/en/tools/file-document/csvsearchtool

The `CSVSearchTool` is a powerful RAG (Retrieval-Augmented Generation) tool designed for semantic searches within a CSV file's content.

# `CSVSearchTool`

<Note>
  **Experimental**: We are still working on improving tools, so there might be unexpected behavior or changes in the future.
</Note>

## Description

This tool is used to perform a RAG (Retrieval-Augmented Generation) search within a CSV file's content. It allows users to semantically search for queries in the content of a specified CSV file.
This feature is particularly useful for extracting information from large CSV datasets where traditional search methods might be inefficient. All tools with "Search" in their name, including CSVSearchTool,
are RAG tools designed for searching different sources of data.

## Installation

Install the crewai\_tools package

```shell theme={null}
pip install 'crewai[tools]'
```

## Example

```python Code theme={null}
from crewai_tools import CSVSearchTool

# Initialize the tool with a specific CSV file. 
# This setup allows the agent to only search the given CSV file.
tool = CSVSearchTool(csv='path/to/your/csvfile.csv')

# OR

# Initialize the tool without a specific CSV file. 
# Agent will need to provide the CSV path at runtime.
tool = CSVSearchTool()
```

## Arguments

The following parameters can be used to customize the `CSVSearchTool`'s behavior:

| Argument | Type     | Description                                                                                                                                                               |
| :------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **csv**  | `string` | *Optional*. The path to the CSV file you want to search. This is a mandatory argument if the tool was initialized without a specific CSV file; otherwise, it is optional. |

## Custom model and embeddings

By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows:

```python Code theme={null}
from chromadb.config import Settings

tool = CSVSearchTool(
    config={
        "embedding_model": {
            "provider": "openai",
            "config": {
                "model": "text-embedding-3-small",
                # "api_key": "sk-...",
            },
        },
        "vectordb": {
            "provider": "chromadb",  # or "qdrant"
            "config": {
                # "settings": Settings(persist_directory="/content/chroma", allow_reset=True, is_persistent=True),
                # from qdrant_client.models import VectorParams, Distance
                # "vectors_config": VectorParams(size=384, distance=Distance.COSINE),
            }
        },
    }
)
```


# Directory Read
Source: https://docs.crewai.com/en/tools/file-document/directoryreadtool

The `DirectoryReadTool` is a powerful utility designed to provide a comprehensive listing of directory contents.

# `DirectoryReadTool`

<Note>
  We are still working on improving tools, so there might be unexpected behavior or changes in the future.
</Note>

## Description

The DirectoryReadTool is a powerful utility designed to provide a comprehensive listing of directory contents.
It can recursively navigate through the specified directory, offering users a detailed enumeration of all files, including those within subdirectories.
This tool is crucial for tasks that require a thorough inventory of directory structures or for validating the organization of files within directories.

## Installation

To utilize the DirectoryReadTool in your project, install the `crewai_tools` package. If this package is not yet part of your environment, you can install it using pip with the command below:

```shell theme={null}
pip install 'crewai[tools]'
```

This command installs the latest version of the `crewai_tools` package, granting access to the DirectoryReadTool among other utilities.

## Example

Employing the DirectoryReadTool is straightforward. The following code snippet demonstrates how to set it up and use the tool to list the contents of a specified directory:

```python Code theme={null}
from crewai_tools import DirectoryReadTool

# Initialize the tool so the agent can read any directory's content 
# it learns about during execution
tool = DirectoryReadTool()

# OR

# Initialize the tool with a specific directory, 
# so the agent can only read the content of the specified directory
tool = DirectoryReadTool(directory='/path/to/your/directory')
```

## Arguments

The following parameters can be used to customize the `DirectoryReadTool`'s behavior:

| Argument      | Type     | Description                                                                                                                                                                                                   |
| :------------ | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **directory** | `string` | *Optional*. An argument that specifies the path to the directory whose contents you wish to list. It accepts both absolute and relative paths, guiding the tool to the desired directory for content listing. |


# Directory RAG Search
Source: https://docs.crewai.com/en/tools/file-document/directorysearchtool

The `DirectorySearchTool` is a powerful RAG (Retrieval-Augmented Generation) tool designed for semantic searches within a directory's content.

# `DirectorySearchTool`

<Note>
  **Experimental**: The DirectorySearchTool is under continuous development. Features and functionalities might evolve, and unexpected behavior may occur as we refine the tool.
</Note>

## Description

The DirectorySearchTool enables semantic search within the content of specified directories, leveraging the Retrieval-Augmented Generation (RAG) methodology for efficient navigation through files. Designed for flexibility, it allows users to dynamically specify search directories at runtime or set a fixed directory during initial setup.

## Installation

To use the DirectorySearchTool, begin by installing the crewai\_tools package. Execute the following command in your terminal:

```shell theme={null}
pip install 'crewai[tools]'
```

## Initialization and Usage

Import the DirectorySearchTool from the `crewai_tools` package to start. You can initialize the tool without specifying a directory, enabling the setting of the search directory at runtime. Alternatively, the tool can be initialized with a predefined directory.

```python Code theme={null}
from crewai_tools import DirectorySearchTool

# For dynamic directory specification at runtime
tool = DirectorySearchTool()

# For fixed directory searches
tool = DirectorySearchTool(directory='/path/to/directory')
```

## Arguments

* `directory`: A string argument that specifies the search directory. This is optional during initialization but required for searches if not set initially.

## Custom Model and Embeddings

The DirectorySearchTool uses OpenAI for embeddings and summarization by default. Customization options for these settings include changing the model provider and configuration, enhancing flexibility for advanced users.

```python Code theme={null}
from chromadb.config import Settings

tool = DirectorySearchTool(
    config={
        "embedding_model": {
            "provider": "openai",
            "config": {
                "model": "text-embedding-3-small",
                # "api_key": "sk-...",
            },
        },
        "vectordb": {
            "provider": "chromadb",  # or "qdrant"
            "config": {
                # "settings": Settings(persist_directory="/content/chroma", allow_reset=True, is_persistent=True),
                # from qdrant_client.models import VectorParams, Distance
                # "vectors_config": VectorParams(size=384, distance=Distance.COSINE),
            }
        },
    }
)
```


# DOCX RAG Search
Source: https://docs.crewai.com/en/tools/file-document/docxsearchtool

The `DOCXSearchTool` is a RAG tool designed for semantic searching within DOCX documents.

# `DOCXSearchTool`

<Note>
  We are still working on improving tools, so there might be unexpected behavior or changes in the future.
</Note>

## Description

The `DOCXSearchTool` is a RAG tool designed for semantic searching within DOCX documents.
It enables users to effectively search and extract relevant information from DOCX files using query-based searches.
This tool is invaluable for data analysis, information management, and research tasks,
streamlining the process of finding specific information within large document collections.

## Installation

Install the crewai\_tools package by running the following command in your terminal:

```shell theme={null}
uv pip install docx2txt 'crewai[tools]'
```

## Example

The following example demonstrates initializing the DOCXSearchTool to search within any DOCX file's content or with a specific DOCX file path.

```python Code theme={null}
from crewai_tools import DOCXSearchTool

# Initialize the tool to search within any DOCX file's content
tool = DOCXSearchTool()

# OR

# Initialize the tool with a specific DOCX file, 
# so the agent can only search the content of the specified DOCX file
tool = DOCXSearchTool(docx='path/to/your/document.docx')
```

## Arguments

The following parameters can be used to customize the `DOCXSearchTool`'s behavior:

| Argument | Type     | Description                                                                                                                                                                                                        |
| :------- | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **docx** | `string` | *Optional*. An argument that specifies the path to the DOCX file you want to search. If not provided during initialization, the tool allows for later specification of any DOCX file's content path for searching. |

## Custom model and embeddings

By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows:

```python Code theme={null}
from chromadb.config import Settings

tool = DOCXSearchTool(
    config={
        "embedding_model": {
            "provider": "openai",
            "config": {
                "model": "text-embedding-3-small",
                # "api_key": "sk-...",
            },
        },
        "vectordb": {
            "provider": "chromadb",  # or "qdrant"
            "config": {
                # "settings": Settings(persist_directory="/content/chroma", allow_reset=True, is_persistent=True),
                # from qdrant_client.models import VectorParams, Distance
                # "vectors_config": VectorParams(size=384, distance=Distance.COSINE),
            }
        },
    }
)
```


# File Read
Source: https://docs.crewai.com/en/tools/file-document/filereadtool

The `FileReadTool` is designed to read files from the local file system.

## Overview

<Note>
  We are still working on improving tools, so there might be unexpected behavior or changes in the future.
</Note>

The FileReadTool conceptually represents a suite of functionalities within the crewai\_tools package aimed at facilitating file reading and content retrieval.
This suite includes tools for processing batch text files, reading runtime configuration files, and importing data for analytics.
It supports a variety of text-based file formats such as `.txt`, `.csv`, `.json`, and more. Depending on the file type, the suite offers specialized functionality,
such as converting JSON content into a Python dictionary for ease of use.

## Installation

To utilize the functionalities previously attributed to the FileReadTool, install the crewai\_tools package:

```shell theme={null}
pip install 'crewai[tools]'
```

## Usage Example

To get started with the FileReadTool:

```python Code theme={null}
from crewai_tools import FileReadTool

# Initialize the tool to read any files the agents knows or lean the path for
file_read_tool = FileReadTool()

# OR

# Initialize the tool with a specific file path, so the agent can only read the content of the specified file
file_read_tool = FileReadTool(file_path='path/to/your/file.txt')
```

## Arguments

* `file_path`: The path to the file you want to read. It accepts both absolute and relative paths. Ensure the file exists and you have the necessary permissions to access it.


# File Write
Source: https://docs.crewai.com/en/tools/file-document/filewritetool

The `FileWriterTool` is designed to write content to files.

# `FileWriterTool`

## Description

The `FileWriterTool` is a component of the crewai\_tools package, designed to simplify the process of writing content to files with cross-platform compatibility (Windows, Linux, macOS).
It is particularly useful in scenarios such as generating reports, saving logs, creating configuration files, and more.
This tool handles path differences across operating systems, supports UTF-8 encoding, and automatically creates directories if they don't exist, making it easier to organize your output reliably across different platforms.

## Installation

Install the crewai\_tools package to use the `FileWriterTool` in your projects:

```shell theme={null}
pip install 'crewai[tools]'
```

## Example

To get started with the `FileWriterTool`:

```python Code theme={null}
from crewai_tools import FileWriterTool

# Initialize the tool
file_writer_tool = FileWriterTool()

# Write content to a file in a specified directory
result = file_writer_tool._run('example.txt', 'This is a test content.', 'test_directory')
print(result)
```

## Arguments

* `filename`: The name of the file you want to create or overwrite.
* `content`: The content to write into the file.
* `directory` (optional): The path to the directory where the file will be created. Defaults to the current directory (`.`). If the directory does not exist, it will be created.

## Conclusion

By integrating the `FileWriterTool` into your crews, the agents can reliably write content to files across different operating systems.
This tool is essential for tasks that require saving output data, creating structured file systems, and handling cross-platform file operations.
It's particularly recommended for Windows users who may encounter file writing issues with standard Python file operations.

By adhering to the setup and usage guidelines provided, incorporating this tool into projects is straightforward and ensures consistent file writing behavior across all platforms.


# JSON RAG Search
Source: https://docs.crewai.com/en/tools/file-document/jsonsearchtool

The `JSONSearchTool` is designed to search JSON files and return the most relevant results.

# `JSONSearchTool`

<Note>
  The JSONSearchTool is currently in an experimental phase. This means the tool
  is under active development, and users might encounter unexpected behavior or
  changes. We highly encourage feedback on any issues or suggestions for
  improvements.
</Note>

## Description

The JSONSearchTool is designed to facilitate efficient and precise searches within JSON file contents. It utilizes a RAG (Retrieve and Generate) search mechanism, allowing users to specify a JSON path for targeted searches within a particular JSON file. This capability significantly improves the accuracy and relevance of search results.

## Installation

To install the JSONSearchTool, use the following pip command:

```shell theme={null}
pip install 'crewai[tools]'
```

## Usage Examples

Here are updated examples on how to utilize the JSONSearchTool effectively for searching within JSON files. These examples take into account the current implementation and usage patterns identified in the codebase.

```python Code theme={null}
from crewai_tools import JSONSearchTool

# General JSON content search
# This approach is suitable when the JSON path is either known beforehand or can be dynamically identified.
tool = JSONSearchTool()

# Restricting search to a specific JSON file
# Use this initialization method when you want to limit the search scope to a specific JSON file.
tool = JSONSearchTool(json_path='./path/to/your/file.json')
```

## Arguments

* `json_path` (str, optional): Specifies the path to the JSON file to be searched. This argument is not required if the tool is initialized for a general search. When provided, it confines the search to the specified JSON file.

## Configuration Options

The JSONSearchTool supports extensive customization through a configuration dictionary. This allows users to select different models for embeddings and summarization based on their requirements.

```python Code theme={null}
tool = JSONSearchTool(
    config={
        "llm": {
            "provider": "ollama",  # Other options include google, openai, anthropic, llama2, etc.
            "config": {
                "model": "llama2",
                # Additional optional configurations can be specified here.
                # temperature=0.5,
                # top_p=1,
                # stream=true,
            },
        },
        "embedding_model": {
            "provider": "google-generativeai", # or openai, ollama, ...
            "config": {
                "model_name": "gemini-embedding-001",
                "task_type": "RETRIEVAL_DOCUMENT",
                # Further customization options can be added here.
            },
        },
    }
)
```


# MDX RAG Search
Source: https://docs.crewai.com/en/tools/file-document/mdxsearchtool

The `MDXSearchTool` is designed to search MDX files and return the most relevant results.

# `MDXSearchTool`

<Note>
  The MDXSearchTool is in continuous development. Features may be added or removed, and functionality could change unpredictably as we refine the tool.
</Note>

## Description

The MDX Search Tool is a component of the `crewai_tools` package aimed at facilitating advanced markdown language extraction. It enables users to effectively search and extract relevant information from MD files using query-based searches. This tool is invaluable for data analysis, information management, and research tasks, streamlining the process of finding specific information within large document collections.

## Installation

Before using the MDX Search Tool, ensure the `crewai_tools` package is installed. If it is not, you can install it with the following command:

```shell theme={null}
pip install 'crewai[tools]'
```

## Usage Example

To use the MDX Search Tool, you must first set up the necessary environment variables. Then, integrate the tool into your crewAI project to begin your market research. Below is a basic example of how to do this:

```python Code theme={null}
from crewai_tools import MDXSearchTool

# Initialize the tool to search any MDX content it learns about during execution
tool = MDXSearchTool()

# OR

# Initialize the tool with a specific MDX file path for an exclusive search within that document
tool = MDXSearchTool(mdx='path/to/your/document.mdx')
```

## Parameters

* mdx: **Optional**. Specifies the MDX file path for the search. It can be provided during initialization.

## Customization of Model and Embeddings

The tool defaults to using OpenAI for embeddings and summarization. For customization, utilize a configuration dictionary as shown below:

```python Code theme={null}
from chromadb.config import Settings

tool = MDXSearchTool(
    config={
        "embedding_model": {
            "provider": "openai",
            "config": {
                "model": "text-embedding-3-small",
                # "api_key": "sk-...",
            },
        },
        "vectordb": {
            "provider": "chromadb",  # or "qdrant"
            "config": {
                # "settings": Settings(persist_directory="/content/chroma", allow_reset=True, is_persistent=True),
                # from qdrant_client.models import VectorParams, Distance
                # "vectors_config": VectorParams(size=384, distance=Distance.COSINE),
            }
        },
    }
)
```


# OCR Tool
Source: https://docs.crewai.com/en/tools/file-document/ocrtool

The `OCRTool` extracts text from local images or image URLs using an LLM with vision.

# `OCRTool`

## Description

Extract text from images (local path or URL). Uses a vision‑capable LLM via CrewAI’s LLM interface.

## Installation

No extra install beyond `crewai-tools`. Ensure your selected LLM supports vision.

## Parameters

### Run Parameters

* `image_path_url` (str, required): Local image path or HTTP(S) URL.

## Examples

### Direct usage

```python Code theme={null}
from crewai_tools import OCRTool

print(OCRTool().run(image_path_url="/tmp/receipt.png"))
```

### With an agent

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import OCRTool

ocr = OCRTool()

agent = Agent(
    role="OCR", 
    goal="Extract text", 
    tools=[ocr],
)

task = Task(
    description="Extract text from https://example.com/invoice.jpg", 
    expected_output="All detected text in plain text",
    agent=agent,
)

crew = Crew(agents=[agent], tasks=[task])
result = crew.kickoff()
```

## Notes

* Ensure the selected LLM supports image inputs.
* For large images, consider downscaling to reduce token usage.
* You can pass a specific LLM instance to the tool (e.g., `LLM(model="gpt-4o")`) if needed, matching the README guidance.

## Example

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import OCRTool

tool = OCRTool()

agent = Agent(
    role="OCR Specialist",
    goal="Extract text from images",
    backstory="Vision‑enabled analyst",
    tools=[tool],
    verbose=True,
)

task = Task(
    description="Extract text from https://example.com/receipt.png",
    expected_output="All detected text in plain text",
    agent=agent,
)

crew = Crew(agents=[agent], tasks=[task])
result = crew.kickoff()
```


# Overview
Source: https://docs.crewai.com/en/tools/file-document/overview

Read, write, and search through various file formats with CrewAI's document processing tools

These tools enable your agents to work with various file formats and document types. From reading PDFs to processing JSON data, these tools handle all your document processing needs.

## **Available Tools**

<CardGroup>
  <Card title="File Read Tool" icon="folders" href="/en/tools/file-document/filereadtool">
    Read content from any file type including text, markdown, and more.
  </Card>

  <Card title="File Write Tool" icon="file-pen" href="/en/tools/file-document/filewritetool">
    Write content to files, create new documents, and save processed data.
  </Card>

  <Card title="PDF Search Tool" icon="file-pdf" href="/en/tools/file-document/pdfsearchtool">
    Search and extract text content from PDF documents efficiently.
  </Card>

  <Card title="DOCX Search Tool" icon="file-word" href="/en/tools/file-document/docxsearchtool">
    Search through Microsoft Word documents and extract relevant content.
  </Card>

  <Card title="JSON Search Tool" icon="brackets-curly" href="/en/tools/file-document/jsonsearchtool">
    Parse and search through JSON files with advanced query capabilities.
  </Card>

  <Card title="CSV Search Tool" icon="table" href="/en/tools/file-document/csvsearchtool">
    Process and search through CSV files, extract specific rows and columns.
  </Card>

  <Card title="XML Search Tool" icon="code" href="/en/tools/file-document/xmlsearchtool">
    Parse XML files and search for specific elements and attributes.
  </Card>

  <Card title="MDX Search Tool" icon="markdown" href="/en/tools/file-document/mdxsearchtool">
    Search through MDX files and extract content from documentation.
  </Card>

  <Card title="TXT Search Tool" icon="file-lines" href="/en/tools/file-document/txtsearchtool">
    Search through plain text files with pattern matching capabilities.
  </Card>

  <Card title="Directory Search Tool" icon="folder-open" href="/en/tools/file-document/directorysearchtool">
    Search for files and folders within directory structures.
  </Card>

  <Card title="Directory Read Tool" icon="folder" href="/en/tools/file-document/directoryreadtool">
    Read and list directory contents, file structures, and metadata.
  </Card>

  <Card title="OCR Tool" icon="image" href="/en/tools/file-document/ocrtool">
    Extract text from images (local files or URLs) using a vision‑capable LLM.
  </Card>

  <Card title="PDF Text Writing Tool" icon="file-pdf" href="/en/tools/file-document/pdf-text-writing-tool">
    Write text at specific coordinates in PDFs, with optional custom fonts.
  </Card>
</CardGroup>

## **Common Use Cases**

* **Document Processing**: Extract and analyze content from various file formats
* **Data Import**: Read structured data from CSV, JSON, and XML files
* **Content Search**: Find specific information within large document collections
* **File Management**: Organize and manipulate files and directories
* **Data Export**: Save processed results to various file formats

## **Quick Start Example**

```python theme={null}
from crewai_tools import FileReadTool, PDFSearchTool, JSONSearchTool

# Create tools
file_reader = FileReadTool()
pdf_searcher = PDFSearchTool()
json_processor = JSONSearchTool()

# Add to your agent
agent = Agent(
    role="Document Analyst",
    tools=[file_reader, pdf_searcher, json_processor],
    goal="Process and analyze various document types"
)
```

## **Tips for Document Processing**

* **File Permissions**: Ensure your agent has proper read/write permissions
* **Large Files**: Consider chunking for very large documents
* **Format Support**: Check tool documentation for supported file formats
* **Error Handling**: Implement proper error handling for corrupted or inaccessible files


# PDF Text Writing Tool
Source: https://docs.crewai.com/en/tools/file-document/pdf-text-writing-tool

The `PDFTextWritingTool` writes text to specific positions in a PDF, supporting custom fonts.

# `PDFTextWritingTool`

## Description

Write text at precise coordinates on a PDF page, optionally embedding a custom TrueType font.

## Parameters

### Run Parameters

* `pdf_path` (str, required): Path to the input PDF.
* `text` (str, required): Text to add.
* `position` (tuple\[int, int], required): `(x, y)` coordinates.
* `font_size` (int, default `12`)
* `font_color` (str, default `"0 0 0 rg"`)
* `font_name` (str, default `"F1"`)
* `font_file` (str, optional): Path to `.ttf` file.
* `page_number` (int, default `0`)

## Example

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import PDFTextWritingTool

tool = PDFTextWritingTool()

agent = Agent(
    role="PDF Editor",
    goal="Annotate PDFs",
    backstory="Documentation specialist",
    tools=[tool],
    verbose=True,
)

task = Task(
    description="Write 'CONFIDENTIAL' at (72, 720) on page 1 of ./sample.pdf",
    expected_output="Confirmation message",
    agent=agent,
)

crew = Crew(
    agents=[agent], 
    tasks=[task],
    verbose=True,
)

result = crew.kickoff()
```

### Direct usage

```python Code theme={null}
from crewai_tools import PDFTextWritingTool

PDFTextWritingTool().run(
  pdf_path="./input.pdf",
  text="CONFIDENTIAL",
  position=(72, 720),
  font_size=18,
  page_number=0,
)
```

## Tips

* Coordinate origin is the bottom‑left corner.
* If using a custom font (`font_file`), ensure it is a valid `.ttf`.


# PDF RAG Search
Source: https://docs.crewai.com/en/tools/file-document/pdfsearchtool

The `PDFSearchTool` is designed to search PDF files and return the most relevant results.

# `PDFSearchTool`

<Note>
  We are still working on improving tools, so there might be unexpected behavior or changes in the future.
</Note>

## Description

The PDFSearchTool is a RAG tool designed for semantic searches within PDF content. It allows for inputting a search query and a PDF document, leveraging advanced search techniques to find relevant content efficiently.
This capability makes it especially useful for extracting specific information from large PDF files quickly.

## Installation

To get started with the PDFSearchTool, first, ensure the crewai\_tools package is installed with the following command:

```shell theme={null}
pip install 'crewai[tools]'
```

## Example

Here's how to use the PDFSearchTool to search within a PDF document:

```python Code theme={null}
from crewai_tools import PDFSearchTool

# Initialize the tool allowing for any PDF content search if the path is provided during execution
tool = PDFSearchTool()

# OR

# Initialize the tool with a specific PDF path for exclusive search within that document
tool = PDFSearchTool(pdf='path/to/your/document.pdf')
```

## Arguments

* `pdf`: **Optional** The PDF path for the search. Can be provided at initialization or within the `run` method's arguments. If provided at initialization, the tool confines its search to the specified document.

## Custom model and embeddings

By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows. Note: a vector database is required because generated embeddings must be stored and queried from a vectordb.

```python Code theme={null}
from crewai_tools import PDFSearchTool

# - embedding_model (required): choose provider + provider-specific config
# - vectordb (required): choose vector DB and pass its config

tool = PDFSearchTool(
    config={
        "embedding_model": {
            # Supported providers: "openai", "azure", "google-generativeai", "google-vertex",
            # "voyageai", "cohere", "huggingface", "jina", "sentence-transformer",
            # "text2vec", "ollama", "openclip", "instructor", "onnx", "roboflow", "watsonx", "custom"
            "provider": "openai",  # or: "google-generativeai", "cohere", "ollama", ...
            "config": {
                # Model identifier for the chosen provider. "model" will be auto-mapped to "model_name" internally.
                "model": "text-embedding-3-small",
                # Optional: API key. If omitted, the tool will use provider-specific env vars
                # (e.g., OPENAI_API_KEY or EMBEDDINGS_OPENAI_API_KEY for OpenAI).
                # "api_key": "sk-...",

                # Provider-specific examples:
                # --- Google Generative AI ---
                # (Set provider="google-generativeai" above)
                # "model_name": "gemini-embedding-001",
                # "task_type": "RETRIEVAL_DOCUMENT",
                # "title": "Embeddings",

                # --- Cohere ---
                # (Set provider="cohere" above)
                # "model": "embed-english-v3.0",

                # --- Ollama (local) ---
                # (Set provider="ollama" above)
                # "model": "nomic-embed-text",
            },
        },
        "vectordb": {
                    "provider": "chromadb",  # or "qdrant"
                    "config": {
                        # For ChromaDB: pass "settings" (chromadb.config.Settings) or rely on defaults.
                        # Example (uncomment and import):
                        # from chromadb.config import Settings
                        # "settings": Settings(
                        #     persist_directory="/content/chroma",
                        #     allow_reset=True,
                        #     is_persistent=True,
                        # ),

                        # For Qdrant: pass "vectors_config" (qdrant_client.models.VectorParams).
                        # Example (uncomment and import):
                        # from qdrant_client.models import VectorParams, Distance
                        # "vectors_config": VectorParams(size=384, distance=Distance.COSINE),

                        # Note: collection name is controlled by the tool (default: "rag_tool_collection"), not set here.
                    }
        },
    }
)
```


# TXT RAG Search
Source: https://docs.crewai.com/en/tools/file-document/txtsearchtool

The `TXTSearchTool` is designed to perform a RAG (Retrieval-Augmented Generation) search within the content of a text file.

## Overview

<Note>
  We are still working on improving tools, so there might be unexpected behavior or changes in the future.
</Note>

This tool is used to perform a RAG (Retrieval-Augmented Generation) search within the content of a text file.
It allows for semantic searching of a query within a specified text file's content,
making it an invaluable resource for quickly extracting information or finding specific sections of text based on the query provided.

## Installation

To use the `TXTSearchTool`, you first need to install the `crewai_tools` package.
This can be done using pip, a package manager for Python.
Open your terminal or command prompt and enter the following command:

```shell theme={null}
pip install 'crewai[tools]'
```

This command will download and install the TXTSearchTool along with any necessary dependencies.

## Example

The following example demonstrates how to use the TXTSearchTool to search within a text file.
This example shows both the initialization of the tool with a specific text file and the subsequent search within that file's content.

```python Code theme={null}
from crewai_tools import TXTSearchTool

# Initialize the tool to search within any text file's content 
# the agent learns about during its execution
tool = TXTSearchTool()

# OR

# Initialize the tool with a specific text file, 
# so the agent can search within the given text file's content
tool = TXTSearchTool(txt='path/to/text/file.txt')
```

## Arguments

* `txt` (str): **Optional**. The path to the text file you want to search.
  This argument is only required if the tool was not initialized with a specific text file;
  otherwise, the search will be conducted within the initially provided text file.

## Custom model and embeddings

By default, the tool uses OpenAI for both embeddings and summarization.
To customize the model, you can use a config dictionary as follows:

```python Code theme={null}
from chromadb.config import Settings

tool = TXTSearchTool(
    config={
        # Required: embeddings provider + config
        "embedding_model": {
            "provider": "openai",  # or google-generativeai, cohere, ollama, ...
            "config": {
                "model": "text-embedding-3-small",
                # "api_key": "sk-...",  # optional if env var is set (e.g., OPENAI_API_KEY or EMBEDDINGS_OPENAI_API_KEY)
                # Provider examples:
                # Google → model_name: "gemini-embedding-001", task_type: "RETRIEVAL_DOCUMENT"
                # Cohere → model: "embed-english-v3.0"
                # Ollama → model: "nomic-embed-text"
            },
        },

        # Required: vector database config
        "vectordb": {
            "provider": "chromadb",  # or "qdrant"
            "config": {
                # Chroma settings (optional persistence)
                # "settings": Settings(
                #     persist_directory="/content/chroma",
                #     allow_reset=True,
                #     is_persistent=True,
                # ),

                # Qdrant vector params example:
                # from qdrant_client.models import VectorParams, Distance
                # "vectors_config": VectorParams(size=384, distance=Distance.COSINE),

                # Note: collection name is controlled by the tool (default: "rag_tool_collection").
            }
        },
    }
)
```


# XML RAG Search
Source: https://docs.crewai.com/en/tools/file-document/xmlsearchtool

The `XMLSearchTool` is designed to perform a RAG (Retrieval-Augmented Generation) search within the content of a XML file.

# `XMLSearchTool`

<Note>
  We are still working on improving tools, so there might be unexpected behavior or changes in the future.
</Note>

## Description

The XMLSearchTool is a cutting-edge RAG tool engineered for conducting semantic searches within XML files.
Ideal for users needing to parse and extract information from XML content efficiently, this tool supports inputting a search query and an optional XML file path.
By specifying an XML path, users can target their search more precisely to the content of that file, thereby obtaining more relevant search outcomes.

## Installation

To start using the XMLSearchTool, you must first install the crewai\_tools package. This can be easily done with the following command:

```shell theme={null}
pip install 'crewai[tools]'
```

## Example

Here are two examples demonstrating how to use the XMLSearchTool.
The first example shows searching within a specific XML file, while the second example illustrates initiating a search without predefining an XML path, providing flexibility in search scope.

```python Code theme={null}
from crewai_tools import XMLSearchTool

# Allow agents to search within any XML file's content 
#as it learns about their paths during execution
tool = XMLSearchTool()

# OR

# Initialize the tool with a specific XML file path 
#for exclusive search within that document
tool = XMLSearchTool(xml='path/to/your/xmlfile.xml')
```

## Arguments

* `xml`: This is the path to the XML file you wish to search.
  It is an optional parameter during the tool's initialization but must be provided either at initialization or as part of the `run` method's arguments to execute a search.

## Custom model and embeddings

By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows:

```python Code   theme={null}
from chromadb.config import Settings

tool = XMLSearchTool(
    config={
        "embedding_model": {
            "provider": "openai",
            "config": {
                "model": "text-embedding-3-small",
                # "api_key": "sk-...",
            },
        },
        "vectordb": {
            "provider": "chromadb",  # or "qdrant"
            "config": {
                # "settings": Settings(persist_directory="/content/chroma", allow_reset=True, is_persistent=True),
                # from qdrant_client.models import VectorParams, Distance
                # "vectors_config": VectorParams(size=384, distance=Distance.COSINE),
            }
        },
    }
)
```


# Tools Overview
Source: https://docs.crewai.com/en/tools/overview

Discover CrewAI's extensive library of 40+ tools to supercharge your AI agents

CrewAI provides an extensive library of pre-built tools to enhance your agents' capabilities. From file processing to web scraping, database queries to AI services - we've got you covered.

## **Tool Categories**

<CardGroup>
  <Card title="File & Document" icon="folder-open" href="/en/tools/file-document/overview">
    Read, write, and search through various file formats including PDF, DOCX, JSON, CSV, and more. Perfect for document processing workflows.
  </Card>

  <Card title="Web Scraping & Browsing" icon="globe" href="/en/tools/web-scraping/overview">
    Extract data from websites, automate browser interactions, and scrape content at scale with tools like Firecrawl, Selenium, and more.
  </Card>

  <Card title="Search & Research" icon="magnifying-glass" href="/en/tools/search-research/overview">
    Perform web searches, find code repositories, research YouTube content, and discover information across the internet.
  </Card>

  <Card title="Database & Data" icon="database" href="/en/tools/database-data/overview">
    Connect to SQL databases, vector stores, and data warehouses. Query MySQL, PostgreSQL, Snowflake, Qdrant, and Weaviate.
  </Card>

  <Card title="AI & Machine Learning" icon="brain" href="/en/tools/ai-ml/overview">
    Generate images with DALL-E, process vision tasks, integrate with LangChain, build RAG systems, and leverage code interpreters.
  </Card>

  <Card title="Cloud & Storage" icon="cloud" href="/en/tools/cloud-storage/overview">
    Interact with cloud services including AWS S3, Amazon Bedrock, and other cloud storage and AI services.
  </Card>

  <Card title="Automation" icon="bolt" href="/en/tools/automation/overview">
    Automate workflows with Apify, Composio, and other platforms to connect your agents with external services.
  </Card>

  <Card title="Integrations" icon="plug" href="/en/tools/tool-integrations/overview">
    Integrate CrewAI with external systems like Amazon Bedrock and the CrewAI Automation toolkit.
  </Card>
</CardGroup>

## **Quick Access**

Need a specific tool? Here are some popular choices:

<CardGroup>
  <Card title="RAG Tool" icon="image" href="/en/tools/ai-ml/ragtool">
    Implement Retrieval-Augmented Generation
  </Card>

  <Card title="Serper Dev" icon="book-atlas" href="/en/tools/search-research/serperdevtool">
    Google search API
  </Card>

  <Card title="File Read" icon="file" href="/en/tools/file-document/filereadtool">
    Read any file type
  </Card>

  <Card title="Scrape Website" icon="globe" href="/en/tools/web-scraping/scrapewebsitetool">
    Extract web content
  </Card>

  <Card title="Code Interpreter" icon="code" href="/en/tools/ai-ml/codeinterpretertool">
    Execute Python code
  </Card>

  <Card title="S3 Reader" icon="cloud" href="/en/tools/cloud-storage/s3readertool">
    Access AWS S3 files
  </Card>
</CardGroup>

## **Getting Started**

To use any tool in your CrewAI project:

1. **Import** the tool in your crew configuration
2. **Add** it to your agent's tools list
3. **Configure** any required API keys or settings

```python theme={null}
from crewai_tools import FileReadTool, SerperDevTool

# Add tools to your agent
agent = Agent(
    role="Research Analyst",
    tools=[FileReadTool(), SerperDevTool()],
    # ... other configuration
)
```

## **Max Usage Count**

You can set a maximum usage count for a tool to prevent it from being used more than a certain number of times.
By default, the max usage count is unlimited.

```python theme={null}
from crewai_tools import FileReadTool

tool = FileReadTool(max_usage_count=5, ...)
```

Ready to explore? Pick a category above to discover tools that fit your use case!


# Arxiv Paper Tool
Source: https://docs.crewai.com/en/tools/search-research/arxivpapertool

The `ArxivPaperTool` searches arXiv for papers matching a query and optionally downloads PDFs.

# `ArxivPaperTool`

## Description

The `ArxivPaperTool` queries the arXiv API for academic papers and returns compact, readable results. It can also optionally download PDFs to disk.

## Installation

This tool has no special installation beyond `crewai-tools`.

```shell theme={null}
uv add crewai-tools
```

No API key is required. This tool uses the public arXiv Atom API.

## Steps to Get Started

1. Initialize the tool.
2. Provide a `search_query` (e.g., "transformer neural network").
3. Optionally set `max_results` (1–100) and enable PDF downloads in the constructor.

## Example

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import ArxivPaperTool

tool = ArxivPaperTool(
    download_pdfs=False,
    save_dir="./arxiv_pdfs",
    use_title_as_filename=True,
)

agent = Agent(
    role="Researcher",
    goal="Find relevant arXiv papers",
    backstory="Expert at literature discovery",
    tools=[tool],
    verbose=True,
)

task = Task(
    description="Search arXiv for 'transformer neural network' and list top 5 results.",
    expected_output="A concise list of 5 relevant papers with titles, links, and summaries.",
    agent=agent,
)

crew = Crew(agents=[agent], tasks=[task])
result = crew.kickoff()
```

### Direct usage (without Agent)

```python Code theme={null}
from crewai_tools import ArxivPaperTool

tool = ArxivPaperTool(
    download_pdfs=True, 
    save_dir="./arxiv_pdfs",
)
print(tool.run(search_query="mixture of experts", max_results=3))
```

## Parameters

### Initialization Parameters

* `download_pdfs` (bool, default `False`): Whether to download PDFs.
* `save_dir` (str, default `./arxiv_pdfs`): Directory to save PDFs.
* `use_title_as_filename` (bool, default `False`): Use paper titles for filenames.

### Run Parameters

* `search_query` (str, required): The arXiv search query.
* `max_results` (int, default `5`, range 1–100): Number of results.

## Output format

The tool returns a human‑readable list of papers with:

* Title
* Link (abs page)
* Snippet/summary (truncated)

When `download_pdfs=True`, PDFs are saved to disk and the summary mentions saved files.

## Usage Notes

* The tool returns formatted text with key metadata and links.
* When `download_pdfs=True`, PDFs will be stored in `save_dir`.

## Troubleshooting

* If you receive a network timeout, re‑try or reduce `max_results`.
* Invalid XML errors indicate an arXiv response parse issue; try a simpler query.
* File system errors (e.g., permission denied) may occur when saving PDFs; ensure `save_dir` is writable.

## Related links

* arXiv API docs: [https://info.arxiv.org/help/api/index.html](https://info.arxiv.org/help/api/index.html)

## Error Handling

* Network issues, invalid XML, and OS errors are handled with informative messages.


# Brave Search
Source: https://docs.crewai.com/en/tools/search-research/bravesearchtool

The `BraveSearchTool` is designed to search the internet using the Brave Search API.

# `BraveSearchTool`

## Description

This tool is designed to perform web searches using the Brave Search API. It allows you to search the internet with a specified query and retrieve relevant results. The tool supports customizable result counts and country-specific searches.

## Installation

To incorporate this tool into your project, follow the installation instructions below:

```shell theme={null}
pip install 'crewai[tools]'
```

## Steps to Get Started

To effectively use the `BraveSearchTool`, follow these steps:

1. **Package Installation**: Confirm that the `crewai[tools]` package is installed in your Python environment.
2. **API Key Acquisition**: Acquire a Brave Search API key at [https://api.search.brave.com/app/keys](https://api.search.brave.com/app/keys) (sign in to generate a key).
3. **Environment Configuration**: Store your obtained API key in an environment variable named `BRAVE_API_KEY` to facilitate its use by the tool.

## Example

The following example demonstrates how to initialize the tool and execute a search with a given query:

```python Code theme={null}
from crewai_tools import BraveSearchTool

# Initialize the tool for internet searching capabilities
tool = BraveSearchTool()

# Execute a search
results = tool.run(search_query="CrewAI agent framework")
print(results)
```

## Parameters

The `BraveSearchTool` accepts the following parameters:

* **search\_query**: Mandatory. The search query you want to use to search the internet.
* **country**: Optional. Specify the country for the search results. Default is empty string.
* **n\_results**: Optional. Number of search results to return. Default is `10`.
* **save\_file**: Optional. Whether to save the search results to a file. Default is `False`.

## Example with Parameters

Here is an example demonstrating how to use the tool with additional parameters:

```python Code theme={null}
from crewai_tools import BraveSearchTool

# Initialize the tool with custom parameters
tool = BraveSearchTool(
    country="US",
    n_results=5,
    save_file=True
)

# Execute a search
results = tool.run(search_query="Latest AI developments")
print(results)
```

## Agent Integration Example

Here's how to integrate the `BraveSearchTool` with a CrewAI agent:

```python Code theme={null}
from crewai import Agent
from crewai.project import agent
from crewai_tools import BraveSearchTool

# Initialize the tool
brave_search_tool = BraveSearchTool()

# Define an agent with the BraveSearchTool
@agent
def researcher(self) -> Agent:
    return Agent(
        config=self.agents_config["researcher"],
        allow_delegation=False,
        tools=[brave_search_tool]
    )
```

## Conclusion

By integrating the `BraveSearchTool` into Python projects, users gain the ability to conduct real-time, relevant searches across the internet directly from their applications. The tool provides a simple interface to the powerful Brave Search API, making it easy to retrieve and process search results programmatically. By adhering to the setup and usage guidelines provided, incorporating this tool into projects is streamlined and straightforward.


# Code Docs RAG Search
Source: https://docs.crewai.com/en/tools/search-research/codedocssearchtool

The `CodeDocsSearchTool` is a powerful RAG (Retrieval-Augmented Generation) tool designed for semantic searches within code documentation.

# `CodeDocsSearchTool`

<Note>
  **Experimental**: We are still working on improving tools, so there might be unexpected behavior or changes in the future.
</Note>

## Description

The CodeDocsSearchTool is a powerful RAG (Retrieval-Augmented Generation) tool designed for semantic searches within code documentation.
It enables users to efficiently find specific information or topics within code documentation. By providing a `docs_url` during initialization,
the tool narrows down the search to that particular documentation site. Alternatively, without a specific `docs_url`,
it searches across a wide array of code documentation known or discovered throughout its execution, making it versatile for various documentation search needs.

## Installation

To start using the CodeDocsSearchTool, first, install the crewai\_tools package via pip:

```shell theme={null}
pip install 'crewai[tools]'
```

## Example

Utilize the CodeDocsSearchTool as follows to conduct searches within code documentation:

```python Code theme={null}
from crewai_tools import CodeDocsSearchTool

# To search any code documentation content 
# if the URL is known or discovered during its execution:
tool = CodeDocsSearchTool()

# OR

# To specifically focus your search on a given documentation site 
# by providing its URL:
tool = CodeDocsSearchTool(docs_url='https://docs.example.com/reference')
```

<Note>
  Substitute '[https://docs.example.com/reference](https://docs.example.com/reference)' with your target documentation URL
  and 'How to use search tool' with the search query relevant to your needs.
</Note>

## Arguments

The following parameters can be used to customize the `CodeDocsSearchTool`'s behavior:

| Argument      | Type     | Description                                                             |
| :------------ | :------- | :---------------------------------------------------------------------- |
| **docs\_url** | `string` | *Optional*. Specifies the URL of the code documentation to be searched. |

## Custom model and embeddings

By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows:

```python Code theme={null}
tool = CodeDocsSearchTool(
    config=dict(
        llm=dict(
            provider="ollama", # or google, openai, anthropic, llama2, ...
            config=dict(
                model="llama2",
                # temperature=0.5,
                # top_p=1,
                # stream=true,
            ),
        ),
        embedder=dict(
            provider="google-generativeai", # or openai, ollama, ...
            config=dict(
                model_name="gemini-embedding-001",
                task_type="RETRIEVAL_DOCUMENT",
                # title="Embeddings",
            ),
        ),
    )
)
```


# Databricks SQL Query Tool
Source: https://docs.crewai.com/en/tools/search-research/databricks-query-tool

The `DatabricksQueryTool` executes SQL queries against Databricks workspace tables.

# `DatabricksQueryTool`

## Description

Run SQL against Databricks workspace tables with either CLI profile or direct host/token authentication.

## Installation

```shell theme={null}
uv add crewai-tools[databricks-sdk]
```

## Environment Variables

* `DATABRICKS_CONFIG_PROFILE` or (`DATABRICKS_HOST` + `DATABRICKS_TOKEN`)

Create a personal access token and find host details in the Databricks workspace under User Settings → Developer.
Docs: [https://docs.databricks.com/en/dev-tools/auth/pat.html](https://docs.databricks.com/en/dev-tools/auth/pat.html)

## Example

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import DatabricksQueryTool

tool = DatabricksQueryTool(
    default_catalog="main", 
    default_schema="default",
)

agent = Agent(
    role="Data Analyst",
    goal="Query Databricks",
    tools=[tool],
    verbose=True,
)

task = Task(
    description="SELECT * FROM my_table LIMIT 10",
    expected_output="10 rows", 
    agent=agent,
)

crew = Crew(
    agents=[agent], 
    tasks=[task],
    verbose=True,
)
result = crew.kickoff()

print(result)
```

## Parameters

* `query` (required): SQL query to execute
* `catalog` (optional): Override default catalog
* `db_schema` (optional): Override default schema
* `warehouse_id` (optional): Override default SQL warehouse
* `row_limit` (optional): Maximum rows to return (default: 1000)

## Defaults on initialization

* `default_catalog`
* `default_schema`
* `default_warehouse_id`

### Error handling & tips

* Authentication errors: verify `DATABRICKS_HOST` begins with `https://` and token is valid.
* Permissions: ensure your SQL warehouse and schema are accessible by your token.
* Limits: long‑running queries should be avoided in agent loops; add filters/limits.


# EXA Search Web Loader
Source: https://docs.crewai.com/en/tools/search-research/exasearchtool

The `EXASearchTool` is designed to perform a semantic search for a specified query from a text's content across the internet.

# `EXASearchTool`

## Description

The EXASearchTool is designed to perform a semantic search for a specified query from a text's content across the internet.
It utilizes the [exa.ai](https://exa.ai/) API to fetch and display the most relevant search results based on the query provided by the user.

## Installation

To incorporate this tool into your project, follow the installation instructions below:

```shell theme={null}
pip install 'crewai[tools]'
```

## Example

The following example demonstrates how to initialize the tool and execute a search with a given query:

```python Code theme={null}
from crewai_tools import EXASearchTool

# Initialize the tool for internet searching capabilities
tool = EXASearchTool()
```

## Steps to Get Started

To effectively use the EXASearchTool, follow these steps:

<Steps>
  <Step title="Package Installation">
    Confirm that the `crewai[tools]` package is installed in your Python environment.
  </Step>

  <Step title="API Key Acquisition">
    Acquire a [exa.ai](https://exa.ai/) API key by registering for a free account at [exa.ai](https://exa.ai/).
  </Step>

  <Step title="Environment Configuration">
    Store your obtained API key in an environment variable named `EXA_API_KEY` to facilitate its use by the tool.
  </Step>
</Steps>

## Conclusion

By integrating the `EXASearchTool` into Python projects, users gain the ability to conduct real-time, relevant searches across the internet directly from their applications.
By adhering to the setup and usage guidelines provided, incorporating this tool into projects is streamlined and straightforward.


# Github Search
Source: https://docs.crewai.com/en/tools/search-research/githubsearchtool

The `GithubSearchTool` is designed to search websites and convert them into clean markdown or structured data.

# `GithubSearchTool`

<Note>
  We are still working on improving tools, so there might be unexpected behavior or changes in the future.
</Note>

## Description

The GithubSearchTool is a Retrieval-Augmented Generation (RAG) tool specifically designed for conducting semantic searches within GitHub repositories. Utilizing advanced semantic search capabilities, it sifts through code, pull requests, issues, and repositories, making it an essential tool for developers, researchers, or anyone in need of precise information from GitHub.

## Installation

To use the GithubSearchTool, first ensure the crewai\_tools package is installed in your Python environment:

```shell theme={null}
pip install 'crewai[tools]'
```

This command installs the necessary package to run the GithubSearchTool along with any other tools included in the crewai\_tools package.

Get a GitHub Personal Access Token at [https://github.com/settings/tokens](https://github.com/settings/tokens) (Developer settings → Fine‑grained tokens or classic tokens).

## Example

Here’s how you can use the GithubSearchTool to perform semantic searches within a GitHub repository:

```python Code theme={null}
from crewai_tools import GithubSearchTool

# Initialize the tool for semantic searches within a specific GitHub repository
tool = GithubSearchTool(
	github_repo='https://github.com/example/repo',
	gh_token='your_github_personal_access_token',
	content_types=['code', 'issue'] # Options: code, repo, pr, issue
)

# OR

# Initialize the tool for semantic searches within a specific GitHub repository, so the agent can search any repository if it learns about during its execution
tool = GithubSearchTool(
	gh_token='your_github_personal_access_token',
	content_types=['code', 'issue'] # Options: code, repo, pr, issue
)
```

## Arguments

* `github_repo` : The URL of the GitHub repository where the search will be conducted. This is a mandatory field and specifies the target repository for your search.
* `gh_token` : Your GitHub Personal Access Token (PAT) required for authentication. You can create one in your GitHub account settings under Developer Settings > Personal Access Tokens.
* `content_types` : Specifies the types of content to include in your search. You must provide a list of content types from the following options: `code` for searching within the code,
  `repo` for searching within the repository's general information, `pr` for searching within pull requests, and `issue` for searching within issues.
  This field is mandatory and allows tailoring the search to specific content types within the GitHub repository.

## Custom model and embeddings

By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows:

```python Code theme={null}
tool = GithubSearchTool(
    config=dict(
        llm=dict(
            provider="ollama", # or google, openai, anthropic, llama2, ...
            config=dict(
                model="llama2",
                # temperature=0.5,
                # top_p=1,
                # stream=true,
            ),
        ),
        embedder=dict(
            provider="google-generativeai", # or openai, ollama, ...
            config=dict(
                model_name="gemini-embedding-001",
                task_type="RETRIEVAL_DOCUMENT",
                # title="Embeddings",
            ),
        ),
    )
)
```


# Linkup Search Tool
Source: https://docs.crewai.com/en/tools/search-research/linkupsearchtool

The `LinkupSearchTool` enables querying the Linkup API for contextual information.

# `LinkupSearchTool`

## Description

The `LinkupSearchTool` provides the ability to query the Linkup API for contextual information and retrieve structured results. This tool is ideal for enriching workflows with up-to-date and reliable information from Linkup, allowing agents to access relevant data during their tasks.

## Installation

To use this tool, you need to install the Linkup SDK:

```shell theme={null}
uv add linkup-sdk
```

## Steps to Get Started

To effectively use the `LinkupSearchTool`, follow these steps:

1. **API Key**: Obtain a Linkup API key.
2. **Environment Setup**: Set up your environment with the API key.
3. **Install SDK**: Install the Linkup SDK using the command above.

## Example

The following example demonstrates how to initialize the tool and use it in an agent:

```python Code theme={null}
from crewai_tools import LinkupSearchTool
from crewai import Agent
import os

# Initialize the tool with your API key
linkup_tool = LinkupSearchTool(api_key=os.getenv("LINKUP_API_KEY"))

# Define an agent that uses the tool
@agent
def researcher(self) -> Agent:
    '''
    This agent uses the LinkupSearchTool to retrieve contextual information
    from the Linkup API.
    '''
    return Agent(
        config=self.agents_config["researcher"],
        tools=[linkup_tool]
    )
```

## Parameters

The `LinkupSearchTool` accepts the following parameters:

### Constructor Parameters

* **api\_key**: Required. Your Linkup API key.

### Run Parameters

* **query**: Required. The search term or phrase.
* **depth**: Optional. The search depth. Default is "standard".
* **output\_type**: Optional. The type of output. Default is "searchResults".

## Advanced Usage

You can customize the search parameters for more specific results:

```python Code theme={null}
# Perform a search with custom parameters
results = linkup_tool.run(
    query="Women Nobel Prize Physics",
    depth="deep",
    output_type="searchResults"
)
```

## Return Format

The tool returns results in the following format:

```json theme={null}
{
  "success": true,
  "results": [
    {
      "name": "Result Title",
      "url": "https://example.com/result",
      "content": "Content of the result..."
    },
    // Additional results...
  ]
}
```

If an error occurs, the response will be:

```json theme={null}
{
  "success": false,
  "error": "Error message"
}
```

## Error Handling

The tool gracefully handles API errors and provides structured feedback. If the API request fails, the tool will return a dictionary with `success: false` and an error message.

## Conclusion

The `LinkupSearchTool` provides a seamless way to integrate Linkup's contextual information retrieval capabilities into your CrewAI agents. By leveraging this tool, agents can access relevant and up-to-date information to enhance their decision-making and task execution.


# Overview
Source: https://docs.crewai.com/en/tools/search-research/overview

Perform web searches, find repositories, and research information across the internet

These tools enable your agents to search the web, research topics, and find information across various platforms including search engines, GitHub, and YouTube.

## **Available Tools**

<CardGroup>
  <Card title="Serper Dev Tool" icon="google" href="/en/tools/search-research/serperdevtool">
    Google search API integration for comprehensive web search capabilities.
  </Card>

  <Card title="Brave Search Tool" icon="shield" href="/en/tools/search-research/bravesearchtool">
    Privacy-focused search with Brave's independent search index.
  </Card>

  <Card title="Exa Search Tool" icon="magnifying-glass" href="/en/tools/search-research/exasearchtool">
    AI-powered search for finding specific and relevant content.
  </Card>

  <Card title="LinkUp Search Tool" icon="link" href="/en/tools/search-research/linkupsearchtool">
    Real-time web search with fresh content indexing.
  </Card>

  <Card title="GitHub Search Tool" icon="github" href="/en/tools/search-research/githubsearchtool">
    Search GitHub repositories, code, issues, and documentation.
  </Card>

  <Card title="Website Search Tool" icon="globe" href="/en/tools/search-research/websitesearchtool">
    Search within specific websites and domains.
  </Card>

  <Card title="Code Docs Search Tool" icon="code" href="/en/tools/search-research/codedocssearchtool">
    Search through code documentation and technical resources.
  </Card>

  <Card title="YouTube Channel Search" icon="youtube" href="/en/tools/search-research/youtubechannelsearchtool">
    Search YouTube channels for specific content and creators.
  </Card>

  <Card title="YouTube Video Search" icon="play" href="/en/tools/search-research/youtubevideosearchtool">
    Find and analyze YouTube videos by topic, keyword, or criteria.
  </Card>

  <Card title="Tavily Search Tool" icon="magnifying-glass" href="/en/tools/search-research/tavilysearchtool">
    Comprehensive web search using Tavily's AI-powered search API.
  </Card>

  <Card title="Tavily Extractor Tool" icon="file-text" href="/en/tools/search-research/tavilyextractortool">
    Extract structured content from web pages using the Tavily API.
  </Card>

  <Card title="Arxiv Paper Tool" icon="box-archive" href="/en/tools/search-research/arxivpapertool">
    Search arXiv and optionally download PDFs.
  </Card>

  <Card title="SerpApi Google Search" icon="search" href="/en/tools/search-research/serpapi-googlesearchtool">
    Google search via SerpApi with structured results.
  </Card>

  <Card title="SerpApi Google Shopping" icon="cart-shopping" href="/en/tools/search-research/serpapi-googleshoppingtool">
    Google Shopping queries via SerpApi.
  </Card>
</CardGroup>

## **Common Use Cases**

* **Market Research**: Search for industry trends and competitor analysis
* **Content Discovery**: Find relevant articles, videos, and resources
* **Code Research**: Search repositories and documentation for solutions
* **Lead Generation**: Research companies and individuals
* **Academic Research**: Find scholarly articles and technical papers

```python theme={null}
from crewai_tools import SerperDevTool, GitHubSearchTool, YoutubeVideoSearchTool, TavilySearchTool, TavilyExtractorTool

# Create research tools
web_search = SerperDevTool()
code_search = GitHubSearchTool()
video_research = YoutubeVideoSearchTool()
tavily_search = TavilySearchTool()
content_extractor = TavilyExtractorTool()

# Add to your agent
agent = Agent(
    role="Research Analyst",
    tools=[web_search, code_search, video_research, tavily_search, content_extractor],
    goal="Gather comprehensive information on any topic"
)
```


# SerpApi Google Search Tool
Source: https://docs.crewai.com/en/tools/search-research/serpapi-googlesearchtool

The `SerpApiGoogleSearchTool` performs Google searches using the SerpApi service.

# `SerpApiGoogleSearchTool`

## Description

Use the `SerpApiGoogleSearchTool` to run Google searches with SerpApi and retrieve structured results. Requires a SerpApi API key.

## Installation

```shell theme={null}
uv add crewai-tools[serpapi]
```

## Environment Variables

* `SERPAPI_API_KEY` (required): API key for SerpApi. Create one at [https://serpapi.com/](https://serpapi.com/) (free tier available).

## Example

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import SerpApiGoogleSearchTool

tool = SerpApiGoogleSearchTool()

agent = Agent(
    role="Researcher",
    goal="Answer questions using Google search",
    backstory="Search specialist",
    tools=[tool],
    verbose=True,
)

task = Task(
    description="Search for the latest CrewAI releases",
    expected_output="A concise list of relevant results with titles and links",
    agent=agent,
)

crew = Crew(agents=[agent], tasks=[task])
result = crew.kickoff()
```

## Notes

* Set `SERPAPI_API_KEY` in the environment. Create a key at [https://serpapi.com/](https://serpapi.com/)
* See also Google Shopping via SerpApi: `/en/tools/search-research/serpapi-googleshoppingtool`

## Parameters

### Run Parameters

* `search_query` (str, required): The Google query.
* `location` (str, optional): Geographic location parameter.

## Notes

* This tool wraps SerpApi and returns structured search results.


# SerpApi Google Shopping Tool
Source: https://docs.crewai.com/en/tools/search-research/serpapi-googleshoppingtool

The `SerpApiGoogleShoppingTool` searches Google Shopping results using SerpApi.

# `SerpApiGoogleShoppingTool`

## Description

Leverage `SerpApiGoogleShoppingTool` to query Google Shopping via SerpApi and retrieve product-oriented results.

## Installation

```shell theme={null}
uv add crewai-tools[serpapi]
```

## Environment Variables

* `SERPAPI_API_KEY` (required): API key for SerpApi. Create one at [https://serpapi.com/](https://serpapi.com/) (free tier available).

## Example

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import SerpApiGoogleShoppingTool

tool = SerpApiGoogleShoppingTool()

agent = Agent(
    role="Shopping Researcher",
    goal="Find relevant products",
    backstory="Expert in product search",
    tools=[tool],
    verbose=True,
)

task = Task(
    description="Search Google Shopping for 'wireless noise-canceling headphones'",
    expected_output="Top relevant products with titles and links",
    agent=agent,
)

crew = Crew(agents=[agent], tasks=[task])
result = crew.kickoff()
```

## Notes

* Set `SERPAPI_API_KEY` in the environment. Create a key at [https://serpapi.com/](https://serpapi.com/)
* See also Google Web Search via SerpApi: `/en/tools/search-research/serpapi-googlesearchtool`

## Parameters

### Run Parameters

* `search_query` (str, required): Product search query.
* `location` (str, optional): Geographic location parameter.


# Google Serper Search
Source: https://docs.crewai.com/en/tools/search-research/serperdevtool

The `SerperDevTool` is designed to search the internet and return the most relevant results.

# `SerperDevTool`

## Description

This tool is designed to perform a semantic search for a specified query from a text's content across the internet. It utilizes the [serper.dev](https://serper.dev) API
to fetch and display the most relevant search results based on the query provided by the user.

## Installation

To effectively use the `SerperDevTool`, follow these steps:

1. **Package Installation**: Confirm that the `crewai[tools]` package is installed in your Python environment.
2. **API Key Acquisition**: Acquire a `serper.dev` API key at [https://serper.dev/](https://serper.dev/) (free tier available).
3. **Environment Configuration**: Store your obtained API key in an environment variable named `SERPER_API_KEY` to facilitate its use by the tool.

To incorporate this tool into your project, follow the installation instructions below:

```shell theme={null}
pip install 'crewai[tools]'
```

## Example

The following example demonstrates how to initialize the tool and execute a search with a given query:

```python Code theme={null}
from crewai_tools import SerperDevTool

# Initialize the tool for internet searching capabilities
tool = SerperDevTool()
```

## Parameters

The `SerperDevTool` comes with several parameters that will be passed to the API :

* **search\_url**: The URL endpoint for the search API. (Default is `https://google.serper.dev/search`)

* **country**: Optional. Specify the country for the search results.

* **location**: Optional. Specify the location for the search results.

* **locale**: Optional. Specify the locale for the search results.

* **n\_results**: Number of search results to return. Default is `10`.

The values for `country`, `location`, `locale` and `search_url` can be found on the [Serper Playground](https://serper.dev/playground).

## Example with Parameters

Here is an example demonstrating how to use the tool with additional parameters:

```python Code theme={null}
from crewai_tools import SerperDevTool

tool = SerperDevTool(
    search_url="https://google.serper.dev/scholar",
    n_results=2,
)

print(tool.run(search_query="ChatGPT"))

# Using Tool: Search the internet

# Search results: Title: Role of chat gpt in public health
# Link: https://link.springer.com/article/10.1007/s10439-023-03172-7
# Snippet: … ChatGPT in public health. In this overview, we will examine the potential uses of ChatGPT in
# ---
# Title: Potential use of chat gpt in global warming
# Link: https://link.springer.com/article/10.1007/s10439-023-03171-8
# Snippet: … as ChatGPT, have the potential to play a critical role in advancing our understanding of climate
# ---

```

```python Code theme={null}
from crewai_tools import SerperDevTool

tool = SerperDevTool(
    country="fr",
    locale="fr",
    location="Paris, Paris, Ile-de-France, France",
    n_results=2,
)

print(tool.run(search_query="Jeux Olympiques"))

# Using Tool: Search the internet

# Search results: Title: Jeux Olympiques de Paris 2024 - Actualités, calendriers, résultats
# Link: https://olympics.com/fr/paris-2024
# Snippet: Quels sont les sports présents aux Jeux Olympiques de Paris 2024 ? · Athlétisme · Aviron · Badminton · Basketball · Basketball 3x3 · Boxe · Breaking · Canoë ...
# ---
# Title: Billetterie Officielle de Paris 2024 - Jeux Olympiques et Paralympiques
# Link: https://tickets.paris2024.org/
# Snippet: Achetez vos billets exclusivement sur le site officiel de la billetterie de Paris 2024 pour participer au plus grand événement sportif au monde.
# ---
```

## Conclusion

By integrating the `SerperDevTool` into Python projects, users gain the ability to conduct real-time, relevant searches across the internet directly from their applications.
The updated parameters allow for more customized and localized search results. By adhering to the setup and usage guidelines provided, incorporating this tool into projects is streamlined and straightforward.


# Tavily Extractor Tool
Source: https://docs.crewai.com/en/tools/search-research/tavilyextractortool

Extract structured content from web pages using the Tavily API

The `TavilyExtractorTool` allows CrewAI agents to extract structured content from web pages using the Tavily API. It can process single URLs or lists of URLs and provides options for controlling the extraction depth and including images.

## Installation

To use the `TavilyExtractorTool`, you need to install the `tavily-python` library:

```shell theme={null}
pip install 'crewai[tools]' tavily-python
```

You also need to set your Tavily API key as an environment variable:

```bash theme={null}
export TAVILY_API_KEY='your-tavily-api-key'
```

## Example Usage

Here's how to initialize and use the `TavilyExtractorTool` within a CrewAI agent:

```python theme={null}
import os
from crewai import Agent, Task, Crew
from crewai_tools import TavilyExtractorTool

# Ensure TAVILY_API_KEY is set in your environment
# os.environ["TAVILY_API_KEY"] = "YOUR_API_KEY"

# Initialize the tool
tavily_tool = TavilyExtractorTool()

# Create an agent that uses the tool
extractor_agent = Agent(
    role='Web Content Extractor',
    goal='Extract key information from specified web pages',
    backstory='You are an expert at extracting relevant content from websites using the Tavily API.',
    tools=[tavily_tool],
    verbose=True
)

# Define a task for the agent
extract_task = Task(
    description='Extract the main content from the URL https://example.com using basic extraction depth.',
    expected_output='A JSON string containing the extracted content from the URL.',
    agent=extractor_agent
)

# Create and run the crew
crew = Crew(
    agents=[extractor_agent],
    tasks=[extract_task],
    verbose=2
)

result = crew.kickoff()
print(result)
```

## Configuration Options

The `TavilyExtractorTool` accepts the following arguments:

* `urls` (Union\[List\[str], str]): **Required**. A single URL string or a list of URL strings to extract data from.
* `include_images` (Optional\[bool]): Whether to include images in the extraction results. Defaults to `False`.
* `extract_depth` (Literal\["basic", "advanced"]): The depth of extraction. Use `"basic"` for faster, surface-level extraction or `"advanced"` for more comprehensive extraction. Defaults to `"basic"`.
* `timeout` (int): The maximum time in seconds to wait for the extraction request to complete. Defaults to `60`.

## Advanced Usage

### Multiple URLs with Advanced Extraction

```python theme={null}
# Example with multiple URLs and advanced extraction
multi_extract_task = Task(
    description='Extract content from https://example.com and https://anotherexample.org using advanced extraction.',
    expected_output='A JSON string containing the extracted content from both URLs.',
    agent=extractor_agent
)

# Configure the tool with custom parameters
custom_extractor = TavilyExtractorTool(
    extract_depth='advanced',
    include_images=True,
    timeout=120
)

agent_with_custom_tool = Agent(
    role="Advanced Content Extractor",
    goal="Extract comprehensive content with images",
    tools=[custom_extractor]
)
```

### Tool Parameters

You can customize the tool's behavior by setting parameters during initialization:

```python theme={null}
# Initialize with custom configuration
extractor_tool = TavilyExtractorTool(
    extract_depth='advanced',  # More comprehensive extraction
    include_images=True,       # Include image results
    timeout=90                 # Custom timeout
)
```

## Features

* **Single or Multiple URLs**: Extract content from one URL or process multiple URLs in a single request
* **Configurable Depth**: Choose between basic (fast) and advanced (comprehensive) extraction modes
* **Image Support**: Optionally include images in the extraction results
* **Structured Output**: Returns well-formatted JSON containing the extracted content
* **Error Handling**: Robust handling of network timeouts and extraction errors

## Response Format

The tool returns a JSON string representing the structured data extracted from the provided URL(s). The exact structure depends on the content of the pages and the `extract_depth` used.

Common response elements include:

* **Title**: The page title
* **Content**: Main text content of the page
* **Images**: Image URLs and metadata (when `include_images=True`)
* **Metadata**: Additional page information like author, description, etc.

## Use Cases

* **Content Analysis**: Extract and analyze content from competitor websites
* **Research**: Gather structured data from multiple sources for analysis
* **Content Migration**: Extract content from existing websites for migration
* **Monitoring**: Regular extraction of content for change detection
* **Data Collection**: Systematic extraction of information from web sources

Refer to the [Tavily API documentation](https://docs.tavily.com/docs/tavily-api/python-sdk#extract) for detailed information about the response structure and available options.


# Tavily Search Tool
Source: https://docs.crewai.com/en/tools/search-research/tavilysearchtool

Perform comprehensive web searches using the Tavily Search API

The `TavilySearchTool` provides an interface to the Tavily Search API, enabling CrewAI agents to perform comprehensive web searches. It allows for specifying search depth, topics, time ranges, included/excluded domains, and whether to include direct answers, raw content, or images in the results.

## Installation

To use the `TavilySearchTool`, you need to install the `tavily-python` library:

```shell theme={null}
pip install 'crewai[tools]' tavily-python
```

## Environment Variables

Ensure your Tavily API key is set as an environment variable:

```bash theme={null}
export TAVILY_API_KEY='your_tavily_api_key'
```

Get an API key at [https://app.tavily.com/](https://app.tavily.com/) (sign up, then create a key).

## Example Usage

Here's how to initialize and use the `TavilySearchTool` within a CrewAI agent:

```python theme={null}
import os
from crewai import Agent, Task, Crew
from crewai_tools import TavilySearchTool

# Ensure the TAVILY_API_KEY environment variable is set
# os.environ["TAVILY_API_KEY"] = "YOUR_TAVILY_API_KEY"

# Initialize the tool
tavily_tool = TavilySearchTool()

# Create an agent that uses the tool
researcher = Agent(
    role='Market Researcher',
    goal='Find information about the latest AI trends',
    backstory='An expert market researcher specializing in technology.',
    tools=[tavily_tool],
    verbose=True
)

# Create a task for the agent
research_task = Task(
    description='Search for the top 3 AI trends in 2024.',
    expected_output='A JSON report summarizing the top 3 AI trends found.',
    agent=researcher
)

# Form the crew and kick it off
crew = Crew(
    agents=[researcher],
    tasks=[research_task],
    verbose=2
)

result = crew.kickoff()
print(result)
```

## Configuration Options

The `TavilySearchTool` accepts the following arguments during initialization or when calling the `run` method:

* `query` (str): **Required**. The search query string.
* `search_depth` (Literal\["basic", "advanced"], optional): The depth of the search. Defaults to `"basic"`.
* `topic` (Literal\["general", "news", "finance"], optional): The topic to focus the search on. Defaults to `"general"`.
* `time_range` (Literal\["day", "week", "month", "year"], optional): The time range for the search. Defaults to `None`.
* `days` (int, optional): The number of days to search back. Relevant if `time_range` is not set. Defaults to `7`.
* `max_results` (int, optional): The maximum number of search results to return. Defaults to `5`.
* `include_domains` (Sequence\[str], optional): A list of domains to prioritize in the search. Defaults to `None`.
* `exclude_domains` (Sequence\[str], optional): A list of domains to exclude from the search. Defaults to `None`.
* `include_answer` (Union\[bool, Literal\["basic", "advanced"]], optional): Whether to include a direct answer synthesized from the search results. Defaults to `False`.
* `include_raw_content` (bool, optional): Whether to include the raw HTML content of the searched pages. Defaults to `False`.
* `include_images` (bool, optional): Whether to include image results. Defaults to `False`.
* `timeout` (int, optional): The request timeout in seconds. Defaults to `60`.

## Advanced Usage

You can configure the tool with custom parameters:

```python theme={null}
# Example: Initialize with specific parameters
custom_tavily_tool = TavilySearchTool(
    search_depth='advanced',
    max_results=10,
    include_answer=True
)

# The agent will use these defaults
agent_with_custom_tool = Agent(
    role="Advanced Researcher",
    goal="Conduct detailed research with comprehensive results",
    tools=[custom_tavily_tool]
)
```

## Features

* **Comprehensive Search**: Access to Tavily's powerful search index
* **Configurable Depth**: Choose between basic and advanced search modes
* **Topic Filtering**: Focus searches on general, news, or finance topics
* **Time Range Control**: Limit results to specific time periods
* **Domain Control**: Include or exclude specific domains
* **Direct Answers**: Get synthesized answers from search results
* **Content Filtering**: Prevent context window issues with automatic content truncation

## Response Format

The tool returns search results as a JSON string containing:

* Search results with titles, URLs, and content snippets
* Optional direct answers to queries
* Optional image results
* Optional raw HTML content (when enabled)

Content for each result is automatically truncated to prevent context window issues while maintaining the most relevant information.


# Website RAG Search
Source: https://docs.crewai.com/en/tools/search-research/websitesearchtool

The `WebsiteSearchTool` is designed to perform a RAG (Retrieval-Augmented Generation) search within the content of a website.

# `WebsiteSearchTool`

<Note>
  The WebsiteSearchTool is currently in an experimental phase. We are actively working on incorporating this tool into our suite of offerings and will update the documentation accordingly.
</Note>

## Description

The WebsiteSearchTool is designed as a concept for conducting semantic searches within the content of websites.
It aims to leverage advanced machine learning models like Retrieval-Augmented Generation (RAG) to navigate and extract information from specified URLs efficiently.
This tool intends to offer flexibility, allowing users to perform searches across any website or focus on specific websites of interest.
Please note, the current implementation details of the WebsiteSearchTool are under development, and its functionalities as described may not yet be accessible.

## Installation

To prepare your environment for when the WebsiteSearchTool becomes available, you can install the foundational package with:

```shell theme={null}
pip install 'crewai[tools]'
```

This command installs the necessary dependencies to ensure that once the tool is fully integrated, users can start using it immediately.

## Example Usage

Below are examples of how the WebsiteSearchTool could be utilized in different scenarios. Please note, these examples are illustrative and represent planned functionality:

```python Code theme={null}
from crewai_tools import WebsiteSearchTool

# Example of initiating tool that agents can use 
# to search across any discovered websites
tool = WebsiteSearchTool()

# Example of limiting the search to the content of a specific website, 
# so now agents can only search within that website
tool = WebsiteSearchTool(website='https://example.com')
```

## Arguments

* `website`: An optional argument intended to specify the website URL for focused searches. This argument is designed to enhance the tool's flexibility by allowing targeted searches when necessary.

## Customization Options

By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows:

```python Code theme={null}
tool = WebsiteSearchTool(
    config=dict(
        llm=dict(
            provider="ollama", # or google, openai, anthropic, llama2, ...
            config=dict(
                model="llama2",
                # temperature=0.5,
                # top_p=1,
                # stream=true,
            ),
        ),
        embedder=dict(
            provider="google-generativeai", # or openai, ollama, ...
            config=dict(
                model_name="gemini-embedding-001",
                task_type="RETRIEVAL_DOCUMENT",
                # title="Embeddings",
            ),
        ),
    )
)
```


# YouTube Channel RAG Search
Source: https://docs.crewai.com/en/tools/search-research/youtubechannelsearchtool

The `YoutubeChannelSearchTool` is designed to perform a RAG (Retrieval-Augmented Generation) search within the content of a Youtube channel.

# `YoutubeChannelSearchTool`

<Note>
  We are still working on improving tools, so there might be unexpected behavior or changes in the future.
</Note>

## Description

This tool is designed to perform semantic searches within a specific Youtube channel's content.
Leveraging the RAG (Retrieval-Augmented Generation) methodology, it provides relevant search results,
making it invaluable for extracting information or finding specific content without the need to manually sift through videos.
It streamlines the search process within Youtube channels, catering to researchers, content creators, and viewers seeking specific information or topics.

## Installation

To utilize the YoutubeChannelSearchTool, the `crewai_tools` package must be installed. Execute the following command in your shell to install:

```shell theme={null}
pip install 'crewai[tools]'
```

## Example

The following example demonstrates how to use the `YoutubeChannelSearchTool` with a CrewAI agent:

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import YoutubeChannelSearchTool

# Initialize the tool for general YouTube channel searches
youtube_channel_tool = YoutubeChannelSearchTool()

# Define an agent that uses the tool
channel_researcher = Agent(
    role="Channel Researcher",
    goal="Extract relevant information from YouTube channels",
    backstory="An expert researcher who specializes in analyzing YouTube channel content.",
    tools=[youtube_channel_tool],
    verbose=True,
)

# Example task to search for information in a specific channel
research_task = Task(
    description="Search for information about machine learning tutorials in the YouTube channel {youtube_channel_handle}",
    expected_output="A summary of the key machine learning tutorials available on the channel.",
    agent=channel_researcher,
)

# Create and run the crew
crew = Crew(agents=[channel_researcher], tasks=[research_task])
result = crew.kickoff(inputs={"youtube_channel_handle": "@exampleChannel"})
```

You can also initialize the tool with a specific YouTube channel handle:

```python Code theme={null}
# Initialize the tool with a specific YouTube channel handle
youtube_channel_tool = YoutubeChannelSearchTool(
    youtube_channel_handle='@exampleChannel'
)

# Define an agent that uses the tool
channel_researcher = Agent(
    role="Channel Researcher",
    goal="Extract relevant information from a specific YouTube channel",
    backstory="An expert researcher who specializes in analyzing YouTube channel content.",
    tools=[youtube_channel_tool],
    verbose=True,
)
```

## Parameters

The `YoutubeChannelSearchTool` accepts the following parameters:

* **youtube\_channel\_handle**: Optional. The handle of the YouTube channel to search within. If provided during initialization, the agent won't need to specify it when using the tool. If the handle doesn't start with '@', it will be automatically added.
* **config**: Optional. Configuration for the underlying RAG system, including LLM and embedder settings.
* **summarize**: Optional. Whether to summarize the retrieved content. Default is `False`.

When using the tool with an agent, the agent will need to provide:

* **search\_query**: Required. The search query to find relevant information in the channel content.
* **youtube\_channel\_handle**: Required only if not provided during initialization. The handle of the YouTube channel to search within.

## Custom Model and Embeddings

By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows:

```python Code   theme={null}
youtube_channel_tool = YoutubeChannelSearchTool(
    config=dict(
        llm=dict(
            provider="ollama", # or google, openai, anthropic, llama2, ...
            config=dict(
                model="llama2",
                # temperature=0.5,
                # top_p=1,
                # stream=true,
            ),
        ),
        embedder=dict(
            provider="google-generativeai", # or openai, ollama, ...
            config=dict(
                model_name="gemini-embedding-001",
                task_type="RETRIEVAL_DOCUMENT",
                # title="Embeddings",
            ),
        ),
    )
)
```

## Agent Integration Example

Here's a more detailed example of how to integrate the `YoutubeChannelSearchTool` with a CrewAI agent:

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import YoutubeChannelSearchTool

# Initialize the tool
youtube_channel_tool = YoutubeChannelSearchTool()

# Define an agent that uses the tool
channel_researcher = Agent(
    role="Channel Researcher",
    goal="Extract and analyze information from YouTube channels",
    backstory="""You are an expert channel researcher who specializes in extracting 
    and analyzing information from YouTube channels. You have a keen eye for detail 
    and can quickly identify key points and insights from video content across an entire channel.""",
    tools=[youtube_channel_tool],
    verbose=True,
)

# Create a task for the agent
research_task = Task(
    description="""
    Search for information about data science projects and tutorials 
    in the YouTube channel {youtube_channel_handle}. 
    
    Focus on:
    1. Key data science techniques covered
    2. Popular tutorial series
    3. Most viewed or recommended videos
    
    Provide a comprehensive summary of these points.
    """,
    expected_output="A detailed summary of data science content available on the channel.",
    agent=channel_researcher,
)

# Run the task
crew = Crew(agents=[channel_researcher], tasks=[research_task])
result = crew.kickoff(inputs={"youtube_channel_handle": "@exampleDataScienceChannel"})
```

## Implementation Details

The `YoutubeChannelSearchTool` is implemented as a subclass of `RagTool`, which provides the base functionality for Retrieval-Augmented Generation:

```python Code theme={null}
class YoutubeChannelSearchTool(RagTool):
    name: str = "Search a Youtube Channels content"
    description: str = "A tool that can be used to semantic search a query from a Youtube Channels content."
    args_schema: Type[BaseModel] = YoutubeChannelSearchToolSchema

    def __init__(self, youtube_channel_handle: Optional[str] = None, **kwargs):
        super().__init__(**kwargs)
        if youtube_channel_handle is not None:
            kwargs["data_type"] = DataType.YOUTUBE_CHANNEL
            self.add(youtube_channel_handle)
            self.description = f"A tool that can be used to semantic search a query the {youtube_channel_handle} Youtube Channels content."
            self.args_schema = FixedYoutubeChannelSearchToolSchema
            self._generate_description()

    def add(
        self,
        youtube_channel_handle: str,
        **kwargs: Any,
    ) -> None:
        if not youtube_channel_handle.startswith("@"):
            youtube_channel_handle = f"@{youtube_channel_handle}"
        super().add(youtube_channel_handle, **kwargs)
```

## Conclusion

The `YoutubeChannelSearchTool` provides a powerful way to search and extract information from YouTube channel content using RAG techniques. By enabling agents to search across an entire channel's videos, it facilitates information extraction and analysis tasks that would otherwise be difficult to perform. This tool is particularly useful for research, content analysis, and knowledge extraction from YouTube channels.


# YouTube Video RAG Search
Source: https://docs.crewai.com/en/tools/search-research/youtubevideosearchtool

The `YoutubeVideoSearchTool` is designed to perform a RAG (Retrieval-Augmented Generation) search within the content of a Youtube video.

# `YoutubeVideoSearchTool`

<Note>
  We are still working on improving tools, so there might be unexpected behavior or changes in the future.
</Note>

## Description

This tool is part of the `crewai_tools` package and is designed to perform semantic searches within Youtube video content, utilizing Retrieval-Augmented Generation (RAG) techniques.
It is one of several "Search" tools in the package that leverage RAG for different sources.
The YoutubeVideoSearchTool allows for flexibility in searches; users can search across any Youtube video content without specifying a video URL,
or they can target their search to a specific Youtube video by providing its URL.

## Installation

To utilize the `YoutubeVideoSearchTool`, you must first install the `crewai_tools` package.
This package contains the `YoutubeVideoSearchTool` among other utilities designed to enhance your data analysis and processing tasks.
Install the package by executing the following command in your terminal:

```shell theme={null}
pip install 'crewai[tools]'
```

## Example

The following example demonstrates how to use the `YoutubeVideoSearchTool` with a CrewAI agent:

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import YoutubeVideoSearchTool

# Initialize the tool for general YouTube video searches
youtube_search_tool = YoutubeVideoSearchTool()

# Define an agent that uses the tool
video_researcher = Agent(
    role="Video Researcher",
    goal="Extract relevant information from YouTube videos",
    backstory="An expert researcher who specializes in analyzing video content.",
    tools=[youtube_search_tool],
    verbose=True,
)

# Example task to search for information in a specific video
research_task = Task(
    description="Search for information about machine learning frameworks in the YouTube video at {youtube_video_url}",
    expected_output="A summary of the key machine learning frameworks mentioned in the video.",
    agent=video_researcher,
)

# Create and run the crew
crew = Crew(agents=[video_researcher], tasks=[research_task])
result = crew.kickoff(inputs={"youtube_video_url": "https://youtube.com/watch?v=example"})
```

You can also initialize the tool with a specific YouTube video URL:

```python Code theme={null}
# Initialize the tool with a specific YouTube video URL
youtube_search_tool = YoutubeVideoSearchTool(
    youtube_video_url='https://youtube.com/watch?v=example'
)

# Define an agent that uses the tool
video_researcher = Agent(
    role="Video Researcher",
    goal="Extract relevant information from a specific YouTube video",
    backstory="An expert researcher who specializes in analyzing video content.",
    tools=[youtube_search_tool],
    verbose=True,
)
```

## Parameters

The `YoutubeVideoSearchTool` accepts the following parameters:

* **youtube\_video\_url**: Optional. The URL of the YouTube video to search within. If provided during initialization, the agent won't need to specify it when using the tool.
* **config**: Optional. Configuration for the underlying RAG system, including LLM and embedder settings.
* **summarize**: Optional. Whether to summarize the retrieved content. Default is `False`.

When using the tool with an agent, the agent will need to provide:

* **search\_query**: Required. The search query to find relevant information in the video content.
* **youtube\_video\_url**: Required only if not provided during initialization. The URL of the YouTube video to search within.

## Custom Model and Embeddings

By default, the tool uses OpenAI for both embeddings and summarization. To customize the model, you can use a config dictionary as follows:

```python Code   theme={null}
youtube_search_tool = YoutubeVideoSearchTool(
    config=dict(
        llm=dict(
            provider="ollama", # or google, openai, anthropic, llama2, ...
            config=dict(
                model="llama2",
                # temperature=0.5,
                # top_p=1,
                # stream=true,
            ),
        ),
        embedder=dict(
            provider="google-generativeai", # or openai, ollama, ...
            config=dict(
                model_name="gemini-embedding-001",
                task_type="RETRIEVAL_DOCUMENT",
                # title="Embeddings",
            ),
        ),
    )
)
```

## Agent Integration Example

Here's a more detailed example of how to integrate the `YoutubeVideoSearchTool` with a CrewAI agent:

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import YoutubeVideoSearchTool

# Initialize the tool
youtube_search_tool = YoutubeVideoSearchTool()

# Define an agent that uses the tool
video_researcher = Agent(
    role="Video Researcher",
    goal="Extract and analyze information from YouTube videos",
    backstory="""You are an expert video researcher who specializes in extracting 
    and analyzing information from YouTube videos. You have a keen eye for detail 
    and can quickly identify key points and insights from video content.""",
    tools=[youtube_search_tool],
    verbose=True,
)

# Create a task for the agent
research_task = Task(
    description="""
    Search for information about recent advancements in artificial intelligence 
    in the YouTube video at {youtube_video_url}. 
    
    Focus on:
    1. Key AI technologies mentioned
    2. Real-world applications discussed
    3. Future predictions made by the speaker
    
    Provide a comprehensive summary of these points.
    """,
    expected_output="A detailed summary of AI advancements, applications, and future predictions from the video.",
    agent=video_researcher,
)

# Run the task
crew = Crew(agents=[video_researcher], tasks=[research_task])
result = crew.kickoff(inputs={"youtube_video_url": "https://youtube.com/watch?v=example"})
```

## Implementation Details

The `YoutubeVideoSearchTool` is implemented as a subclass of `RagTool`, which provides the base functionality for Retrieval-Augmented Generation:

```python Code theme={null}
class YoutubeVideoSearchTool(RagTool):
    name: str = "Search a Youtube Video content"
    description: str = "A tool that can be used to semantic search a query from a Youtube Video content."
    args_schema: Type[BaseModel] = YoutubeVideoSearchToolSchema

    def __init__(self, youtube_video_url: Optional[str] = None, **kwargs):
        super().__init__(**kwargs)
        if youtube_video_url is not None:
            kwargs["data_type"] = DataType.YOUTUBE_VIDEO
            self.add(youtube_video_url)
            self.description = f"A tool that can be used to semantic search a query the {youtube_video_url} Youtube Video content."
            self.args_schema = FixedYoutubeVideoSearchToolSchema
            self._generate_description()
```

## Conclusion

The `YoutubeVideoSearchTool` provides a powerful way to search and extract information from YouTube video content using RAG techniques. By enabling agents to search within video content, it facilitates information extraction and analysis tasks that would otherwise be difficult to perform. This tool is particularly useful for research, content analysis, and knowledge extraction from video sources.


# Bright Data Tools
Source: https://docs.crewai.com/en/tools/web-scraping/brightdata-tools

Bright Data integrations for SERP search, Web Unlocker scraping, and Dataset API.

# Bright Data Tools

This set of tools integrates Bright Data services for web extraction.

## Installation

```shell theme={null}
uv add crewai-tools requests aiohttp
```

## Environment Variables

* `BRIGHT_DATA_API_KEY` (required)
* `BRIGHT_DATA_ZONE` (for SERP/Web Unlocker)

Create credentials at [https://brightdata.com/](https://brightdata.com/) (sign up, then create an API token and zone).
See their docs: [https://developers.brightdata.com/](https://developers.brightdata.com/)

## Included Tools

* `BrightDataSearchTool`: SERP search (Google/Bing/Yandex) with geo/language/device options.
* `BrightDataWebUnlockerTool`: Scrape pages with anti-bot bypass and rendering.
* `BrightDataDatasetTool`: Run Dataset API jobs and fetch results.

## Examples

### SERP Search

```python Code theme={null}
from crewai_tools import BrightDataSearchTool

tool = BrightDataSearchTool(
    query="CrewAI", 
    country="us",
)

print(tool.run())
```

### Web Unlocker

```python Code theme={null}
from crewai_tools import BrightDataWebUnlockerTool

tool = BrightDataWebUnlockerTool(
    url="https://example.com", 
    format="markdown",
)

print(tool.run(url="https://example.com"))
```

### Dataset API

```python Code theme={null}
from crewai_tools import BrightDataDatasetTool

tool = BrightDataDatasetTool(
    dataset_type="ecommerce", 
    url="https://example.com/product",
)

print(tool.run())
```

## Troubleshooting

* 401/403: verify `BRIGHT_DATA_API_KEY` and `BRIGHT_DATA_ZONE`.
* Empty/blocked content: enable rendering or try a different zone.

## Example

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import BrightDataSearchTool

tool = BrightDataSearchTool(
    query="CrewAI", 
    country="us",
)

agent = Agent(
    role="Web Researcher",
    goal="Search with Bright Data",
    backstory="Finds reliable results",
    tools=[tool],
    verbose=True,
)

task = Task(
    description="Search for CrewAI and summarize top results",
    expected_output="Short summary with links",
    agent=agent,
)

crew = Crew(
    agents=[agent], 
    tasks=[task],
    verbose=True,
)

result = crew.kickoff()
```


# Browserbase Web Loader
Source: https://docs.crewai.com/en/tools/web-scraping/browserbaseloadtool

Browserbase is a developer platform to reliably run, manage, and monitor headless browsers.

# `BrowserbaseLoadTool`

## Description

[Browserbase](https://browserbase.com) is a developer platform to reliably run, manage, and monitor headless browsers.

Power your AI data retrievals with:

* [Serverless Infrastructure](https://docs.browserbase.com/under-the-hood) providing reliable browsers to extract data from complex UIs
* [Stealth Mode](https://docs.browserbase.com/features/stealth-mode) with included fingerprinting tactics and automatic captcha solving
* [Session Debugger](https://docs.browserbase.com/features/sessions) to inspect your Browser Session with networks timeline and logs
* [Live Debug](https://docs.browserbase.com/guides/session-debug-connection/browser-remote-control) to quickly debug your automation

## Installation

* Get an API key and Project ID from [browserbase.com](https://browserbase.com) and set it in environment variables (`BROWSERBASE_API_KEY`, `BROWSERBASE_PROJECT_ID`).
* Install the [Browserbase SDK](http://github.com/browserbase/python-sdk) along with `crewai[tools]` package:

```shell theme={null}
pip install browserbase 'crewai[tools]'
```

## Example

Utilize the BrowserbaseLoadTool as follows to allow your agent to load websites:

```python Code theme={null}
from crewai_tools import BrowserbaseLoadTool

# Initialize the tool with the Browserbase API key and Project ID
tool = BrowserbaseLoadTool()
```

## Arguments

The following parameters can be used to customize the `BrowserbaseLoadTool`'s behavior:

| Argument          | Type     | Description                                                                           |
| :---------------- | :------- | :------------------------------------------------------------------------------------ |
| **api\_key**      | `string` | *Optional*. Browserbase API key. Default is `BROWSERBASE_API_KEY` env variable.       |
| **project\_id**   | `string` | *Optional*. Browserbase Project ID. Default is `BROWSERBASE_PROJECT_ID` env variable. |
| **text\_content** | `bool`   | *Optional*. Retrieve only text content. Default is `False`.                           |
| **session\_id**   | `string` | *Optional*. Provide an existing Session ID.                                           |
| **proxy**         | `bool`   | *Optional*. Enable/Disable Proxies. Default is `False`.                               |


# Firecrawl Crawl Website
Source: https://docs.crewai.com/en/tools/web-scraping/firecrawlcrawlwebsitetool

The `FirecrawlCrawlWebsiteTool` is designed to crawl and convert websites into clean markdown or structured data.

# `FirecrawlCrawlWebsiteTool`

## Description

[Firecrawl](https://firecrawl.dev) is a platform for crawling and convert any website into clean markdown or structured data.

## Installation

* Get an API key from [firecrawl.dev](https://firecrawl.dev) and set it in environment variables (`FIRECRAWL_API_KEY`).
* Install the [Firecrawl SDK](https://github.com/mendableai/firecrawl) along with `crewai[tools]` package:

```shell theme={null}
pip install firecrawl-py 'crewai[tools]'
```

## Example

Utilize the FirecrawlScrapeFromWebsiteTool as follows to allow your agent to load websites:

```python Code theme={null}
from crewai_tools import FirecrawlCrawlWebsiteTool

tool = FirecrawlCrawlWebsiteTool(url='firecrawl.dev')
```

## Arguments

* `api_key`: Optional. Specifies Firecrawl API key. Defaults is the `FIRECRAWL_API_KEY` environment variable.
* `url`: The base URL to start crawling from.
* `page_options`: Optional.
  * `onlyMainContent`: Optional. Only return the main content of the page excluding headers, navs, footers, etc.
  * `includeHtml`: Optional. Include the raw HTML content of the page. Will output a html key in the response.
* `crawler_options`: Optional. Options for controlling the crawling behavior.
  * `includes`: Optional. URL patterns to include in the crawl.
  * `exclude`: Optional. URL patterns to exclude from the crawl.
  * `generateImgAltText`: Optional. Generate alt text for images using LLMs (requires a paid plan).
  * `returnOnlyUrls`: Optional. If true, returns only the URLs as a list in the crawl status. Note: the response will be a list of URLs inside the data, not a list of documents.
  * `maxDepth`: Optional. Maximum depth to crawl. Depth 1 is the base URL, depth 2 includes the base URL and its direct children, and so on.
  * `mode`: Optional. The crawling mode to use. Fast mode crawls 4x faster on websites without a sitemap but may not be as accurate and shouldn't be used on heavily JavaScript-rendered websites.
  * `limit`: Optional. Maximum number of pages to crawl.
  * `timeout`: Optional. Timeout in milliseconds for the crawling operation.


# Firecrawl Scrape Website
Source: https://docs.crewai.com/en/tools/web-scraping/firecrawlscrapewebsitetool

The `FirecrawlScrapeWebsiteTool` is designed to scrape websites and convert them into clean markdown or structured data.

# `FirecrawlScrapeWebsiteTool`

## Description

[Firecrawl](https://firecrawl.dev) is a platform for crawling and convert any website into clean markdown or structured data.

## Installation

* Get an API key from [firecrawl.dev](https://firecrawl.dev) and set it in environment variables (`FIRECRAWL_API_KEY`).
* Install the [Firecrawl SDK](https://github.com/mendableai/firecrawl) along with `crewai[tools]` package:

```shell theme={null}
pip install firecrawl-py 'crewai[tools]'
```

## Example

Utilize the FirecrawlScrapeWebsiteTool as follows to allow your agent to load websites:

```python Code theme={null}
from crewai_tools import FirecrawlScrapeWebsiteTool

tool = FirecrawlScrapeWebsiteTool(url='firecrawl.dev')
```

## Arguments

* `api_key`: Optional. Specifies Firecrawl API key. Defaults is the `FIRECRAWL_API_KEY` environment variable.
* `url`: The URL to scrape.
* `page_options`: Optional.
  * `onlyMainContent`: Optional. Only return the main content of the page excluding headers, navs, footers, etc.
  * `includeHtml`: Optional. Include the raw HTML content of the page. Will output a html key in the response.
* `extractor_options`: Optional. Options for LLM-based extraction of structured information from the page content
  * `mode`: The extraction mode to use, currently supports 'llm-extraction'
  * `extractionPrompt`: Optional. A prompt describing what information to extract from the page
  * `extractionSchema`: Optional. The schema for the data to be extracted
* `timeout`: Optional. Timeout in milliseconds for the request


# Hyperbrowser Load Tool
Source: https://docs.crewai.com/en/tools/web-scraping/hyperbrowserloadtool

The `HyperbrowserLoadTool` enables web scraping and crawling using Hyperbrowser.

# `HyperbrowserLoadTool`

## Description

The `HyperbrowserLoadTool` enables web scraping and crawling using [Hyperbrowser](https://hyperbrowser.ai), a platform for running and scaling headless browsers. This tool allows you to scrape a single page or crawl an entire site, returning the content in properly formatted markdown or HTML.

Key Features:

* Instant Scalability - Spin up hundreds of browser sessions in seconds without infrastructure headaches
* Simple Integration - Works seamlessly with popular tools like Puppeteer and Playwright
* Powerful APIs - Easy to use APIs for scraping/crawling any site
* Bypass Anti-Bot Measures - Built-in stealth mode, ad blocking, automatic CAPTCHA solving, and rotating proxies

## Installation

To use this tool, you need to install the Hyperbrowser SDK:

```shell theme={null}
uv add hyperbrowser
```

## Steps to Get Started

To effectively use the `HyperbrowserLoadTool`, follow these steps:

1. **Sign Up**: Head to [Hyperbrowser](https://app.hyperbrowser.ai/) to sign up and generate an API key.
2. **API Key**: Set the `HYPERBROWSER_API_KEY` environment variable or pass it directly to the tool constructor.
3. **Install SDK**: Install the Hyperbrowser SDK using the command above.

## Example

The following example demonstrates how to initialize the tool and use it to scrape a website:

```python Code theme={null}
from crewai_tools import HyperbrowserLoadTool
from crewai import Agent

# Initialize the tool with your API key
tool = HyperbrowserLoadTool(api_key="your_api_key")  # Or use environment variable

# Define an agent that uses the tool
@agent
def web_researcher(self) -> Agent:
    '''
    This agent uses the HyperbrowserLoadTool to scrape websites
    and extract information.
    '''
    return Agent(
        config=self.agents_config["web_researcher"],
        tools=[tool]
    )
```

## Parameters

The `HyperbrowserLoadTool` accepts the following parameters:

### Constructor Parameters

* **api\_key**: Optional. Your Hyperbrowser API key. If not provided, it will be read from the `HYPERBROWSER_API_KEY` environment variable.

### Run Parameters

* **url**: Required. The website URL to scrape or crawl.
* **operation**: Optional. The operation to perform on the website. Either 'scrape' or 'crawl'. Default is 'scrape'.
* **params**: Optional. Additional parameters for the scrape or crawl operation.

## Supported Parameters

For detailed information on all supported parameters, visit:

* [Scrape Parameters](https://docs.hyperbrowser.ai/reference/sdks/python/scrape#start-scrape-job-and-wait)
* [Crawl Parameters](https://docs.hyperbrowser.ai/reference/sdks/python/crawl#start-crawl-job-and-wait)

## Return Format

The tool returns content in the following format:

* For **scrape** operations: The content of the page in markdown or HTML format.
* For **crawl** operations: The content of each page separated by dividers, including the URL of each page.

## Conclusion

The `HyperbrowserLoadTool` provides a powerful way to scrape and crawl websites, handling complex scenarios like anti-bot measures, CAPTCHAs, and more. By leveraging Hyperbrowser's platform, this tool enables agents to access and extract web content efficiently.


# Overview
Source: https://docs.crewai.com/en/tools/web-scraping/overview

Extract data from websites and automate browser interactions with powerful scraping tools

These tools enable your agents to interact with the web, extract data from websites, and automate browser-based tasks. From simple web scraping to complex browser automation, these tools cover all your web interaction needs.

## **Available Tools**

<CardGroup>
  <Card title="Scrape Website Tool" icon="globe" href="/en/tools/web-scraping/scrapewebsitetool">
    General-purpose web scraping tool for extracting content from any website.
  </Card>

  <Card title="Scrape Element Tool" icon="crosshairs" href="/en/tools/web-scraping/scrapeelementfromwebsitetool">
    Target specific elements on web pages with precision scraping capabilities.
  </Card>

  <Card title="Firecrawl Crawl Tool" icon="spider" href="/en/tools/web-scraping/firecrawlcrawlwebsitetool">
    Crawl entire websites systematically with Firecrawl's powerful engine.
  </Card>

  <Card title="Firecrawl Scrape Tool" icon="fire" href="/en/tools/web-scraping/firecrawlscrapewebsitetool">
    High-performance web scraping with Firecrawl's advanced capabilities.
  </Card>

  <Card title="Firecrawl Search Tool" icon="magnifying-glass" href="/en/tools/web-scraping/firecrawlsearchtool">
    Search and extract specific content using Firecrawl's search features.
  </Card>

  <Card title="Selenium Scraping Tool" icon="robot" href="/en/tools/web-scraping/seleniumscrapingtool">
    Browser automation and scraping with Selenium WebDriver capabilities.
  </Card>

  <Card title="ScrapFly Tool" icon="plane" href="/en/tools/web-scraping/scrapflyscrapetool">
    Professional web scraping with ScrapFly's premium scraping service.
  </Card>

  <Card title="ScrapGraph Tool" icon="network-wired" href="/en/tools/web-scraping/scrapegraphscrapetool">
    Graph-based web scraping for complex data relationships.
  </Card>

  <Card title="Spider Tool" icon="spider" href="/en/tools/web-scraping/spidertool">
    Comprehensive web crawling and data extraction capabilities.
  </Card>

  <Card title="BrowserBase Tool" icon="browser" href="/en/tools/web-scraping/browserbaseloadtool">
    Cloud-based browser automation with BrowserBase infrastructure.
  </Card>

  <Card title="HyperBrowser Tool" icon="window-maximize" href="/en/tools/web-scraping/hyperbrowserloadtool">
    Fast browser interactions with HyperBrowser's optimized engine.
  </Card>

  <Card title="Stagehand Tool" icon="hand" href="/en/tools/web-scraping/stagehandtool">
    Intelligent browser automation with natural language commands.
  </Card>

  <Card title="Oxylabs Scraper Tool" icon="globe" href="/en/tools/web-scraping/oxylabsscraperstool">
    Access web data at scale with Oxylabs.
  </Card>

  <Card title="Bright Data Tools" icon="spider" href="/en/tools/web-scraping/brightdata-tools">
    SERP search, Web Unlocker, and Dataset API integrations.
  </Card>
</CardGroup>

## **Common Use Cases**

* **Data Extraction**: Scrape product information, prices, and reviews
* **Content Monitoring**: Track changes on websites and news sources
* **Lead Generation**: Extract contact information and business data
* **Market Research**: Gather competitive intelligence and market data
* **Testing & QA**: Automate browser testing and validation workflows
* **Social Media**: Extract posts, comments, and social media analytics

## **Quick Start Example**

```python theme={null}
from crewai_tools import ScrapeWebsiteTool, FirecrawlScrapeWebsiteTool, SeleniumScrapingTool

# Create scraping tools
simple_scraper = ScrapeWebsiteTool()
advanced_scraper = FirecrawlScrapeWebsiteTool()
browser_automation = SeleniumScrapingTool()

# Add to your agent
agent = Agent(
    role="Web Research Specialist",
    tools=[simple_scraper, advanced_scraper, browser_automation],
    goal="Extract and analyze web data efficiently"
)
```

## **Scraping Best Practices**

* **Respect robots.txt**: Always check and follow website scraping policies
* **Rate Limiting**: Implement delays between requests to avoid overwhelming servers
* **User Agents**: Use appropriate user agent strings to identify your bot
* **Legal Compliance**: Ensure your scraping activities comply with terms of service
* **Error Handling**: Implement robust error handling for network issues and blocked requests
* **Data Quality**: Validate and clean extracted data before processing

## **Tool Selection Guide**

* **Simple Tasks**: Use `ScrapeWebsiteTool` for basic content extraction
* **JavaScript-Heavy Sites**: Use `SeleniumScrapingTool` for dynamic content
* **Scale & Performance**: Use `FirecrawlScrapeWebsiteTool` for high-volume scraping
* **Cloud Infrastructure**: Use `BrowserBaseLoadTool` for scalable browser automation
* **Complex Workflows**: Use `StagehandTool` for intelligent browser interactions


# Oxylabs Scrapers
Source: https://docs.crewai.com/en/tools/web-scraping/oxylabsscraperstool

Oxylabs Scrapers allow to easily access the information from the respective sources. Please see the list of available sources below:
  - `Amazon Product`
  - `Amazon Search`
  - `Google Seach`
  - `Universal`


## Installation

Get the credentials by creating an Oxylabs Account [here](https://oxylabs.io).

```shell theme={null}
pip install 'crewai[tools]' oxylabs
```

Check [Oxylabs Documentation](https://developers.oxylabs.io/scraping-solutions/web-scraper-api/targets) to get more information about API parameters.

# `OxylabsAmazonProductScraperTool`

### Example

```python theme={null}
from crewai_tools import OxylabsAmazonProductScraperTool

# make sure OXYLABS_USERNAME and OXYLABS_PASSWORD variables are set
tool = OxylabsAmazonProductScraperTool()

result = tool.run(query="AAAAABBBBCC")

print(result)
```

### Parameters

* `query` - 10-symbol ASIN code.
* `domain` - domain localization for Amazon.
* `geo_location` - the *Deliver to* location.
* `user_agent_type` - device type and browser.
* `render` - enables JavaScript rendering when set to `html`.
* `callback_url` - URL to your callback endpoint.
* `context` - Additional advanced settings and controls for specialized requirements.
* `parse` - returns parsed data when set to true.
* `parsing_instructions` - define your own parsing and data transformation logic that will be executed on an HTML scraping result.

### Advanced example

```python theme={null}
from crewai_tools import OxylabsAmazonProductScraperTool

# make sure OXYLABS_USERNAME and OXYLABS_PASSWORD variables are set
tool = OxylabsAmazonProductScraperTool(
    config={
        "domain": "com",
        "parse": True,
        "context": [
            {
                "key": "autoselect_variant",
                "value": True
            }
        ]
    }
)

result = tool.run(query="AAAAABBBBCC")

print(result)
```

# `OxylabsAmazonSearchScraperTool`

### Example

```python theme={null}
from crewai_tools import OxylabsAmazonSearchScraperTool

# make sure OXYLABS_USERNAME and OXYLABS_PASSWORD variables are set
tool = OxylabsAmazonSearchScraperTool()

result = tool.run(query="headsets")

print(result)
```

### Parameters

* `query` - Amazon search term.
* `domain` - Domain localization for Bestbuy.
* `start_page` - starting page number.
* `pages` - number of pages to retrieve.
* `geo_location` - the *Deliver to* location.
* `user_agent_type` - device type and browser.
* `render` - enables JavaScript rendering when set to `html`.
* `callback_url` - URL to your callback endpoint.
* `context` - Additional advanced settings and controls for specialized requirements.
* `parse` - returns parsed data when set to true.
* `parsing_instructions` - define your own parsing and data transformation logic that will be executed on an HTML scraping result.

### Advanced example

```python theme={null}
from crewai_tools import OxylabsAmazonSearchScraperTool

# make sure OXYLABS_USERNAME and OXYLABS_PASSWORD variables are set
tool = OxylabsAmazonSearchScraperTool(
    config={
        "domain": 'nl',
        "start_page": 2,
        "pages": 2,
        "parse": True,
        "context": [
            {'key': 'category_id', 'value': 16391693031}
        ],
    }
)

result = tool.run(query='nirvana tshirt')

print(result)
```

# `OxylabsGoogleSearchScraperTool`

### Example

```python theme={null}
from crewai_tools import OxylabsGoogleSearchScraperTool

# make sure OXYLABS_USERNAME and OXYLABS_PASSWORD variables are set
tool = OxylabsGoogleSearchScraperTool()

result = tool.run(query="iPhone 16")

print(result)
```

### Parameters

* `query` - search keyword.
* `domain` - domain localization for Google.
* `start_page` - starting page number.
* `pages` - number of pages to retrieve.
* `limit` - number of results to retrieve in each page.
* `locale` - `Accept-Language` header value which changes your Google search page web interface language.
* `geo_location` - the geographical location that the result should be adapted for. Using this parameter correctly is extremely important to get the right data.
* `user_agent_type` - device type and browser.
* `render` - enables JavaScript rendering when set to `html`.
* `callback_url` - URL to your callback endpoint.
* `context` - Additional advanced settings and controls for specialized requirements.
* `parse` - returns parsed data when set to true.
* `parsing_instructions` - define your own parsing and data transformation logic that will be executed on an HTML scraping result.

### Advanced example

```python theme={null}
from crewai_tools import OxylabsGoogleSearchScraperTool

# make sure OXYLABS_USERNAME and OXYLABS_PASSWORD variables are set
tool = OxylabsGoogleSearchScraperTool(
    config={
        "parse": True,
        "geo_location": "Paris, France",
        "user_agent_type": "tablet",
    }
)

result = tool.run(query="iPhone 16")

print(result)
```

# `OxylabsUniversalScraperTool`

### Example

```python theme={null}
from crewai_tools import OxylabsUniversalScraperTool

# make sure OXYLABS_USERNAME and OXYLABS_PASSWORD variables are set
tool = OxylabsUniversalScraperTool()

result = tool.run(url="https://ip.oxylabs.io")

print(result)
```

### Parameters

* `url` - website url to scrape.
* `user_agent_type` - device type and browser.
* `geo_location` - sets the proxy's geolocation to retrieve data.
* `render` - enables JavaScript rendering when set to `html`.
* `callback_url` - URL to your callback endpoint.
* `context` - Additional advanced settings and controls for specialized requirements.
* `parse` - returns parsed data when set to `true`, as long as a dedicated parser exists for the submitted URL's page type.
* `parsing_instructions` - define your own parsing and data transformation logic that will be executed on an HTML scraping result.

### Advanced example

```python theme={null}
from crewai_tools import OxylabsUniversalScraperTool

# make sure OXYLABS_USERNAME and OXYLABS_PASSWORD variables are set
tool = OxylabsUniversalScraperTool(
    config={
        "render": "html",
        "user_agent_type": "mobile",
        "context": [
            {"key": "force_headers", "value": True},
            {"key": "force_cookies", "value": True},
            {
                "key": "headers",
                "value": {
                    "Custom-Header-Name": "custom header content",
                },
            },
            {
                "key": "cookies",
                "value": [
                    {"key": "NID", "value": "1234567890"},
                    {"key": "1P JAR", "value": "0987654321"},
                ],
            },
            {"key": "http_method", "value": "get"},
            {"key": "follow_redirects", "value": True},
            {"key": "successful_status_codes", "value": [808, 909]},
        ],
    }
)

result = tool.run(url="https://ip.oxylabs.io")

print(result)
```


# Scrape Element From Website Tool
Source: https://docs.crewai.com/en/tools/web-scraping/scrapeelementfromwebsitetool

The `ScrapeElementFromWebsiteTool` enables CrewAI agents to extract specific elements from websites using CSS selectors.

# `ScrapeElementFromWebsiteTool`

## Description

The `ScrapeElementFromWebsiteTool` is designed to extract specific elements from websites using CSS selectors. This tool allows CrewAI agents to scrape targeted content from web pages, making it useful for data extraction tasks where only specific parts of a webpage are needed.

## Installation

To use this tool, you need to install the required dependencies:

```shell theme={null}
uv add requests beautifulsoup4
```

## Steps to Get Started

To effectively use the `ScrapeElementFromWebsiteTool`, follow these steps:

1. **Install Dependencies**: Install the required packages using the command above.
2. **Identify CSS Selectors**: Determine the CSS selectors for the elements you want to extract from the website.
3. **Initialize the Tool**: Create an instance of the tool with the necessary parameters.

## Example

The following example demonstrates how to use the `ScrapeElementFromWebsiteTool` to extract specific elements from a website:

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import ScrapeElementFromWebsiteTool

# Initialize the tool
scrape_tool = ScrapeElementFromWebsiteTool()

# Define an agent that uses the tool
web_scraper_agent = Agent(
    role="Web Scraper",
    goal="Extract specific information from websites",
    backstory="An expert in web scraping who can extract targeted content from web pages.",
    tools=[scrape_tool],
    verbose=True,
)

# Example task to extract headlines from a news website
scrape_task = Task(
    description="Extract the main headlines from the CNN homepage. Use the CSS selector '.headline' to target the headline elements.",
    expected_output="A list of the main headlines from CNN.",
    agent=web_scraper_agent,
)

# Create and run the crew
crew = Crew(agents=[web_scraper_agent], tasks=[scrape_task])
result = crew.kickoff()
```

You can also initialize the tool with predefined parameters:

```python Code theme={null}
# Initialize the tool with predefined parameters
scrape_tool = ScrapeElementFromWebsiteTool(
    website_url="https://www.example.com",
    css_element=".main-content"
)
```

## Parameters

The `ScrapeElementFromWebsiteTool` accepts the following parameters during initialization:

* **website\_url**: Optional. The URL of the website to scrape. If provided during initialization, the agent won't need to specify it when using the tool.
* **css\_element**: Optional. The CSS selector for the elements to extract. If provided during initialization, the agent won't need to specify it when using the tool.
* **cookies**: Optional. A dictionary containing cookies to be sent with the request. This can be useful for websites that require authentication.

## Usage

When using the `ScrapeElementFromWebsiteTool` with an agent, the agent will need to provide the following parameters (unless they were specified during initialization):

* **website\_url**: The URL of the website to scrape.
* **css\_element**: The CSS selector for the elements to extract.

The tool will return the text content of all elements matching the CSS selector, joined by newlines.

```python Code theme={null}
# Example of using the tool with an agent
web_scraper_agent = Agent(
    role="Web Scraper",
    goal="Extract specific elements from websites",
    backstory="An expert in web scraping who can extract targeted content using CSS selectors.",
    tools=[scrape_tool],
    verbose=True,
)

# Create a task for the agent to extract specific elements
extract_task = Task(
    description="""
    Extract all product titles from the featured products section on example.com.
    Use the CSS selector '.product-title' to target the title elements.
    """,
    expected_output="A list of product titles from the website",
    agent=web_scraper_agent,
)

# Run the task through a crew
crew = Crew(agents=[web_scraper_agent], tasks=[extract_task])
result = crew.kickoff()
```

## Implementation Details

The `ScrapeElementFromWebsiteTool` uses the `requests` library to fetch the web page and `BeautifulSoup` to parse the HTML and extract the specified elements:

```python Code theme={null}
class ScrapeElementFromWebsiteTool(BaseTool):
    name: str = "Read a website content"
    description: str = "A tool that can be used to read a website content."
    
    # Implementation details...
    
    def _run(self, **kwargs: Any) -> Any:
        website_url = kwargs.get("website_url", self.website_url)
        css_element = kwargs.get("css_element", self.css_element)
        page = requests.get(
            website_url,
            headers=self.headers,
            cookies=self.cookies if self.cookies else {},
        )
        parsed = BeautifulSoup(page.content, "html.parser")
        elements = parsed.select(css_element)
        return "\n".join([element.get_text() for element in elements])
```

## Conclusion

The `ScrapeElementFromWebsiteTool` provides a powerful way to extract specific elements from websites using CSS selectors. By enabling agents to target only the content they need, it makes web scraping tasks more efficient and focused. This tool is particularly useful for data extraction, content monitoring, and research tasks where specific information needs to be extracted from web pages.


# Scrapegraph Scrape Tool
Source: https://docs.crewai.com/en/tools/web-scraping/scrapegraphscrapetool

The `ScrapegraphScrapeTool` leverages Scrapegraph AI's SmartScraper API to intelligently extract content from websites.

# `ScrapegraphScrapeTool`

## Description

The `ScrapegraphScrapeTool` is designed to leverage Scrapegraph AI's SmartScraper API to intelligently extract content from websites. This tool provides advanced web scraping capabilities with AI-powered content extraction, making it ideal for targeted data collection and content analysis tasks. Unlike traditional web scrapers, it can understand the context and structure of web pages to extract the most relevant information based on natural language prompts.

## Installation

To use this tool, you need to install the Scrapegraph Python client:

```shell theme={null}
uv add scrapegraph-py
```

You'll also need to set up your Scrapegraph API key as an environment variable:

```shell theme={null}
export SCRAPEGRAPH_API_KEY="your_api_key"
```

You can obtain an API key from [Scrapegraph AI](https://scrapegraphai.com).

## Steps to Get Started

To effectively use the `ScrapegraphScrapeTool`, follow these steps:

1. **Install Dependencies**: Install the required package using the command above.
2. **Set Up API Key**: Set your Scrapegraph API key as an environment variable or provide it during initialization.
3. **Initialize the Tool**: Create an instance of the tool with the necessary parameters.
4. **Define Extraction Prompts**: Create natural language prompts to guide the extraction of specific content.

## Example

The following example demonstrates how to use the `ScrapegraphScrapeTool` to extract content from a website:

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import ScrapegraphScrapeTool

# Initialize the tool
scrape_tool = ScrapegraphScrapeTool(api_key="your_api_key")

# Define an agent that uses the tool
web_scraper_agent = Agent(
    role="Web Scraper",
    goal="Extract specific information from websites",
    backstory="An expert in web scraping who can extract targeted content from web pages.",
    tools=[scrape_tool],
    verbose=True,
)

# Example task to extract product information from an e-commerce site
scrape_task = Task(
    description="Extract product names, prices, and descriptions from the featured products section of example.com.",
    expected_output="A structured list of product information including names, prices, and descriptions.",
    agent=web_scraper_agent,
)

# Create and run the crew
crew = Crew(agents=[web_scraper_agent], tasks=[scrape_task])
result = crew.kickoff()
```

You can also initialize the tool with predefined parameters:

```python Code theme={null}
# Initialize the tool with predefined parameters
scrape_tool = ScrapegraphScrapeTool(
    website_url="https://www.example.com",
    user_prompt="Extract all product prices and descriptions",
    api_key="your_api_key"
)
```

## Parameters

The `ScrapegraphScrapeTool` accepts the following parameters during initialization:

* **api\_key**: Optional. Your Scrapegraph API key. If not provided, it will look for the `SCRAPEGRAPH_API_KEY` environment variable.
* **website\_url**: Optional. The URL of the website to scrape. If provided during initialization, the agent won't need to specify it when using the tool.
* **user\_prompt**: Optional. Custom instructions for content extraction. If provided during initialization, the agent won't need to specify it when using the tool.
* **enable\_logging**: Optional. Whether to enable logging for the Scrapegraph client. Default is `False`.

## Usage

When using the `ScrapegraphScrapeTool` with an agent, the agent will need to provide the following parameters (unless they were specified during initialization):

* **website\_url**: The URL of the website to scrape.
* **user\_prompt**: Optional. Custom instructions for content extraction. Default is "Extract the main content of the webpage".

The tool will return the extracted content based on the provided prompt.

```python Code theme={null}
# Example of using the tool with an agent
web_scraper_agent = Agent(
    role="Web Scraper",
    goal="Extract specific information from websites",
    backstory="An expert in web scraping who can extract targeted content from web pages.",
    tools=[scrape_tool],
    verbose=True,
)

# Create a task for the agent to extract specific content
extract_task = Task(
    description="Extract the main heading and summary from example.com",
    expected_output="The main heading and summary from the website",
    agent=web_scraper_agent,
)

# Run the task
crew = Crew(agents=[web_scraper_agent], tasks=[extract_task])
result = crew.kickoff()
```

## Error Handling

The `ScrapegraphScrapeTool` may raise the following exceptions:

* **ValueError**: When API key is missing or URL format is invalid.
* **RateLimitError**: When API rate limits are exceeded.
* **RuntimeError**: When scraping operation fails (network issues, API errors).

It's recommended to instruct agents to handle potential errors gracefully:

```python Code theme={null}
# Create a task that includes error handling instructions
robust_extract_task = Task(
    description="""
    Extract the main heading from example.com.
    Be aware that you might encounter errors such as:
    - Invalid URL format
    - Missing API key
    - Rate limit exceeded
    - Network or API errors
    
    If you encounter any errors, provide a clear explanation of what went wrong
    and suggest possible solutions.
    """,
    expected_output="Either the extracted heading or a clear error explanation",
    agent=web_scraper_agent,
)
```

## Rate Limiting

The Scrapegraph API has rate limits that vary based on your subscription plan. Consider the following best practices:

* Implement appropriate delays between requests when processing multiple URLs.
* Handle rate limit errors gracefully in your application.
* Check your API plan limits on the Scrapegraph dashboard.

## Implementation Details

The `ScrapegraphScrapeTool` uses the Scrapegraph Python client to interact with the SmartScraper API:

```python Code theme={null}
class ScrapegraphScrapeTool(BaseTool):
    """
    A tool that uses Scrapegraph AI to intelligently scrape website content.
    """
    
    # Implementation details...
    
    def _run(self, **kwargs: Any) -> Any:
        website_url = kwargs.get("website_url", self.website_url)
        user_prompt = (
            kwargs.get("user_prompt", self.user_prompt)
            or "Extract the main content of the webpage"
        )

        if not website_url:
            raise ValueError("website_url is required")

        # Validate URL format
        self._validate_url(website_url)

        try:
            # Make the SmartScraper request
            response = self._client.smartscraper(
                website_url=website_url,
                user_prompt=user_prompt,
            )

            return response
        # Error handling...
```

## Conclusion

The `ScrapegraphScrapeTool` provides a powerful way to extract content from websites using AI-powered understanding of web page structure. By enabling agents to target specific information using natural language prompts, it makes web scraping tasks more efficient and focused. This tool is particularly useful for data extraction, content monitoring, and research tasks where specific information needs to be extracted from web pages.


# Scrape Website
Source: https://docs.crewai.com/en/tools/web-scraping/scrapewebsitetool

The `ScrapeWebsiteTool` is designed to extract and read the content of a specified website.

# `ScrapeWebsiteTool`

<Note>
  We are still working on improving tools, so there might be unexpected behavior or changes in the future.
</Note>

## Description

A tool designed to extract and read the content of a specified website. It is capable of handling various types of web pages by making HTTP requests and parsing the received HTML content.
This tool can be particularly useful for web scraping tasks, data collection, or extracting specific information from websites.

## Installation

Install the crewai\_tools package

```shell theme={null}
pip install 'crewai[tools]'
```

## Example

```python theme={null}
from crewai_tools import ScrapeWebsiteTool

# To enable scrapping any website it finds during it's execution
tool = ScrapeWebsiteTool()

# Initialize the tool with the website URL, 
# so the agent can only scrap the content of the specified website
tool = ScrapeWebsiteTool(website_url='https://www.example.com')

# Extract the text from the site
text = tool.run()
print(text)
```

## Arguments

| Argument         | Type     | Description                                                                                                                                        |
| :--------------- | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------- |
| **website\_url** | `string` | **Mandatory** website URL to read the file. This is the primary input for the tool, specifying which website's content should be scraped and read. |


# Scrapfly Scrape Website Tool
Source: https://docs.crewai.com/en/tools/web-scraping/scrapflyscrapetool

The `ScrapflyScrapeWebsiteTool` leverages Scrapfly's web scraping API to extract content from websites in various formats.

# `ScrapflyScrapeWebsiteTool`

## Description

The `ScrapflyScrapeWebsiteTool` is designed to leverage [Scrapfly](https://scrapfly.io/)'s web scraping API to extract content from websites. This tool provides advanced web scraping capabilities with headless browser support, proxies, and anti-bot bypass features. It allows for extracting web page data in various formats, including raw HTML, markdown, and plain text, making it ideal for a wide range of web scraping tasks.

## Installation

To use this tool, you need to install the Scrapfly SDK:

```shell theme={null}
uv add scrapfly-sdk
```

You'll also need to obtain a Scrapfly API key by registering at [scrapfly.io/register](https://www.scrapfly.io/register/).

## Steps to Get Started

To effectively use the `ScrapflyScrapeWebsiteTool`, follow these steps:

1. **Install Dependencies**: Install the Scrapfly SDK using the command above.
2. **Obtain API Key**: Register at Scrapfly to get your API key.
3. **Initialize the Tool**: Create an instance of the tool with your API key.
4. **Configure Scraping Parameters**: Customize the scraping parameters based on your needs.

## Example

The following example demonstrates how to use the `ScrapflyScrapeWebsiteTool` to extract content from a website:

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import ScrapflyScrapeWebsiteTool

# Initialize the tool
scrape_tool = ScrapflyScrapeWebsiteTool(api_key="your_scrapfly_api_key")

# Define an agent that uses the tool
web_scraper_agent = Agent(
    role="Web Scraper",
    goal="Extract information from websites",
    backstory="An expert in web scraping who can extract content from any website.",
    tools=[scrape_tool],
    verbose=True,
)

# Example task to extract content from a website
scrape_task = Task(
    description="Extract the main content from the product page at https://web-scraping.dev/products and summarize the available products.",
    expected_output="A summary of the products available on the website.",
    agent=web_scraper_agent,
)

# Create and run the crew
crew = Crew(agents=[web_scraper_agent], tasks=[scrape_task])
result = crew.kickoff()
```

You can also customize the scraping parameters:

```python Code theme={null}
# Example with custom scraping parameters
web_scraper_agent = Agent(
    role="Web Scraper",
    goal="Extract information from websites with custom parameters",
    backstory="An expert in web scraping who can extract content from any website.",
    tools=[scrape_tool],
    verbose=True,
)

# The agent will use the tool with parameters like:
# url="https://web-scraping.dev/products"
# scrape_format="markdown"
# ignore_scrape_failures=True
# scrape_config={
#     "asp": True,  # Bypass scraping blocking solutions, like Cloudflare
#     "render_js": True,  # Enable JavaScript rendering with a cloud headless browser
#     "proxy_pool": "public_residential_pool",  # Select a proxy pool
#     "country": "us",  # Select a proxy location
#     "auto_scroll": True,  # Auto scroll the page
# }

scrape_task = Task(
    description="Extract the main content from the product page at https://web-scraping.dev/products using advanced scraping options including JavaScript rendering and proxy settings.",
    expected_output="A detailed summary of the products with all available information.",
    agent=web_scraper_agent,
)
```

## Parameters

The `ScrapflyScrapeWebsiteTool` accepts the following parameters:

### Initialization Parameters

* **api\_key**: Required. Your Scrapfly API key.

### Run Parameters

* **url**: Required. The URL of the website to scrape.
* **scrape\_format**: Optional. The format in which to extract the web page content. Options are "raw" (HTML), "markdown", or "text". Default is "markdown".
* **scrape\_config**: Optional. A dictionary containing additional Scrapfly scraping configuration options.
* **ignore\_scrape\_failures**: Optional. Whether to ignore failures during scraping. If set to `True`, the tool will return `None` instead of raising an exception when scraping fails.

## Scrapfly Configuration Options

The `scrape_config` parameter allows you to customize the scraping behavior with the following options:

* **asp**: Enable anti-scraping protection bypass.
* **render\_js**: Enable JavaScript rendering with a cloud headless browser.
* **proxy\_pool**: Select a proxy pool (e.g., "public\_residential\_pool", "datacenter").
* **country**: Select a proxy location (e.g., "us", "uk").
* **auto\_scroll**: Automatically scroll the page to load lazy-loaded content.
* **js**: Execute custom JavaScript code by the headless browser.

For a complete list of configuration options, refer to the [Scrapfly API documentation](https://scrapfly.io/docs/scrape-api/getting-started).

## Usage

When using the `ScrapflyScrapeWebsiteTool` with an agent, the agent will need to provide the URL of the website to scrape and can optionally specify the format and additional configuration options:

```python Code theme={null}
# Example of using the tool with an agent
web_scraper_agent = Agent(
    role="Web Scraper",
    goal="Extract information from websites",
    backstory="An expert in web scraping who can extract content from any website.",
    tools=[scrape_tool],
    verbose=True,
)

# Create a task for the agent
scrape_task = Task(
    description="Extract the main content from example.com in markdown format.",
    expected_output="The main content of example.com in markdown format.",
    agent=web_scraper_agent,
)

# Run the task
crew = Crew(agents=[web_scraper_agent], tasks=[scrape_task])
result = crew.kickoff()
```

For more advanced usage with custom configuration:

```python Code theme={null}
# Create a task with more specific instructions
advanced_scrape_task = Task(
    description="""
    Extract content from example.com with the following requirements:
    - Convert the content to plain text format
    - Enable JavaScript rendering
    - Use a US-based proxy
    - Handle any scraping failures gracefully
    """,
    expected_output="The extracted content from example.com",
    agent=web_scraper_agent,
)
```

## Error Handling

By default, the `ScrapflyScrapeWebsiteTool` will raise an exception if scraping fails. Agents can be instructed to handle failures gracefully by specifying the `ignore_scrape_failures` parameter:

```python Code theme={null}
# Create a task that instructs the agent to handle errors
error_handling_task = Task(
    description="""
    Extract content from a potentially problematic website and make sure to handle any 
    scraping failures gracefully by setting ignore_scrape_failures to True.
    """,
    expected_output="Either the extracted content or a graceful error message",
    agent=web_scraper_agent,
)
```

## Implementation Details

The `ScrapflyScrapeWebsiteTool` uses the Scrapfly SDK to interact with the Scrapfly API:

```python Code theme={null}
class ScrapflyScrapeWebsiteTool(BaseTool):
    name: str = "Scrapfly web scraping API tool"
    description: str = (
        "Scrape a webpage url using Scrapfly and return its content as markdown or text"
    )
    
    # Implementation details...
    
    def _run(
        self,
        url: str,
        scrape_format: str = "markdown",
        scrape_config: Optional[Dict[str, Any]] = None,
        ignore_scrape_failures: Optional[bool] = None,
    ):
        from scrapfly import ScrapeApiResponse, ScrapeConfig

        scrape_config = scrape_config if scrape_config is not None else {}
        try:
            response: ScrapeApiResponse = self.scrapfly.scrape(
                ScrapeConfig(url, format=scrape_format, **scrape_config)
            )
            return response.scrape_result["content"]
        except Exception as e:
            if ignore_scrape_failures:
                logger.error(f"Error fetching data from {url}, exception: {e}")
                return None
            else:
                raise e
```

## Conclusion

The `ScrapflyScrapeWebsiteTool` provides a powerful way to extract content from websites using Scrapfly's advanced web scraping capabilities. With features like headless browser support, proxies, and anti-bot bypass, it can handle complex websites and extract content in various formats. This tool is particularly useful for data extraction, content monitoring, and research tasks where reliable web scraping is required.


# Selenium Scraper
Source: https://docs.crewai.com/en/tools/web-scraping/seleniumscrapingtool

The `SeleniumScrapingTool` is designed to extract and read the content of a specified website using Selenium.

# `SeleniumScrapingTool`

<Note>
  This tool is currently in development. As we refine its capabilities, users may encounter unexpected behavior.
  Your feedback is invaluable to us for making improvements.
</Note>

## Description

The `SeleniumScrapingTool` is crafted for high-efficiency web scraping tasks.
It allows for precise extraction of content from web pages by using CSS selectors to target specific elements.
Its design caters to a wide range of scraping needs, offering flexibility to work with any provided website URL.

## Installation

To use this tool, you need to install the CrewAI tools package and Selenium:

```shell theme={null}
pip install 'crewai[tools]'
uv add selenium webdriver-manager
```

You'll also need to have Chrome installed on your system, as the tool uses Chrome WebDriver for browser automation.

## Example

The following example demonstrates how to use the `SeleniumScrapingTool` with a CrewAI agent:

```python Code theme={null}
from crewai import Agent, Task, Crew, Process
from crewai_tools import SeleniumScrapingTool

# Initialize the tool
selenium_tool = SeleniumScrapingTool()

# Define an agent that uses the tool
web_scraper_agent = Agent(
    role="Web Scraper",
    goal="Extract information from websites using Selenium",
    backstory="An expert web scraper who can extract content from dynamic websites.",
    tools=[selenium_tool],
    verbose=True,
)

# Example task to scrape content from a website
scrape_task = Task(
    description="Extract the main content from the homepage of example.com. Use the CSS selector 'main' to target the main content area.",
    expected_output="The main content from example.com's homepage.",
    agent=web_scraper_agent,
)

# Create and run the crew
crew = Crew(
    agents=[web_scraper_agent],
    tasks=[scrape_task],
    verbose=True,
    process=Process.sequential,
)
result = crew.kickoff()
```

You can also initialize the tool with predefined parameters:

```python Code theme={null}
# Initialize the tool with predefined parameters
selenium_tool = SeleniumScrapingTool(
    website_url='https://example.com',
    css_element='.main-content',
    wait_time=5
)

# Define an agent that uses the tool
web_scraper_agent = Agent(
    role="Web Scraper",
    goal="Extract information from websites using Selenium",
    backstory="An expert web scraper who can extract content from dynamic websites.",
    tools=[selenium_tool],
    verbose=True,
)
```

## Parameters

The `SeleniumScrapingTool` accepts the following parameters during initialization:

* **website\_url**: Optional. The URL of the website to scrape. If provided during initialization, the agent won't need to specify it when using the tool.
* **css\_element**: Optional. The CSS selector for the elements to extract. If provided during initialization, the agent won't need to specify it when using the tool.
* **cookie**: Optional. A dictionary containing cookie information, useful for simulating a logged-in session to access restricted content.
* **wait\_time**: Optional. Specifies the delay (in seconds) before scraping, allowing the website and any dynamic content to fully load. Default is `3` seconds.
* **return\_html**: Optional. Whether to return the HTML content instead of just the text. Default is `False`.

When using the tool with an agent, the agent will need to provide the following parameters (unless they were specified during initialization):

* **website\_url**: Required. The URL of the website to scrape.
* **css\_element**: Required. The CSS selector for the elements to extract.

## Agent Integration Example

Here's a more detailed example of how to integrate the `SeleniumScrapingTool` with a CrewAI agent:

```python Code theme={null}
from crewai import Agent, Task, Crew, Process
from crewai_tools import SeleniumScrapingTool

# Initialize the tool
selenium_tool = SeleniumScrapingTool()

# Define an agent that uses the tool
web_scraper_agent = Agent(
    role="Web Scraper",
    goal="Extract and analyze information from dynamic websites",
    backstory="""You are an expert web scraper who specializes in extracting 
    content from dynamic websites that require browser automation. You have 
    extensive knowledge of CSS selectors and can identify the right selectors 
    to target specific content on any website.""",
    tools=[selenium_tool],
    verbose=True,
)

# Create a task for the agent
scrape_task = Task(
    description="""
    Extract the following information from the news website at {website_url}:
    
    1. The headlines of all featured articles (CSS selector: '.headline')
    2. The publication dates of these articles (CSS selector: '.pub-date')
    3. The author names where available (CSS selector: '.author')
    
    Compile this information into a structured format with each article's details grouped together.
    """,
    expected_output="A structured list of articles with their headlines, publication dates, and authors.",
    agent=web_scraper_agent,
)

# Run the task
crew = Crew(
    agents=[web_scraper_agent],
    tasks=[scrape_task],
    verbose=True,
    process=Process.sequential,
)
result = crew.kickoff(inputs={"website_url": "https://news-example.com"})
```

## Implementation Details

The `SeleniumScrapingTool` uses Selenium WebDriver to automate browser interactions:

```python Code theme={null}
class SeleniumScrapingTool(BaseTool):
    name: str = "Read a website content"
    description: str = "A tool that can be used to read a website content."
    args_schema: Type[BaseModel] = SeleniumScrapingToolSchema
    
    def _run(self, **kwargs: Any) -> Any:
        website_url = kwargs.get("website_url", self.website_url)
        css_element = kwargs.get("css_element", self.css_element)
        return_html = kwargs.get("return_html", self.return_html)
        driver = self._create_driver(website_url, self.cookie, self.wait_time)

        content = self._get_content(driver, css_element, return_html)
        driver.close()

        return "\n".join(content)
```

The tool performs the following steps:

1. Creates a headless Chrome browser instance
2. Navigates to the specified URL
3. Waits for the specified time to allow the page to load
4. Adds any cookies if provided
5. Extracts content based on the CSS selector
6. Returns the extracted content as text or HTML
7. Closes the browser instance

## Handling Dynamic Content

The `SeleniumScrapingTool` is particularly useful for scraping websites with dynamic content that is loaded via JavaScript. By using a real browser instance, it can:

1. Execute JavaScript on the page
2. Wait for dynamic content to load
3. Interact with elements if needed
4. Extract content that would not be available with simple HTTP requests

You can adjust the `wait_time` parameter to ensure that all dynamic content has loaded before extraction.

## Conclusion

The `SeleniumScrapingTool` provides a powerful way to extract content from websites using browser automation. By enabling agents to interact with websites as a real user would, it facilitates scraping of dynamic content that would be difficult or impossible to extract using simpler methods. This tool is particularly useful for research, data collection, and monitoring tasks that involve modern web applications with JavaScript-rendered content.


# Spider Scraper
Source: https://docs.crewai.com/en/tools/web-scraping/spidertool

The `SpiderTool` is designed to extract and read the content of a specified website using Spider.

# `SpiderTool`

## Description

[Spider](https://spider.cloud/?ref=crewai) is the [fastest](https://github.com/spider-rs/spider/blob/main/benches/BENCHMARKS.md#benchmark-results)
open source scraper and crawler that returns LLM-ready data.
It converts any website into pure HTML, markdown, metadata or text while enabling you to crawl with custom actions using AI.

## Installation

To use the `SpiderTool` you need to download the [Spider SDK](https://pypi.org/project/spider-client/)
and the `crewai[tools]` SDK too:

```shell theme={null}
pip install spider-client 'crewai[tools]'
```

## Example

This example shows you how you can use the `SpiderTool` to enable your agent to scrape and crawl websites.
The data returned from the Spider API is already LLM-ready, so no need to do any cleaning there.

```python Code theme={null}
from crewai_tools import SpiderTool

def main():
    spider_tool = SpiderTool()

    searcher = Agent(
        role="Web Research Expert",
        goal="Find related information from specific URL's",
        backstory="An expert web researcher that uses the web extremely well",
        tools=[spider_tool],
        verbose=True,
    )

    return_metadata = Task(
        description="Scrape https://spider.cloud with a limit of 1 and enable metadata",
        expected_output="Metadata and 10 word summary of spider.cloud",
        agent=searcher
    )

    crew = Crew(
        agents=[searcher],
        tasks=[
            return_metadata,
        ],
        verbose=2
    )

    crew.kickoff()

if __name__ == "__main__":
    main()
```

## Arguments

| Argument                | Type     | Description                                                                                                                       |
| :---------------------- | :------- | :-------------------------------------------------------------------------------------------------------------------------------- |
| **api\_key**            | `string` | Specifies Spider API key. If not specified, it looks for `SPIDER_API_KEY` in environment variables.                               |
| **params**              | `object` | Optional parameters for the request. Defaults to `{"return_format": "markdown"}` to optimize content for LLMs.                    |
| **request**             | `string` | Type of request to perform (`http`, `chrome`, `smart`). `smart` defaults to HTTP, switching to JavaScript rendering if needed.    |
| **limit**               | `int`    | Max pages to crawl per website. Set to `0` or omit for unlimited.                                                                 |
| **depth**               | `int`    | Max crawl depth. Set to `0` for no limit.                                                                                         |
| **cache**               | `bool`   | Enables HTTP caching to speed up repeated runs. Default is `true`.                                                                |
| **budget**              | `object` | Sets path-based limits for crawled pages, e.g., `{"*":1}` for root page only.                                                     |
| **locale**              | `string` | Locale for the request, e.g., `en-US`.                                                                                            |
| **cookies**             | `string` | HTTP cookies for the request.                                                                                                     |
| **stealth**             | `bool`   | Enables stealth mode for Chrome requests to avoid detection. Default is `true`.                                                   |
| **headers**             | `object` | HTTP headers as a map of key-value pairs for all requests.                                                                        |
| **metadata**            | `bool`   | Stores metadata about pages and content, aiding AI interoperability. Defaults to `false`.                                         |
| **viewport**            | `object` | Sets Chrome viewport dimensions. Default is `800x600`.                                                                            |
| **encoding**            | `string` | Specifies encoding type, e.g., `UTF-8`, `SHIFT_JIS`.                                                                              |
| **subdomains**          | `bool`   | Includes subdomains in the crawl. Default is `false`.                                                                             |
| **user\_agent**         | `string` | Custom HTTP user agent. Defaults to a random agent.                                                                               |
| **store\_data**         | `bool`   | Enables data storage for the request. Overrides `storageless` when set. Default is `false`.                                       |
| **gpt\_config**         | `object` | Allows AI to generate crawl actions, with optional chaining steps via an array for `"prompt"`.                                    |
| **fingerprint**         | `bool`   | Enables advanced fingerprinting for Chrome.                                                                                       |
| **storageless**         | `bool`   | Prevents all data storage, including AI embeddings. Default is `false`.                                                           |
| **readability**         | `bool`   | Pre-processes content for reading via [Mozilla’s readability](https://github.com/mozilla/readability). Improves content for LLMs. |
| **return\_format**      | `string` | Format to return data: `markdown`, `raw`, `text`, `html2text`. Use `raw` for default page format.                                 |
| **proxy\_enabled**      | `bool`   | Enables high-performance proxies to avoid network-level blocking.                                                                 |
| **query\_selector**     | `string` | CSS query selector for content extraction from markup.                                                                            |
| **full\_resources**     | `bool`   | Downloads all resources linked to the website.                                                                                    |
| **request\_timeout**    | `int`    | Timeout in seconds for requests (5-60). Default is `30`.                                                                          |
| **run\_in\_background** | `bool`   | Runs the request in the background, useful for data storage and triggering dashboard crawls. No effect if `storageless` is set.   |


# Stagehand Tool
Source: https://docs.crewai.com/en/tools/web-scraping/stagehandtool

Web automation tool that integrates Stagehand with CrewAI for browser interaction and automation

# Overview

The `StagehandTool` integrates the [Stagehand](https://docs.stagehand.dev/get_started/introduction) framework with CrewAI, enabling agents to interact with websites and automate browser tasks using natural language instructions.

## Overview

Stagehand is a powerful browser automation framework built by Browserbase that allows AI agents to:

* Navigate to websites
* Click buttons, links, and other elements
* Fill in forms
* Extract data from web pages
* Observe and identify elements
* Perform complex workflows

The StagehandTool wraps the Stagehand Python SDK to provide CrewAI agents with browser control capabilities through three core primitives:

1. **Act**: Perform actions like clicking, typing, or navigating
2. **Extract**: Extract structured data from web pages
3. **Observe**: Identify and analyze elements on the page

## Prerequisites

Before using this tool, ensure you have:

1. A [Browserbase](https://www.browserbase.com/) account with API key and project ID
2. An API key for an LLM (OpenAI or Anthropic Claude)
3. The Stagehand Python SDK installed

Install the required dependency:

```bash theme={null}
pip install stagehand-py
```

## Usage

### Basic Implementation

The StagehandTool can be implemented in two ways:

#### 1. Using Context Manager (Recommended)

<Tip>
  The context manager approach is recommended as it ensures proper cleanup of resources even if exceptions occur.
</Tip>

```python theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import StagehandTool
from stagehand.schemas import AvailableModel

# Initialize the tool with your API keys using a context manager
with StagehandTool(
    api_key="your-browserbase-api-key",
    project_id="your-browserbase-project-id",
    model_api_key="your-llm-api-key",  # OpenAI or Anthropic API key
    model_name=AvailableModel.CLAUDE_3_7_SONNET_LATEST,  # Optional: specify which model to use
) as stagehand_tool:
    # Create an agent with the tool
    researcher = Agent(
        role="Web Researcher",
        goal="Find and summarize information from websites",
        backstory="I'm an expert at finding information online.",
        verbose=True,
        tools=[stagehand_tool],
    )

    # Create a task that uses the tool
    research_task = Task(
        description="Go to https://www.example.com and tell me what you see on the homepage.",
        agent=researcher,
    )

    # Run the crew
    crew = Crew(
        agents=[researcher],
        tasks=[research_task],
        verbose=True,
    )

    result = crew.kickoff()
    print(result)
```

#### 2. Manual Resource Management

```python theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import StagehandTool
from stagehand.schemas import AvailableModel

# Initialize the tool with your API keys
stagehand_tool = StagehandTool(
    api_key="your-browserbase-api-key",
    project_id="your-browserbase-project-id",
    model_api_key="your-llm-api-key",
    model_name=AvailableModel.CLAUDE_3_7_SONNET_LATEST,
)

try:
    # Create an agent with the tool
    researcher = Agent(
        role="Web Researcher",
        goal="Find and summarize information from websites",
        backstory="I'm an expert at finding information online.",
        verbose=True,
        tools=[stagehand_tool],
    )

    # Create a task that uses the tool
    research_task = Task(
        description="Go to https://www.example.com and tell me what you see on the homepage.",
        agent=researcher,
    )

    # Run the crew
    crew = Crew(
        agents=[researcher],
        tasks=[research_task],
        verbose=True,
    )

    result = crew.kickoff()
    print(result)
finally:
    # Explicitly clean up resources
    stagehand_tool.close()
```

## Command Types

The StagehandTool supports three different command types for specific web automation tasks:

### 1. Act Command

The `act` command type (default) enables webpage interactions like clicking buttons, filling forms, and navigation.

```python theme={null}
# Perform an action (default behavior)
result = stagehand_tool.run(
    instruction="Click the login button", 
    url="https://example.com",
    command_type="act"  # Default, so can be omitted
)

# Fill out a form
result = stagehand_tool.run(
    instruction="Fill the contact form with name 'John Doe', email 'john@example.com', and message 'Hello world'", 
    url="https://example.com/contact"
)
```

### 2. Extract Command

The `extract` command type retrieves structured data from webpages.

```python theme={null}
# Extract all product information
result = stagehand_tool.run(
    instruction="Extract all product names, prices, and descriptions", 
    url="https://example.com/products",
    command_type="extract"
)

# Extract specific information with a selector
result = stagehand_tool.run(
    instruction="Extract the main article title and content", 
    url="https://example.com/blog/article",
    command_type="extract",
    selector=".article-container"  # Optional CSS selector
)
```

### 3. Observe Command

The `observe` command type identifies and analyzes webpage elements.

```python theme={null}
# Find interactive elements
result = stagehand_tool.run(
    instruction="Find all interactive elements in the navigation menu", 
    url="https://example.com",
    command_type="observe"
)

# Identify form fields
result = stagehand_tool.run(
    instruction="Identify all the input fields in the registration form", 
    url="https://example.com/register",
    command_type="observe",
    selector="#registration-form"
)
```

## Configuration Options

Customize the StagehandTool behavior with these parameters:

```python theme={null}
stagehand_tool = StagehandTool(
    api_key="your-browserbase-api-key",
    project_id="your-browserbase-project-id",
    model_api_key="your-llm-api-key",
    model_name=AvailableModel.CLAUDE_3_7_SONNET_LATEST,
    dom_settle_timeout_ms=5000,  # Wait longer for DOM to settle
    headless=True,  # Run browser in headless mode
    self_heal=True,  # Attempt to recover from errors
    wait_for_captcha_solves=True,  # Wait for CAPTCHA solving
    verbose=1,  # Control logging verbosity (0-3)
)
```

## Best Practices

1. **Be Specific**: Provide detailed instructions for better results
2. **Choose Appropriate Command Type**: Select the right command type for your task
3. **Use Selectors**: Leverage CSS selectors to improve accuracy
4. **Break Down Complex Tasks**: Split complex workflows into multiple tool calls
5. **Implement Error Handling**: Add error handling for potential issues

## Troubleshooting

Common issues and solutions:

* **Session Issues**: Verify API keys for both Browserbase and LLM provider
* **Element Not Found**: Increase `dom_settle_timeout_ms` for slower pages
* **Action Failures**: Use `observe` to identify correct elements first
* **Incomplete Data**: Refine instructions or provide specific selectors

## Additional Resources

For questions about the CrewAI integration:

* Join Stagehand's [Slack community](https://stagehand.dev/slack)
* Open an issue in the [Stagehand repository](https://github.com/browserbase/stagehand)
* Visit [Stagehand documentation](https://docs.stagehand.dev/)


# CrewAI Documentation
Source: https://docs.crewai.com/index

Build collaborative AI agents, crews, and flows — production ready from day one.

<div>
  <img alt="CrewAI" />

  <div>
    <h1>Ship multi‑agent systems with confidence</h1>

    <p>
      Design agents, orchestrate crews, and automate flows with guardrails, memory, knowledge, and observability baked in.
    </p>
  </div>

  <div>
    <a href="/en/quickstart">Get started</a>
    <a href="/en/changelog">View changelog</a>
    <a href="/en/api-reference/introduction">API Reference</a>
  </div>
</div>

<div />

## Get started

<CardGroup>
  <Card title="Introduction" href="/en/introduction" icon="sparkles">
    Overview of CrewAI concepts, architecture, and what you can build with agents, crews, and flows.
  </Card>

  <Card title="Installation" href="/en/installation" icon="wrench">
    Install via `uv`, configure API keys, and set up the CLI for local development.
  </Card>

  <Card title="Quickstart" href="/en/quickstart" icon="rocket">
    Spin up your first crew in minutes. Learn the core runtime, project layout, and dev loop.
  </Card>
</CardGroup>

## Build the basics

<CardGroup>
  <Card title="Agents" href="/en/concepts/agents" icon="users">
    Compose agents with tools, memory, knowledge, and structured outputs using Pydantic. Includes templates and best practices.
  </Card>

  <Card title="Flows" href="/en/concepts/flows" icon="arrow-progress">
    Orchestrate start/listen/router steps, manage state, persist execution, and resume long-running workflows.
  </Card>

  <Card title="Tasks & Processes" href="/en/concepts/tasks" icon="check">
    Define sequential, hierarchical, or hybrid processes with guardrails, callbacks, and human-in-the-loop triggers.
  </Card>
</CardGroup>

## Enterprise journey

<CardGroup>
  <Card title="Deploy automations" href="/en/enterprise/features/automations" icon="server">
    Manage environments, redeploy safely, and monitor live runs directly from the Enterprise console.
  </Card>

  <Card title="Triggers & Flows" href="/en/enterprise/guides/automation-triggers" icon="bolt">
    Connect Gmail, Slack, Salesforce, and more. Pass trigger payloads into crews and flows automatically.
  </Card>

  <Card title="Team management" href="/en/enterprise/guides/team-management" icon="users-gear">
    Invite teammates, configure RBAC, and control access to production automations.
  </Card>
</CardGroup>

## What’s new

<CardGroup>
  <Card title="Triggers overview" href="/en/enterprise/guides/automation-triggers" icon="sparkles">
    Unified overview for Gmail, Drive, Outlook, Teams, OneDrive, HubSpot, and more — now with sample payloads and crews.
  </Card>

  <Card title="Integration tools" href="/en/tools/integration/overview" icon="plug">
    Call existing CrewAI automations or Amazon Bedrock Agents directly from your crews using the updated integration toolkit.
  </Card>
</CardGroup>

<Callout title="Explore real-world patterns" icon="github">
  Browse the <a href="/en/examples/cookbooks">examples and cookbooks</a> for end-to-end reference implementations across agents, flows, and enterprise automations.
</Callout>

## Stay connected

<CardGroup>
  <Card title="Star us on GitHub" href="https://github.com/crewAIInc/crewAI" icon="star">
    If CrewAI helps you ship faster, give us a star and share your builds with the community.
  </Card>

  <Card title="Join the community" href="https://community.crewai.com" icon="comments">
    Ask questions, showcase workflows, and request features alongside other builders.
  </Card>
</CardGroup>


# Agent Repositories
Source: https://docs.crewai.com/en/enterprise/features/agent-repositories

Learn how to use Agent Repositories to share and reuse your agents across teams and projects

Agent Repositories allow enterprise users to store, share, and reuse agent definitions across teams and projects. This feature enables organizations to maintain a centralized library of standardized agents, promoting consistency and reducing duplication of effort.

<Frame>
  <img alt="Agent Repositories" />
</Frame>

## Benefits of Agent Repositories

* **Standardization**: Maintain consistent agent definitions across your organization
* **Reusability**: Create an agent once and use it in multiple crews and projects
* **Governance**: Implement organization-wide policies for agent configurations
* **Collaboration**: Enable teams to share and build upon each other's work

## Creating and Use Agent Repositories

1. You must have an account at CrewAI, try the [free plan](https://app.crewai.com).
2. Create agents with specific roles and goals for your workflows.
3. Configure tools and capabilities for each specialized assistant.
4. Deploy agents across projects via visual interface or API integration.

<Frame>
  <img alt="Agent Repositories" />
</Frame>

### Loading Agents from Repositories

You can load agents from repositories in your code using the `from_repository` parameter to run locally:

```python theme={null}
from crewai import Agent

# Create an agent by loading it from a repository
# The agent is loaded with all its predefined configurations
researcher = Agent(
    from_repository="market-research-agent"
)
```

### Overriding Repository Settings

You can override specific settings from the repository by providing them in the configuration:

```python theme={null}
researcher = Agent(
    from_repository="market-research-agent",
    goal="Research the latest trends in AI development",  # Override the repository goal
    verbose=True  # Add a setting not in the repository
)
```

### Example: Creating a Crew with Repository Agents

```python theme={null}
from crewai import Crew, Agent, Task

# Load agents from repositories
researcher = Agent(
    from_repository="market-research-agent"
)

writer = Agent(
    from_repository="content-writer-agent"
)

# Create tasks
research_task = Task(
    description="Research the latest trends in AI",
    agent=researcher
)

writing_task = Task(
    description="Write a comprehensive report based on the research",
    agent=writer
)

# Create the crew
crew = Crew(
    agents=[researcher, writer],
    tasks=[research_task, writing_task],
    verbose=True
)

# Run the crew
result = crew.kickoff()
```

### Example: Using `kickoff()` with Repository Agents

You can also use repository agents directly with the `kickoff()` method for simpler interactions:

```python theme={null}
from crewai import Agent
from pydantic import BaseModel
from typing import List

# Define a structured output format
class MarketAnalysis(BaseModel):
    key_trends: List[str]
    opportunities: List[str]
    recommendation: str

# Load an agent from repository
analyst = Agent(
    from_repository="market-analyst-agent",
    verbose=True
)

# Get a free-form response
result = analyst.kickoff("Analyze the AI market in 2025")
print(result.raw)  # Access the raw response

# Get structured output
structured_result = analyst.kickoff(
    "Provide a structured analysis of the AI market in 2025",
    response_format=MarketAnalysis
)

# Access structured data
print(f"Key Trends: {structured_result.pydantic.key_trends}")
print(f"Recommendation: {structured_result.pydantic.recommendation}")
```

## Best Practices

1. **Naming Convention**: Use clear, descriptive names for your repository agents
2. **Documentation**: Include comprehensive descriptions for each agent
3. **Tool Management**: Ensure that tools referenced by repository agents are available in your environment
4. **Access Control**: Manage permissions to ensure only authorized team members can modify repository agents

## Organization Management

To switch between organizations or see your current organization, use the CrewAI CLI:

```bash theme={null}
# View current organization
crewai org current

# Switch to a different organization
crewai org switch <org_id>

# List all available organizations
crewai org list
```

<Note>
  When loading agents from repositories, you must be authenticated and switched to the correct organization. If you receive errors, check your authentication status and organization settings using the CLI commands above.
</Note>


# Automations
Source: https://docs.crewai.com/en/enterprise/features/automations

Manage, deploy, and monitor your live crews (automations) in one place.

## Overview

Automations is the live operations hub for your deployed crews. Use it to deploy from GitHub or a ZIP file, manage environment variables, re‑deploy when needed, and monitor the status of each automation.

<Frame>
  <img alt="Automations Overview" />
</Frame>

## Deployment Methods

### Deploy from GitHub

Use this for version‑controlled projects and continuous deployment.

<Steps>
  <Step title="Connect GitHub">
    Click <b>Configure GitHub</b> and authorize access.
  </Step>

  <Step title="Select Repository & Branch">
    Choose the <b>Repository</b> and <b>Branch</b> you want to deploy from.
  </Step>

  <Step title="Enable Auto‑deploy (optional)">
    Turn on <b>Automatically deploy new commits</b> to ship updates on every push.
  </Step>

  <Step title="Add Environment Variables">
    Add secrets individually or use <b>Bulk View</b> for multiple variables.
  </Step>

  <Step title="Deploy">
    Click <b>Deploy</b> to create your live automation.
  </Step>
</Steps>

<Frame>
  <img alt="GitHub Deployment" />
</Frame>

### Deploy from ZIP

Ship quickly without Git—upload a compressed package of your project.

<Steps>
  <Step title="Choose File">
    Select the ZIP archive from your computer.
  </Step>

  <Step title="Add Environment Variables">
    Provide any required variables or keys.
  </Step>

  <Step title="Deploy">
    Click <b>Deploy</b> to create your live automation.
  </Step>
</Steps>

<Frame>
  <img alt="ZIP Deployment" />
</Frame>

## Automations Dashboard

The table lists all live automations with key details:

* **CREW**: Automation name
* **STATUS**: Online / Failed / In Progress
* **URL**: Endpoint for kickoff/status
* **TOKEN**: Automation token
* **ACTIONS**: Re‑deploy, delete, and more

Use the top‑right controls to filter and search:

* Search by name
* Filter by <b>Status</b>
* Filter by <b>Source</b> (GitHub / Studio / ZIP)

Once deployed, you can view the automation details and have the **Options** dropdown menu to `chat with this crew`, `Export React Component` and `Export as MCP`.

<Frame>
  <img alt="Automations Table" />
</Frame>

## Best Practices

* Prefer GitHub deployments for version control and CI/CD
* Use re‑deploy to roll forward after code or config updates or set it to auto-deploy on every push

## Related

<CardGroup>
  <Card title="Deploy a Crew" href="/en/enterprise/guides/deploy-crew" icon="rocket">
    Deploy a Crew from GitHub or ZIP file.
  </Card>

  <Card title="Automation Triggers" href="/en/enterprise/guides/automation-triggers" icon="trigger">
    Trigger automations via webhooks or API.
  </Card>

  <Card title="Webhook Automation" href="/en/enterprise/guides/webhook-automation" icon="webhook">
    Stream real-time events and updates to your systems.
  </Card>
</CardGroup>


# Crew Studio
Source: https://docs.crewai.com/en/enterprise/features/crew-studio

Build new automations with AI assistance, a visual editor, and integrated testing.

## Overview

Crew Studio is an interactive, AI‑assisted workspace for creating new automations from scratch using natural language and a visual workflow editor.

<Frame>
  <img alt="Crew Studio Overview" />
</Frame>

## Prompt‑based Creation

* Describe the automation you want; the AI generates agents, tasks, and tools.
* Use voice input via the microphone icon if preferred.
* Start from built‑in prompts for common use cases.

<Frame>
  <img alt="Prompt Builder" />
</Frame>

## Visual Editor

The canvas reflects the workflow as nodes and edges with three supporting panels that allow you to configure the workflow easily without writing code; a.k.a. "**vibe coding AI Agents**".

You can use the drag-and-drop functionality to add agents, tasks, and tools to the canvas or you can use the chat section to build the agents. Both approaches share state and can be used interchangeably.

* **AI Thoughts (left)**: streaming reasoning as the workflow is designed
* **Canvas (center)**: agents and tasks as connected nodes
* **Resources (right)**: drag‑and‑drop components (agents, tasks, tools)

<Frame>
  <img alt="Visual Canvas" />
</Frame>

## Execution & Debugging

Switch to the <b>Execution</b> view to run and observe the workflow:

* Event timeline
* Detailed logs (Details, Messages, Raw Data)
* Local test runs before publishing

<Frame>
  <img alt="Execution View" />
</Frame>

## Publish & Export

* <b>Publish</b> to deploy a live automation
* <b>Download</b> source as a ZIP for local development or customization

<Frame>
  <img alt="Publish & Download" />
</Frame>

Once published, you can view the automation details and have the **Options** dropdown menu to `chat with this crew`, `Export React Component` and `Export as MCP`.

<Frame>
  <img alt="Published Automation" />
</Frame>

## Best Practices

* Iterate quickly in Studio; publish only when stable
* Keep tools constrained to minimum permissions needed
* Use Traces to validate behavior and performance

## Related

<CardGroup>
  <Card title="Enable Crew Studio" href="/en/enterprise/guides/enable-crew-studio" icon="palette">
    Enable Crew Studio.
  </Card>

  <Card title="Build a Crew" href="/en/enterprise/guides/build-crew" icon="paintbrush">
    Build a Crew.
  </Card>

  <Card title="Deploy a Crew" href="/en/enterprise/guides/deploy-crew" icon="rocket">
    Deploy a Crew from GitHub or ZIP file.
  </Card>

  <Card title="Export a React Component" href="/en/enterprise/guides/react-component-export" icon="download">
    Export a React Component.
  </Card>
</CardGroup>


# Flow HITL Management
Source: https://docs.crewai.com/en/enterprise/features/flow-hitl-management

Enterprise-grade human review for Flows with email-first notifications, routing rules, and auto-response capabilities

<Note>
  Flow HITL Management features require the `@human_feedback` decorator, available in **CrewAI version 1.8.0 or higher**. These features apply specifically to **Flows**, not Crews.
</Note>

CrewAI Enterprise provides a comprehensive Human-in-the-Loop (HITL) management system for Flows that transforms AI workflows into collaborative human-AI processes. The platform uses an **email-first architecture** that enables anyone with an email address to respond to review requests—no platform account required.

## Overview

<CardGroup>
  <Card title="Email-First Design" icon="envelope">
    Responders can reply directly to notification emails to provide feedback
  </Card>

  <Card title="Flexible Routing" icon="route">
    Route requests to specific emails based on method patterns or flow state
  </Card>

  <Card title="Auto-Response" icon="clock">
    Configure automatic fallback responses when no human replies in time
  </Card>
</CardGroup>

### Key Benefits

* **Simple mental model**: Email addresses are universal; no need to manage platform users or roles
* **External responders**: Anyone with an email can respond, even non-platform users
* **Dynamic assignment**: Pull assignee email directly from flow state (e.g., `sales_rep_email`)
* **Reduced configuration**: Fewer settings to configure, faster time to value
* **Email as primary channel**: Most users prefer responding via email over logging into a dashboard

## Setting Up Human Review Points in Flows

Configure human review checkpoints within your Flows using the `@human_feedback` decorator. When execution reaches a review point, the system pauses, notifies the assignee via email, and waits for a response.

```python theme={null}
from crewai.flow.flow import Flow, start, listen, or_
from crewai.flow.human_feedback import human_feedback, HumanFeedbackResult

class ContentApprovalFlow(Flow):
    @start()
    def generate_content(self):
        return "Generated marketing copy for Q1 campaign..."

    @human_feedback(
        message="Please review this content for brand compliance:",
        emit=["approved", "rejected", "needs_revision"],
    )
    @listen(or_("generate_content", "needs_revision"))
    def review_content(self):
        return "Marketing copy for review..."

    @listen("approved")
    def publish_content(self, result: HumanFeedbackResult):
        print(f"Publishing approved content. Reviewer notes: {result.feedback}")

    @listen("rejected")
    def archive_content(self, result: HumanFeedbackResult):
        print(f"Content rejected. Reason: {result.feedback}")
```

For complete implementation details, see the [Human Feedback in Flows](/en/learn/human-feedback-in-flows) guide.

### Decorator Parameters

| Parameter | Type        | Description                                         |
| --------- | ----------- | --------------------------------------------------- |
| `message` | `str`       | The message displayed to the human reviewer         |
| `emit`    | `list[str]` | Valid response options (displayed as buttons in UI) |

## Platform Configuration

Access HITL configuration from: **Deployment → Settings → Human in the Loop Configuration**

<Frame>
  <img alt="HITL Configuration Settings" />
</Frame>

### Email Notifications

Toggle to enable or disable email notifications for HITL requests.

| Setting             | Default | Description                            |
| ------------------- | ------- | -------------------------------------- |
| Email Notifications | Enabled | Send emails when feedback is requested |

<Note>
  When disabled, responders must use the dashboard UI or you must configure webhooks for custom notification systems.
</Note>

### SLA Target

Set a target response time for tracking and metrics purposes.

| Setting              | Description                                                       |
| -------------------- | ----------------------------------------------------------------- |
| SLA Target (minutes) | Target response time. Used for dashboard metrics and SLA tracking |

Leave empty to disable SLA tracking.

## Email Notifications & Responses

The HITL system uses an email-first architecture where responders can reply directly to notification emails.

### How Email Responses Work

<Steps>
  <Step title="Notification Sent">
    When a HITL request is created, an email is sent to the assigned responder with the review content and context.
  </Step>

  <Step title="Reply-To Address">
    The email includes a special reply-to address with a signed token for authentication.
  </Step>

  <Step title="User Replies">
    The responder simply replies to the email with their feedback—no login required.
  </Step>

  <Step title="Token Validation">
    The platform receives the reply, verifies the signed token, and matches the sender email.
  </Step>

  <Step title="Flow Resumes">
    The feedback is recorded and the flow continues with the human's input.
  </Step>
</Steps>

### Response Format

Responders can reply with:

* **Emit option**: If the reply matches an `emit` option (e.g., "approved"), it's used directly
* **Free-form text**: Any text response is passed to the flow as feedback
* **Plain text**: The first line of the reply body is used as feedback

### Confirmation Emails

After processing a reply, the responder receives a confirmation email indicating whether the feedback was successfully submitted or if an error occurred.

### Email Token Security

* Tokens are cryptographically signed for security
* Tokens expire after 7 days
* Sender email must match the token's authorized email
* Confirmation/error emails are sent after processing

## Routing Rules

Route HITL requests to specific email addresses based on method patterns.

<Frame>
  <img alt="HITL Routing Rules Configuration" />
</Frame>

### Rule Structure

```json theme={null}
{
  "name": "Approvals to Finance",
  "match": {
    "method_name": "approve_*"
  },
  "assign_to_email": "finance@company.com",
  "assign_from_input": "manager_email"
}
```

### Matching Patterns

| Pattern            | Description          | Example Match                       |
| ------------------ | -------------------- | ----------------------------------- |
| `approve_*`        | Wildcard (any chars) | `approve_payment`, `approve_vendor` |
| `review_?`         | Single char          | `review_a`, `review_1`              |
| `validate_payment` | Exact match          | `validate_payment` only             |

### Assignment Priority

1. **Dynamic assignment** (`assign_from_input`): If configured, pulls email from flow state
2. **Static email** (`assign_to_email`): Falls back to configured email
3. **Deployment creator**: If no rule matches, the deployment creator's email is used

### Dynamic Assignment Example

If your flow state contains `{"sales_rep_email": "alice@company.com"}`, configure:

```json theme={null}
{
  "name": "Route to Sales Rep",
  "match": {
    "method_name": "review_*"
  },
  "assign_from_input": "sales_rep_email"
}
```

The request will be assigned to `alice@company.com` automatically.

<Tip>
  **Use Case**: Pull the assignee from your CRM, database, or previous flow step to dynamically route reviews to the right person.
</Tip>

## Auto-Response

Automatically respond to HITL requests if no human responds within a timeout. This ensures flows don't hang indefinitely.

### Configuration

| Setting           | Description                                      |
| ----------------- | ------------------------------------------------ |
| Enabled           | Toggle to enable auto-response                   |
| Timeout (minutes) | Time to wait before auto-responding              |
| Default Outcome   | The response value (must match an `emit` option) |

<Frame>
  <img alt="HITL Auto-Response Configuration" />
</Frame>

### Use Cases

* **SLA compliance**: Ensure flows don't hang indefinitely
* **Default approval**: Auto-approve low-risk requests after timeout
* **Graceful degradation**: Continue with a safe default when reviewers are unavailable

<Warning>
  Use auto-response carefully. Only enable it for non-critical reviews where a default response is acceptable.
</Warning>

## Review Process

### Dashboard Interface

The HITL review interface provides a clean, focused experience for reviewers:

* **Markdown Rendering**: Rich formatting for review content with syntax highlighting
* **Context Panel**: View flow state, execution history, and related information
* **Feedback Input**: Provide detailed feedback and comments with your decision
* **Quick Actions**: One-click emit option buttons with optional comments

<Frame>
  <img alt="HITL Pending Requests List" />
</Frame>

### Response Methods

Reviewers can respond via three channels:

| Method          | Description                              |
| --------------- | ---------------------------------------- |
| **Email Reply** | Reply directly to the notification email |
| **Dashboard**   | Use the Enterprise dashboard UI          |
| **API/Webhook** | Programmatic response via API            |

### History & Audit Trail

Every HITL interaction is tracked with a complete timeline:

* Decision history (approve/reject/revise)
* Reviewer identity and timestamp
* Feedback and comments provided
* Response method (email/dashboard/API)
* Response time metrics

## Analytics & Monitoring

Track HITL performance with comprehensive analytics.

### Performance Dashboard

<Frame>
  <img alt="HITL Metrics Dashboard" />
</Frame>

<CardGroup>
  <Card title="Response Times" icon="stopwatch">
    Monitor average and median response times by reviewer or flow.
  </Card>

  <Card title="Volume Trends" icon="chart-bar">
    Analyze review volume patterns to optimize team capacity.
  </Card>

  <Card title="Decision Distribution" icon="chart-pie">
    View approval/rejection rates across different review types.
  </Card>

  <Card title="SLA Tracking" icon="chart-line">
    Track percentage of reviews completed within SLA targets.
  </Card>
</CardGroup>

### Audit & Compliance

Enterprise-ready audit capabilities for regulatory requirements:

* Complete decision history with timestamps
* Reviewer identity verification
* Immutable audit logs
* Export capabilities for compliance reporting

## Common Use Cases

<AccordionGroup>
  <Accordion title="Security Reviews" icon="shield-halved">
    **Use Case**: Internal security questionnaire automation with human validation

    * AI generates responses to security questionnaires
    * Security team reviews and validates accuracy via email
    * Approved responses are compiled into final submission
    * Full audit trail for compliance
  </Accordion>

  <Accordion title="Content Approval" icon="file-lines">
    **Use Case**: Marketing content requiring legal/brand review

    * AI generates marketing copy or social media content
    * Route to brand team email for voice/tone review
    * Automatic publishing upon approval
  </Accordion>

  <Accordion title="Financial Approvals" icon="money-bill">
    **Use Case**: Expense reports, contract terms, budget allocations

    * AI pre-processes and categorizes financial requests
    * Route based on amount thresholds using dynamic assignment
    * Maintain complete audit trail for financial compliance
  </Accordion>

  <Accordion title="Dynamic Assignment from CRM" icon="database">
    **Use Case**: Route reviews to account owners from your CRM

    * Flow fetches account owner email from CRM
    * Store email in flow state (e.g., `account_owner_email`)
    * Use `assign_from_input` to route to the right person automatically
  </Accordion>

  <Accordion title="Quality Assurance" icon="magnifying-glass">
    **Use Case**: AI output validation before customer delivery

    * AI generates customer-facing content or responses
    * QA team reviews via email notification
    * Feedback loops improve AI performance over time
  </Accordion>
</AccordionGroup>

## Webhooks API

When your Flows pause for human feedback, you can configure webhooks to send request data to your own application. This enables:

* Building custom approval UIs
* Integrating with internal tools (Jira, ServiceNow, custom dashboards)
* Routing approvals to third-party systems
* Mobile app notifications
* Automated decision systems

<Frame>
  <img alt="HITL Webhook Configuration" />
</Frame>

### Configuring Webhooks

<Steps>
  <Step title="Navigate to Settings">
    Go to your **Deployment** → **Settings** → **Human in the Loop**
  </Step>

  <Step title="Expand Webhooks Section">
    Click to expand the **Webhooks** configuration
  </Step>

  <Step title="Add Your Webhook URL">
    Enter your webhook URL (must be HTTPS in production)
  </Step>

  <Step title="Save Configuration">
    Click **Save Configuration** to activate
  </Step>
</Steps>

You can configure multiple webhooks. Each active webhook receives all HITL events.

### Webhook Events

Your endpoint will receive HTTP POST requests for these events:

| Event Type    | When Triggered                            |
| ------------- | ----------------------------------------- |
| `new_request` | A flow pauses and requests human feedback |

### Webhook Payload

All webhooks receive a JSON payload with this structure:

```json theme={null}
{
  "event": "new_request",
  "request": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "flow_id": "flow_abc123",
    "method_name": "review_article",
    "message": "Please review this article for publication.",
    "emit_options": ["approved", "rejected", "request_changes"],
    "state": {
      "article_id": 12345,
      "author": "john@example.com",
      "category": "technology"
    },
    "metadata": {},
    "created_at": "2026-01-14T12:00:00Z"
  },
  "deployment": {
    "id": 456,
    "name": "Content Review Flow",
    "organization_id": 789
  },
  "callback_url": "https://api.crewai.com/...",
  "assigned_to_email": "reviewer@company.com"
}
```

### Responding to Requests

To submit feedback, **POST to the `callback_url`** included in the webhook payload.

```http theme={null}
POST {callback_url}
Content-Type: application/json

{
  "feedback": "Approved. Great article!",
  "source": "my_custom_app"
}
```

### Security

<Info>
  All webhook requests are cryptographically signed using HMAC-SHA256 to ensure authenticity and prevent tampering.
</Info>

#### Webhook Security

* **HMAC-SHA256 signatures**: Every webhook includes a cryptographic signature
* **Per-webhook secrets**: Each webhook has its own unique signing secret
* **Encrypted at rest**: Signing secrets are encrypted in our database
* **Timestamp verification**: Prevents replay attacks

#### Signature Headers

Each webhook request includes these headers:

| Header        | Description                                  |
| ------------- | -------------------------------------------- |
| `X-Signature` | HMAC-SHA256 signature: `sha256=<hex_digest>` |
| `X-Timestamp` | Unix timestamp when the request was signed   |

#### Verification

Verify by computing:

```python theme={null}
import hmac
import hashlib

expected = hmac.new(
    signing_secret.encode(),
    f"{timestamp}.{payload}".encode(),
    hashlib.sha256
).hexdigest()

if hmac.compare_digest(expected, signature):
    # Valid signature
```

### Error Handling

Your webhook endpoint should return a 2xx status code to acknowledge receipt:

| Your Response | Our Behavior                   |
| ------------- | ------------------------------ |
| 2xx           | Webhook delivered successfully |
| 4xx/5xx       | Logged as failed, no retry     |
| Timeout (30s) | Logged as failed, no retry     |

## Security & RBAC

### Dashboard Access

HITL access is controlled at the deployment level:

| Permission                  | Capability                                  |
| --------------------------- | ------------------------------------------- |
| `manage_human_feedback`     | Configure HITL settings, view all requests  |
| `respond_to_human_feedback` | Respond to requests, view assigned requests |

### Email Response Authorization

For email replies:

1. The reply-to token encodes the authorized email
2. Sender email must match the token's email
3. Token must not be expired (7-day default)
4. Request must still be pending

### Audit Trail

All HITL actions are logged:

* Request creation
* Assignment changes
* Response submission (with source: dashboard/email/API)
* Flow resume status

## Troubleshooting

### Emails Not Sending

1. Check "Email Notifications" is enabled in configuration
2. Verify routing rules match the method name
3. Verify assignee email is valid
4. Check deployment creator fallback if no routing rules match

### Email Replies Not Processing

1. Check token hasn't expired (7-day default)
2. Verify sender email matches assigned email
3. Ensure request is still pending (not already responded)

### Flow Not Resuming

1. Check request status in dashboard
2. Verify callback URL is accessible
3. Ensure deployment is still running

## Best Practices

<Tip>
  **Start Simple**: Begin with email notifications to deployment creator, then add routing rules as your workflows mature.
</Tip>

1. **Use Dynamic Assignment**: Pull assignee emails from your flow state for flexible routing.

2. **Configure Auto-Response**: Set up a fallback for non-critical reviews to prevent flows from hanging.

3. **Monitor Response Times**: Use analytics to identify bottlenecks and optimize your review process.

4. **Keep Review Messages Clear**: Write clear, actionable messages in the `@human_feedback` decorator.

5. **Test Email Flow**: Send test requests to verify email delivery before going to production.

## Related Resources

<CardGroup>
  <Card title="Human Feedback in Flows" icon="code" href="/en/learn/human-feedback-in-flows">
    Implementation guide for the `@human_feedback` decorator
  </Card>

  <Card title="Flow HITL Workflow Guide" icon="route" href="/en/enterprise/guides/human-in-the-loop">
    Step-by-step guide for setting up HITL workflows
  </Card>

  <Card title="RBAC Configuration" icon="shield-check" href="/en/enterprise/features/rbac">
    Configure role-based access control for your organization
  </Card>

  <Card title="Webhook Streaming" icon="bolt" href="/en/enterprise/features/webhook-streaming">
    Set up real-time event notifications
  </Card>
</CardGroup>


# Hallucination Guardrail
Source: https://docs.crewai.com/en/enterprise/features/hallucination-guardrail

Prevent and detect AI hallucinations in your CrewAI tasks

## Overview

The Hallucination Guardrail is an enterprise feature that validates AI-generated content to ensure it's grounded in facts and doesn't contain hallucinations. It analyzes task outputs against reference context and provides detailed feedback when potentially hallucinated content is detected.

## What are Hallucinations?

AI hallucinations occur when language models generate content that appears plausible but is factually incorrect or not supported by the provided context. The Hallucination Guardrail helps prevent these issues by:

* Comparing outputs against reference context
* Evaluating faithfulness to source material
* Providing detailed feedback on problematic content
* Supporting custom thresholds for validation strictness

## Basic Usage

### Setting Up the Guardrail

```python theme={null}
from crewai.tasks.hallucination_guardrail import HallucinationGuardrail
from crewai import LLM

# Basic usage - will use task's expected_output as context
guardrail = HallucinationGuardrail(
    llm=LLM(model="gpt-4o-mini")
)

# With explicit reference context
context_guardrail = HallucinationGuardrail(
    context="AI helps with various tasks including analysis and generation.",
    llm=LLM(model="gpt-4o-mini")
)
```

### Adding to Tasks

```python theme={null}
from crewai import Task

# Create your task with the guardrail
task = Task(
    description="Write a summary about AI capabilities",
    expected_output="A factual summary based on the provided context",
    agent=my_agent,
    guardrail=guardrail  # Add the guardrail to validate output
)
```

## Advanced Configuration

### Custom Threshold Validation

For stricter validation, you can set a custom faithfulness threshold (0-10 scale):

```python theme={null}
# Strict guardrail requiring high faithfulness score
strict_guardrail = HallucinationGuardrail(
    context="Quantum computing uses qubits that exist in superposition states.",
    llm=LLM(model="gpt-4o-mini"),
    threshold=8.0  # Requires score >= 8 to pass validation
)
```

### Including Tool Response Context

When your task uses tools, you can include tool responses for more accurate validation:

```python theme={null}
# Guardrail with tool response context
weather_guardrail = HallucinationGuardrail(
    context="Current weather information for the requested location",
    llm=LLM(model="gpt-4o-mini"),
    tool_response="Weather API returned: Temperature 22°C, Humidity 65%, Clear skies"
)
```

## How It Works

### Validation Process

1. **Context Analysis**: The guardrail compares task output against the provided reference context
2. **Faithfulness Scoring**: Uses an internal evaluator to assign a faithfulness score (0-10)
3. **Verdict Determination**: Determines if content is faithful or contains hallucinations
4. **Threshold Checking**: If a custom threshold is set, validates against that score
5. **Feedback Generation**: Provides detailed reasons when validation fails

### Validation Logic

* **Default Mode**: Uses verdict-based validation (FAITHFUL vs HALLUCINATED)
* **Threshold Mode**: Requires faithfulness score to meet or exceed the specified threshold
* **Error Handling**: Gracefully handles evaluation errors and provides informative feedback

## Guardrail Results

The guardrail returns structured results indicating validation status:

```python theme={null}
# Example of guardrail result structure
{
    "valid": False,
    "feedback": "Content appears to be hallucinated (score: 4.2/10, verdict: HALLUCINATED). The output contains information not supported by the provided context."
}
```

### Result Properties

* **valid**: Boolean indicating whether the output passed validation
* **feedback**: Detailed explanation when validation fails, including:
  * Faithfulness score
  * Verdict classification
  * Specific reasons for failure

## Integration with Task System

### Automatic Validation

When a guardrail is added to a task, it automatically validates the output before the task is marked as complete:

```python theme={null}
# Task output validation flow
task_output = agent.execute_task(task)
validation_result = guardrail(task_output)

if validation_result.valid:
    # Task completes successfully
    return task_output
else:
    # Task fails with validation feedback
    raise ValidationError(validation_result.feedback)
```

### Event Tracking

The guardrail integrates with CrewAI's event system to provide observability:

* **Validation Started**: When guardrail evaluation begins
* **Validation Completed**: When evaluation finishes with results
* **Validation Failed**: When technical errors occur during evaluation

## Best Practices

### Context Guidelines

<Steps>
  <Step title="Provide Comprehensive Context">
    Include all relevant factual information that the AI should base its output on:

    ```python theme={null}
    context = """
    Company XYZ was founded in 2020 and specializes in renewable energy solutions.
    They have 150 employees and generated $50M revenue in 2023.
    Their main products include solar panels and wind turbines.
    """
    ```
  </Step>

  <Step title="Keep Context Relevant">
    Only include information directly related to the task to avoid confusion:

    ```python theme={null}
    # Good: Focused context
    context = "The current weather in New York is 18°C with light rain."

    # Avoid: Unrelated information
    context = "The weather is 18°C. The city has 8 million people. Traffic is heavy."
    ```
  </Step>

  <Step title="Update Context Regularly">
    Ensure your reference context reflects current, accurate information.
  </Step>
</Steps>

### Threshold Selection

<Steps>
  <Step title="Start with Default Validation">
    Begin without custom thresholds to understand baseline performance.
  </Step>

  <Step title="Adjust Based on Requirements">
    * **High-stakes content**: Use threshold 8-10 for maximum accuracy
    * **General content**: Use threshold 6-7 for balanced validation
    * **Creative content**: Use threshold 4-5 or default verdict-based validation
  </Step>

  <Step title="Monitor and Iterate">
    Track validation results and adjust thresholds based on false positives/negatives.
  </Step>
</Steps>

## Performance Considerations

### Impact on Execution Time

* **Validation Overhead**: Each guardrail adds \~1-3 seconds per task
* **LLM Efficiency**: Choose efficient models for evaluation (e.g., gpt-4o-mini)

### Cost Optimization

* **Model Selection**: Use smaller, efficient models for guardrail evaluation
* **Context Size**: Keep reference context concise but comprehensive
* **Caching**: Consider caching validation results for repeated content

## Troubleshooting

<Accordion title="Validation Always Fails">
  **Possible Causes:**

  * Context is too restrictive or unrelated to task output
  * Threshold is set too high for the content type
  * Reference context contains outdated information

  **Solutions:**

  * Review and update context to match task requirements
  * Lower threshold or use default verdict-based validation
  * Ensure context is current and accurate
</Accordion>

<Accordion title="False Positives (Valid Content Marked Invalid)">
  **Possible Causes:**

  * Threshold too high for creative or interpretive tasks
  * Context doesn't cover all valid aspects of the output
  * Evaluation model being overly conservative

  **Solutions:**

  * Lower threshold or use default validation
  * Expand context to include broader acceptable content
  * Test with different evaluation models
</Accordion>

<Accordion title="Evaluation Errors">
  **Possible Causes:**

  * Network connectivity issues
  * LLM model unavailable or rate limited
  * Malformed task output or context

  **Solutions:**

  * Check network connectivity and LLM service status
  * Implement retry logic for transient failures
  * Validate task output format before guardrail evaluation
</Accordion>

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with hallucination guardrail configuration or troubleshooting.
</Card>


# Marketplace
Source: https://docs.crewai.com/en/enterprise/features/marketplace

Discover, install, and govern reusable assets for your enterprise crews.

## Overview

The Marketplace provides a curated surface for discovering integrations, internal tools, and reusable assets that accelerate crew development.

<Frame>
  <img alt="Marketplace Overview" />
</Frame>

## Discoverability

* Browse by category and capability
* Search for assets by name or keyword

## Install & Enable

* One‑click install for approved assets
* Enable or disable per crew as needed
* Configure required environment variables and scopes

<Frame>
  <img alt="Install & Configure" />
</Frame>

You can also download the templates directly from the marketplace by clicking on the `Download` button so
you can use them locally or refine them to your needs.

## Related

<CardGroup>
  <Card title="Tools & Integrations" href="/en/enterprise/features/tools-and-integrations" icon="wrench">
    Connect external apps and manage internal tools your agents can use.
  </Card>

  <Card title="Tool Repository" href="/en/enterprise/guides/tool-repository#tool-repository" icon="toolbox">
    Publish and install tools to enhance your crews' capabilities.
  </Card>

  <Card title="Agents Repository" href="/en/enterprise/features/agent-repositories" icon="people-group">
    Store, share, and reuse agent definitions across teams and projects.
  </Card>
</CardGroup>


# PII Redaction for Traces
Source: https://docs.crewai.com/en/enterprise/features/pii-trace-redactions

Automatically redact sensitive data from crew and flow execution traces

## Overview

PII Redaction is a CrewAI AMP feature that automatically detects and masks Personally Identifiable Information (PII) in your crew and flow execution traces. This ensures sensitive data like credit card numbers, social security numbers, email addresses, and names are not exposed in your CrewAI AMP traces. You can also create custom recognizers to protect organization-specific data.

<Info>
  PII Redaction is available on the Enterprise plan.
  Deployment must be version 1.8.0 or higher.
</Info>

<Frame>
  <img alt="PII Redaction Overview" />
</Frame>

## Why PII Redaction Matters

When running AI agents in production, sensitive information often flows through your crews:

* Customer data from CRM integrations
* Financial information from payment processors
* Personal details from form submissions
* Internal employee data

Without proper redaction, this data appears in traces, making compliance with regulations like GDPR, HIPAA, and PCI-DSS challenging. PII Redaction solves this by automatically masking sensitive data before it's stored in traces.

## How It Works

1. **Detect** - Scan trace event data for known PII patterns
2. **Classify** - Identify the type of sensitive data (credit card, SSN, email, etc.)
3. **Mask/Redact** - Replace the sensitive data with masked values based on your configuration

```
Original: "Contact john.doe@company.com or call 555-123-4567"
Redacted: "Contact <EMAIL_ADDRESS> or call <PHONE_NUMBER>"
```

## Enabling PII Redaction

<Info>
  You must be on the Enterprise plan and your deployment must be version 1.8.0 or higher to use this feature.
</Info>

<Steps>
  <Step title="Navigate to Crew Settings">
    In the CrewAI AMP dashboard, select your deployed crew and go to one of your deployments/automations, then navigate to **Settings** → **PII Protection**.
  </Step>

  <Step title="Enable PII Protection">
    Toggle on **PII Redaction for Traces**. This will enable automatic scanning and redaction of trace data.

    <Info>
      You need to manually enable PII Redaction for each deployment.
    </Info>

    <Frame>
      <img alt="Enable PII Redaction" />
    </Frame>
  </Step>

  <Step title="Configure Entity Types">
    Select which types of PII to detect and redact. Each entity can be individually enabled or disabled.

    <Frame>
      <img alt="Configure Entities" />
    </Frame>
  </Step>

  <Step title="Save">
    Save your configuration. PII redaction will be active on all subsequent crew executions, no redeployment is needed.
  </Step>
</Steps>

## Supported Entity Types

CrewAI supports the following PII entity types, organized by category.

### Global Entities

| Entity            | Description                                   | Example                                       |
| ----------------- | --------------------------------------------- | --------------------------------------------- |
| `CREDIT_CARD`     | Credit/debit card numbers                     | "4111-1111-1111-1111"                         |
| `CRYPTO`          | Cryptocurrency wallet addresses               | "bc1qxy2kgd..."                               |
| `DATE_TIME`       | Dates and times                               | "January 15, 2024"                            |
| `EMAIL_ADDRESS`   | Email addresses                               | "[john@example.com](mailto:john@example.com)" |
| `IBAN_CODE`       | International bank account numbers            | "DE89 3704 0044 0532 0130 00"                 |
| `IP_ADDRESS`      | IPv4 and IPv6 addresses                       | "192.168.1.1"                                 |
| `LOCATION`        | Geographic locations                          | "New York City"                               |
| `MEDICAL_LICENSE` | Medical license numbers                       | "MD12345"                                     |
| `NRP`             | Nationalities, religious, or political groups | -                                             |
| `PERSON`          | Personal names                                | "John Doe"                                    |
| `PHONE_NUMBER`    | Phone numbers in various formats              | "+1 (555) 123-4567"                           |
| `URL`             | Web URLs                                      | "[https://example.com](https://example.com)"  |

### US-Specific Entities

| Entity              | Description                 | Example       |
| ------------------- | --------------------------- | ------------- |
| `US_BANK_NUMBER`    | US Bank account numbers     | "1234567890"  |
| `US_DRIVER_LICENSE` | US Driver's license numbers | "D1234567"    |
| `US_ITIN`           | Individual Taxpayer ID      | "900-70-0000" |
| `US_PASSPORT`       | US Passport numbers         | "123456789"   |
| `US_SSN`            | Social Security Numbers     | "123-45-6789" |

## Redaction Actions

For each enabled entity, you can configure how the data is redacted:

| Action   | Description                        | Example Output  |
| -------- | ---------------------------------- | --------------- |
| `mask`   | Replace with the entity type label | `<CREDIT_CARD>` |
| `redact` | Completely remove the text         | *(empty)*       |

## Custom Recognizers

In addition to built-in entities, you can create **custom recognizers** to detect organization-specific PII patterns.

<Frame>
  <img alt="Custom Recognizers" />
</Frame>

### Recognizer Types

You have two options for custom recognizers:

| Type                      | Best For                                 | Example Use Case                                  |
| ------------------------- | ---------------------------------------- | ------------------------------------------------- |
| **Pattern-based (Regex)** | Structured data with predictable formats | Salary amounts, employee IDs, project codes       |
| **Deny-list**             | Exact string matches                     | Company names, internal codenames, specific terms |

### Creating a Custom Recognizer

<Steps>
  <Step title="Navigate to Custom Recognizers">
    Go to your Organization **Settings** → **Organization** → **Add Recognizer**.
  </Step>

  <Step title="Configure the Recognizer">
    <Frame>
      <img alt="Configure Recognizer" />
    </Frame>

    Configure the following fields:

    * **Name**: A descriptive name for the recognizer
    * **Entity Type**: The entity label that will appear in redacted output (e.g., `EMPLOYEE_ID`, `SALARY`)
    * **Type**: Choose between Regex Pattern or Deny List
    * **Pattern/Values**: Regex pattern or list of strings to match
    * **Confidence Threshold**: Minimum score (0.0-1.0) required for a match to trigger redaction. Higher values (e.g., 0.8) reduce false positives but may miss some matches. Lower values (e.g., 0.5) catch more matches but may over-redact. Default is 0.8.
    * **Context Words** (optional): Words that increase detection confidence when found nearby
  </Step>

  <Step title="Save">
    Save the recognizer. It will be available to enable on your deployments.
  </Step>
</Steps>

### Understanding Entity Types

The **Entity Type** determines how matched content appears in redacted traces:

```
Entity Type: SALARY
Pattern: salary:\s*\$\s*\d+
Input: "Employee salary: $50,000"
Output: "Employee <SALARY>"
```

### Using Context Words

Context words improve accuracy by increasing confidence when specific terms appear near the matched pattern:

```
Context Words: "project", "code", "internal"
Entity Type: PROJECT_CODE
Pattern: PRJ-\d{4}
```

When "project" or "code" appears near "PRJ-1234", the recognizer has higher confidence it's a true match, reducing false positives.

## Viewing Redacted Traces

Once PII redaction is enabled, your traces will show redacted values in place of sensitive data:

```
Task Output: "Customer <PERSON> placed order #12345.
Contact email: <EMAIL_ADDRESS>, phone: <PHONE_NUMBER>.
Payment processed for card ending in <CREDIT_CARD>."
```

Redacted values are clearly marked with angle brackets and the entity type label (e.g., `<EMAIL_ADDRESS>`), making it easy to understand what data was protected while still allowing you to debug and monitor crew behavior.

## Best Practices

### Performance Considerations

<Steps>
  <Step title="Enable Only Needed Entities">
    Each enabled entity adds processing overhead. Only enable entities relevant to your data.
  </Step>

  <Step title="Use Specific Patterns">
    For custom recognizers, use specific patterns to reduce false positives and improve performance. Regex patterns are best when identifying specific patterns in the traces such as salary, employee id, project code, etc. Deny-list recognizers are best when identifying exact strings in the traces such as company names, internal codenames, etc.
  </Step>

  <Step title="Leverage Context Words">
    Context words improve accuracy by only triggering detection when surrounding text matches.
  </Step>
</Steps>

## Troubleshooting

<Accordion title="PII Not Being Redacted">
  **Possible Causes:**

  * Entity type not enabled in configuration
  * Pattern doesn't match the data format
  * Custom recognizer has syntax errors

  **Solutions:**

  * Verify entity is enabled in Settings → Security
  * Test regex patterns with sample data
  * Check logs for configuration errors
</Accordion>

<Accordion title="Too Much Data Being Redacted">
  **Possible Causes:**

  * Overly broad entity types enabled (e.g., `DATE_TIME` catches dates everywhere)
  * Custom recognizer patterns are too general

  **Solutions:**

  * Disable entities that cause false positives
  * Make custom patterns more specific
  * Add context words to improve accuracy
</Accordion>

<Accordion title="Performance Issues">
  **Possible Causes:**

  * Too many entities enabled
  * NLP-based entities (`PERSON`, `LOCATION`, `NRP`) are computationally expensive as they use machine learning models

  **Solutions:**

  * Only enable entities you actually need
  * Consider using pattern-based alternatives where possible
  * Monitor trace processing times in the dashboard
</Accordion>

***

## Practical Example: Salary Pattern Matching

This example demonstrates how to create a custom recognizer to detect and mask salary information in your traces.

### Use Case

Your crew processes employee or financial data that includes salary information in formats like:

* `salary: $50,000`
* `salary: $125,000.00`
* `salary:$1,500.50`

You want to automatically mask these values to protect sensitive compensation data.

### Configuration

<Frame>
  <img alt="Salary Recognizer Configuration" />
</Frame>

| Field                    | Value                                       |
| ------------------------ | ------------------------------------------- |
| **Name**                 | `SALARY`                                    |
| **Entity Type**          | `SALARY`                                    |
| **Type**                 | Regex Pattern                               |
| **Regex Pattern**        | `salary:\s*\$\s*\d{1,3}(,\d{3})*(\.\d{2})?` |
| **Action**               | Mask                                        |
| **Confidence Threshold** | `0.8`                                       |
| **Context Words**        | `salary, compensation, pay, wage, income`   |

### Regex Pattern Breakdown

| Pattern Component | Meaning                                                      |
| ----------------- | ------------------------------------------------------------ |
| `salary:`         | Matches the literal text "salary:"                           |
| `\s*`             | Matches zero or more whitespace characters                   |
| `\$`              | Matches the dollar sign (escaped)                            |
| `\s*`             | Matches zero or more whitespace characters after \$          |
| `\d{1,3}`         | Matches 1-3 digits (e.g., "1", "50", "125")                  |
| `(,\d{3})*`       | Matches comma-separated thousands (e.g., ",000", ",500,000") |
| `(\.\d{2})?`      | Optionally matches cents (e.g., ".00", ".50")                |

### Example Results

```
Original: "Employee record shows salary: $125,000.00 annually"
Redacted: "Employee record shows <SALARY> annually"

Original: "Base salary:$50,000 with bonus potential"
Redacted: "Base <SALARY> with bonus potential"
```

<Tip>
  Adding context words like "salary", "compensation", "pay", "wage", and "income" helps increase detection confidence when these terms appear near the matched pattern, reducing false positives.
</Tip>

### Enable the Recognizer for Your Deployments

<Warning>
  Creating a custom recognizer at the organization level does not automatically enable it for your deployments. You must manually enable each recognizer for every deployment where you want it applied.
</Warning>

After creating your custom recognizer, enable it for each deployment:

<Steps>
  <Step title="Navigate to Your Deployment">
    Go to your deployment/automation and open **Settings** → **PII Protection**.
  </Step>

  <Step title="Select Custom Recognizers">
    Under **Mask Recognizers**, you'll see your organization-defined recognizers. Check the box next to the recognizers you want to enable.

    <Frame>
      <img alt="Enable Custom Recognizer" />
    </Frame>
  </Step>

  <Step title="Save Configuration">
    Save your changes. The recognizer will be active on all subsequent executions for this deployment.
  </Step>
</Steps>

<Info>
  Repeat this process for each deployment where you need the custom recognizer. This gives you granular control over which recognizers are active in different environments (e.g., development vs. production).
</Info>


# Role-Based Access Control (RBAC)
Source: https://docs.crewai.com/en/enterprise/features/rbac

Control access to crews, tools, and data with roles, scopes, and granular permissions.

## Overview

RBAC in CrewAI AMP enables secure, scalable access management through a combination of organization‑level roles and automation‑level visibility controls.

<Frame>
  <img alt="RBAC overview in CrewAI AMP" />
</Frame>

## Users and Roles

Each member in your CrewAI workspace is assigned a role, which determines their access across various features.

You can:

* Use predefined roles (Owner, Member)
* Create custom roles tailored to specific permissions
* Assign roles at any time through the settings panel

You can configure users and roles in Settings → Roles.

<Steps>
  <Step title="Open Roles settings">
    Go to <b>Settings → Roles</b> in CrewAI AMP.
  </Step>

  <Step title="Choose a role type">
    Use a predefined role (<b>Owner</b>, <b>Member</b>) or click
    <b>Create role</b> to define a custom one.
  </Step>

  <Step title="Assign to members">
    Select users and assign the role. You can change this anytime.
  </Step>
</Steps>

### Configuration summary

| Area                  | Where to configure                 | Options                                 |
| :-------------------- | :--------------------------------- | :-------------------------------------- |
| Users & Roles         | Settings → Roles                   | Predefined: Owner, Member; Custom roles |
| Automation visibility | Automation → Settings → Visibility | Private; Whitelist users/roles          |

## Automation‑level Access Control

In addition to organization‑wide roles, CrewAI Automations support fine‑grained visibility settings that let you restrict access to specific automations by user or role.

This is useful for:

* Keeping sensitive or experimental automations private
* Managing visibility across large teams or external collaborators
* Testing automations in isolated contexts

Deployments can be configured as private, meaning only whitelisted users and roles will be able to:

* View the deployment
* Run it or interact with its API
* Access its logs, metrics, and settings

The organization owner always has access, regardless of visibility settings.

You can configure automation‑level access control in Automation → Settings → Visibility tab.

<Steps>
  <Step title="Open Visibility tab">
    Navigate to <b>Automation → Settings → Visibility</b>.
  </Step>

  <Step title="Set visibility">
    Choose <b>Private</b> to restrict access. The organization owner always
    retains access.
  </Step>

  <Step title="Whitelist access">
    Add specific users and roles allowed to view, run, and access
    logs/metrics/settings.
  </Step>

  <Step title="Save and verify">
    Save changes, then confirm that non‑whitelisted users cannot view or run the
    automation.
  </Step>
</Steps>

### Private visibility: access outcomes

| Action                       | Owner | Whitelisted user/role | Not whitelisted |
| :--------------------------- | :---- | :-------------------- | :-------------- |
| View automation              | ✓     | ✓                     | ✗               |
| Run automation/API           | ✓     | ✓                     | ✗               |
| Access logs/metrics/settings | ✓     | ✓                     | ✗               |

<Tip>
  The organization owner always has access. In private mode, only whitelisted
  users and roles can view, run, and access logs/metrics/settings.
</Tip>

<Frame>
  <img alt="Automation Visibility settings in CrewAI AMP" />
</Frame>

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with RBAC questions.
</Card>


# Tools & Integrations
Source: https://docs.crewai.com/en/enterprise/features/tools-and-integrations

Connect external apps and manage internal tools your agents can use.

## Overview

Tools & Integrations is the central hub for connecting third‑party apps and managing internal tools that your agents can use at runtime.

<Frame>
  <img alt="Tools & Integrations Overview" />
</Frame>

## Explore

<Tabs>
  <Tab title="Integrations" icon="plug">
    ## Agent Apps (Integrations)

    Connect enterprise‑grade applications (e.g., Gmail, Google Drive, HubSpot, Slack) via OAuth to enable agent actions.

    <Steps>
      <Step title="Connect">
        Click <b>Connect</b> on an app and complete OAuth.
      </Step>

      <Step title="Configure">
        Optionally adjust scopes, triggers, and action availability.
      </Step>

      <Step title="Use in Agents">
        Connected services become available as tools for your agents.
      </Step>
    </Steps>

    <Frame>
      <img alt="Integrations Grid" />
    </Frame>

    ### Connect your Account

    1. Go to <Link href="https://app.crewai.com/crewai_plus/connectors">Integrations</Link>
    2. Click <b>Connect</b> on the desired service
    3. Complete the OAuth flow and grant scopes
    4. Copy your Enterprise Token from <Link href="https://app.crewai.com/crewai_plus/settings/integrations">Integration Settings</Link>

    <Frame>
      <img alt="Enterprise Token" />
    </Frame>

    ### Install Integration Tools

    To use the integrations locally, you need to install the latest `crewai-tools` package.

    ```bash theme={null}
    uv add crewai-tools
    ```

    ### Environment Variable Setup

    <Note>
      To use integrations with `Agent(apps=[])`, you must set the
      `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
      Token.
    </Note>

    ```bash theme={null}
    export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
    ```

    Or add it to your `.env` file:

    ```
    CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
    ```

    ### Usage Example

    <Tip>
      Use the new streamlined approach to integrate enterprise apps. Simply specify
      the app and its actions directly in the Agent configuration.
    </Tip>

    ```python theme={null}
    from crewai import Agent, Task, Crew

    # Create an agent with Gmail capabilities
    email_agent = Agent(
        role="Email Manager",
        goal="Manage and organize email communications",
        backstory="An AI assistant specialized in email management and communication.",
        apps=['gmail', 'gmail/send_email']  # Using canonical name 'gmail'
    )

    # Task to send an email
    email_task = Task(
        description="Draft and send a follow-up email to john@example.com about the project update",
        agent=email_agent,
        expected_output="Confirmation that email was sent successfully"
    )

    # Run the task
    crew = Crew(
        agents=[email_agent],
        tasks=[email_task]
    )

    # Run the crew
    crew.kickoff()
    ```

    ### Filtering Tools

    ```python theme={null}
    from crewai import Agent, Task, Crew

    # Create agent with specific Gmail actions only
    gmail_agent = Agent(
        role="Gmail Manager",
        goal="Manage gmail communications and notifications",
        backstory="An AI assistant that helps coordinate gmail communications.",
        apps=['gmail/fetch_emails']  # Using canonical name with specific action
    )

    notification_task = Task(
        description="Find the email from john@example.com",
        agent=gmail_agent,
        expected_output="Email found from john@example.com"
    )

    crew = Crew(
        agents=[gmail_agent],
        tasks=[notification_task]
    )
    ```

    On a deployed crew, you can specify which actions are available for each integration from the service settings page.

    <Frame>
      <img alt="Filter Actions" />
    </Frame>

    ### Scoped Deployments (multi‑user orgs)

    You can scope each integration to a specific user. For example, a crew that connects to Google can use a specific user’s Gmail account.

    <Tip>Useful when different teams/users must keep data access separated.</Tip>

    Use the `user_bearer_token` to scope authentication to the requesting user. If the user isn’t logged in, the crew won’t use connected integrations. Otherwise it falls back to the default bearer token configured for the deployment.

    <Frame>
      <img alt="User Bearer Token" />
    </Frame>

    <div />

    ### Catalog

    #### Communication & Collaboration

    * Gmail — Manage emails and drafts
    * Slack — Workspace notifications and alerts
    * Microsoft — Office 365 and Teams integration

    #### Project Management

    * Jira — Issue tracking and project management
    * ClickUp — Task and productivity management
    * Asana — Team task and project coordination
    * Notion — Page and database management
    * Linear — Software project and bug tracking
    * GitHub — Repository and issue management

    #### Customer Relationship Management

    * Salesforce — CRM account and opportunity management
    * HubSpot — Sales pipeline and contact management
    * Zendesk — Customer support ticket management

    #### Business & Finance

    * Stripe — Payment processing and customer management
    * Shopify — E‑commerce store and product management

    #### Productivity & Storage

    * Google Sheets — Spreadsheet data synchronization
    * Google Calendar — Event and schedule management
    * Box — File storage and document management

    …and more to come!
  </Tab>

  <Tab title="Internal Tools" icon="toolbox">
    ## Internal Tools

    Create custom tools locally, publish them on CrewAI AMP Tool Repository and use them in your agents.

    <Tip>
      Before running the commands below, make sure you log in to your CrewAI AMP
      account by running this command: `bash crewai login `
    </Tip>

    <Frame>
      <img alt="Internal Tool Detail" />
    </Frame>

    <Steps>
      <Step title="Create">
        Create a new tool locally. `bash crewai tool create your-tool `
      </Step>

      <Step title="Publish">
        Publish the tool to the CrewAI AMP Tool Repository. `bash crewai tool
                    publish `
      </Step>

      <Step title="Install">
        Install the tool from the CrewAI AMP Tool Repository. `bash crewai tool
                    install your-tool `
      </Step>
    </Steps>

    Manage:

    * Name and description
    * Visibility (Private / Public)
    * Required environment variables
    * Version history and downloads
    * Team and role access

    <Frame>
      <img alt="Internal Tool Detail" />
    </Frame>
  </Tab>
</Tabs>

## Related

<CardGroup>
  <Card title="Tool Repository" href="/en/enterprise/guides/tool-repository#tool-repository" icon="toolbox">
    Create, publish, and version custom tools for your organization.
  </Card>

  <Card title="Webhook Automation" href="/en/enterprise/guides/webhook-automation" icon="bolt">
    Automate workflows and integrate with external platforms and services.
  </Card>
</CardGroup>


# Traces
Source: https://docs.crewai.com/en/enterprise/features/traces

Using Traces to monitor your Crews

## Overview

Traces provide comprehensive visibility into your crew executions, helping you monitor performance, debug issues, and optimize your AI agent workflows.

## What are Traces?

Traces in CrewAI AMP are detailed execution records that capture every aspect of your crew's operation, from initial inputs to final outputs. They record:

* Agent thoughts and reasoning
* Task execution details
* Tool usage and outputs
* Token consumption metrics
* Execution times
* Cost estimates

<Frame>
  <img alt="Traces Overview" />
</Frame>

## Accessing Traces

<Steps>
  <Step title="Navigate to the Traces Tab">
    Once in your CrewAI AMP dashboard, click on the **Traces** to view all execution records.
  </Step>

  <Step title="Select an Execution">
    You'll see a list of all crew executions, sorted by date. Click on any execution to view its detailed trace.
  </Step>
</Steps>

## Understanding the Trace Interface

The trace interface is divided into several sections, each providing different insights into your crew's execution:

### 1. Execution Summary

The top section displays high-level metrics about the execution:

* **Total Tokens**: Number of tokens consumed across all tasks
* **Prompt Tokens**: Tokens used in prompts to the LLM
* **Completion Tokens**: Tokens generated in LLM responses
* **Requests**: Number of API calls made
* **Execution Time**: Total duration of the crew run
* **Estimated Cost**: Approximate cost based on token usage

<Frame>
  <img alt="Execution Summary" />
</Frame>

### 2. Tasks & Agents

This section shows all tasks and agents that were part of the crew execution:

* Task name and agent assignment
* Agents and LLMs used for each task
* Status (completed/failed)
* Individual execution time of the task

<Frame>
  <img alt="Task List" />
</Frame>

### 3. Final Output

Displays the final result produced by the crew after all tasks are completed.

<Frame>
  <img alt="Final Output" />
</Frame>

### 4. Execution Timeline

A visual representation of when each task started and ended, helping you identify bottlenecks or parallel execution patterns.

<Frame>
  <img alt="Execution Timeline" />
</Frame>

### 5. Detailed Task View

When you click on a specific task in the timeline or task list, you'll see:

<Frame>
  <img alt="Detailed Task View" />
</Frame>

* **Task Key**: Unique identifier for the task
* **Task ID**: Technical identifier in the system
* **Status**: Current state (completed/running/failed)
* **Agent**: Which agent performed the task
* **LLM**: Language model used for this task
* **Start/End Time**: When the task began and completed
* **Execution Time**: Duration of this specific task
* **Task Description**: What the agent was instructed to do
* **Expected Output**: What output format was requested
* **Input**: Any input provided to this task from previous tasks
* **Output**: The actual result produced by the agent

## Using Traces for Debugging

Traces are invaluable for troubleshooting issues with your crews:

<Steps>
  <Step title="Identify Failure Points">
    When a crew execution doesn't produce the expected results, examine the trace to find where things went wrong. Look for:

    * Failed tasks
    * Unexpected agent decisions
    * Tool usage errors
    * Misinterpreted instructions

    <Frame>
      <img alt="Failure Points" />
    </Frame>
  </Step>

  <Step title="Optimize Performance">
    Use execution metrics to identify performance bottlenecks:

    * Tasks that took longer than expected
    * Excessive token usage
    * Redundant tool operations
    * Unnecessary API calls
  </Step>

  <Step title="Improve Cost Efficiency">
    Analyze token usage and cost estimates to optimize your crew's efficiency:

    * Consider using smaller models for simpler tasks
    * Refine prompts to be more concise
    * Cache frequently accessed information
    * Structure tasks to minimize redundant operations
  </Step>
</Steps>

## Performance and batching

CrewAI batches trace uploads to reduce overhead on high-volume runs:

* A TraceBatchManager buffers events and sends them in batches via the Plus API client
* Reduces network chatter and improves reliability on flaky connections
* Automatically enabled in the default trace listener; no configuration needed

This yields more stable tracing under load while preserving detailed task/agent telemetry.

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with trace analysis or any other
  CrewAI AMP features.
</Card>


# Webhook Streaming
Source: https://docs.crewai.com/en/enterprise/features/webhook-streaming

Using Webhook Streaming to stream events to your webhook

## Overview

Enterprise Event Streaming lets you receive real-time webhook updates about your crews and flows deployed to
CrewAI AMP, such as model calls, tool usage, and flow steps.

## Usage

When using the Kickoff API, include a `webhooks` object to your request, for example:

```json theme={null}
{
  "inputs": { "foo": "bar" },
  "webhooks": {
    "events": ["crew_kickoff_started", "llm_call_started"],
    "url": "https://your.endpoint/webhook",
    "realtime": false,
    "authentication": {
      "strategy": "bearer",
      "token": "my-secret-token"
    }
  }
}
```

If `realtime` is set to `true`, each event is delivered individually and immediately, at the cost of crew/flow performance.

## Webhook Format

Each webhook sends a list of events:

```json theme={null}
{
  "events": [
    {
      "id": "event-id",
      "execution_id": "crew-run-id",
      "timestamp": "2025-02-16T10:58:44.965Z",
      "type": "llm_call_started",
      "data": {
        "model": "gpt-4",
        "messages": [
          { "role": "system", "content": "You are an assistant." },
          { "role": "user", "content": "Summarize this article." }
        ]
      }
    }
  ]
}
```

The `data` object structure varies by event type. Refer to the [event list](https://github.com/crewAIInc/crewAI/tree/main/lib/crewai/src/crewai/events/types) on GitHub.

As requests are sent over HTTP, the order of events can't be guaranteed. If you need ordering, use the `timestamp` field.

## Supported Events

CrewAI supports both system events and custom events in Enterprise Event Streaming. These events are sent to your configured webhook endpoint during crew and flow execution.

### Flow Events:

* `flow_created`
* `flow_started`
* `flow_finished`
* `flow_plot`
* `method_execution_started`
* `method_execution_finished`
* `method_execution_failed`

### Agent Events:

* `agent_execution_started`
* `agent_execution_completed`
* `agent_execution_error`
* `lite_agent_execution_started`
* `lite_agent_execution_completed`
* `lite_agent_execution_error`
* `agent_logs_started`
* `agent_logs_execution`
* `agent_evaluation_started`
* `agent_evaluation_completed`
* `agent_evaluation_failed`

### Crew Events:

* `crew_kickoff_started`
* `crew_kickoff_completed`
* `crew_kickoff_failed`
* `crew_train_started`
* `crew_train_completed`
* `crew_train_failed`
* `crew_test_started`
* `crew_test_completed`
* `crew_test_failed`
* `crew_test_result`

### Task Events:

* `task_started`
* `task_completed`
* `task_failed`
* `task_evaluation`

### Tool Usage Events:

* `tool_usage_started`
* `tool_usage_finished`
* `tool_usage_error`
* `tool_validate_input_error`
* `tool_selection_error`
* `tool_execution_error`

### LLM Events:

* `llm_call_started`
* `llm_call_completed`
* `llm_call_failed`
* `llm_stream_chunk`

### LLM Guardrail Events:

* `llm_guardrail_started`
* `llm_guardrail_completed`

### Memory Events:

* `memory_query_started`
* `memory_query_completed`
* `memory_query_failed`
* `memory_save_started`
* `memory_save_completed`
* `memory_save_failed`
* `memory_retrieval_started`
* `memory_retrieval_completed`

### Knowledge Events:

* `knowledge_search_query_started`
* `knowledge_search_query_completed`
* `knowledge_search_query_failed`
* `knowledge_query_started`
* `knowledge_query_completed`
* `knowledge_query_failed`

### Reasoning Events:

* `agent_reasoning_started`
* `agent_reasoning_completed`
* `agent_reasoning_failed`

Event names match the internal event bus. See GitHub for the full list of events.

You can emit your own custom events, and they will be delivered through the webhook stream alongside system events.

<CardGroup>
  <Card title="GitHub" icon="github" href="https://github.com/crewAIInc/crewAI/tree/main/src/crewai/utilities/events">
    Full list of events
  </Card>

  <Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
    Contact our support team for assistance with webhook integration or
    troubleshooting.
  </Card>
</CardGroup>


# Triggers Overview
Source: https://docs.crewai.com/en/enterprise/guides/automation-triggers

Understand how CrewAI AMP triggers work, how to manage them, and where to find integration-specific playbooks

CrewAI AMP triggers connect your automations to real-time events across the tools your teams already use. Instead of polling systems or relying on manual kickoffs, triggers listen for changes—new emails, calendar updates, CRM status changes—and immediately launch the crew or flow you specify.

<Frame>
  <img alt="Automation Triggers Overview" />
</Frame>

### Integration Playbooks

Deep-dive guides walk through setup and sample workflows for each integration:

<CardGroup>
  <Card title="Gmail Trigger" icon="envelope">
    <a href="/en/enterprise/guides/gmail-trigger">Enable crews when emails arrive or threads update.</a>
  </Card>

  <Card title="Google Calendar Trigger" icon="calendar-days">
    <a href="/en/enterprise/guides/google-calendar-trigger">
      React to calendar events as they are created, updated, or cancelled.
    </a>
  </Card>

  <Card title="Google Drive Trigger" icon="folder-open">
    <a href="/en/enterprise/guides/google-drive-trigger">
      Handle Drive file uploads, edits, and deletions.
    </a>
  </Card>

  <Card title="Outlook Trigger" icon="envelope-open">
    <a href="/en/enterprise/guides/outlook-trigger">
      Automate responses to new Outlook messages and calendar updates.
    </a>
  </Card>

  <Card title="OneDrive Trigger" icon="cloud">
    <a href="/en/enterprise/guides/onedrive-trigger">
      Audit file activity and sharing changes in OneDrive.
    </a>
  </Card>

  <Card title="Microsoft Teams Trigger" icon="comments">
    <a href="/en/enterprise/guides/microsoft-teams-trigger">
      Kick off workflows when new Teams chats start.
    </a>
  </Card>

  <Card title="HubSpot Trigger" icon="hubspot">
    <a href="/en/enterprise/guides/hubspot-trigger">
      Launch automations from HubSpot workflows and lifecycle events.
    </a>
  </Card>

  <Card title="Salesforce Trigger" icon="salesforce">
    <a href="/en/enterprise/guides/salesforce-trigger">
      Connect Salesforce processes to CrewAI for CRM automation.
    </a>
  </Card>

  <Card title="Slack Trigger" icon="slack">
    <a href="/en/enterprise/guides/slack-trigger">
      Start crews directly from Slack slash commands.
    </a>
  </Card>

  <Card title="Zapier Trigger" icon="bolt">
    <a href="/en/enterprise/guides/zapier-trigger">Bridge CrewAI with thousands of Zapier-supported apps.</a>
  </Card>
</CardGroup>

## Trigger Capabilities

With triggers, you can:

* **Respond to real-time events** - Automatically execute workflows when specific conditions are met
* **Integrate with external systems** - Connect with platforms like Gmail, Outlook, OneDrive, JIRA, Slack, Stripe and more
* **Scale your automation** - Handle high-volume events without manual intervention
* **Maintain context** - Access trigger data within your crews and flows

## Managing Triggers

### Viewing Available Triggers

To access and manage your automation triggers:

1. Navigate to your deployment in the CrewAI dashboard
2. Click on the **Triggers** tab to view all available trigger integrations

<Frame>
  <img alt="List of available automation triggers" />
</Frame>

This view shows all the trigger integrations available for your deployment, along with their current connection status.

### Enabling and Disabling Triggers

Each trigger can be easily enabled or disabled using the toggle switch:

<Frame>
  <img alt="Enable or disable triggers with toggle" />
</Frame>

* **Enabled (blue toggle)**: The trigger is active and will automatically execute your deployment when the specified events occur
* **Disabled (gray toggle)**: The trigger is inactive and will not respond to events

Simply click the toggle to change the trigger state. Changes take effect immediately.

### Monitoring Trigger Executions

Track the performance and history of your triggered executions:

<Frame>
  <img alt="List of executions triggered by automation" />
</Frame>

## Building Trigger-Driven Automations

Before building your automation, it's helpful to understand the structure of trigger payloads that your crews and flows will receive.

### Trigger Setup Checklist

Before wiring a trigger into production, make sure you:

* Connect the integration under **Tools & Integrations** and complete any OAuth or API key steps
* Enable the trigger toggle on the deployment that should respond to events
* Provide any required environment variables (API tokens, tenant IDs, shared secrets)
* Create or update tasks that can parse the incoming payload within the first crew task or flow step
* Decide whether to pass trigger context automatically using `allow_crewai_trigger_context`
* Set up monitoring—webhook logs, CrewAI execution history, and optional external alerting

### Testing Triggers Locally with CLI

The CrewAI CLI provides powerful commands to help you develop and test trigger-driven automations without deploying to production.

#### List Available Triggers

View all available triggers for your connected integrations:

```bash theme={null}
crewai triggers list
```

This command displays all triggers available based on your connected integrations, showing:

* Integration name and connection status
* Available trigger types
* Trigger names and descriptions

#### Simulate Trigger Execution

Test your crew with realistic trigger payloads before deployment:

```bash theme={null}
crewai triggers run <trigger_name>
```

For example:

```bash theme={null}
crewai triggers run microsoft_onedrive/file_changed
```

This command:

* Executes your crew locally
* Passes a complete, realistic trigger payload
* Simulates exactly how your crew will be called in production

<Warning>
  **Important Development Notes:**

  * Use `crewai triggers run <trigger>` to simulate trigger execution during development
  * Using `crewai run` will NOT simulate trigger calls and won't pass the trigger payload
  * After deployment, your crew will be executed with the actual trigger payload
  * If your crew expects parameters that aren't in the trigger payload, execution may fail
</Warning>

### Triggers with Crew

Your existing crew definitions work seamlessly with triggers, you just need to have a task to parse the received payload:

```python theme={null}
@CrewBase
class MyAutomatedCrew:
    @agent
    def researcher(self) -> Agent:
        return Agent(
            config=self.agents_config['researcher'],
        )

    @task
    def parse_trigger_payload(self) -> Task:
        return Task(
            config=self.tasks_config['parse_trigger_payload'],
            agent=self.researcher(),
        )

    @task
    def analyze_trigger_content(self) -> Task:
        return Task(
            config=self.tasks_config['analyze_trigger_data'],
            agent=self.researcher(),
        )
```

The crew will automatically receive and can access the trigger payload through the standard CrewAI context mechanisms.

<Note>
  Crew and Flow inputs can include `crewai_trigger_payload`. CrewAI
  automatically injects this payload: - Tasks: appended to the first task's
  description by default ("Trigger Payload: ") - Control
  via `allow_crewai_trigger_context`: set `True` to always inject, `False` to
  never inject - Flows: any `@start()` method that accepts a
  `crewai_trigger_payload` parameter will receive it
</Note>

### Integration with Flows

For flows, you have more control over how trigger data is handled:

#### Accessing Trigger Payload

All `@start()` methods in your flows will accept an additional parameter called `crewai_trigger_payload`:

```python theme={null}
from crewai.flow import Flow, start, listen

class MyAutomatedFlow(Flow):
    @start()
    def handle_trigger(self, crewai_trigger_payload: dict = None):
        """
        This start method can receive trigger data
        """
        if crewai_trigger_payload:
            # Process the trigger data
            trigger_id = crewai_trigger_payload.get('id')
            event_data = crewai_trigger_payload.get('payload', {})

            # Store in flow state for use by other methods
            self.state.trigger_id = trigger_id
            self.state.trigger_type = event_data

            return event_data

        # Handle manual execution
        return None

    @listen(handle_trigger)
    def process_data(self, trigger_data):
        """
        Process the data from the trigger
        """
        # ... process the trigger
```

#### Triggering Crews from Flows

When kicking off a crew within a flow that was triggered, pass the trigger payload as it:

```python theme={null}
@start()
def delegate_to_crew(self, crewai_trigger_payload: dict = None):
    """
    Delegate processing to a specialized crew
    """
    crew = MySpecializedCrew()

    # Pass the trigger payload to the crew
    result = crew.crew().kickoff(
        inputs={
            'a_custom_parameter': "custom_value",
            'crewai_trigger_payload': crewai_trigger_payload
        },
    )

    return result
```

## Troubleshooting

**Trigger not firing:**

* Verify the trigger is enabled in your deployment's Triggers tab
* Check integration connection status under Tools & Integrations
* Ensure all required environment variables are properly configured

**Execution failures:**

* Check the execution logs for error details
* Use `crewai triggers run <trigger_name>` to test locally and see the exact payload structure
* Verify your crew can handle the `crewai_trigger_payload` parameter
* Ensure your crew doesn't expect parameters that aren't included in the trigger payload

**Development issues:**

* Always test with `crewai triggers run <trigger>` before deploying to see the complete payload
* Remember that `crewai run` does NOT simulate trigger calls—use `crewai triggers run` instead
* Use `crewai triggers list` to verify which triggers are available for your connected integrations
* After deployment, your crew will receive the actual trigger payload, so test thoroughly locally first

Automation triggers transform your CrewAI deployments into responsive, event-driven systems that can seamlessly integrate with your existing business processes and tools.


# Gmail Trigger
Source: https://docs.crewai.com/en/enterprise/guides/gmail-trigger

Trigger automations when Gmail events occur (e.g., new emails, labels).

## Overview

Use the Gmail Trigger to kick off your deployed crews when Gmail events happen in connected accounts, such as receiving a new email or messages matching a label/filter.

<Tip>
  Make sure Gmail is connected in Tools & Integrations and the trigger is
  enabled for your deployment.
</Tip>

## Enabling the Gmail Trigger

1. Open your deployment in CrewAI AMP
2. Go to the **Triggers** tab
3. Locate **Gmail** and switch the toggle to enable

<Frame>
  <img alt="Enable or disable triggers with toggle" />
</Frame>

## Example: Process new emails

When a new email arrives, the Gmail Trigger will send the payload to your Crew or Flow. Below is a Crew example that parses and processes the trigger payload.

```python theme={null}
@CrewBase
class GmailProcessingCrew:
    @agent
    def parser(self) -> Agent:
        return Agent(
            config=self.agents_config['parser'],
        )

    @task
    def parse_gmail_payload(self) -> Task:
        return Task(
            config=self.tasks_config['parse_gmail_payload'],
            agent=self.parser(),
        )

    @task
    def act_on_email(self) -> Task:
        return Task(
            config=self.tasks_config['act_on_email'],
            agent=self.parser(),
        )
```

The Gmail payload will be available via the standard context mechanisms.

### Testing Locally

Test your Gmail trigger integration locally using the CrewAI CLI:

```bash theme={null}
# View all available triggers
crewai triggers list

# Simulate a Gmail trigger with realistic payload
crewai triggers run gmail/new_email_received
```

The `crewai triggers run` command will execute your crew with a complete Gmail payload, allowing you to test your parsing logic before deployment.

<Warning>
  Use `crewai triggers run gmail/new_email_received` (not `crewai run`) to
  simulate trigger execution during development. After deployment, your crew
  will automatically receive the trigger payload.
</Warning>

## Monitoring Executions

Track history and performance of triggered runs:

<Frame>
  <img alt="List of executions triggered by automation" />
</Frame>

## Troubleshooting

* Ensure Gmail is connected in Tools & Integrations
* Verify the Gmail Trigger is enabled on the Triggers tab
* Test locally with `crewai triggers run gmail/new_email_received` to see the exact payload structure
* Check the execution logs and confirm the payload is passed as `crewai_trigger_payload`
* Remember: use `crewai triggers run` (not `crewai run`) to simulate trigger execution


# Google Calendar Trigger
Source: https://docs.crewai.com/en/enterprise/guides/google-calendar-trigger

Kick off crews when Google Calendar events are created, updated, or cancelled

## Overview

Use the Google Calendar trigger to launch automations whenever calendar events change. Common use cases include briefing a team before a meeting, notifying stakeholders when a critical event is cancelled, or summarizing daily schedules.

<Tip>
  Make sure Google Calendar is connected in **Tools & Integrations** and enabled
  for the deployment you want to automate.
</Tip>

## Enabling the Google Calendar Trigger

1. Open your deployment in CrewAI AMP
2. Go to the **Triggers** tab
3. Locate **Google Calendar** and switch the toggle to enable

<Frame>
  <img alt="Enable or disable triggers with toggle" />
</Frame>

## Example: Summarize meeting details

The snippet below mirrors the `calendar-event-crew.py` example in the trigger repository. It parses the payload, analyses the attendees and timing, and produces a meeting brief for downstream tools.

```python theme={null}
from calendar_event_crew import GoogleCalendarEventTrigger

crew = GoogleCalendarEventTrigger().crew()
result = crew.kickoff({
    "crewai_trigger_payload": calendar_payload,
})
print(result.raw)
```

Use `crewai_trigger_payload` exactly as it is delivered by the trigger so the crew can extract the proper fields.

## Testing Locally

Test your Google Calendar trigger integration locally using the CrewAI CLI:

```bash theme={null}
# View all available triggers
crewai triggers list

# Simulate a Google Calendar trigger with realistic payload
crewai triggers run google_calendar/event_changed
```

The `crewai triggers run` command will execute your crew with a complete Calendar payload, allowing you to test your parsing logic before deployment.

<Warning>
  Use `crewai triggers run google_calendar/event_changed` (not `crewai run`) to
  simulate trigger execution during development. After deployment, your crew
  will automatically receive the trigger payload.
</Warning>

## Monitoring Executions

The **Executions** list in the deployment dashboard tracks every triggered run and surfaces payload metadata, output summaries, and errors.

<Frame>
  <img alt="List of executions triggered by automation" />
</Frame>

## Troubleshooting

* Ensure the correct Google account is connected and the trigger is enabled
* Test locally with `crewai triggers run google_calendar/event_changed` to see the exact payload structure
* Confirm your workflow handles all-day events (payloads use `start.date` and `end.date` instead of timestamps)
* Check execution logs if reminders or attendee arrays are missing—calendar permissions can limit fields in the payload
* Remember: use `crewai triggers run` (not `crewai run`) to simulate trigger execution


# Google Drive Trigger
Source: https://docs.crewai.com/en/enterprise/guides/google-drive-trigger

Respond to Google Drive file events with automated crews

## Overview

Trigger your automations when files are created, updated, or removed in Google Drive. Typical workflows include summarizing newly uploaded content, enforcing sharing policies, or notifying owners when critical files change.

<Tip>
  Connect Google Drive in **Tools & Integrations** and confirm the trigger is
  enabled for the automation you want to monitor.
</Tip>

## Enabling the Google Drive Trigger

1. Open your deployment in CrewAI AMP
2. Go to the **Triggers** tab
3. Locate **Google Drive** and switch the toggle to enable

<Frame>
  <img alt="Enable or disable triggers with toggle" />
</Frame>

## Example: Summarize file activity

The drive example crews parse the payload to extract file metadata, evaluate permissions, and publish a summary.

```python theme={null}
from drive_file_crew import GoogleDriveFileTrigger

crew = GoogleDriveFileTrigger().crew()
crew.kickoff({
    "crewai_trigger_payload": drive_payload,
})
```

## Testing Locally

Test your Google Drive trigger integration locally using the CrewAI CLI:

```bash theme={null}
# View all available triggers
crewai triggers list

# Simulate a Google Drive trigger with realistic payload
crewai triggers run google_drive/file_changed
```

The `crewai triggers run` command will execute your crew with a complete Drive payload, allowing you to test your parsing logic before deployment.

<Warning>
  Use `crewai triggers run google_drive/file_changed` (not `crewai run`) to
  simulate trigger execution during development. After deployment, your crew
  will automatically receive the trigger payload.
</Warning>

## Monitoring Executions

Track history and performance of triggered runs with the **Executions** list in the deployment dashboard.

<Frame>
  <img alt="List of executions triggered by automation" />
</Frame>

## Troubleshooting

* Verify Google Drive is connected and the trigger toggle is enabled
* Test locally with `crewai triggers run google_drive/file_changed` to see the exact payload structure
* If a payload is missing permission data, ensure the connected account has access to the file or folder
* The trigger sends file IDs only; use the Drive API if you need to fetch binary content during the crew run
* Remember: use `crewai triggers run` (not `crewai run`) to simulate trigger execution


# Microsoft Teams Trigger
Source: https://docs.crewai.com/en/enterprise/guides/microsoft-teams-trigger

Kick off crews from Microsoft Teams chat activity

## Overview

Use the Microsoft Teams trigger to start automations whenever a new chat is created. Common patterns include summarizing inbound requests, routing urgent messages to support teams, or creating follow-up tasks in other systems.

<Tip>
  Confirm Microsoft Teams is connected under **Tools & Integrations** and
  enabled in the **Triggers** tab for your deployment.
</Tip>

## Enabling the Microsoft Teams Trigger

1. Open your deployment in CrewAI AMP
2. Go to the **Triggers** tab
3. Locate **Microsoft Teams** and switch the toggle to enable

<Frame>
  <img alt="Enable or disable triggers with toggle" />
</Frame>

## Example: Summarize a new chat thread

```python theme={null}
from teams_chat_created_crew import MicrosoftTeamsChatTrigger

crew = MicrosoftTeamsChatTrigger().crew()
result = crew.kickoff({
    "crewai_trigger_payload": teams_payload,
})
print(result.raw)
```

The crew parses thread metadata (subject, created time, roster) and generates an action plan for the receiving team.

## Testing Locally

Test your Microsoft Teams trigger integration locally using the CrewAI CLI:

```bash theme={null}
# View all available triggers
crewai triggers list

# Simulate a Microsoft Teams trigger with realistic payload
crewai triggers run microsoft_teams/teams_message_created
```

The `crewai triggers run` command will execute your crew with a complete Teams payload, allowing you to test your parsing logic before deployment.

<Warning>
  Use `crewai triggers run microsoft_teams/teams_message_created` (not `crewai
      run`) to simulate trigger execution during development. After deployment, your
  crew will automatically receive the trigger payload.
</Warning>

## Troubleshooting

* Ensure the Teams connection is active; it must be refreshed if the tenant revokes permissions
* Test locally with `crewai triggers run microsoft_teams/teams_message_created` to see the exact payload structure
* Confirm the webhook subscription in Microsoft 365 is still valid if payloads stop arriving
* Review execution logs for payload shape mismatches—Graph notifications may omit fields when a chat is private or restricted
* Remember: use `crewai triggers run` (not `crewai run`) to simulate trigger execution


# OneDrive Trigger
Source: https://docs.crewai.com/en/enterprise/guides/onedrive-trigger

Automate responses to OneDrive file activity

## Overview

Start automations when files change inside OneDrive. You can generate audit summaries, notify security teams about external sharing, or update downstream line-of-business systems with new document metadata.

<Tip>
  Connect OneDrive in **Tools & Integrations** and toggle the trigger on for
  your deployment.
</Tip>

## Enabling the OneDrive Trigger

1. Open your deployment in CrewAI AMP
2. Go to the **Triggers** tab
3. Locate **OneDrive** and switch the toggle to enable

<Frame>
  <img alt="Enable or disable triggers with toggle" />
</Frame>

## Example: Audit file permissions

```python theme={null}
from onedrive_file_crew import OneDriveFileTrigger

crew = OneDriveFileTrigger().crew()
crew.kickoff({
    "crewai_trigger_payload": onedrive_payload,
})
```

The crew inspects file metadata, user activity, and permission changes to produce a compliance-friendly summary.

## Testing Locally

Test your OneDrive trigger integration locally using the CrewAI CLI:

```bash theme={null}
# View all available triggers
crewai triggers list

# Simulate a OneDrive trigger with realistic payload
crewai triggers run microsoft_onedrive/file_changed
```

The `crewai triggers run` command will execute your crew with a complete OneDrive payload, allowing you to test your parsing logic before deployment.

<Warning>
  Use `crewai triggers run microsoft_onedrive/file_changed` (not `crewai run`)
  to simulate trigger execution during development. After deployment, your crew
  will automatically receive the trigger payload.
</Warning>

## Troubleshooting

* Ensure the connected account has permission to read the file metadata included in the webhook
* Test locally with `crewai triggers run microsoft_onedrive/file_changed` to see the exact payload structure
* If the trigger fires but the payload is missing `permissions`, confirm the site-level sharing settings allow Graph to return this field
* For large tenants, filter notifications upstream so the crew only runs on relevant directories
* Remember: use `crewai triggers run` (not `crewai run`) to simulate trigger execution


# Outlook Trigger
Source: https://docs.crewai.com/en/enterprise/guides/outlook-trigger

Launch automations from Outlook emails and calendar updates

## Overview

Automate responses when Outlook delivers a new message or when an event is removed from the calendar. Teams commonly route escalations, file tickets, or alert attendees of cancellations.

<Tip>
  Connect Outlook in **Tools & Integrations** and ensure the trigger is enabled
  for your deployment.
</Tip>

## Enabling the Outlook Trigger

1. Open your deployment in CrewAI AMP
2. Go to the **Triggers** tab
3. Locate **Outlook** and switch the toggle to enable

<Frame>
  <img alt="Enable or disable triggers with toggle" />
</Frame>

## Example: Summarize a new email

```python theme={null}
from outlook_message_crew import OutlookMessageTrigger

crew = OutlookMessageTrigger().crew()
crew.kickoff({
    "crewai_trigger_payload": outlook_payload,
})
```

The crew extracts sender details, subject, body preview, and attachments before generating a structured response.

## Testing Locally

Test your Outlook trigger integration locally using the CrewAI CLI:

```bash theme={null}
# View all available triggers
crewai triggers list

# Simulate an Outlook trigger with realistic payload
crewai triggers run microsoft_outlook/email_received
```

The `crewai triggers run` command will execute your crew with a complete Outlook payload, allowing you to test your parsing logic before deployment.

<Warning>
  Use `crewai triggers run microsoft_outlook/email_received` (not `crewai run`)
  to simulate trigger execution during development. After deployment, your crew
  will automatically receive the trigger payload.
</Warning>

## Troubleshooting

* Verify the Outlook connector is still authorized; the subscription must be renewed periodically
* Test locally with `crewai triggers run microsoft_outlook/email_received` to see the exact payload structure
* If attachments are missing, confirm the webhook subscription includes the `includeResourceData` flag
* Review execution logs when events fail to match—cancellation payloads lack attendee lists by design and the crew should account for that
* Remember: use `crewai triggers run` (not `crewai run`) to simulate trigger execution


# Asana Integration
Source: https://docs.crewai.com/en/enterprise/integrations/asana

Team task and project coordination with Asana integration for CrewAI.

## Overview

Enable your agents to manage tasks, projects, and team coordination through Asana. Create tasks, update project status, manage assignments, and streamline your team's workflow with AI-powered automation.

## Prerequisites

Before using the Asana integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* An Asana account with appropriate permissions
* Connected your Asana account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up Asana Integration

### 1. Connect Your Asana Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Asana** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for task and project management
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="asana/create_comment">
    **Description:** Create a comment in Asana.

    **Parameters:**

    * `task` (string, required): Task ID - The ID of the Task the comment will be added to. The comment will be authored by the currently authenticated user.
    * `text` (string, required): Text (example: "This is a comment.").
  </Accordion>

  <Accordion title="asana/create_project">
    **Description:** Create a project in Asana.

    **Parameters:**

    * `name` (string, required): Name (example: "Stuff to buy").
    * `workspace` (string, required): Workspace - Use Connect Portal Workflow Settings to allow users to select which Workspace to create Projects in. Defaults to the user's first Workspace if left blank.
    * `team` (string, optional): Team - Use Connect Portal Workflow Settings to allow users to select which Team to share this Project with. Defaults to the user's first Team if left blank.
    * `notes` (string, optional): Notes (example: "These are things we need to purchase.").
  </Accordion>

  <Accordion title="asana/get_projects">
    **Description:** Get a list of projects in Asana.

    **Parameters:**

    * `archived` (string, optional): Archived - Choose "true" to show archived projects, "false" to display only active projects, or "default" to show both archived and active projects.
      * Options: `default`, `true`, `false`
  </Accordion>

  <Accordion title="asana/get_project_by_id">
    **Description:** Get a project by ID in Asana.

    **Parameters:**

    * `projectFilterId` (string, required): Project ID.
  </Accordion>

  <Accordion title="asana/create_task">
    **Description:** Create a task in Asana.

    **Parameters:**

    * `name` (string, required): Name (example: "Task Name").
    * `workspace` (string, optional): Workspace - Use Connect Portal Workflow Settings to allow users to select which Workspace to create Tasks in. Defaults to the user's first Workspace if left blank..
    * `project` (string, optional): Project - Use Connect Portal Workflow Settings to allow users to select which Project to create this Task in.
    * `notes` (string, optional): Notes.
    * `dueOnDate` (string, optional): Due On - The date on which this task is due. Cannot be used together with Due At. (example: "YYYY-MM-DD").
    * `dueAtDate` (string, optional): Due At - The date and time (ISO timestamp) at which this task is due. Cannot be used together with Due On. (example: "2019-09-15T02:06:58.147Z").
    * `assignee` (string, optional): Assignee - The ID of the Asana user this task will be assigned to. Use Connect Portal Workflow Settings to allow users to select an Assignee.
    * `gid` (string, optional): External ID - An ID from your application to associate this task with. You can use this ID to sync updates to this task later.
  </Accordion>

  <Accordion title="asana/update_task">
    **Description:** Update a task in Asana.

    **Parameters:**

    * `taskId` (string, required): Task ID - The ID of the Task that will be updated.
    * `completeStatus` (string, optional): Completed Status.
      * Options: `true`, `false`
    * `name` (string, optional): Name (example: "Task Name").
    * `notes` (string, optional): Notes.
    * `dueOnDate` (string, optional): Due On - The date on which this task is due. Cannot be used together with Due At. (example: "YYYY-MM-DD").
    * `dueAtDate` (string, optional): Due At - The date and time (ISO timestamp) at which this task is due. Cannot be used together with Due On. (example: "2019-09-15T02:06:58.147Z").
    * `assignee` (string, optional): Assignee - The ID of the Asana user this task will be assigned to. Use Connect Portal Workflow Settings to allow users to select an Assignee.
    * `gid` (string, optional): External ID - An ID from your application to associate this task with. You can use this ID to sync updates to this task later.
  </Accordion>

  <Accordion title="asana/get_tasks">
    **Description:** Get a list of tasks in Asana.

    **Parameters:**

    * `workspace` (string, optional): Workspace - The ID of the Workspace to filter tasks on. Use Connect Portal Workflow Settings to allow users to select a Workspace.
    * `project` (string, optional): Project - The ID of the Project to filter tasks on. Use Connect Portal Workflow Settings to allow users to select a Project.
    * `assignee` (string, optional): Assignee - The ID of the assignee to filter tasks on. Use Connect Portal Workflow Settings to allow users to select an Assignee.
    * `completedSince` (string, optional): Completed since - Only return tasks that are either incomplete or that have been completed since this time (ISO or Unix timestamp). (example: "2014-04-25T16:15:47-04:00").
  </Accordion>

  <Accordion title="asana/get_tasks_by_id">
    **Description:** Get a list of tasks by ID in Asana.

    **Parameters:**

    * `taskId` (string, required): Task ID.
  </Accordion>

  <Accordion title="asana/get_task_by_external_id">
    **Description:** Get a task by external ID in Asana.

    **Parameters:**

    * `gid` (string, required): External ID - The ID that this task is associated or synced with, from your application.
  </Accordion>

  <Accordion title="asana/add_task_to_section">
    **Description:** Add a task to a section in Asana.

    **Parameters:**

    * `sectionId` (string, required): Section ID - The ID of the section to add this task to.
    * `taskId` (string, required): Task ID - The ID of the task. (example: "1204619611402340").
    * `beforeTaskId` (string, optional): Before Task ID - The ID of a task in this section that this task will be inserted before. Cannot be used with After Task ID. (example: "1204619611402340").
    * `afterTaskId` (string, optional): After Task ID - The ID of a task in this section that this task will be inserted after. Cannot be used with Before Task ID. (example: "1204619611402340").
  </Accordion>

  <Accordion title="asana/get_teams">
    **Description:** Get a list of teams in Asana.

    **Parameters:**

    * `workspace` (string, required): Workspace - Returns the teams in this workspace visible to the authorized user.
  </Accordion>

  <Accordion title="asana/get_workspaces">
    **Description:** Get a list of workspaces in Asana.

    **Parameters:** None required.
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Asana Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with Asana capabilities
asana_agent = Agent(
    role="Project Manager",
    goal="Manage tasks and projects in Asana efficiently",
    backstory="An AI assistant specialized in project management and task coordination.",
    apps=['asana']  # All Asana actions will be available
)

# Task to create a new project
create_project_task = Task(
    description="Create a new project called 'Q1 Marketing Campaign' in the Marketing workspace",
    agent=asana_agent,
    expected_output="Confirmation that the project was created successfully with project ID"
)

# Run the task
crew = Crew(
    agents=[asana_agent],
    tasks=[create_project_task]
)

crew.kickoff()
```

### Filtering Specific Asana Tools

```python theme={null}
from crewai import Agent, Task, Crew

# Create agent with specific Asana actions only
task_manager_agent = Agent(
    role="Task Manager",
    goal="Create and manage tasks efficiently",
    backstory="An AI assistant that focuses on task creation and management.",
    apps=[
        'asana/create_task',
        'asana/update_task',
        'asana/get_tasks'
    ]  # Specific Asana actions
)

# Task to create and assign a task
task_management = Task(
    description="Create a task called 'Review quarterly reports' and assign it to the appropriate team member",
    agent=task_manager_agent,
    expected_output="Task created and assigned successfully"
)

crew = Crew(
    agents=[task_manager_agent],
    tasks=[task_management]
)

crew.kickoff()
```

### Advanced Project Management

```python theme={null}
from crewai import Agent, Task, Crew

project_coordinator = Agent(
    role="Project Coordinator",
    goal="Coordinate project activities and track progress",
    backstory="An experienced project coordinator who ensures projects run smoothly.",
    apps=['asana']
)

# Complex task involving multiple Asana operations
coordination_task = Task(
    description="""
    1. Get all active projects in the workspace
    2. For each project, get the list of incomplete tasks
    3. Create a summary report task in the 'Management Reports' project
    4. Add comments to overdue tasks to request status updates
    """,
    agent=project_coordinator,
    expected_output="Summary report created and status update requests sent for overdue tasks"
)

crew = Crew(
    agents=[project_coordinator],
    tasks=[coordination_task]
)

crew.kickoff()
```


# Box Integration
Source: https://docs.crewai.com/en/enterprise/integrations/box

File storage and document management with Box integration for CrewAI.

## Overview

Enable your agents to manage files, folders, and documents through Box. Upload files, organize folder structures, search content, and streamline your team's document management with AI-powered automation.

## Prerequisites

Before using the Box integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Box account with appropriate permissions
* Connected your Box account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up Box Integration

### 1. Connect Your Box Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Box** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for file and folder management
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="box/save_file">
    **Description:** Save a file from URL in Box.

    **Parameters:**

    * `fileAttributes` (object, required): Attributes - File metadata including name, parent folder, and timestamps.
      ```json theme={null}
      {
        "content_created_at": "2012-12-12T10:53:43-08:00",
        "content_modified_at": "2012-12-12T10:53:43-08:00",
        "name": "qwerty.png",
        "parent": { "id": "1234567" }
      }
      ```
    * `file` (string, required): File URL - Files must be smaller than 50MB in size. (example: "[https://picsum.photos/200/300](https://picsum.photos/200/300)").
  </Accordion>

  <Accordion title="box/save_file_from_object">
    **Description:** Save a file in Box.

    **Parameters:**

    * `file` (string, required): File - Accepts a File Object containing file data. Files must be smaller than 50MB in size.
    * `fileName` (string, required): File Name (example: "qwerty.png").
    * `folder` (string, optional): Folder - Use Connect Portal Workflow Settings to allow users to select the File's Folder destination. Defaults to the user's root folder if left blank.
  </Accordion>

  <Accordion title="box/get_file_by_id">
    **Description:** Get a file by ID in Box.

    **Parameters:**

    * `fileId` (string, required): File ID - The unique identifier that represents a file. (example: "12345").
  </Accordion>

  <Accordion title="box/list_files">
    **Description:** List files in Box.

    **Parameters:**

    * `folderId` (string, required): Folder ID - The unique identifier that represents a folder. (example: "0").
    * `filterFormula` (object, optional): A filter in disjunctive normal form - OR of AND groups of single conditions.
      ```json theme={null}
      {
        "operator": "OR",
        "conditions": [
          {
            "operator": "AND",
            "conditions": [
              {
                "field": "direction",
                "operator": "$stringExactlyMatches",
                "value": "ASC"
              }
            ]
          }
        ]
      }
      ```
  </Accordion>

  <Accordion title="box/create_folder">
    **Description:** Create a folder in Box.

    **Parameters:**

    * `folderName` (string, required): Name - The name for the new folder. (example: "New Folder").
    * `folderParent` (object, required): Parent Folder - The parent folder where the new folder will be created.
      ```json theme={null}
      {
        "id": "123456"
      }
      ```
  </Accordion>

  <Accordion title="box/move_folder">
    **Description:** Move a folder in Box.

    **Parameters:**

    * `folderId` (string, required): Folder ID - The unique identifier that represents a folder. (example: "0").
    * `folderName` (string, required): Name - The name for the folder. (example: "New Folder").
    * `folderParent` (object, required): Parent Folder - The new parent folder destination.
      ```json theme={null}
      {
        "id": "123456"
      }
      ```
  </Accordion>

  <Accordion title="box/get_folder_by_id">
    **Description:** Get a folder by ID in Box.

    **Parameters:**

    * `folderId` (string, required): Folder ID - The unique identifier that represents a folder. (example: "0").
  </Accordion>

  <Accordion title="box/search_folders">
    **Description:** Search folders in Box.

    **Parameters:**

    * `folderId` (string, required): Folder ID - The folder to search within.
    * `filterFormula` (object, optional): A filter in disjunctive normal form - OR of AND groups of single conditions.
      ```json theme={null}
      {
        "operator": "OR",
        "conditions": [
          {
            "operator": "AND",
            "conditions": [
              {
                "field": "sort",
                "operator": "$stringExactlyMatches",
                "value": "name"
              }
            ]
          }
        ]
      }
      ```
  </Accordion>

  <Accordion title="box/delete_folder">
    **Description:** Delete a folder in Box.

    **Parameters:**

    * `folderId` (string, required): Folder ID - The unique identifier that represents a folder. (example: "0").
    * `recursive` (boolean, optional): Recursive - Delete a folder that is not empty by recursively deleting the folder and all of its content.
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Box Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew
from crewai import Agent, Task, Crew

# Create an agent with Box capabilities
box_agent = Agent(
    role="Document Manager",
    goal="Manage files and folders in Box efficiently",
    backstory="An AI assistant specialized in document management and file organization.",
    apps=['box']  # All Box actions will be available
)

# Task to create a folder structure
create_structure_task = Task(
    description="Create a folder called 'Project Files' in the root directory and upload a document from URL",
    agent=box_agent,
    expected_output="Folder created and file uploaded successfully"
)

# Run the task
crew = Crew(
    agents=[box_agent],
    tasks=[create_structure_task]
)

crew.kickoff()
```

### Filtering Specific Box Tools

```python theme={null}
from crewai import Agent, Task, Crew

# Create agent with specific Box actions only
file_organizer_agent = Agent(
    role="File Organizer",
    goal="Organize and manage file storage efficiently",
    backstory="An AI assistant that focuses on file organization and storage management.",
    apps=['box/create_folder', 'box/save_file', 'box/list_files']  # Specific Box actions
)

# Task to organize files
organization_task = Task(
    description="Create a folder structure for the marketing team and organize existing files",
    agent=file_organizer_agent,
    expected_output="Folder structure created and files organized"
)

crew = Crew(
    agents=[file_organizer_agent],
    tasks=[organization_task]
)

crew.kickoff()
```

### Advanced File Management

```python theme={null}
from crewai import Agent, Task, Crew

file_manager = Agent(
    role="File Manager",
    goal="Maintain organized file structure and manage document lifecycle",
    backstory="An experienced file manager who ensures documents are properly organized and accessible.",
    apps=['box']
)

# Complex task involving multiple Box operations
management_task = Task(
    description="""
    1. List all files in the root folder
    2. Create monthly archive folders for the current year
    3. Move old files to appropriate archive folders
    4. Generate a summary report of the file organization
    """,
    agent=file_manager,
    expected_output="Files organized into archive structure with summary report"
)

crew = Crew(
    agents=[file_manager],
    tasks=[management_task]
)

crew.kickoff()
```


# ClickUp Integration
Source: https://docs.crewai.com/en/enterprise/integrations/clickup

Task and productivity management with ClickUp integration for CrewAI.

## Overview

Enable your agents to manage tasks, projects, and productivity workflows through ClickUp. Create and update tasks, organize projects, manage team assignments, and streamline your productivity management with AI-powered automation.

## Prerequisites

Before using the ClickUp integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A ClickUp account with appropriate permissions
* Connected your ClickUp account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up ClickUp Integration

### 1. Connect Your ClickUp Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **ClickUp** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for task and project management
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="clickup/search_tasks">
    **Description:** Search for tasks in ClickUp using advanced filters.

    **Parameters:**

    * `taskFilterFormula` (object, optional): A filter in disjunctive normal form - OR of AND groups of single conditions.
      ```json theme={null}
      {
        "operator": "OR",
        "conditions": [
          {
            "operator": "AND",
            "conditions": [
              {
                "field": "statuses%5B%5D",
                "operator": "$stringExactlyMatches",
                "value": "open"
              }
            ]
          }
        ]
      }
      ```
      Available fields: `space_ids%5B%5D`, `project_ids%5B%5D`, `list_ids%5B%5D`, `statuses%5B%5D`, `include_closed`, `assignees%5B%5D`, `tags%5B%5D`, `due_date_gt`, `due_date_lt`, `date_created_gt`, `date_created_lt`, `date_updated_gt`, `date_updated_lt`
  </Accordion>

  <Accordion title="clickup/get_task_in_list">
    **Description:** Get tasks in a specific list in ClickUp.

    **Parameters:**

    * `listId` (string, required): List - Select a List to get tasks from. Use Connect Portal User Settings to allow users to select a ClickUp List.
    * `taskFilterFormula` (string, optional): Search for tasks that match specified filters. For example: name=task1.
  </Accordion>

  <Accordion title="clickup/create_task">
    **Description:** Create a task in ClickUp.

    **Parameters:**

    * `listId` (string, required): List - Select a List to create this task in. Use Connect Portal User Settings to allow users to select a ClickUp List.
    * `name` (string, required): Name - The task name.
    * `description` (string, optional): Description - Task description.
    * `status` (string, optional): Status - Select a Status for this task. Use Connect Portal User Settings to allow users to select a ClickUp Status.
    * `assignees` (string, optional): Assignees - Select a Member (or an array of member IDs) to be assigned to this task. Use Connect Portal User Settings to allow users to select a ClickUp Member.
    * `dueDate` (string, optional): Due Date - Specify a date for this task to be due on.
    * `additionalFields` (string, optional): Additional Fields - Specify additional fields to include on this task as JSON.
  </Accordion>

  <Accordion title="clickup/update_task">
    **Description:** Update a task in ClickUp.

    **Parameters:**

    * `taskId` (string, required): Task ID - The ID of the task to update.
    * `listId` (string, required): List - Select a List to create this task in. Use Connect Portal User Settings to allow users to select a ClickUp List.
    * `name` (string, optional): Name - The task name.
    * `description` (string, optional): Description - Task description.
    * `status` (string, optional): Status - Select a Status for this task. Use Connect Portal User Settings to allow users to select a ClickUp Status.
    * `assignees` (string, optional): Assignees - Select a Member (or an array of member IDs) to be assigned to this task. Use Connect Portal User Settings to allow users to select a ClickUp Member.
    * `dueDate` (string, optional): Due Date - Specify a date for this task to be due on.
    * `additionalFields` (string, optional): Additional Fields - Specify additional fields to include on this task as JSON.
  </Accordion>

  <Accordion title="clickup/delete_task">
    **Description:** Delete a task in ClickUp.

    **Parameters:**

    * `taskId` (string, required): Task ID - The ID of the task to delete.
  </Accordion>

  <Accordion title="clickup/get_list">
    **Description:** Get List information in ClickUp.

    **Parameters:**

    * `spaceId` (string, required): Space ID - The ID of the space containing the lists.
  </Accordion>

  <Accordion title="clickup/get_custom_fields_in_list">
    **Description:** Get Custom Fields in a List in ClickUp.

    **Parameters:**

    * `listId` (string, required): List ID - The ID of the list to get custom fields from.
  </Accordion>

  <Accordion title="clickup/get_all_fields_in_list">
    **Description:** Get All Fields in a List in ClickUp.

    **Parameters:**

    * `listId` (string, required): List ID - The ID of the list to get all fields from.
  </Accordion>

  <Accordion title="clickup/get_space">
    **Description:** Get Space information in ClickUp.

    **Parameters:**

    * `spaceId` (string, optional): Space ID - The ID of the space to retrieve.
  </Accordion>

  <Accordion title="clickup/get_folders">
    **Description:** Get Folders in ClickUp.

    **Parameters:**

    * `spaceId` (string, required): Space ID - The ID of the space containing the folders.
  </Accordion>

  <Accordion title="clickup/get_member">
    **Description:** Get Member information in ClickUp.

    **Parameters:** None required.
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic ClickUp Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew
from crewai import Agent, Task, Crew

# Create an agent with Clickup capabilities
clickup_agent = Agent(
    role="Task Manager",
    goal="Manage tasks and projects in ClickUp efficiently",
    backstory="An AI assistant specialized in task management and productivity coordination.",
    apps=['clickup']  # All Clickup actions will be available
)

# Task to create a new task
create_task = Task(
    description="Create a task called 'Review Q1 Reports' in the Marketing list with high priority",
    agent=clickup_agent,
    expected_output="Task created successfully with task ID"
)

# Run the task
crew = Crew(
    agents=[clickup_agent],
    tasks=[create_task]
)

crew.kickoff()
```

### Filtering Specific ClickUp Tools

```python theme={null}

task_coordinator = Agent(
    role="Task Coordinator",
    goal="Create and manage tasks efficiently",
    backstory="An AI assistant that focuses on task creation and status management.",
    apps=['clickup/create_task']
)

# Task to manage task workflow
task_workflow = Task(
    description="Create a task for project planning and assign it to the development team",
    agent=task_coordinator,
    expected_output="Task created and assigned successfully"
)

crew = Crew(
    agents=[task_coordinator],
    tasks=[task_workflow]
)

crew.kickoff()
```

### Advanced Project Management

```python theme={null}
from crewai import Agent, Task, Crew

project_manager = Agent(
    role="Project Manager",
    goal="Coordinate project activities and track team productivity",
    backstory="An experienced project manager who ensures projects are delivered on time.",
    apps=['clickup']
)

# Complex task involving multiple ClickUp operations
project_coordination = Task(
    description="""
    1. Get all open tasks in the current space
    2. Identify overdue tasks and update their status
    3. Create a weekly report task summarizing project progress
    4. Assign the report task to the team lead
    """,
    agent=project_manager,
    expected_output="Project status updated and weekly report task created and assigned"
)

crew = Crew(
    agents=[project_manager],
    tasks=[project_coordination]
)

crew.kickoff()
```

### Task Search and Management

```python theme={null}
from crewai import Agent, Task, Crew

task_analyst = Agent(
    role="Task Analyst",
    goal="Analyze task patterns and optimize team productivity",
    backstory="An AI assistant that analyzes task data to improve team efficiency.",
    apps=['clickup']
)

# Task to analyze and optimize task distribution
task_analysis = Task(
    description="""
    Search for all tasks assigned to team members in the last 30 days,
    analyze completion patterns, and create optimization recommendations
    """,
    agent=task_analyst,
    expected_output="Task analysis report with optimization recommendations"
)

crew = Crew(
    agents=[task_analyst],
    tasks=[task_analysis]
)

crew.kickoff()
```

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with ClickUp integration setup or
  troubleshooting.
</Card>


# GitHub Integration
Source: https://docs.crewai.com/en/enterprise/integrations/github

Repository and issue management with GitHub integration for CrewAI.

## Overview

Enable your agents to manage repositories, issues, and releases through GitHub. Create and update issues, manage releases, track project development, and streamline your software development workflow with AI-powered automation.

## Prerequisites

Before using the GitHub integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A GitHub account with appropriate repository permissions
* Connected your GitHub account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up GitHub Integration

### 1. Connect Your GitHub Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **GitHub** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for repository and issue management
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="github/create_issue">
    **Description:** Create an issue in GitHub.

    **Parameters:**

    * `owner` (string, required): Owner - Specify the name of the account owner of the associated repository for this Issue. (example: "abc").
    * `repo` (string, required): Repository - Specify the name of the associated repository for this Issue.
    * `title` (string, required): Issue Title - Specify the title of the issue to create.
    * `body` (string, optional): Issue Body - Specify the body contents of the issue to create.
    * `assignees` (string, optional): Assignees - Specify the assignee(s)' GitHub login as an array of strings for this issue. (example: `["octocat"]`).
  </Accordion>

  <Accordion title="github/update_issue">
    **Description:** Update an issue in GitHub.

    **Parameters:**

    * `owner` (string, required): Owner - Specify the name of the account owner of the associated repository for this Issue. (example: "abc").
    * `repo` (string, required): Repository - Specify the name of the associated repository for this Issue.
    * `issue_number` (string, required): Issue Number - Specify the number of the issue to update.
    * `title` (string, required): Issue Title - Specify the title of the issue to update.
    * `body` (string, optional): Issue Body - Specify the body contents of the issue to update.
    * `assignees` (string, optional): Assignees - Specify the assignee(s)' GitHub login as an array of strings for this issue. (example: `["octocat"]`).
    * `state` (string, optional): State - Specify the updated state of the issue.
      * Options: `open`, `closed`
  </Accordion>

  <Accordion title="github/get_issue_by_number">
    **Description:** Get an issue by number in GitHub.

    **Parameters:**

    * `owner` (string, required): Owner - Specify the name of the account owner of the associated repository for this Issue. (example: "abc").
    * `repo` (string, required): Repository - Specify the name of the associated repository for this Issue.
    * `issue_number` (string, required): Issue Number - Specify the number of the issue to fetch.
  </Accordion>

  <Accordion title="github/lock_issue">
    **Description:** Lock an issue in GitHub.

    **Parameters:**

    * `owner` (string, required): Owner - Specify the name of the account owner of the associated repository for this Issue. (example: "abc").
    * `repo` (string, required): Repository - Specify the name of the associated repository for this Issue.
    * `issue_number` (string, required): Issue Number - Specify the number of the issue to lock.
    * `lock_reason` (string, required): Lock Reason - Specify a reason for locking the issue or pull request conversation.
      * Options: `off-topic`, `too heated`, `resolved`, `spam`
  </Accordion>

  <Accordion title="github/search_issue">
    **Description:** Search for issues in GitHub.

    **Parameters:**

    * `owner` (string, required): Owner - Specify the name of the account owner of the associated repository for this Issue. (example: "abc").
    * `repo` (string, required): Repository - Specify the name of the associated repository for this Issue.
    * `filter` (object, required): A filter in disjunctive normal form - OR of AND groups of single conditions.
      ```json theme={null}
      {
        "operator": "OR",
        "conditions": [
          {
            "operator": "AND",
            "conditions": [
              {
                "field": "assignee",
                "operator": "$stringExactlyMatches",
                "value": "octocat"
              }
            ]
          }
        ]
      }
      ```
      Available fields: `assignee`, `creator`, `mentioned`, `labels`
  </Accordion>

  <Accordion title="github/create_release">
    **Description:** Create a release in GitHub.

    **Parameters:**

    * `owner` (string, required): Owner - Specify the name of the account owner of the associated repository for this Release. (example: "abc").
    * `repo` (string, required): Repository - Specify the name of the associated repository for this Release.
    * `tag_name` (string, required): Name - Specify the name of the release tag to be created. (example: "v1.0.0").
    * `target_commitish` (string, optional): Target - Specify the target of the release. This can either be a branch name or a commit SHA. Defaults to the main branch. (example: "master").
    * `body` (string, optional): Body - Specify a description for this release.
    * `draft` (string, optional): Draft - Specify whether the created release should be a draft (unpublished) release.
      * Options: `true`, `false`
    * `prerelease` (string, optional): Prerelease - Specify whether the created release should be a prerelease.
      * Options: `true`, `false`
    * `discussion_category_name` (string, optional): Discussion Category Name - If specified, a discussion of the specified category is created and linked to the release. The value must be a category that already exists in the repository.
    * `generate_release_notes` (string, optional): Release Notes - Specify whether the created release should automatically create release notes using the provided name and body specified.
      * Options: `true`, `false`
  </Accordion>

  <Accordion title="github/update_release">
    **Description:** Update a release in GitHub.

    **Parameters:**

    * `owner` (string, required): Owner - Specify the name of the account owner of the associated repository for this Release. (example: "abc").
    * `repo` (string, required): Repository - Specify the name of the associated repository for this Release.
    * `id` (string, required): Release ID - Specify the ID of the release to update.
    * `tag_name` (string, optional): Name - Specify the name of the release tag to be updated. (example: "v1.0.0").
    * `target_commitish` (string, optional): Target - Specify the target of the release. This can either be a branch name or a commit SHA. Defaults to the main branch. (example: "master").
    * `body` (string, optional): Body - Specify a description for this release.
    * `draft` (string, optional): Draft - Specify whether the created release should be a draft (unpublished) release.
      * Options: `true`, `false`
    * `prerelease` (string, optional): Prerelease - Specify whether the created release should be a prerelease.
      * Options: `true`, `false`
    * `discussion_category_name` (string, optional): Discussion Category Name - If specified, a discussion of the specified category is created and linked to the release. The value must be a category that already exists in the repository.
    * `generate_release_notes` (string, optional): Release Notes - Specify whether the created release should automatically create release notes using the provided name and body specified.
      * Options: `true`, `false`
  </Accordion>

  <Accordion title="github/get_release_by_id">
    **Description:** Get a release by ID in GitHub.

    **Parameters:**

    * `owner` (string, required): Owner - Specify the name of the account owner of the associated repository for this Release. (example: "abc").
    * `repo` (string, required): Repository - Specify the name of the associated repository for this Release.
    * `id` (string, required): Release ID - Specify the release ID of the release to fetch.
  </Accordion>

  <Accordion title="github/get_release_by_tag_name">
    **Description:** Get a release by tag name in GitHub.

    **Parameters:**

    * `owner` (string, required): Owner - Specify the name of the account owner of the associated repository for this Release. (example: "abc").
    * `repo` (string, required): Repository - Specify the name of the associated repository for this Release.
    * `tag_name` (string, required): Name - Specify the tag of the release to fetch. (example: "v1.0.0").
  </Accordion>

  <Accordion title="github/delete_release">
    **Description:** Delete a release in GitHub.

    **Parameters:**

    * `owner` (string, required): Owner - Specify the name of the account owner of the associated repository for this Release. (example: "abc").
    * `repo` (string, required): Repository - Specify the name of the associated repository for this Release.
    * `id` (string, required): Release ID - Specify the ID of the release to delete.
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic GitHub Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew
from crewai import Agent, Task, Crew

# Create an agent with Github capabilities
github_agent = Agent(
    role="Repository Manager",
    goal="Manage GitHub repositories, issues, and releases efficiently",
    backstory="An AI assistant specialized in repository management and issue tracking.",
    apps=['github']  # All Github actions will be available
)

# Task to create a new issue
create_issue_task = Task(
    description="Create a bug report issue for the login functionality in the main repository",
    agent=github_agent,
    expected_output="Issue created successfully with issue number"
)

# Run the task
crew = Crew(
    agents=[github_agent],
    tasks=[create_issue_task]
)

crew.kickoff()
```

### Filtering Specific GitHub Tools

```python theme={null}

issue_manager = Agent(
    role="Issue Manager",
    goal="Create and manage GitHub issues efficiently",
    backstory="An AI assistant that focuses on issue tracking and management.",
    apps=['github/create_issue']
)

# Task to manage issue workflow
issue_workflow = Task(
    description="Create a feature request issue and assign it to the development team",
    agent=issue_manager,
    expected_output="Feature request issue created and assigned successfully"
)

crew = Crew(
    agents=[issue_manager],
    tasks=[issue_workflow]
)

crew.kickoff()
```

### Release Management

```python theme={null}
from crewai import Agent, Task, Crew

release_manager = Agent(
    role="Release Manager",
    goal="Manage software releases and versioning",
    backstory="An experienced release manager who handles version control and release processes.",
    apps=['github']
)

# Task to create a new release
release_task = Task(
    description="""
    Create a new release v2.1.0 for the project with:
    - Auto-generated release notes
    - Target the main branch
    - Include a description of new features and bug fixes
    """,
    agent=release_manager,
    expected_output="Release v2.1.0 created successfully with release notes"
)

crew = Crew(
    agents=[release_manager],
    tasks=[release_task]
)

crew.kickoff()
```

### Issue Tracking and Management

```python theme={null}
from crewai import Agent, Task, Crew

project_coordinator = Agent(
    role="Project Coordinator",
    goal="Track and coordinate project issues and development progress",
    backstory="An AI assistant that helps coordinate development work and track project progress.",
    apps=['github']
)

# Complex task involving multiple GitHub operations
coordination_task = Task(
    description="""
    1. Search for all open issues assigned to the current milestone
    2. Identify overdue issues and update their priority labels
    3. Create a weekly progress report issue
    4. Lock resolved issues that have been inactive for 30 days
    """,
    agent=project_coordinator,
    expected_output="Project coordination completed with progress report and issue management"
)

crew = Crew(
    agents=[project_coordinator],
    tasks=[coordination_task]
)

crew.kickoff()
```

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with GitHub integration setup or
  troubleshooting.
</Card>


# Gmail Integration
Source: https://docs.crewai.com/en/enterprise/integrations/gmail

Email and contact management with Gmail integration for CrewAI.

## Overview

Enable your agents to manage emails, contacts, and drafts through Gmail. Send emails, search messages, manage contacts, create drafts, and streamline your email communications with AI-powered automation.

## Prerequisites

Before using the Gmail integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Gmail account with appropriate permissions
* Connected your Gmail account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up Gmail Integration

### 1. Connect Your Gmail Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Gmail** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for email and contact management
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="gmail/fetch_emails">
    **Description:** Retrieve a list of messages.

    **Parameters:**

    * `userId` (string, required): The user's email address or 'me' for the authenticated user. (default: "me")
    * `q` (string, optional): Search query to filter messages (e.g., 'from:[someone@example.com](mailto:someone@example.com) is:unread').
    * `maxResults` (integer, optional): Maximum number of messages to return (1-500). (default: 100)
    * `pageToken` (string, optional): Page token to retrieve a specific page of results.
    * `labelIds` (array, optional): Only return messages with labels that match all of the specified label IDs.
    * `includeSpamTrash` (boolean, optional): Include messages from SPAM and TRASH in the results. (default: false)
  </Accordion>

  <Accordion title="gmail/send_email">
    **Description:** Send an email.

    **Parameters:**

    * `to` (string, required): Recipient email address.
    * `subject` (string, required): Email subject line.
    * `body` (string, required): Email message content.
    * `userId` (string, optional): The user's email address or 'me' for the authenticated user. (default: "me")
    * `cc` (string, optional): CC email addresses (comma-separated).
    * `bcc` (string, optional): BCC email addresses (comma-separated).
    * `from` (string, optional): Sender email address (if different from authenticated user).
    * `replyTo` (string, optional): Reply-to email address.
    * `threadId` (string, optional): Thread ID if replying to an existing conversation.
  </Accordion>

  <Accordion title="gmail/delete_email">
    **Description:** Delete an email by ID.

    **Parameters:**

    * `userId` (string, required): The user's email address or 'me' for the authenticated user.
    * `id` (string, required): The ID of the message to delete.
  </Accordion>

  <Accordion title="gmail/create_draft">
    **Description:** Create a new draft email.

    **Parameters:**

    * `userId` (string, required): The user's email address or 'me' for the authenticated user.
    * `message` (object, required): Message object containing the draft content.
      * `raw` (string, required): Base64url encoded email message.
  </Accordion>

  <Accordion title="gmail/get_message">
    **Description:** Retrieve a specific message by ID.

    **Parameters:**

    * `userId` (string, required): The user's email address or 'me' for the authenticated user. (default: "me")
    * `id` (string, required): The ID of the message to retrieve.
    * `format` (string, optional): The format to return the message in. Options: "full", "metadata", "minimal", "raw". (default: "full")
    * `metadataHeaders` (array, optional): When given and format is METADATA, only include headers specified.
  </Accordion>

  <Accordion title="gmail/get_attachment">
    **Description:** Retrieve a message attachment.

    **Parameters:**

    * `userId` (string, required): The user's email address or 'me' for the authenticated user. (default: "me")
    * `messageId` (string, required): The ID of the message containing the attachment.
    * `id` (string, required): The ID of the attachment to retrieve.
  </Accordion>

  <Accordion title="gmail/fetch_thread">
    **Description:** Retrieve a specific email thread by ID.

    **Parameters:**

    * `userId` (string, required): The user's email address or 'me' for the authenticated user. (default: "me")
    * `id` (string, required): The ID of the thread to retrieve.
    * `format` (string, optional): The format to return the messages in. Options: "full", "metadata", "minimal". (default: "full")
    * `metadataHeaders` (array, optional): When given and format is METADATA, only include headers specified.
  </Accordion>

  <Accordion title="gmail/modify_thread">
    **Description:** Modify the labels applied to a thread.

    **Parameters:**

    * `userId` (string, required): The user's email address or 'me' for the authenticated user. (default: "me")
    * `id` (string, required): The ID of the thread to modify.
    * `addLabelIds` (array, optional): A list of IDs of labels to add to this thread.
    * `removeLabelIds` (array, optional): A list of IDs of labels to remove from this thread.
  </Accordion>

  <Accordion title="gmail/trash_thread">
    **Description:** Move a thread to the trash.

    **Parameters:**

    * `userId` (string, required): The user's email address or 'me' for the authenticated user. (default: "me")
    * `id` (string, required): The ID of the thread to trash.
  </Accordion>

  <Accordion title="gmail/untrash_thread">
    **Description:** Remove a thread from the trash.

    **Parameters:**

    * `userId` (string, required): The user's email address or 'me' for the authenticated user. (default: "me")
    * `id` (string, required): The ID of the thread to untrash.
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Gmail Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with Gmail capabilities
gmail_agent = Agent(
    role="Email Manager",
    goal="Manage email communications and messages efficiently",
    backstory="An AI assistant specialized in email management and communication.",
    apps=['gmail']  # All Gmail actions will be available
)

# Task to send a follow-up email
send_email_task = Task(
    description="Send a follow-up email to john@example.com about the project update meeting",
    agent=gmail_agent,
    expected_output="Email sent successfully with confirmation"
)

# Run the task
crew = Crew(
    agents=[gmail_agent],
    tasks=[send_email_task]
)

crew.kickoff()
```

### Filtering Specific Gmail Tools

```python theme={null}
from crewai import Agent, Task, Crew

# Create agent with specific Gmail actions only
email_coordinator = Agent(
    role="Email Coordinator",
    goal="Coordinate email communications and manage drafts",
    backstory="An AI assistant that focuses on email coordination and draft management.",
    apps=[
        'gmail/send_email',
        'gmail/fetch_emails',
        'gmail/create_draft'
    ]
)

# Task to prepare and send emails
email_coordination = Task(
    description="Search for emails from the marketing team, create a summary draft, and send it to stakeholders",
    agent=email_coordinator,
    expected_output="Summary email sent to stakeholders"
)

crew = Crew(
    agents=[email_coordinator],
    tasks=[email_coordination]
)

crew.kickoff()
```

### Email Search and Analysis

```python theme={null}
from crewai import Agent, Task, Crew

# Create agent with Gmail search and analysis capabilities
email_analyst = Agent(
    role="Email Analyst",
    goal="Analyze email patterns and provide insights",
    backstory="An AI assistant that analyzes email data to provide actionable insights.",
    apps=['gmail/fetch_emails', 'gmail/get_message']  # Specific actions for email analysis
)

# Task to analyze email patterns
analysis_task = Task(
    description="""
    Search for all unread emails from the last 7 days,
    categorize them by sender domain,
    and create a summary report of communication patterns
    """,
    agent=email_analyst,
    expected_output="Email analysis report with communication patterns and recommendations"
)

crew = Crew(
    agents=[email_analyst],
    tasks=[analysis_task]
)

crew.kickoff()
```

### Thread Management

```python theme={null}
from crewai import Agent, Task, Crew

# Create agent with Gmail thread management capabilities
thread_manager = Agent(
    role="Thread Manager",
    goal="Organize and manage email threads efficiently",
    backstory="An AI assistant that specializes in email thread organization and management.",
    apps=[
        'gmail/fetch_thread',
        'gmail/modify_thread',
        'gmail/trash_thread'
    ]
)

# Task to organize email threads
thread_task = Task(
    description="""
    1. Fetch all threads from the last month
    2. Apply appropriate labels to organize threads by project
    3. Archive or trash threads that are no longer relevant
    """,
    agent=thread_manager,
    expected_output="Email threads organized with appropriate labels and cleanup completed"
)

crew = Crew(
    agents=[thread_manager],
    tasks=[thread_task]
)

crew.kickoff()
```

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Gmail integration setup or
  troubleshooting.
</Card>


# Google Calendar Integration
Source: https://docs.crewai.com/en/enterprise/integrations/google_calendar

Event and schedule management with Google Calendar integration for CrewAI.

## Overview

Enable your agents to manage calendar events, schedules, and availability through Google Calendar. Create and update events, manage attendees, check availability, and streamline your scheduling workflows with AI-powered automation.

## Prerequisites

Before using the Google Calendar integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Google account with Google Calendar access
* Connected your Google account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up Google Calendar Integration

### 1. Connect Your Google Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Google Calendar** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for calendar access
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="google_calendar/get_availability">
    **Description:** Get calendar availability (free/busy information).

    **Parameters:**

    * `timeMin` (string, required): Start time (RFC3339 format)
    * `timeMax` (string, required): End time (RFC3339 format)
    * `items` (array, required): Calendar IDs to check
      ```json theme={null}
      [
        {
          "id": "calendar_id"
        }
      ]
      ```
    * `timeZone` (string, optional): Time zone used in the response. The default is UTC.
    * `groupExpansionMax` (integer, optional): Maximal number of calendar identifiers to be provided for a single group. Maximum: 100
    * `calendarExpansionMax` (integer, optional): Maximal number of calendars for which FreeBusy information is to be provided. Maximum: 50
  </Accordion>

  <Accordion title="google_calendar/create_event">
    **Description:** Create a new event in the specified calendar.

    **Parameters:**

    * `calendarId` (string, required): Calendar ID (use 'primary' for main calendar)
    * `summary` (string, required): Event title/summary
    * `start_dateTime` (string, required): Start time in RFC3339 format (e.g., 2024-01-20T10:00:00-07:00)
    * `end_dateTime` (string, required): End time in RFC3339 format
    * `description` (string, optional): Event description
    * `timeZone` (string, optional): Time zone (e.g., America/Los\_Angeles)
    * `location` (string, optional): Geographic location of the event as free-form text.
    * `attendees` (array, optional): List of attendees for the event.
      ```json theme={null}
      [
        {
          "email": "attendee@example.com",
          "displayName": "Attendee Name",
          "optional": false
        }
      ]
      ```
    * `reminders` (object, optional): Information about the event's reminders.
      ```json theme={null}
      {
        "useDefault": true,
        "overrides": [
          {
            "method": "email",
            "minutes": 15
          }
        ]
      }
      ```
    * `conferenceData` (object, optional): The conference-related information, such as details of a Google Meet conference.
      ```json theme={null}
      {
        "createRequest": {
          "requestId": "unique-request-id",
          "conferenceSolutionKey": {
            "type": "hangoutsMeet"
          }
        }
      }
      ```
    * `visibility` (string, optional): Visibility of the event. Options: default, public, private, confidential. Default: default
    * `transparency` (string, optional): Whether the event blocks time on the calendar. Options: opaque, transparent. Default: opaque
  </Accordion>

  <Accordion title="google_calendar/view_events">
    **Description:** Retrieve events for the specified calendar.

    **Parameters:**

    * `calendarId` (string, required): Calendar ID (use 'primary' for main calendar)
    * `timeMin` (string, optional): Lower bound for events (RFC3339)
    * `timeMax` (string, optional): Upper bound for events (RFC3339)
    * `maxResults` (integer, optional): Maximum number of events (default 10). Minimum: 1, Maximum: 2500
    * `orderBy` (string, optional): The order of the events returned in the result. Options: startTime, updated. Default: startTime
    * `singleEvents` (boolean, optional): Whether to expand recurring events into instances and only return single one-off events and instances of recurring events. Default: true
    * `showDeleted` (boolean, optional): Whether to include deleted events (with status equals cancelled) in the result. Default: false
    * `showHiddenInvitations` (boolean, optional): Whether to include hidden invitations in the result. Default: false
    * `q` (string, optional): Free text search terms to find events that match these terms in any field.
    * `pageToken` (string, optional): Token specifying which result page to return.
    * `timeZone` (string, optional): Time zone used in the response.
    * `updatedMin` (string, optional): Lower bound for an event's last modification time (RFC3339) to filter by.
    * `iCalUID` (string, optional): Specifies an event ID in the iCalendar format to be provided in the response.
  </Accordion>

  <Accordion title="google_calendar/update_event">
    **Description:** Update an existing event.

    **Parameters:**

    * `calendarId` (string, required): Calendar ID
    * `eventId` (string, required): Event ID to update
    * `summary` (string, optional): Updated event title
    * `description` (string, optional): Updated event description
    * `start_dateTime` (string, optional): Updated start time
    * `end_dateTime` (string, optional): Updated end time
  </Accordion>

  <Accordion title="google_calendar/delete_event">
    **Description:** Delete a specified event.

    **Parameters:**

    * `calendarId` (string, required): Calendar ID
    * `eventId` (string, required): Event ID to delete
  </Accordion>

  <Accordion title="google_calendar/view_calendar_list">
    **Description:** Retrieve user's calendar list.

    **Parameters:**

    * `maxResults` (integer, optional): Maximum number of entries returned on one result page. Minimum: 1
    * `pageToken` (string, optional): Token specifying which result page to return.
    * `showDeleted` (boolean, optional): Whether to include deleted calendar list entries in the result. Default: false
    * `showHidden` (boolean, optional): Whether to show hidden entries. Default: false
    * `minAccessRole` (string, optional): The minimum access role for the user in the returned entries. Options: freeBusyReader, owner, reader, writer
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Calendar Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with Google Calendar capabilities
calendar_agent = Agent(
    role="Schedule Manager",
    goal="Manage calendar events and scheduling efficiently",
    backstory="An AI assistant specialized in calendar management and scheduling coordination.",
    apps=['google_calendar']  # All Google Calendar actions will be available
)

# Task to create a meeting
create_meeting_task = Task(
    description="Create a team standup meeting for tomorrow at 9 AM with the development team",
    agent=calendar_agent,
    expected_output="Meeting created successfully with Google Meet link"
)

# Run the task
crew = Crew(
    agents=[calendar_agent],
    tasks=[create_meeting_task]
)

crew.kickoff()
```

### Filtering Specific Calendar Tools

```python theme={null}
meeting_coordinator = Agent(
    role="Meeting Coordinator",
    goal="Coordinate meetings and check availability",
    backstory="An AI assistant that focuses on meeting scheduling and availability management.",
    apps=['google_calendar/create_event', 'google_calendar/get_availability']
)

# Task to schedule a meeting with availability check
schedule_meeting = Task(
    description="Check availability for next week and schedule a project review meeting with stakeholders",
    agent=meeting_coordinator,
    expected_output="Meeting scheduled after checking availability of all participants"
)

crew = Crew(
    agents=[meeting_coordinator],
    tasks=[schedule_meeting]
)

crew.kickoff()
```

### Event Management and Updates

```python theme={null}
from crewai import Agent, Task, Crew

event_manager = Agent(
    role="Event Manager",
    goal="Manage and update calendar events efficiently",
    backstory="An experienced event manager who handles event logistics and updates.",
    apps=['google_calendar']
)

# Task to manage event updates
event_management = Task(
    description="""
    1. List all events for this week
    2. Update any events that need location changes to include video conference links
    3. Check availability for upcoming meetings
    """,
    agent=event_manager,
    expected_output="Weekly events updated with proper locations and availability checked"
)

crew = Crew(
    agents=[event_manager],
    tasks=[event_management]
)

crew.kickoff()
```

### Availability and Calendar Management

```python theme={null}
from crewai import Agent, Task, Crew

availability_coordinator = Agent(
    role="Availability Coordinator",
    goal="Coordinate availability and manage calendars for scheduling",
    backstory="An AI assistant that specializes in availability management and calendar coordination.",
    apps=['google_calendar']
)

# Task to coordinate availability
availability_task = Task(
    description="""
    1. Get the list of available calendars
    2. Check availability for all calendars next Friday afternoon
    3. Create a team meeting for the first available 2-hour slot
    4. Include Google Meet link and send invitations
    """,
    agent=availability_coordinator,
    expected_output="Team meeting scheduled based on availability with all team members invited"
)

crew = Crew(
    agents=[availability_coordinator],
    tasks=[availability_task]
)

crew.kickoff()
```

### Automated Scheduling Workflows

```python theme={null}
from crewai import Agent, Task, Crew

scheduling_automator = Agent(
    role="Scheduling Automator",
    goal="Automate scheduling workflows and calendar management",
    backstory="An AI assistant that automates complex scheduling scenarios and calendar workflows.",
    apps=['google_calendar']
)

# Complex scheduling automation task
automation_task = Task(
    description="""
    1. List all upcoming events for the next two weeks
    2. Identify any scheduling conflicts or back-to-back meetings
    3. Suggest optimal meeting times by checking availability
    4. Create buffer time between meetings where needed
    5. Update event descriptions with agenda items and meeting links
    """,
    agent=scheduling_automator,
    expected_output="Calendar optimized with resolved conflicts, buffer times, and updated meeting details"
)

crew = Crew(
    agents=[scheduling_automator],
    tasks=[automation_task]
)

crew.kickoff()
```

## Troubleshooting

### Common Issues

**Authentication Errors**

* Ensure your Google account has the necessary permissions for calendar access
* Verify that the OAuth connection includes all required scopes for Google Calendar API
* Check if calendar sharing settings allow the required access level

**Event Creation Issues**

* Verify that time formats are correct (RFC3339 format)
* Ensure attendee email addresses are properly formatted
* Check that the target calendar exists and is accessible
* Verify time zones are correctly specified

**Availability and Time Conflicts**

* Use proper RFC3339 format for time ranges when checking availability
* Ensure time zones are consistent across all operations
* Verify that calendar IDs are correct when checking multiple calendars

**Event Updates and Deletions**

* Verify that event IDs are correct and events exist
* Ensure you have edit permissions for the events
* Check that calendar ownership allows modifications

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Google Calendar integration setup
  or troubleshooting.
</Card>


# Google Contacts Integration
Source: https://docs.crewai.com/en/enterprise/integrations/google_contacts

Contact and directory management with Google Contacts integration for CrewAI.

## Overview

Enable your agents to manage contacts and directory information through Google Contacts. Access personal contacts, search directory people, create and update contact information, and manage contact groups with AI-powered automation.

## Prerequisites

Before using the Google Contacts integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Google account with Google Contacts access
* Connected your Google account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up Google Contacts Integration

### 1. Connect Your Google Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Google Contacts** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for contacts and directory access
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="google_contacts/get_contacts">
    **Description:** Retrieve user's contacts from Google Contacts.

    **Parameters:**

    * `pageSize` (integer, optional): Number of contacts to return (max 1000). Minimum: 1, Maximum: 1000
    * `pageToken` (string, optional): The token of the page to retrieve.
    * `personFields` (string, optional): Fields to include (e.g., 'names,emailAddresses,phoneNumbers'). Default: names,emailAddresses,phoneNumbers
    * `requestSyncToken` (boolean, optional): Whether the response should include a sync token. Default: false
    * `sortOrder` (string, optional): The order in which the connections should be sorted. Options: LAST\_MODIFIED\_ASCENDING, LAST\_MODIFIED\_DESCENDING, FIRST\_NAME\_ASCENDING, LAST\_NAME\_ASCENDING
  </Accordion>

  <Accordion title="google_contacts/search_contacts">
    **Description:** Search for contacts using a query string.

    **Parameters:**

    * `query` (string, required): Search query string
    * `readMask` (string, required): Fields to read (e.g., 'names,emailAddresses,phoneNumbers')
    * `pageSize` (integer, optional): Number of results to return. Minimum: 1, Maximum: 30
    * `pageToken` (string, optional): Token specifying which result page to return.
    * `sources` (array, optional): The sources to search in. Options: READ\_SOURCE\_TYPE\_CONTACT, READ\_SOURCE\_TYPE\_PROFILE. Default: READ\_SOURCE\_TYPE\_CONTACT
  </Accordion>

  <Accordion title="google_contacts/list_directory_people">
    **Description:** List people in the authenticated user's directory.

    **Parameters:**

    * `sources` (array, required): Directory sources to search within. Options: DIRECTORY\_SOURCE\_TYPE\_DOMAIN\_PROFILE, DIRECTORY\_SOURCE\_TYPE\_DOMAIN\_CONTACT. Default: DIRECTORY\_SOURCE\_TYPE\_DOMAIN\_PROFILE
    * `pageSize` (integer, optional): Number of people to return. Minimum: 1, Maximum: 1000
    * `pageToken` (string, optional): Token specifying which result page to return.
    * `readMask` (string, optional): Fields to read (e.g., 'names,emailAddresses')
    * `requestSyncToken` (boolean, optional): Whether the response should include a sync token. Default: false
    * `mergeSources` (array, optional): Additional data to merge into the directory people responses. Options: CONTACT
  </Accordion>

  <Accordion title="google_contacts/search_directory_people">
    **Description:** Search for people in the directory.

    **Parameters:**

    * `query` (string, required): Search query
    * `sources` (string, required): Directory sources (use 'DIRECTORY\_SOURCE\_TYPE\_DOMAIN\_PROFILE')
    * `pageSize` (integer, optional): Number of results to return
    * `readMask` (string, optional): Fields to read
  </Accordion>

  <Accordion title="google_contacts/list_other_contacts">
    **Description:** List other contacts (not in user's personal contacts).

    **Parameters:**

    * `pageSize` (integer, optional): Number of contacts to return. Minimum: 1, Maximum: 1000
    * `pageToken` (string, optional): Token specifying which result page to return.
    * `readMask` (string, optional): Fields to read
    * `requestSyncToken` (boolean, optional): Whether the response should include a sync token. Default: false
  </Accordion>

  <Accordion title="google_contacts/search_other_contacts">
    **Description:** Search other contacts.

    **Parameters:**

    * `query` (string, required): Search query
    * `readMask` (string, required): Fields to read (e.g., 'names,emailAddresses')
    * `pageSize` (integer, optional): Number of results
  </Accordion>

  <Accordion title="google_contacts/get_person">
    **Description:** Get a single person's contact information by resource name.

    **Parameters:**

    * `resourceName` (string, required): The resource name of the person to get (e.g., 'people/c123456789')
    * `personFields` (string, optional): Fields to include (e.g., 'names,emailAddresses,phoneNumbers'). Default: names,emailAddresses,phoneNumbers
  </Accordion>

  <Accordion title="google_contacts/create_contact">
    **Description:** Create a new contact in the user's address book.

    **Parameters:**

    * `names` (array, optional): Person's names
      ```json theme={null}
      [
        {
          "givenName": "John",
          "familyName": "Doe",
          "displayName": "John Doe"
        }
      ]
      ```
    * `emailAddresses` (array, optional): Email addresses
      ```json theme={null}
      [
        {
          "value": "john.doe@example.com",
          "type": "work"
        }
      ]
      ```
    * `phoneNumbers` (array, optional): Phone numbers
      ```json theme={null}
      [
        {
          "value": "+1234567890",
          "type": "mobile"
        }
      ]
      ```
    * `addresses` (array, optional): Postal addresses
      ```json theme={null}
      [
        {
          "formattedValue": "123 Main St, City, State 12345",
          "type": "home"
        }
      ]
      ```
    * `organizations` (array, optional): Organizations/companies
      ```json theme={null}
      [
        {
          "name": "Company Name",
          "title": "Job Title",
          "type": "work"
        }
      ]
      ```
  </Accordion>

  <Accordion title="google_contacts/update_contact">
    **Description:** Update an existing contact's information.

    **Parameters:**

    * `resourceName` (string, required): The resource name of the person to update (e.g., 'people/c123456789')
    * `updatePersonFields` (string, required): Fields to update (e.g., 'names,emailAddresses,phoneNumbers')
    * `names` (array, optional): Person's names
    * `emailAddresses` (array, optional): Email addresses
    * `phoneNumbers` (array, optional): Phone numbers
  </Accordion>

  <Accordion title="google_contacts/delete_contact">
    **Description:** Delete a contact from the user's address book.

    **Parameters:**

    * `resourceName` (string, required): The resource name of the person to delete (e.g., 'people/c123456789')
  </Accordion>

  <Accordion title="google_contacts/batch_get_people">
    **Description:** Get information about multiple people in a single request.

    **Parameters:**

    * `resourceNames` (array, required): Resource names of people to get. Maximum: 200 items
    * `personFields` (string, optional): Fields to include (e.g., 'names,emailAddresses,phoneNumbers'). Default: names,emailAddresses,phoneNumbers
  </Accordion>

  <Accordion title="google_contacts/list_contact_groups">
    **Description:** List the user's contact groups (labels).

    **Parameters:**

    * `pageSize` (integer, optional): Number of contact groups to return. Minimum: 1, Maximum: 1000
    * `pageToken` (string, optional): Token specifying which result page to return.
    * `groupFields` (string, optional): Fields to include (e.g., 'name,memberCount,clientData'). Default: name,memberCount
  </Accordion>

  <Accordion title="google_contacts/get_contact_group">
    **Description:** Get a specific contact group by resource name.

    **Parameters:**

    * `resourceName` (string, required): The resource name of the contact group (e.g., 'contactGroups/myContactGroup')
    * `maxMembers` (integer, optional): Maximum number of members to include. Minimum: 0, Maximum: 20000
    * `groupFields` (string, optional): Fields to include (e.g., 'name,memberCount,clientData'). Default: name,memberCount
  </Accordion>

  <Accordion title="google_contacts/create_contact_group">
    **Description:** Create a new contact group (label).

    **Parameters:**

    * `name` (string, required): The name of the contact group
    * `clientData` (array, optional): Client-specific data
      ```json theme={null}
      [
        {
          "key": "data_key",
          "value": "data_value"
        }
      ]
      ```
  </Accordion>

  <Accordion title="google_contacts/update_contact_group">
    **Description:** Update a contact group's information.

    **Parameters:**

    * `resourceName` (string, required): The resource name of the contact group (e.g., 'contactGroups/myContactGroup')
    * `name` (string, required): The name of the contact group
    * `clientData` (array, optional): Client-specific data
      ```json theme={null}
      [
        {
          "key": "data_key",
          "value": "data_value"
        }
      ]
      ```
  </Accordion>

  <Accordion title="google_contacts/delete_contact_group">
    **Description:** Delete a contact group.

    **Parameters:**

    * `resourceName` (string, required): The resource name of the contact group to delete (e.g., 'contactGroups/myContactGroup')
    * `deleteContacts` (boolean, optional): Whether to delete contacts in the group as well. Default: false
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Google Contacts Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with Google Contacts capabilities
contacts_agent = Agent(
    role="Contact Manager",
    goal="Manage contacts and directory information efficiently",
    backstory="An AI assistant specialized in contact management and directory operations.",
    apps=['google_contacts']  # All Google Contacts actions will be available
)

# Task to retrieve and organize contacts
contact_management_task = Task(
    description="Retrieve all contacts and organize them by company affiliation",
    agent=contacts_agent,
    expected_output="Contacts retrieved and organized by company with summary report"
)

# Run the task
crew = Crew(
    agents=[contacts_agent],
    tasks=[contact_management_task]
)

crew.kickoff()
```

### Directory Search and Management

```python theme={null}
from crewai import Agent, Task, Crew

directory_manager = Agent(
    role="Directory Manager",
    goal="Search and manage directory people and contacts",
    backstory="An AI assistant that specializes in directory management and people search.",
    apps=[
        'google_contacts/search_directory_people',
        'google_contacts/list_directory_people',
        'google_contacts/search_contacts'
    ]
)

# Task to search and manage directory
directory_task = Task(
    description="Search for team members in the company directory and create a team contact list",
    agent=directory_manager,
    expected_output="Team directory compiled with contact information"
)

crew = Crew(
    agents=[directory_manager],
    tasks=[directory_task]
)

crew.kickoff()
```

### Contact Creation and Updates

```python theme={null}
from crewai import Agent, Task, Crew

contact_curator = Agent(
    role="Contact Curator",
    goal="Create and update contact information systematically",
    backstory="An AI assistant that maintains accurate and up-to-date contact information.",
    apps=['google_contacts']
)

# Task to create and update contacts
curation_task = Task(
    description="""
    1. Search for existing contacts related to new business partners
    2. Create new contacts for partners not in the system
    3. Update existing contact information with latest details
    4. Organize contacts into appropriate groups
    """,
    agent=contact_curator,
    expected_output="Contact database updated with new partners and organized groups"
)

crew = Crew(
    agents=[contact_curator],
    tasks=[curation_task]
)

crew.kickoff()
```

### Contact Group Management

```python theme={null}
from crewai import Agent, Task, Crew

group_organizer = Agent(
    role="Contact Group Organizer",
    goal="Organize contacts into meaningful groups and categories",
    backstory="An AI assistant that specializes in contact organization and group management.",
    apps=['google_contacts']
)

# Task to organize contact groups
organization_task = Task(
    description="""
    1. List all existing contact groups
    2. Analyze contact distribution across groups
    3. Create new groups for better organization
    4. Move contacts to appropriate groups based on their information
    """,
    agent=group_organizer,
    expected_output="Contacts organized into logical groups with improved structure"
)

crew = Crew(
    agents=[group_organizer],
    tasks=[organization_task]
)

crew.kickoff()
```

### Comprehensive Contact Management

```python theme={null}
from crewai import Agent, Task, Crew

contact_specialist = Agent(
    role="Contact Management Specialist",
    goal="Provide comprehensive contact management across all sources",
    backstory="An AI assistant that handles all aspects of contact management including personal, directory, and other contacts.",
    apps=['google_contacts']
)

# Complex contact management task
comprehensive_task = Task(
    description="""
    1. Retrieve contacts from all sources (personal, directory, other)
    2. Search for duplicate contacts and merge information
    3. Update outdated contact information
    4. Create missing contacts for important stakeholders
    5. Organize contacts into meaningful groups
    6. Generate a comprehensive contact report
    """,
    agent=contact_specialist,
    expected_output="Complete contact management performed with unified contact database and detailed report"
)

crew = Crew(
    agents=[contact_specialist],
    tasks=[comprehensive_task]
)

crew.kickoff()
```

## Troubleshooting

### Common Issues

**Permission Errors**

* Ensure your Google account has appropriate permissions for contacts access
* Verify that the OAuth connection includes required scopes for Google Contacts API
* Check that directory access permissions are granted for organization contacts

**Resource Name Format Issues**

* Ensure resource names follow the correct format (e.g., 'people/c123456789' for contacts)
* Verify that contact group resource names use the format 'contactGroups/groupId'
* Check that resource names exist and are accessible

**Search and Query Issues**

* Ensure search queries are properly formatted and not empty
* Use appropriate readMask fields for the data you need
* Verify that search sources are correctly specified (contacts vs profiles)

**Contact Creation and Updates**

* Ensure required fields are provided when creating contacts
* Verify that email addresses and phone numbers are properly formatted
* Check that updatePersonFields parameter includes all fields being updated

**Directory Access Issues**

* Ensure you have appropriate permissions to access organization directory
* Verify that directory sources are correctly specified
* Check that your organization allows API access to directory information

**Pagination and Limits**

* Be mindful of page size limits (varies by endpoint)
* Use pageToken for pagination through large result sets
* Respect API rate limits and implement appropriate delays

**Contact Groups and Organization**

* Ensure contact group names are unique when creating new groups
* Verify that contacts exist before adding them to groups
* Check that you have permissions to modify contact groups

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Google Contacts integration setup
  or troubleshooting.
</Card>


# Google Docs Integration
Source: https://docs.crewai.com/en/enterprise/integrations/google_docs

Document creation and editing with Google Docs integration for CrewAI.

## Overview

Enable your agents to create, edit, and manage Google Docs documents with text manipulation and formatting. Automate document creation, insert and replace text, manage content ranges, and streamline your document workflows with AI-powered automation.

## Prerequisites

Before using the Google Docs integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Google account with Google Docs access
* Connected your Google account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up Google Docs Integration

### 1. Connect Your Google Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Google Docs** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for document access
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="google_docs/create_document">
    **Description:** Create a new Google Document.

    **Parameters:**

    * `title` (string, optional): The title for the new document.
  </Accordion>

  <Accordion title="google_docs/get_document">
    **Description:** Get the contents and metadata of a Google Document.

    **Parameters:**

    * `documentId` (string, required): The ID of the document to retrieve.
    * `includeTabsContent` (boolean, optional): Whether to include tab content. Default is `false`.
    * `suggestionsViewMode` (string, optional): The suggestions view mode to apply to the document. Enum: `DEFAULT_FOR_CURRENT_ACCESS`, `PREVIEW_SUGGESTIONS_ACCEPTED`, `PREVIEW_WITHOUT_SUGGESTIONS`. Default is `DEFAULT_FOR_CURRENT_ACCESS`.
  </Accordion>

  <Accordion title="google_docs/batch_update">
    **Description:** Apply one or more updates to a Google Document.

    **Parameters:**

    * `documentId` (string, required): The ID of the document to update.
    * `requests` (array, required): A list of updates to apply to the document. Each item is an object representing a request.
    * `writeControl` (object, optional): Provides control over how write requests are executed. Contains `requiredRevisionId` (string) and `targetRevisionId` (string).
  </Accordion>

  <Accordion title="google_docs/insert_text">
    **Description:** Insert text into a Google Document at a specific location.

    **Parameters:**

    * `documentId` (string, required): The ID of the document to update.
    * `text` (string, required): The text to insert.
    * `index` (integer, optional): The zero-based index where to insert the text. Default is `1`.
  </Accordion>

  <Accordion title="google_docs/replace_text">
    **Description:** Replace all instances of text in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The ID of the document to update.
    * `containsText` (string, required): The text to find and replace.
    * `replaceText` (string, required): The text to replace it with.
    * `matchCase` (boolean, optional): Whether the search should respect case. Default is `false`.
  </Accordion>

  <Accordion title="google_docs/delete_content_range">
    **Description:** Delete content from a specific range in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The ID of the document to update.
    * `startIndex` (integer, required): The start index of the range to delete.
    * `endIndex` (integer, required): The end index of the range to delete.
  </Accordion>

  <Accordion title="google_docs/insert_page_break">
    **Description:** Insert a page break at a specific location in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The ID of the document to update.
    * `index` (integer, optional): The zero-based index where to insert the page break. Default is `1`.
  </Accordion>

  <Accordion title="google_docs/create_named_range">
    **Description:** Create a named range in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The ID of the document to update.
    * `name` (string, required): The name for the named range.
    * `startIndex` (integer, required): The start index of the range.
    * `endIndex` (integer, required): The end index of the range.
  </Accordion>

  <Accordion title="google_docs/create_document_with_content">
    **Description:** Create a new Google Document with content in one action.

    **Parameters:**

    * `title` (string, required): The title for the new document. Appears at the top of the document and in Google Drive.
    * `content` (string, optional): The text content to insert into the document. Use `\n` for new paragraphs.
  </Accordion>

  <Accordion title="google_docs/append_text">
    **Description:** Append text to the end of a Google Document. Automatically inserts at the document end without needing to specify an index.

    **Parameters:**

    * `documentId` (string, required): The document ID from create\_document response or URL.
    * `text` (string, required): Text to append at the end of the document. Use `\n` for new paragraphs.
  </Accordion>

  <Accordion title="google_docs/set_text_bold">
    **Description:** Make text bold or remove bold formatting in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `startIndex` (integer, required): Start position of text to format.
    * `endIndex` (integer, required): End position of text to format (exclusive).
    * `bold` (boolean, required): Set `true` to make bold, `false` to remove bold.
  </Accordion>

  <Accordion title="google_docs/set_text_italic">
    **Description:** Make text italic or remove italic formatting in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `startIndex` (integer, required): Start position of text to format.
    * `endIndex` (integer, required): End position of text to format (exclusive).
    * `italic` (boolean, required): Set `true` to make italic, `false` to remove italic.
  </Accordion>

  <Accordion title="google_docs/set_text_underline">
    **Description:** Add or remove underline formatting from text in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `startIndex` (integer, required): Start position of text to format.
    * `endIndex` (integer, required): End position of text to format (exclusive).
    * `underline` (boolean, required): Set `true` to underline, `false` to remove underline.
  </Accordion>

  <Accordion title="google_docs/set_text_strikethrough">
    **Description:** Add or remove strikethrough formatting from text in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `startIndex` (integer, required): Start position of text to format.
    * `endIndex` (integer, required): End position of text to format (exclusive).
    * `strikethrough` (boolean, required): Set `true` to add strikethrough, `false` to remove.
  </Accordion>

  <Accordion title="google_docs/set_font_size">
    **Description:** Change the font size of text in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `startIndex` (integer, required): Start position of text to format.
    * `endIndex` (integer, required): End position of text to format (exclusive).
    * `fontSize` (number, required): Font size in points. Common sizes: 10, 11, 12, 14, 16, 18, 24, 36.
  </Accordion>

  <Accordion title="google_docs/set_text_color">
    **Description:** Change the color of text using RGB values (0-1 scale) in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `startIndex` (integer, required): Start position of text to format.
    * `endIndex` (integer, required): End position of text to format (exclusive).
    * `red` (number, required): Red component (0-1). Example: `1` for full red.
    * `green` (number, required): Green component (0-1). Example: `0.5` for half green.
    * `blue` (number, required): Blue component (0-1). Example: `0` for no blue.
  </Accordion>

  <Accordion title="google_docs/create_hyperlink">
    **Description:** Turn existing text into a clickable hyperlink in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `startIndex` (integer, required): Start position of text to make into a link.
    * `endIndex` (integer, required): End position of text to make into a link (exclusive).
    * `url` (string, required): The URL the link should point to. Example: `"https://example.com"`.
  </Accordion>

  <Accordion title="google_docs/apply_heading_style">
    **Description:** Apply a heading or paragraph style to a text range in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `startIndex` (integer, required): Start position of paragraph(s) to style.
    * `endIndex` (integer, required): End position of paragraph(s) to style.
    * `style` (string, required): The style to apply. Enum: `NORMAL_TEXT`, `TITLE`, `SUBTITLE`, `HEADING_1`, `HEADING_2`, `HEADING_3`, `HEADING_4`, `HEADING_5`, `HEADING_6`.
  </Accordion>

  <Accordion title="google_docs/set_paragraph_alignment">
    **Description:** Set text alignment for paragraphs in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `startIndex` (integer, required): Start position of paragraph(s) to align.
    * `endIndex` (integer, required): End position of paragraph(s) to align.
    * `alignment` (string, required): Text alignment. Enum: `START` (left), `CENTER`, `END` (right), `JUSTIFIED`.
  </Accordion>

  <Accordion title="google_docs/set_line_spacing">
    **Description:** Set line spacing for paragraphs in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `startIndex` (integer, required): Start position of paragraph(s).
    * `endIndex` (integer, required): End position of paragraph(s).
    * `lineSpacing` (number, required): Line spacing as percentage. `100` = single, `115` = 1.15x, `150` = 1.5x, `200` = double.
  </Accordion>

  <Accordion title="google_docs/create_paragraph_bullets">
    **Description:** Convert paragraphs to a bulleted or numbered list in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `startIndex` (integer, required): Start position of paragraphs to convert to list.
    * `endIndex` (integer, required): End position of paragraphs to convert to list.
    * `bulletPreset` (string, required): Bullet/numbering style. Enum: `BULLET_DISC_CIRCLE_SQUARE`, `BULLET_DIAMONDX_ARROW3D_SQUARE`, `BULLET_CHECKBOX`, `BULLET_ARROW_DIAMOND_DISC`, `BULLET_STAR_CIRCLE_SQUARE`, `NUMBERED_DECIMAL_ALPHA_ROMAN`, `NUMBERED_DECIMAL_ALPHA_ROMAN_PARENS`, `NUMBERED_DECIMAL_NESTED`, `NUMBERED_UPPERALPHA_ALPHA_ROMAN`, `NUMBERED_UPPERROMAN_UPPERALPHA_DECIMAL`.
  </Accordion>

  <Accordion title="google_docs/delete_paragraph_bullets">
    **Description:** Remove bullets or numbering from paragraphs in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `startIndex` (integer, required): Start position of list paragraphs.
    * `endIndex` (integer, required): End position of list paragraphs.
  </Accordion>

  <Accordion title="google_docs/insert_table_with_content">
    **Description:** Insert a table with content into a Google Document in one action. Provide content as a 2D array.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `rows` (integer, required): Number of rows in the table.
    * `columns` (integer, required): Number of columns in the table.
    * `index` (integer, optional): Position to insert the table. If not provided, the table is inserted at the end of the document.
    * `content` (array, required): Table content as a 2D array. Each inner array is a row. Example: `[["Year", "Revenue"], ["2023", "$43B"], ["2024", "$45B"]]`.
  </Accordion>

  <Accordion title="google_docs/insert_table_row">
    **Description:** Insert a new row above or below a reference cell in an existing table.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `tableStartIndex` (integer, required): The start index of the table. Get from get\_document.
    * `rowIndex` (integer, required): Row index (0-based) of reference cell.
    * `columnIndex` (integer, optional): Column index (0-based) of reference cell. Default is `0`.
    * `insertBelow` (boolean, optional): If `true`, insert below the reference row. If `false`, insert above. Default is `true`.
  </Accordion>

  <Accordion title="google_docs/insert_table_column">
    **Description:** Insert a new column left or right of a reference cell in an existing table.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `tableStartIndex` (integer, required): The start index of the table.
    * `rowIndex` (integer, optional): Row index (0-based) of reference cell. Default is `0`.
    * `columnIndex` (integer, required): Column index (0-based) of reference cell.
    * `insertRight` (boolean, optional): If `true`, insert to the right. If `false`, insert to the left. Default is `true`.
  </Accordion>

  <Accordion title="google_docs/delete_table_row">
    **Description:** Delete a row from an existing table in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `tableStartIndex` (integer, required): The start index of the table.
    * `rowIndex` (integer, required): Row index (0-based) to delete.
    * `columnIndex` (integer, optional): Column index (0-based) of any cell in the row. Default is `0`.
  </Accordion>

  <Accordion title="google_docs/delete_table_column">
    **Description:** Delete a column from an existing table in a Google Document.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `tableStartIndex` (integer, required): The start index of the table.
    * `rowIndex` (integer, optional): Row index (0-based) of any cell in the column. Default is `0`.
    * `columnIndex` (integer, required): Column index (0-based) to delete.
  </Accordion>

  <Accordion title="google_docs/merge_table_cells">
    **Description:** Merge a range of table cells into a single cell. Content from all cells is preserved.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `tableStartIndex` (integer, required): The start index of the table.
    * `rowIndex` (integer, required): Starting row index (0-based) for the merge.
    * `columnIndex` (integer, required): Starting column index (0-based) for the merge.
    * `rowSpan` (integer, required): Number of rows to merge.
    * `columnSpan` (integer, required): Number of columns to merge.
  </Accordion>

  <Accordion title="google_docs/unmerge_table_cells">
    **Description:** Unmerge previously merged table cells back into individual cells.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `tableStartIndex` (integer, required): The start index of the table.
    * `rowIndex` (integer, required): Row index (0-based) of the merged cell.
    * `columnIndex` (integer, required): Column index (0-based) of the merged cell.
    * `rowSpan` (integer, required): Number of rows the merged cell spans.
    * `columnSpan` (integer, required): Number of columns the merged cell spans.
  </Accordion>

  <Accordion title="google_docs/insert_inline_image">
    **Description:** Insert an image from a public URL into a Google Document. The image must be publicly accessible, under 50MB, and in PNG/JPEG/GIF format.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `uri` (string, required): Public URL of the image. Must be accessible without authentication.
    * `index` (integer, optional): Position to insert the image. If not provided, the image is inserted at the end of the document. Default is `1`.
  </Accordion>

  <Accordion title="google_docs/insert_section_break">
    **Description:** Insert a section break to create document sections with different formatting.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `index` (integer, required): Position to insert the section break.
    * `sectionType` (string, required): The type of section break. Enum: `CONTINUOUS` (stays on same page), `NEXT_PAGE` (starts a new page).
  </Accordion>

  <Accordion title="google_docs/create_header">
    **Description:** Create a header for the document. Returns a headerId which can be used with insert\_text to add header content.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `type` (string, optional): Header type. Enum: `DEFAULT`. Default is `DEFAULT`.
  </Accordion>

  <Accordion title="google_docs/create_footer">
    **Description:** Create a footer for the document. Returns a footerId which can be used with insert\_text to add footer content.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `type` (string, optional): Footer type. Enum: `DEFAULT`. Default is `DEFAULT`.
  </Accordion>

  <Accordion title="google_docs/delete_header">
    **Description:** Delete a header from the document. Use get\_document to find the headerId.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `headerId` (string, required): The header ID to delete. Get from get\_document response.
  </Accordion>

  <Accordion title="google_docs/delete_footer">
    **Description:** Delete a footer from the document. Use get\_document to find the footerId.

    **Parameters:**

    * `documentId` (string, required): The document ID.
    * `footerId` (string, required): The footer ID to delete. Get from get\_document response.
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Google Docs Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with Google Docs capabilities
docs_agent = Agent(
    role="Document Creator",
    goal="Create and manage Google Docs documents efficiently",
    backstory="An AI assistant specialized in Google Docs document creation and editing.",
    apps=['google_docs']  # All Google Docs actions will be available
)

# Task to create a new document
create_doc_task = Task(
    description="Create a new Google Document titled 'Project Status Report'",
    agent=docs_agent,
    expected_output="New Google Document 'Project Status Report' created successfully"
)

# Run the task
crew = Crew(
    agents=[docs_agent],
    tasks=[create_doc_task]
)

crew.kickoff()
```

### Text Editing and Content Management

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent focused on text editing
text_editor = Agent(
    role="Document Editor",
    goal="Edit and update content in Google Docs documents",
    backstory="An AI assistant skilled in precise text editing and content management.",
    apps=['google_docs/insert_text', 'google_docs/replace_text', 'google_docs/delete_content_range']
)

# Task to edit document content
edit_content_task = Task(
    description="In document 'your_document_id', insert the text 'Executive Summary: ' at the beginning, then replace all instances of 'TODO' with 'COMPLETED'.",
    agent=text_editor,
    expected_output="Document updated with new text inserted and TODO items replaced."
)

crew = Crew(
    agents=[text_editor],
    tasks=[edit_content_task]
)

crew.kickoff()
```

### Advanced Document Operations

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent for advanced document operations
document_formatter = Agent(
    role="Document Formatter",
    goal="Apply advanced formatting and structure to Google Docs",
    backstory="An AI assistant that handles complex document formatting and organization.",
    apps=['google_docs/batch_update', 'google_docs/insert_page_break', 'google_docs/create_named_range']
)

# Task to format document
format_doc_task = Task(
    description="In document 'your_document_id', insert a page break at position 100, create a named range called 'Introduction' for characters 1-50, and apply batch formatting updates.",
    agent=document_formatter,
    expected_output="Document formatted with page break, named range, and styling applied."
)

crew = Crew(
    agents=[document_formatter],
    tasks=[format_doc_task]
)

crew.kickoff()
```

## Troubleshooting

### Common Issues

**Authentication Errors**

* Ensure your Google account has the necessary permissions for Google Docs access.
* Verify that the OAuth connection includes all required scopes (`https://www.googleapis.com/auth/documents`).

**Document ID Issues**

* Double-check document IDs for correctness.
* Ensure the document exists and is accessible to your account.
* Document IDs can be found in the Google Docs URL.

**Text Insertion and Range Operations**

* When using `insert_text` or `delete_content_range`, ensure index positions are valid.
* Remember that Google Docs uses zero-based indexing.
* The document must have content at the specified index positions.

**Batch Update Request Formatting**

* When using `batch_update`, ensure the `requests` array is correctly formatted according to the Google Docs API documentation.
* Complex updates require specific JSON structures for each request type.

**Replace Text Operations**

* For `replace_text`, ensure the `containsText` parameter exactly matches the text you want to replace.
* Use `matchCase` parameter to control case sensitivity.

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Google Docs integration setup or
  troubleshooting.
</Card>


# Google Drive Integration
Source: https://docs.crewai.com/en/enterprise/integrations/google_drive

File storage and management with Google Drive integration for CrewAI.

## Overview

Enable your agents to manage files and folders through Google Drive. Upload, download, organize, and share files, create folders, and streamline your document management workflows with AI-powered automation.

## Prerequisites

Before using the Google Drive integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Google account with Google Drive access
* Connected your Google account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up Google Drive Integration

### 1. Connect Your Google Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Google Drive** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for file and folder management
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="google_drive/get_file">
    **Description:** Get a file by ID from Google Drive.

    **Parameters:**

    * `file_id` (string, required): The ID of the file to retrieve.
  </Accordion>

  <Accordion title="google_drive/list_files">
    **Description:** List files in Google Drive.

    **Parameters:**

    * `q` (string, optional): Query string to filter files (example: "name contains 'report'").
    * `page_size` (integer, optional): Maximum number of files to return (default: 100, max: 1000).
    * `page_token` (string, optional): Token for retrieving the next page of results.
    * `order_by` (string, optional): Sort order (example: "name", "createdTime desc", "modifiedTime").
    * `spaces` (string, optional): Comma-separated list of spaces to query (drive, appDataFolder, photos).
  </Accordion>

  <Accordion title="google_drive/upload_file">
    **Description:** Upload a file to Google Drive.

    **Parameters:**

    * `name` (string, required): Name of the file to create.
    * `content` (string, required): Content of the file to upload.
    * `mime_type` (string, optional): MIME type of the file (example: "text/plain", "application/pdf").
    * `parent_folder_id` (string, optional): ID of the parent folder where the file should be created.
    * `description` (string, optional): Description of the file.
  </Accordion>

  <Accordion title="google_drive/download_file">
    **Description:** Download a file from Google Drive.

    **Parameters:**

    * `file_id` (string, required): The ID of the file to download.
    * `mime_type` (string, optional): MIME type for export (required for Google Workspace documents).
  </Accordion>

  <Accordion title="google_drive/create_folder">
    **Description:** Create a new folder in Google Drive.

    **Parameters:**

    * `name` (string, required): Name of the folder to create.
    * `parent_folder_id` (string, optional): ID of the parent folder where the new folder should be created.
    * `description` (string, optional): Description of the folder.
  </Accordion>

  <Accordion title="google_drive/delete_file">
    **Description:** Delete a file from Google Drive.

    **Parameters:**

    * `file_id` (string, required): The ID of the file to delete.
  </Accordion>

  <Accordion title="google_drive/share_file">
    **Description:** Share a file in Google Drive with specific users or make it public.

    **Parameters:**

    * `file_id` (string, required): The ID of the file to share.
    * `role` (string, required): The role granted by this permission (reader, writer, commenter, owner).
    * `type` (string, required): The type of the grantee (user, group, domain, anyone).
    * `email_address` (string, optional): The email address of the user or group to share with (required for user/group types).
    * `domain` (string, optional): The domain to share with (required for domain type).
    * `send_notification_email` (boolean, optional): Whether to send a notification email (default: true).
    * `email_message` (string, optional): A plain text custom message to include in the notification email.
  </Accordion>

  <Accordion title="google_drive/update_file">
    **Description:** Update an existing file in Google Drive.

    **Parameters:**

    * `file_id` (string, required): The ID of the file to update.
    * `name` (string, optional): New name for the file.
    * `content` (string, optional): New content for the file.
    * `mime_type` (string, optional): New MIME type for the file.
    * `description` (string, optional): New description for the file.
    * `add_parents` (string, optional): Comma-separated list of parent folder IDs to add.
    * `remove_parents` (string, optional): Comma-separated list of parent folder IDs to remove.
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Google Drive Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with Google Drive capabilities
drive_agent = Agent(
    role="File Manager",
    goal="Manage files and folders in Google Drive efficiently",
    backstory="An AI assistant specialized in document and file management.",
    apps=['google_drive']  # All Google Drive actions will be available
)

# Task to organize files
organize_files_task = Task(
    description="List all files in the root directory and organize them into appropriate folders",
    agent=drive_agent,
    expected_output="Summary of files organized with folder structure"
)

# Run the task
crew = Crew(
    agents=[drive_agent],
    tasks=[organize_files_task]
)

crew.kickoff()
```

### Filtering Specific Google Drive Tools

```python theme={null}
from crewai import Agent, Task, Crew

# Create agent with specific Google Drive actions only
file_manager_agent = Agent(
    role="Document Manager",
    goal="Upload and manage documents efficiently",
    backstory="An AI assistant that focuses on document upload and organization.",
    apps=[
        'google_drive/upload_file',
        'google_drive/create_folder',
        'google_drive/share_file'
    ]  # Specific Google Drive actions
)

# Task to upload and share documents
document_task = Task(
    description="Upload the quarterly report and share it with the finance team",
    agent=file_manager_agent,
    expected_output="Document uploaded and sharing permissions configured"
)

crew = Crew(
    agents=[file_manager_agent],
    tasks=[document_task]
)

crew.kickoff()
```

### Advanced File Management

```python theme={null}
from crewai import Agent, Task, Crew

file_organizer = Agent(
    role="File Organizer",
    goal="Maintain organized file structure and manage permissions",
    backstory="An experienced file manager who ensures proper organization and access control.",
    apps=['google_drive']
)

# Complex task involving multiple Google Drive operations
organization_task = Task(
    description="""
    1. List all files in the shared folder
    2. Create folders for different document types (Reports, Presentations, Spreadsheets)
    3. Move files to appropriate folders based on their type
    4. Set appropriate sharing permissions for each folder
    5. Create a summary document of the organization changes
    """,
    agent=file_organizer,
    expected_output="Files organized into categorized folders with proper permissions and summary report"
)

crew = Crew(
    agents=[file_organizer],
    tasks=[organization_task]
)

crew.kickoff()
```


# Google Sheets Integration
Source: https://docs.crewai.com/en/enterprise/integrations/google_sheets

Spreadsheet data synchronization with Google Sheets integration for CrewAI.

## Overview

Enable your agents to manage spreadsheet data through Google Sheets. Read rows, create new entries, update existing data, and streamline your data management workflows with AI-powered automation. Perfect for data tracking, reporting, and collaborative data management.

## Prerequisites

Before using the Google Sheets integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Google account with Google Sheets access
* Connected your Google account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)
* Spreadsheets with proper column headers for data operations

## Setting Up Google Sheets Integration

### 1. Connect Your Google Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Google Sheets** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for spreadsheet access
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="google_sheets/get_spreadsheet">
    **Description:** Retrieve properties and data of a spreadsheet.

    **Parameters:**

    * `spreadsheetId` (string, required): The ID of the spreadsheet to retrieve.
    * `ranges` (array, optional): The ranges to retrieve from the spreadsheet.
    * `includeGridData` (boolean, optional): True if grid data should be returned. Default: false
    * `fields` (string, optional): The fields to include in the response. Use this to improve performance by only returning needed data.
  </Accordion>

  <Accordion title="google_sheets/get_values">
    **Description:** Returns a range of values from a spreadsheet.

    **Parameters:**

    * `spreadsheetId` (string, required): The ID of the spreadsheet to retrieve data from.
    * `range` (string, required): The A1 notation or R1C1 notation of the range to retrieve values from.
    * `valueRenderOption` (string, optional): How values should be represented in the output. Options: FORMATTED\_VALUE, UNFORMATTED\_VALUE, FORMULA. Default: FORMATTED\_VALUE
    * `dateTimeRenderOption` (string, optional): How dates, times, and durations should be represented in the output. Options: SERIAL\_NUMBER, FORMATTED\_STRING. Default: SERIAL\_NUMBER
    * `majorDimension` (string, optional): The major dimension that results should use. Options: ROWS, COLUMNS. Default: ROWS
  </Accordion>

  <Accordion title="google_sheets/update_values">
    **Description:** Sets values in a range of a spreadsheet.

    **Parameters:**

    * `spreadsheetId` (string, required): The ID of the spreadsheet to update.
    * `range` (string, required): The A1 notation of the range to update.
    * `values` (array, required): The data to be written. Each array represents a row.
      ```json theme={null}
      [
        ["Value1", "Value2", "Value3"],
        ["Value4", "Value5", "Value6"]
      ]
      ```
    * `valueInputOption` (string, optional): How the input data should be interpreted. Options: RAW, USER\_ENTERED. Default: USER\_ENTERED
  </Accordion>

  <Accordion title="google_sheets/append_values">
    **Description:** Appends values to a spreadsheet.

    **Parameters:**

    * `spreadsheetId` (string, required): The ID of the spreadsheet to update.
    * `range` (string, required): The A1 notation of a range to search for a logical table of data.
    * `values` (array, required): The data to append. Each array represents a row.
      ```json theme={null}
      [
        ["Value1", "Value2", "Value3"],
        ["Value4", "Value5", "Value6"]
      ]
      ```
    * `valueInputOption` (string, optional): How the input data should be interpreted. Options: RAW, USER\_ENTERED. Default: USER\_ENTERED
    * `insertDataOption` (string, optional): How the input data should be inserted. Options: OVERWRITE, INSERT\_ROWS. Default: INSERT\_ROWS
  </Accordion>

  <Accordion title="google_sheets/create_spreadsheet">
    **Description:** Creates a new spreadsheet.

    **Parameters:**

    * `title` (string, required): The title of the new spreadsheet.
    * `sheets` (array, optional): The sheets that are part of the spreadsheet.
      ```json theme={null}
      [
        {
          "properties": {
            "title": "Sheet1"
          }
        }
      ]
      ```
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Google Sheets Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with Google Sheets capabilities
sheets_agent = Agent(
    role="Data Manager",
    goal="Manage spreadsheet data and track information efficiently",
    backstory="An AI assistant specialized in data management and spreadsheet operations.",
    apps=['google_sheets']
)

# Task to add new data to a spreadsheet
data_entry_task = Task(
    description="Add a new customer record to the customer database spreadsheet with name, email, and signup date",
    agent=sheets_agent,
    expected_output="New customer record added successfully to the spreadsheet"
)

# Run the task
crew = Crew(
    agents=[sheets_agent],
    tasks=[data_entry_task]
)

crew.kickoff()
```

### Filtering Specific Google Sheets Tools

```python theme={null}
from crewai import Agent, Task, Crew

# Create agent with specific Google Sheets actions only
data_collector = Agent(
    role="Data Collector",
    goal="Collect and organize data in spreadsheets",
    backstory="An AI assistant that focuses on data collection and organization.",
    apps=[
        'google_sheets/get_values',
        'google_sheets/update_values'
    ]
)

# Task to collect and organize data
data_collection = Task(
    description="Retrieve current inventory data and add new product entries to the inventory spreadsheet",
    agent=data_collector,
    expected_output="Inventory data retrieved and new products added successfully"
)

crew = Crew(
    agents=[data_collector],
    tasks=[data_collection]
)

crew.kickoff()
```

### Data Analysis and Reporting

```python theme={null}
from crewai import Agent, Task, Crew

data_analyst = Agent(
    role="Data Analyst",
    goal="Analyze spreadsheet data and generate insights",
    backstory="An experienced data analyst who extracts insights from spreadsheet data.",
    apps=['google_sheets']
)

# Task to analyze data and create reports
analysis_task = Task(
    description="""
    1. Retrieve all sales data from the current month's spreadsheet
    2. Analyze the data for trends and patterns
    3. Create a summary report in a new row with key metrics
    """,
    agent=data_analyst,
    expected_output="Sales data analyzed and summary report created with key insights"
)

crew = Crew(
    agents=[data_analyst],
    tasks=[analysis_task]
)

crew.kickoff()
```

### Spreadsheet Creation and Management

```python theme={null}
from crewai import Agent, Task, Crew

spreadsheet_manager = Agent(
    role="Spreadsheet Manager",
    goal="Create and manage spreadsheets efficiently",
    backstory="An AI assistant that specializes in creating and organizing spreadsheets.",
    apps=['google_sheets']
)

# Task to create and set up new spreadsheets
setup_task = Task(
    description="""
    1. Create a new spreadsheet for quarterly reports
    2. Set up proper headers and structure
    3. Add initial data and formatting
    """,
    agent=spreadsheet_manager,
    expected_output="New quarterly report spreadsheet created and properly structured"
)

crew = Crew(
    agents=[spreadsheet_manager],
    tasks=[setup_task]
)

crew.kickoff()
```

### Automated Data Updates

```python theme={null}
from crewai import Agent, Task, Crew

data_updater = Agent(
    role="Data Updater",
    goal="Automatically update and maintain spreadsheet data",
    backstory="An AI assistant that maintains data accuracy and updates records automatically.",
    apps=['google_sheets']
)

# Task to update data based on conditions
update_task = Task(
    description="""
    1. Get spreadsheet properties and structure
    2. Read current data from specific ranges
    3. Update values in target ranges with new data
    4. Append new records to the bottom of the sheet
    """,
    agent=data_updater,
    expected_output="Spreadsheet data updated successfully with new values and records"
)

crew = Crew(
    agents=[data_updater],
    tasks=[update_task]
)

crew.kickoff()
```

### Complex Data Management Workflow

```python theme={null}
from crewai import Agent, Task, Crew

workflow_manager = Agent(
    role="Data Workflow Manager",
    goal="Manage complex data workflows across multiple spreadsheets",
    backstory="An AI assistant that orchestrates complex data operations across multiple spreadsheets.",
    apps=['google_sheets']
)

# Complex workflow task
workflow_task = Task(
    description="""
    1. Get all customer data from the main customer spreadsheet
    2. Create a new monthly summary spreadsheet
    3. Append summary data to the new spreadsheet
    4. Update customer status based on activity metrics
    5. Generate reports with proper formatting
    """,
    agent=workflow_manager,
    expected_output="Monthly customer workflow completed with new spreadsheet and updated data"
)

crew = Crew(
    agents=[workflow_manager],
    tasks=[workflow_task]
)

crew.kickoff()
```

## Troubleshooting

### Common Issues

**Permission Errors**

* Ensure your Google account has edit access to the target spreadsheets
* Verify that the OAuth connection includes required scopes for Google Sheets API
* Check that spreadsheets are shared with the authenticated account

**Spreadsheet Structure Issues**

* Ensure worksheets have proper column headers before creating or updating rows
* Verify that range notation (A1 format) is correct for the target cells
* Check that the specified spreadsheet ID exists and is accessible

**Data Type and Format Issues**

* Ensure data values match the expected format for each column
* Use proper date formats for date columns (ISO format recommended)
* Verify that numeric values are properly formatted for number columns

**Range and Cell Reference Issues**

* Use proper A1 notation for ranges (e.g., "A1:C10", "Sheet1!A1:B5")
* Ensure range references don't exceed the actual spreadsheet dimensions
* Verify that sheet names in range references match actual sheet names

**Value Input and Rendering Options**

* Choose appropriate `valueInputOption` (RAW vs USER\_ENTERED) for your data
* Select proper `valueRenderOption` based on how you want data formatted
* Consider `dateTimeRenderOption` for consistent date/time handling

**Spreadsheet Creation Issues**

* Ensure spreadsheet titles are unique and follow naming conventions
* Verify that sheet properties are properly structured when creating sheets
* Check that you have permissions to create new spreadsheets in your account

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Google Sheets integration setup
  or troubleshooting.
</Card>


# Google Slides Integration
Source: https://docs.crewai.com/en/enterprise/integrations/google_slides

Presentation creation and management with Google Slides integration for CrewAI.

## Overview

Enable your agents to create, edit, and manage Google Slides presentations. Create presentations, update content, import data from Google Sheets, manage pages and thumbnails, and streamline your presentation workflows with AI-powered automation.

## Prerequisites

Before using the Google Slides integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Google account with Google Slides access
* Connected your Google account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up Google Slides Integration

### 1. Connect Your Google Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Google Slides** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for presentations, spreadsheets, and drive access
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="google_slides/create_blank_presentation">
    **Description:** Creates a blank presentation with no content.

    **Parameters:**

    * `title` (string, required): The title of the presentation.
  </Accordion>

  <Accordion title="google_slides/get_presentation_metadata">
    **Description:** Get lightweight metadata about a presentation (title, slide count, slide IDs). Use this first before fetching full content.

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation to retrieve.
  </Accordion>

  <Accordion title="google_slides/get_presentation_text">
    **Description:** Extract all text content from a presentation. Returns slide IDs and text from shapes and tables only (no formatting).

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation.
  </Accordion>

  <Accordion title="google_slides/get_presentation">
    **Description:** Retrieves a presentation by ID.

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation to retrieve.
    * `fields` (string, optional): The fields to include in the response. Use this to improve performance by only returning needed data.
  </Accordion>

  <Accordion title="google_slides/batch_update_presentation">
    **Description:** Applies updates, add content, or remove content from a presentation.

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation to update.
    * `requests` (array, required): A list of updates to apply to the presentation.
      ```json theme={null}
      [
        {
          "insertText": {
            "objectId": "slide_id",
            "text": "Your text content here"
          }
        }
      ]
      ```
    * `writeControl` (object, optional): Provides control over how write requests are executed.
      ```json theme={null}
      {
        "requiredRevisionId": "revision_id_string"
      }
      ```
  </Accordion>

  <Accordion title="google_slides/get_slide_text">
    **Description:** Extract text content from a single slide. Returns only text from shapes and tables (no formatting or styling).

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation.
    * `pageObjectId` (string, required): The ID of the slide/page to get text from.
  </Accordion>

  <Accordion title="google_slides/get_page">
    **Description:** Retrieves a specific page by its ID.

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation.
    * `pageObjectId` (string, required): The ID of the page to retrieve.
  </Accordion>

  <Accordion title="google_slides/get_thumbnail">
    **Description:** Generates a page thumbnail.

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation.
    * `pageObjectId` (string, required): The ID of the page for thumbnail generation.
  </Accordion>

  <Accordion title="google_slides/create_slide">
    **Description:** Add an additional blank slide to a presentation. New presentations already have one blank slide - check get\_presentation\_metadata first. For slides with title/body areas, use create\_slide\_with\_layout instead.

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation.
    * `insertionIndex` (integer, optional): Where to insert the slide (0-based). If omitted, adds at the end.
  </Accordion>

  <Accordion title="google_slides/create_slide_with_layout">
    **Description:** Create a slide with a predefined layout containing placeholder areas for title, body, etc. This is better than create\_slide for structured content. After creating, use get\_page to find placeholder IDs, then insert text into them.

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation.
    * `layout` (string, required): Layout type. One of: `BLANK`, `TITLE`, `TITLE_AND_BODY`, `TITLE_AND_TWO_COLUMNS`, `TITLE_ONLY`, `SECTION_HEADER`, `ONE_COLUMN_TEXT`, `MAIN_POINT`, `BIG_NUMBER`. TITLE\_AND\_BODY is best for title+description. TITLE for title-only slides. SECTION\_HEADER for section dividers.
    * `insertionIndex` (integer, optional): Where to insert (0-based). Omit to add at end.
  </Accordion>

  <Accordion title="google_slides/create_text_box">
    **Description:** Create a text box on a slide with content. Use this for titles, descriptions, paragraphs - not tables. Optionally specify position (x, y) and size (width, height) in EMU units (914400 EMU = 1 inch).

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation.
    * `slideId` (string, required): The ID of the slide to add the text box to.
    * `text` (string, required): The text content for the text box.
    * `x` (integer, optional): X position in EMU (914400 = 1 inch). Default: 914400 (1 inch from left).
    * `y` (integer, optional): Y position in EMU (914400 = 1 inch). Default: 914400 (1 inch from top).
    * `width` (integer, optional): Width in EMU. Default: 7315200 (\~8 inches).
    * `height` (integer, optional): Height in EMU. Default: 914400 (\~1 inch).
  </Accordion>

  <Accordion title="google_slides/delete_slide">
    **Description:** Remove a slide from the presentation. Use get\_presentation first to find the slide ID.

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation.
    * `slideId` (string, required): The object ID of the slide to delete. Get from get\_presentation.
  </Accordion>

  <Accordion title="google_slides/duplicate_slide">
    **Description:** Create a copy of an existing slide. The duplicate is inserted immediately after the original.

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation.
    * `slideId` (string, required): The object ID of the slide to duplicate. Get from get\_presentation.
  </Accordion>

  <Accordion title="google_slides/move_slides">
    **Description:** Reorder slides by moving them to a new position. Slide IDs must be in their current presentation order (no duplicates).

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation.
    * `slideIds` (array of strings, required): Array of slide IDs to move. Must be in current presentation order.
    * `insertionIndex` (integer, required): Target position (0-based). 0 = beginning, slide count = end.
  </Accordion>

  <Accordion title="google_slides/insert_youtube_video">
    **Description:** Embed a YouTube video on a slide. The video ID is the value after "v=" in YouTube URLs (e.g., for youtube.com/watch?v=abc123, use "abc123").

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation.
    * `slideId` (string, required): The ID of the slide to add the video to. Get from get\_presentation.
    * `videoId` (string, required): The YouTube video ID (the value after v= in the URL).
  </Accordion>

  <Accordion title="google_slides/insert_drive_video">
    **Description:** Embed a video from Google Drive on a slide. The file ID can be found in the Drive file URL.

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation.
    * `slideId` (string, required): The ID of the slide to add the video to. Get from get\_presentation.
    * `fileId` (string, required): The Google Drive file ID of the video.
  </Accordion>

  <Accordion title="google_slides/set_slide_background_image">
    **Description:** Set a background image for a slide. The image URL must be publicly accessible.

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation.
    * `slideId` (string, required): The ID of the slide to set the background for. Get from get\_presentation.
    * `imageUrl` (string, required): Publicly accessible URL of the image to use as background.
  </Accordion>

  <Accordion title="google_slides/create_table">
    **Description:** Create an empty table on a slide. To create a table with content, use create\_table\_with\_content instead.

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation.
    * `slideId` (string, required): The ID of the slide to add the table to. Get from get\_presentation.
    * `rows` (integer, required): Number of rows in the table.
    * `columns` (integer, required): Number of columns in the table.
  </Accordion>

  <Accordion title="google_slides/create_table_with_content">
    **Description:** Create a table with content in one action. Provide content as a 2D array where each inner array is a row. Example: \[\["Header1", "Header2"], \["Row1Col1", "Row1Col2"]].

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation.
    * `slideId` (string, required): The ID of the slide to add the table to. Get from get\_presentation.
    * `rows` (integer, required): Number of rows in the table.
    * `columns` (integer, required): Number of columns in the table.
    * `content` (array, required): Table content as 2D array. Each inner array is a row. Example: \[\["Year", "Revenue"], \["2023", "\$10M"]].
  </Accordion>

  <Accordion title="google_slides/import_data_from_sheet">
    **Description:** Imports data from a Google Sheet into a presentation.

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation.
    * `sheetId` (string, required): The ID of the Google Sheet to import from.
    * `dataRange` (string, required): The range of data to import from the sheet.
  </Accordion>

  <Accordion title="google_slides/upload_file_to_drive">
    **Description:** Uploads a file to Google Drive associated with the presentation.

    **Parameters:**

    * `file` (string, required): The file data to upload.
    * `presentationId` (string, required): The ID of the presentation to link the uploaded file.
  </Accordion>

  <Accordion title="google_slides/link_file_to_presentation">
    **Description:** Links a file in Google Drive to a presentation.

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation.
    * `fileId` (string, required): The ID of the file to link.
  </Accordion>

  <Accordion title="google_slides/get_all_presentations">
    **Description:** Lists all presentations accessible to the user.

    **Parameters:**

    * `pageSize` (integer, optional): The number of presentations to return per page.
    * `pageToken` (string, optional): A token for pagination.
  </Accordion>

  <Accordion title="google_slides/delete_presentation">
    **Description:** Deletes a presentation by ID.

    **Parameters:**

    * `presentationId` (string, required): The ID of the presentation to delete.
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Google Slides Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with Google Slides capabilities
slides_agent = Agent(
    role="Presentation Manager",
    goal="Create and manage presentations efficiently",
    backstory="An AI assistant specialized in presentation creation and content management.",
    apps=['google_slides']  # All Google Slides actions will be available
)

# Task to create a presentation
create_presentation_task = Task(
    description="Create a new presentation for the quarterly business review with key slides",
    agent=slides_agent,
    expected_output="Quarterly business review presentation created with structured content"
)

# Run the task
crew = Crew(
    agents=[slides_agent],
    tasks=[create_presentation_task]
)

crew.kickoff()
```

### Presentation Content Management

```python theme={null}
from crewai import Agent, Task, Crew

content_manager = Agent(
    role="Content Manager",
    goal="Manage presentation content and updates",
    backstory="An AI assistant that focuses on content creation and presentation updates.",
    apps=[
        'google_slides/create_blank_presentation',
        'google_slides/batch_update_presentation',
        'google_slides/get_presentation'
    ]
)

# Task to create and update presentations
content_task = Task(
    description="Create a new presentation and add content slides with charts and text",
    agent=content_manager,
    expected_output="Presentation created with updated content and visual elements"
)

crew = Crew(
    agents=[content_manager],
    tasks=[content_task]
)

crew.kickoff()
```

### Data Integration and Visualization

```python theme={null}
from crewai import Agent, Task, Crew

data_visualizer = Agent(
    role="Data Visualizer",
    goal="Create presentations with data imported from spreadsheets",
    backstory="An AI assistant that specializes in data visualization and presentation integration.",
    apps=['google_slides']
)

# Task to create data-driven presentations
visualization_task = Task(
    description="""
    1. Create a new presentation for monthly sales report
    2. Import data from the sales spreadsheet
    3. Create charts and visualizations from the imported data
    4. Generate thumbnails for slide previews
    """,
    agent=data_visualizer,
    expected_output="Data-driven presentation created with imported spreadsheet data and visualizations"
)

crew = Crew(
    agents=[data_visualizer],
    tasks=[visualization_task]
)

crew.kickoff()
```

### Presentation Library Management

```python theme={null}
from crewai import Agent, Task, Crew

library_manager = Agent(
    role="Presentation Library Manager",
    goal="Manage and organize presentation libraries",
    backstory="An AI assistant that manages presentation collections and file organization.",
    apps=['google_slides']
)

# Task to manage presentation library
library_task = Task(
    description="""
    1. List all existing presentations
    2. Generate thumbnails for presentation previews
    3. Upload supporting files to Drive and link to presentations
    4. Organize presentations by topic and date
    """,
    agent=library_manager,
    expected_output="Presentation library organized with thumbnails and linked supporting files"
)

crew = Crew(
    agents=[library_manager],
    tasks=[library_task]
)

crew.kickoff()
```

### Automated Presentation Workflows

```python theme={null}
from crewai import Agent, Task, Crew

presentation_automator = Agent(
    role="Presentation Automator",
    goal="Automate presentation creation and management workflows",
    backstory="An AI assistant that automates complex presentation workflows and content generation.",
    apps=['google_slides']
)

# Complex presentation automation task
automation_task = Task(
    description="""
    1. Create multiple presentations for different departments
    2. Import relevant data from various spreadsheets
    3. Update existing presentations with new content
    4. Generate thumbnails for all presentations
    5. Link supporting documents from Drive
    6. Create a master index presentation with links to all others
    """,
    agent=presentation_automator,
    expected_output="Automated presentation workflow completed with multiple presentations and organized structure"
)

crew = Crew(
    agents=[presentation_automator],
    tasks=[automation_task]
)

crew.kickoff()
```

### Template and Content Creation

```python theme={null}
from crewai import Agent, Task, Crew

template_creator = Agent(
    role="Template Creator",
    goal="Create presentation templates and standardized content",
    backstory="An AI assistant that creates consistent presentation templates and content standards.",
    apps=['google_slides']
)

# Task to create templates
template_task = Task(
    description="""
    1. Create blank presentation templates for different use cases
    2. Add standard layouts and content placeholders
    3. Create sample presentations with best practices
    4. Generate thumbnails for template previews
    5. Upload template assets to Drive and link appropriately
    """,
    agent=template_creator,
    expected_output="Presentation templates created with standardized layouts and linked assets"
)

crew = Crew(
    agents=[template_creator],
    tasks=[template_task]
)

crew.kickoff()
```

## Troubleshooting

### Common Issues

**Permission Errors**

* Ensure your Google account has appropriate permissions for Google Slides
* Verify that the OAuth connection includes required scopes for presentations, spreadsheets, and drive access
* Check that presentations are shared with the authenticated account

**Presentation ID Issues**

* Verify that presentation IDs are correct and presentations exist
* Ensure you have access permissions to the presentations you're trying to modify
* Check that presentation IDs are properly formatted

**Content Update Issues**

* Ensure batch update requests are properly formatted according to Google Slides API specifications
* Verify that object IDs for slides and elements exist in the presentation
* Check that write control revision IDs are current if using optimistic concurrency

**Data Import Issues**

* Verify that Google Sheet IDs are correct and accessible
* Ensure data ranges are properly specified using A1 notation
* Check that you have read permissions for the source spreadsheets

**File Upload and Linking Issues**

* Ensure file data is properly encoded for upload
* Verify that Drive file IDs are correct when linking files
* Check that you have appropriate Drive permissions for file operations

**Page and Thumbnail Operations**

* Verify that page object IDs exist in the specified presentation
* Ensure presentations have content before attempting to generate thumbnails
* Check that page structure is valid for thumbnail generation

**Pagination and Listing Issues**

* Use appropriate page sizes for listing presentations
* Implement proper pagination using page tokens for large result sets
* Handle empty result sets gracefully

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Google Slides integration setup
  or troubleshooting.
</Card>


# HubSpot Integration
Source: https://docs.crewai.com/en/enterprise/integrations/hubspot

Manage companies and contacts in HubSpot with CrewAI.

## Overview

Enable your agents to manage companies and contacts within HubSpot. Create new records and streamline your CRM processes with AI-powered automation.

## Prerequisites

Before using the HubSpot integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription.
* A HubSpot account with appropriate permissions.
* Connected your HubSpot account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors).

## Setting Up HubSpot Integration

### 1. Connect Your HubSpot Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors).
2. Find **HubSpot** in the Authentication Integrations section.
3. Click **Connect** and complete the OAuth flow.
4. Grant the necessary permissions for company and contact management.
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="hubspot/create_company">
    **Description:** Create a new company record in HubSpot.

    **Parameters:**

    * `name` (string, required): Name of the company.
    * `domain` (string, optional): Company Domain Name.
    * `industry` (string, optional): Industry. Must be one of the predefined values from HubSpot.
    * `phone` (string, optional): Phone Number.
    * `hubspot_owner_id` (string, optional): Company owner ID.
    * `type` (string, optional): Type of the company. Available values: `PROSPECT`, `PARTNER`, `RESELLER`, `VENDOR`, `OTHER`.
    * `city` (string, optional): City.
    * `state` (string, optional): State/Region.
    * `zip` (string, optional): Postal Code.
    * `numberofemployees` (number, optional): Number of Employees.
    * `annualrevenue` (number, optional): Annual Revenue.
    * `timezone` (string, optional): Time Zone.
    * `description` (string, optional): Description.
    * `linkedin_company_page` (string, optional): LinkedIn Company Page URL.
    * `company_email` (string, optional): Company Email.
    * `first_name` (string, optional): First Name of a contact at the company.
    * `last_name` (string, optional): Last Name of a contact at the company.
    * `about_us` (string, optional): About Us.
    * `hs_csm_sentiment` (string, optional): CSM Sentiment. Available values: `at_risk`, `neutral`, `healthy`.
    * `closedate` (string, optional): Close Date.
    * `hs_keywords` (string, optional): Company Keywords. Must be one of the predefined values.
    * `country` (string, optional): Country/Region.
    * `hs_country_code` (string, optional): Country/Region Code.
    * `hs_employee_range` (string, optional): Employee range.
    * `facebook_company_page` (string, optional): Facebook Company Page URL.
    * `facebookfans` (number, optional): Number of Facebook Fans.
    * `hs_gps_coordinates` (string, optional): GPS Coordinates.
    * `hs_gps_error` (string, optional): GPS Error.
    * `googleplus_page` (string, optional): Google Plus Page URL.
    * `owneremail` (string, optional): HubSpot Owner Email.
    * `ownername` (string, optional): HubSpot Owner Name.
    * `hs_ideal_customer_profile` (string, optional): Ideal Customer Profile Tier. Available values: `tier_1`, `tier_2`, `tier_3`.
    * `hs_industry_group` (string, optional): Industry group.
    * `is_public` (boolean, optional): Is Public.
    * `hs_last_metered_enrichment_timestamp` (string, optional): Last Metered Enrichment Timestamp.
    * `hs_lead_status` (string, optional): Lead Status. Available values: `NEW`, `OPEN`, `IN_PROGRESS`, `OPEN_DEAL`, `UNQUALIFIED`, `ATTEMPTED_TO_CONTACT`, `CONNECTED`, `BAD_TIMING`.
    * `lifecyclestage` (string, optional): Lifecycle Stage. Available values: `subscriber`, `lead`, `marketingqualifiedlead`, `salesqualifiedlead`, `opportunity`, `customer`, `evangelist`, `other`.
    * `linkedinbio` (string, optional): LinkedIn Bio.
    * `hs_linkedin_handle` (string, optional): LinkedIn handle.
    * `hs_live_enrichment_deadline` (string, optional): Live enrichment deadline.
    * `hs_logo_url` (string, optional): Logo URL.
    * `hs_analytics_source` (string, optional): Original Traffic Source.
    * `hs_pinned_engagement_id` (number, optional): Pinned Engagement ID.
    * `hs_quick_context` (string, optional): Quick context.
    * `hs_revenue_range` (string, optional): Revenue range.
    * `hs_state_code` (string, optional): State/Region Code.
    * `address` (string, optional): Street Address.
    * `address2` (string, optional): Street Address 2.
    * `hs_is_target_account` (boolean, optional): Target Account.
    * `hs_target_account` (string, optional): Target Account Tier. Available values: `tier_1`, `tier_2`, `tier_3`.
    * `hs_target_account_recommendation_snooze_time` (string, optional): Target Account Recommendation Snooze Time.
    * `hs_target_account_recommendation_state` (string, optional): Target Account Recommendation State. Available values: `DISMISSED`, `NONE`, `SNOOZED`.
    * `total_money_raised` (string, optional): Total Money Raised.
    * `twitterbio` (string, optional): Twitter Bio.
    * `twitterfollowers` (number, optional): Twitter Followers.
    * `twitterhandle` (string, optional): Twitter Handle.
    * `web_technologies` (string, optional): Web Technologies used. Must be one of the predefined values.
    * `website` (string, optional): Website URL.
    * `founded_year` (string, optional): Year Founded.
  </Accordion>

  <Accordion title="hubspot/create_contact">
    **Description:** Create a new contact record in HubSpot.

    **Parameters:**

    * `email` (string, required): Email address of the contact.
    * `firstname` (string, optional): First Name.
    * `lastname` (string, optional): Last Name.
    * `phone` (string, optional): Phone Number.
    * `hubspot_owner_id` (string, optional): Contact owner.
    * `lifecyclestage` (string, optional): Lifecycle Stage. Available values: `subscriber`, `lead`, `marketingqualifiedlead`, `salesqualifiedlead`, `opportunity`, `customer`, `evangelist`, `other`.
    * `hs_lead_status` (string, optional): Lead Status. Available values: `NEW`, `OPEN`, `IN_PROGRESS`, `OPEN_DEAL`, `UNQUALIFIED`, `ATTEMPTED_TO_CONTACT`, `CONNECTED`, `BAD_TIMING`.
    * `annualrevenue` (string, optional): Annual Revenue.
    * `hs_buying_role` (string, optional): Buying Role.
    * `cc_emails` (string, optional): CC Emails.
    * `ch_customer_id` (string, optional): Chargify Customer ID.
    * `ch_customer_reference` (string, optional): Chargify Customer Reference.
    * `chargify_sites` (string, optional): Chargify Site(s).
    * `city` (string, optional): City.
    * `hs_facebook_ad_clicked` (boolean, optional): Clicked Facebook ad.
    * `hs_linkedin_ad_clicked` (string, optional): Clicked LinkedIn Ad.
    * `hs_clicked_linkedin_ad` (string, optional): Clicked on a LinkedIn Ad.
    * `closedate` (string, optional): Close Date.
    * `company` (string, optional): Company Name.
    * `company_size` (string, optional): Company size.
    * `country` (string, optional): Country/Region.
    * `hs_country_region_code` (string, optional): Country/Region Code.
    * `date_of_birth` (string, optional): Date of birth.
    * `degree` (string, optional): Degree.
    * `hs_email_customer_quarantined_reason` (string, optional): Email address quarantine reason.
    * `hs_role` (string, optional): Employment Role. Must be one of the predefined values.
    * `hs_seniority` (string, optional): Employment Seniority. Must be one of the predefined values.
    * `hs_sub_role` (string, optional): Employment Sub Role. Must be one of the predefined values.
    * `hs_employment_change_detected_date` (string, optional): Employment change detected date.
    * `hs_enriched_email_bounce_detected` (boolean, optional): Enriched Email Bounce Detected.
    * `hs_facebookid` (string, optional): Facebook ID.
    * `hs_facebook_click_id` (string, optional): Facebook click id.
    * `fax` (string, optional): Fax Number.
    * `field_of_study` (string, optional): Field of study.
    * `followercount` (number, optional): Follower Count.
    * `gender` (string, optional): Gender.
    * `hs_google_click_id` (string, optional): Google ad click id.
    * `graduation_date` (string, optional): Graduation date.
    * `owneremail` (string, optional): HubSpot Owner Email (legacy).
    * `ownername` (string, optional): HubSpot Owner Name (legacy).
    * `industry` (string, optional): Industry.
    * `hs_inferred_language_codes` (string, optional): Inferred Language Codes. Must be one of the predefined values.
    * `jobtitle` (string, optional): Job Title.
    * `hs_job_change_detected_date` (string, optional): Job change detected date.
    * `job_function` (string, optional): Job function.
    * `hs_journey_stage` (string, optional): Journey Stage. Must be one of the predefined values.
    * `kloutscoregeneral` (number, optional): Klout Score.
    * `hs_last_metered_enrichment_timestamp` (string, optional): Last Metered Enrichment Timestamp.
    * `hs_latest_source` (string, optional): Latest Traffic Source.
    * `hs_latest_source_timestamp` (string, optional): Latest Traffic Source Date.
    * `hs_legal_basis` (string, optional): Legal basis for processing contact's data.
    * `linkedinbio` (string, optional): LinkedIn Bio.
    * `linkedinconnections` (number, optional): LinkedIn Connections.
    * `hs_linkedin_url` (string, optional): LinkedIn URL.
    * `hs_linkedinid` (string, optional): Linkedin ID.
    * `hs_live_enrichment_deadline` (string, optional): Live enrichment deadline.
    * `marital_status` (string, optional): Marital Status.
    * `hs_content_membership_email` (string, optional): Member email.
    * `hs_content_membership_notes` (string, optional): Membership Notes.
    * `message` (string, optional): Message.
    * `military_status` (string, optional): Military status.
    * `mobilephone` (string, optional): Mobile Phone Number.
    * `numemployees` (string, optional): Number of Employees.
    * `hs_analytics_source` (string, optional): Original Traffic Source.
    * `photo` (string, optional): Photo.
    * `hs_pinned_engagement_id` (number, optional): Pinned engagement ID.
    * `zip` (string, optional): Postal Code.
    * `hs_language` (string, optional): Preferred language. Must be one of the predefined values.
    * `associatedcompanyid` (number, optional): Primary Associated Company ID.
    * `hs_email_optout_survey_reason` (string, optional): Reason for opting out of email.
    * `relationship_status` (string, optional): Relationship Status.
    * `hs_returning_to_office_detected_date` (string, optional): Returning to office detected date.
    * `salutation` (string, optional): Salutation.
    * `school` (string, optional): School.
    * `seniority` (string, optional): Seniority.
    * `hs_feedback_show_nps_web_survey` (boolean, optional): Should be shown an NPS web survey.
    * `start_date` (string, optional): Start date.
    * `state` (string, optional): State/Region.
    * `hs_state_code` (string, optional): State/Region Code.
    * `hs_content_membership_status` (string, optional): Status.
    * `address` (string, optional): Street Address.
    * `tax_exempt` (string, optional): Tax Exempt.
    * `hs_timezone` (string, optional): Time Zone. Must be one of the predefined values.
    * `twitterbio` (string, optional): Twitter Bio.
    * `hs_twitterid` (string, optional): Twitter ID.
    * `twitterprofilephoto` (string, optional): Twitter Profile Photo.
    * `twitterhandle` (string, optional): Twitter Username.
    * `vat_number` (string, optional): VAT Number.
    * `ch_verified` (string, optional): Verified for ACH/eCheck Payments.
    * `website` (string, optional): Website URL.
    * `hs_whatsapp_phone_number` (string, optional): WhatsApp Phone Number.
    * `work_email` (string, optional): Work email.
    * `hs_googleplusid` (string, optional): googleplus ID.
  </Accordion>

  <Accordion title="hubspot/create_deal">
    **Description:** Create a new deal record in HubSpot.

    **Parameters:**

    * `dealname` (string, required): Name of the deal.
    * `amount` (number, optional): The value of the deal.
    * `dealstage` (string, optional): The pipeline stage of the deal.
    * `pipeline` (string, optional): The pipeline the deal belongs to.
    * `closedate` (string, optional): The date the deal is expected to close.
    * `hubspot_owner_id` (string, optional): The owner of the deal.
    * `dealtype` (string, optional): The type of deal. Available values: `newbusiness`, `existingbusiness`.
    * `description` (string, optional): A description of the deal.
    * `hs_priority` (string, optional): The priority of the deal. Available values: `low`, `medium`, `high`.
  </Accordion>

  <Accordion title="hubspot/create_record_engagements">
    **Description:** Create a new engagement (e.g., note, email, call, meeting, task) in HubSpot.

    **Parameters:**

    * `engagementType` (string, required): The type of engagement. Available values: `NOTE`, `EMAIL`, `CALL`, `MEETING`, `TASK`.
    * `hubspot_owner_id` (string, optional): The user the activity is assigned to.
    * `hs_timestamp` (string, optional): The date and time of the activity.
    * `hs_note_body` (string, optional): The body of the note. (Used for `NOTE`)
    * `hs_task_subject` (string, optional): The title of the task. (Used for `TASK`)
    * `hs_task_body` (string, optional): The notes for the task. (Used for `TASK`)
    * `hs_task_status` (string, optional): The status of the task. (Used for `TASK`)
    * `hs_meeting_title` (string, optional): The title of the meeting. (Used for `MEETING`)
    * `hs_meeting_body` (string, optional): The description for the meeting. (Used for `MEETING`)
    * `hs_meeting_start_time` (string, optional): The start time of the meeting. (Used for `MEETING`)
    * `hs_meeting_end_time` (string, optional): The end time of the meeting. (Used for `MEETING`)
  </Accordion>

  <Accordion title="hubspot/update_company">
    **Description:** Update an existing company record in HubSpot.

    **Parameters:**

    * `recordId` (string, required): The ID of the company to update.
    * `name` (string, optional): Name of the company.
    * `domain` (string, optional): Company Domain Name.
    * `industry` (string, optional): Industry.
    * `phone` (string, optional): Phone Number.
    * `city` (string, optional): City.
    * `state` (string, optional): State/Region.
    * `zip` (string, optional): Postal Code.
    * `numberofemployees` (number, optional): Number of Employees.
    * `annualrevenue` (number, optional): Annual Revenue.
    * `description` (string, optional): Description.
  </Accordion>

  <Accordion title="hubspot/create_record_any">
    **Description:** Create a record for a specified object type in HubSpot.

    **Parameters:**

    * `recordType` (string, required): The object type ID of the custom object.
    * Additional parameters depend on the custom object's schema.
  </Accordion>

  <Accordion title="hubspot/update_contact">
    **Description:** Update an existing contact record in HubSpot.

    **Parameters:**

    * `recordId` (string, required): The ID of the contact to update.
    * `firstname` (string, optional): First Name.
    * `lastname` (string, optional): Last Name.
    * `email` (string, optional): Email address.
    * `phone` (string, optional): Phone Number.
    * `company` (string, optional): Company Name.
    * `jobtitle` (string, optional): Job Title.
    * `lifecyclestage` (string, optional): Lifecycle Stage.
  </Accordion>

  <Accordion title="hubspot/update_deal">
    **Description:** Update an existing deal record in HubSpot.

    **Parameters:**

    * `recordId` (string, required): The ID of the deal to update.
    * `dealname` (string, optional): Name of the deal.
    * `amount` (number, optional): The value of the deal.
    * `dealstage` (string, optional): The pipeline stage of the deal.
    * `pipeline` (string, optional): The pipeline the deal belongs to.
    * `closedate` (string, optional): The date the deal is expected to close.
    * `dealtype` (string, optional): The type of deal.
  </Accordion>

  <Accordion title="hubspot/update_record_engagements">
    **Description:** Update an existing engagement in HubSpot.

    **Parameters:**

    * `recordId` (string, required): The ID of the engagement to update.
    * `hs_note_body` (string, optional): The body of the note.
    * `hs_task_subject` (string, optional): The title of the task.
    * `hs_task_body` (string, optional): The notes for the task.
    * `hs_task_status` (string, optional): The status of the task.
  </Accordion>

  <Accordion title="hubspot/update_record_any">
    **Description:** Update a record for a specified object type in HubSpot.

    **Parameters:**

    * `recordId` (string, required): The ID of the record to update.
    * `recordType` (string, required): The object type ID of the custom object.
    * Additional parameters depend on the custom object's schema.
  </Accordion>

  <Accordion title="hubspot/list_companies">
    **Description:** Get a list of company records from HubSpot.

    **Parameters:**

    * `paginationParameters` (object, optional): Use `pageCursor` to fetch subsequent pages.
  </Accordion>

  <Accordion title="hubspot/list_contacts">
    **Description:** Get a list of contact records from HubSpot.

    **Parameters:**

    * `paginationParameters` (object, optional): Use `pageCursor` to fetch subsequent pages.
  </Accordion>

  <Accordion title="hubspot/list_deals">
    **Description:** Get a list of deal records from HubSpot.

    **Parameters:**

    * `paginationParameters` (object, optional): Use `pageCursor` to fetch subsequent pages.
  </Accordion>

  <Accordion title="hubspot/get_records_engagements">
    **Description:** Get a list of engagement records from HubSpot.

    **Parameters:**

    * `objectName` (string, required): The type of engagement to fetch (e.g., "notes").
    * `paginationParameters` (object, optional): Use `pageCursor` to fetch subsequent pages.
  </Accordion>

  <Accordion title="hubspot/get_records_any">
    **Description:** Get a list of records for any specified object type in HubSpot.

    **Parameters:**

    * `recordType` (string, required): The object type ID of the custom object.
    * `paginationParameters` (object, optional): Use `pageCursor` to fetch subsequent pages.
  </Accordion>

  <Accordion title="hubspot/get_company">
    **Description:** Get a single company record by its ID.

    **Parameters:**

    * `recordId` (string, required): The ID of the company to retrieve.
  </Accordion>

  <Accordion title="hubspot/get_contact">
    **Description:** Get a single contact record by its ID.

    **Parameters:**

    * `recordId` (string, required): The ID of the contact to retrieve.
  </Accordion>

  <Accordion title="hubspot/get_deal">
    **Description:** Get a single deal record by its ID.

    **Parameters:**

    * `recordId` (string, required): The ID of the deal to retrieve.
  </Accordion>

  <Accordion title="hubspot/get_record_by_id_engagements">
    **Description:** Get a single engagement record by its ID.

    **Parameters:**

    * `recordId` (string, required): The ID of the engagement to retrieve.
  </Accordion>

  <Accordion title="hubspot/get_record_by_id_any">
    **Description:** Get a single record of any specified object type by its ID.

    **Parameters:**

    * `recordType` (string, required): The object type ID of the custom object.
    * `recordId` (string, required): The ID of the record to retrieve.
  </Accordion>

  <Accordion title="hubspot/search_companies">
    **Description:** Search for company records in HubSpot using a filter formula.

    **Parameters:**

    * `filterFormula` (object, optional): A filter in disjunctive normal form (OR of ANDs).
    * `paginationParameters` (object, optional): Use `pageCursor` to fetch subsequent pages.
  </Accordion>

  <Accordion title="hubspot/search_contacts">
    **Description:** Search for contact records in HubSpot using a filter formula.

    **Parameters:**

    * `filterFormula` (object, optional): A filter in disjunctive normal form (OR of ANDs).
    * `paginationParameters` (object, optional): Use `pageCursor` to fetch subsequent pages.
  </Accordion>

  <Accordion title="hubspot/search_deals">
    **Description:** Search for deal records in HubSpot using a filter formula.

    **Parameters:**

    * `filterFormula` (object, optional): A filter in disjunctive normal form (OR of ANDs).
    * `paginationParameters` (object, optional): Use `pageCursor` to fetch subsequent pages.
  </Accordion>

  <Accordion title="hubspot/search_records_engagements">
    **Description:** Search for engagement records in HubSpot using a filter formula.

    **Parameters:**

    * `engagementFilterFormula` (object, optional): A filter for engagements.
    * `paginationParameters` (object, optional): Use `pageCursor` to fetch subsequent pages.
  </Accordion>

  <Accordion title="hubspot/search_records_any">
    **Description:** Search for records of any specified object type in HubSpot.

    **Parameters:**

    * `recordType` (string, required): The object type ID to search.
    * `filterFormula` (string, optional): The filter formula to apply.
    * `paginationParameters` (object, optional): Use `pageCursor` to fetch subsequent pages.
  </Accordion>

  <Accordion title="hubspot/delete_record_companies">
    **Description:** Delete a company record by its ID.

    **Parameters:**

    * `recordId` (string, required): The ID of the company to delete.
  </Accordion>

  <Accordion title="hubspot/delete_record_contacts">
    **Description:** Delete a contact record by its ID.

    **Parameters:**

    * `recordId` (string, required): The ID of the contact to delete.
  </Accordion>

  <Accordion title="hubspot/delete_record_deals">
    **Description:** Delete a deal record by its ID.

    **Parameters:**

    * `recordId` (string, required): The ID of the deal to delete.
  </Accordion>

  <Accordion title="hubspot/delete_record_engagements">
    **Description:** Delete an engagement record by its ID.

    **Parameters:**

    * `recordId` (string, required): The ID of the engagement to delete.
  </Accordion>

  <Accordion title="hubspot/delete_record_any">
    **Description:** Delete a record of any specified object type by its ID.

    **Parameters:**

    * `recordType` (string, required): The object type ID of the custom object.
    * `recordId` (string, required): The ID of the record to delete.
  </Accordion>

  <Accordion title="hubspot/get_contacts_by_list_id">
    **Description:** Get contacts from a specific list by its ID.

    **Parameters:**

    * `listId` (string, required): The ID of the list to get contacts from.
    * `paginationParameters` (object, optional): Use `pageCursor` for subsequent pages.
  </Accordion>

  <Accordion title="hubspot/describe_action_schema">
    **Description:** Get the expected schema for a given object type and operation.

    **Parameters:**

    * `recordType` (string, required): The object type ID (e.g., 'companies').
    * `operation` (string, required): The operation type (e.g., 'CREATE\_RECORD').
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic HubSpot Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with HubSpot capabilities
hubspot_agent = Agent(
    role="CRM Manager",
    goal="Manage company and contact records in HubSpot",
    backstory="An AI assistant specialized in CRM management.",
    apps=['hubspot']  # All HubSpot actions will be available
)

# Task to create a new company
create_company_task = Task(
    description="Create a new company in HubSpot with name 'Innovate Corp' and domain 'innovatecorp.com'.",
    agent=hubspot_agent,
    expected_output="Company created successfully with confirmation"
)

# Run the task
crew = Crew(
    agents=[hubspot_agent],
    tasks=[create_company_task]
)

crew.kickoff()
```

### Filtering Specific HubSpot Tools

```python theme={null}
from crewai import Agent, Task, Crew

# Create agent with specific HubSpot actions only
contact_creator = Agent(
    role="Contact Creator",
    goal="Create new contacts in HubSpot",
    backstory="An AI assistant that focuses on creating new contact entries in the CRM.",
    apps=['hubspot/create_contact']  # Only contact creation action
)

# Task to create a contact
create_contact = Task(
    description="Create a new contact for 'John Doe' with email 'john.doe@example.com'.",
    agent=contact_creator,
    expected_output="Contact created successfully in HubSpot."
)

crew = Crew(
    agents=[contact_creator],
    tasks=[create_contact]
)

crew.kickoff()
```

### Contact Management

```python theme={null}
from crewai import Agent, Task, Crew

# Create agent with HubSpot contact management capabilities
crm_manager = Agent(
    role="CRM Manager",
    goal="Manage and organize HubSpot contacts efficiently.",
    backstory="An experienced CRM manager who maintains an organized contact database.",
    apps=['hubspot']  # All HubSpot actions including contact management
)

# Task to manage contacts
contact_task = Task(
    description="Create a new contact for 'Jane Smith' at 'Global Tech Inc.' with email 'jane.smith@globaltech.com'.",
    agent=crm_manager,
    expected_output="Contact database updated with the new contact."
)

crew = Crew(
    agents=[crm_manager],
    tasks=[contact_task]
)

crew.kickoff()
```

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with HubSpot integration setup or
  troubleshooting.
</Card>


# Jira Integration
Source: https://docs.crewai.com/en/enterprise/integrations/jira

Issue tracking and project management with Jira integration for CrewAI.

## Overview

Enable your agents to manage issues, projects, and workflows through Jira. Create and update issues, track project progress, manage assignments, and streamline your project management with AI-powered automation.

## Prerequisites

Before using the Jira integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Jira account with appropriate project permissions
* Connected your Jira account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up Jira Integration

### 1. Connect Your Jira Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Jira** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for issue and project management
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="jira/create_issue">
    **Description:** Create an issue in Jira.

    **Parameters:**

    * `summary` (string, required): Summary - A brief one-line summary of the issue. (example: "The printer stopped working").
    * `project` (string, optional): Project - The project which the issue belongs to. Defaults to the user's first project if not provided. Use Connect Portal Workflow Settings to allow users to select a Project.
    * `issueType` (string, optional): Issue type - Defaults to Task if not provided.
    * `jiraIssueStatus` (string, optional): Status - Defaults to the project's first status if not provided.
    * `assignee` (string, optional): Assignee - Defaults to the authenticated user if not provided.
    * `descriptionType` (string, optional): Description Type - Select the Description Type.
      * Options: `description`, `descriptionJSON`
    * `description` (string, optional): Description - A detailed description of the issue. This field appears only when 'descriptionType' = 'description'.
    * `additionalFields` (string, optional): Additional Fields - Specify any other fields that should be included in JSON format. Use Connect Portal Workflow Settings to allow users to select which Issue Fields to update.
      ```json theme={null}
      {
        "customfield_10001": "value"
      }
      ```
  </Accordion>

  <Accordion title="jira/update_issue">
    **Description:** Update an issue in Jira.

    **Parameters:**

    * `issueKey` (string, required): Issue Key (example: "TEST-1234").
    * `summary` (string, optional): Summary - A brief one-line summary of the issue. (example: "The printer stopped working").
    * `issueType` (string, optional): Issue type - Use Connect Portal Workflow Settings to allow users to select an Issue Type.
    * `jiraIssueStatus` (string, optional): Status - Use Connect Portal Workflow Settings to allow users to select a Status.
    * `assignee` (string, optional): Assignee - Use Connect Portal Workflow Settings to allow users to select an Assignee.
    * `descriptionType` (string, optional): Description Type - Select the Description Type.
      * Options: `description`, `descriptionJSON`
    * `description` (string, optional): Description - A detailed description of the issue. This field appears only when 'descriptionType' = 'description'.
    * `additionalFields` (string, optional): Additional Fields - Specify any other fields that should be included in JSON format.
  </Accordion>

  <Accordion title="jira/get_issue_by_key">
    **Description:** Get an issue by key in Jira.

    **Parameters:**

    * `issueKey` (string, required): Issue Key (example: "TEST-1234").
  </Accordion>

  <Accordion title="jira/filter_issues">
    **Description:** Search issues in Jira using filters.

    **Parameters:**

    * `jqlQuery` (object, optional): A filter in disjunctive normal form - OR of AND groups of single conditions.
      ```json theme={null}
      {
        "operator": "OR",
        "conditions": [
          {
            "operator": "AND",
            "conditions": [
              {
                "field": "status",
                "operator": "$stringExactlyMatches",
                "value": "Open"
              }
            ]
          }
        ]
      }
      ```
      Available operators: `$stringExactlyMatches`, `$stringDoesNotExactlyMatch`, `$stringIsIn`, `$stringIsNotIn`, `$stringContains`, `$stringDoesNotContain`, `$stringGreaterThan`, `$stringLessThan`
    * `limit` (string, optional): Limit results - Limit the maximum number of issues to return. Defaults to 10 if left blank.
  </Accordion>

  <Accordion title="jira/search_by_jql">
    **Description:** Search issues by JQL in Jira.

    **Parameters:**

    * `jqlQuery` (string, required): JQL Query (example: "project = PROJECT").
    * `paginationParameters` (object, optional): Pagination parameters for paginated results.
      ```json theme={null}
      {
        "pageCursor": "cursor_string"
      }
      ```
  </Accordion>

  <Accordion title="jira/update_issue_any">
    **Description:** Update any issue in Jira. Use DESCRIBE\_ACTION\_SCHEMA to get properties schema for this function.

    **Parameters:** No specific parameters - use JIRA\_DESCRIBE\_ACTION\_SCHEMA first to get the expected schema.
  </Accordion>

  <Accordion title="jira/describe_action_schema">
    **Description:** Get the expected schema for an issue type. Use this function first if no other function matches the issue type you want to operate on.

    **Parameters:**

    * `issueTypeId` (string, required): Issue Type ID.
    * `projectKey` (string, required): Project key.
    * `operation` (string, required): Operation Type value, for example CREATE\_ISSUE or UPDATE\_ISSUE.
  </Accordion>

  <Accordion title="jira/get_projects">
    **Description:** Get Projects in Jira.

    **Parameters:**

    * `paginationParameters` (object, optional): Pagination Parameters.
      ```json theme={null}
      {
        "pageCursor": "cursor_string"
      }
      ```
  </Accordion>

  <Accordion title="jira/get_issue_types_by_project">
    **Description:** Get Issue Types by project in Jira.

    **Parameters:**

    * `project` (string, required): Project key.
  </Accordion>

  <Accordion title="jira/get_issue_types">
    **Description:** Get all Issue Types in Jira.

    **Parameters:** None required.
  </Accordion>

  <Accordion title="jira/get_issue_status_by_project">
    **Description:** Get issue statuses for a given project.

    **Parameters:**

    * `project` (string, required): Project key.
  </Accordion>

  <Accordion title="jira/get_all_assignees_by_project">
    **Description:** Get assignees for a given project.

    **Parameters:**

    * `project` (string, required): Project key.
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Jira Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew
from crewai import Agent, Task, Crew

# Create an agent with Jira capabilities
jira_agent = Agent(
    role="Issue Manager",
    goal="Manage Jira issues and track project progress efficiently",
    backstory="An AI assistant specialized in issue tracking and project management.",
    apps=['jira']  # All Jira actions will be available
)

# Task to create a bug report
create_bug_task = Task(
    description="Create a bug report for the login functionality with high priority and assign it to the development team",
    agent=jira_agent,
    expected_output="Bug report created successfully with issue key"
)

# Run the task
crew = Crew(
    agents=[jira_agent],
    tasks=[create_bug_task]
)

crew.kickoff()
```

### Filtering Specific Jira Tools

```python theme={null}

issue_coordinator = Agent(
    role="Issue Coordinator",
    goal="Create and manage Jira issues efficiently",
    backstory="An AI assistant that focuses on issue creation and management.",
    apps=['jira']
)

# Task to manage issue workflow
issue_workflow = Task(
    description="Create a feature request issue and update the status of related issues",
    agent=issue_coordinator,
    expected_output="Feature request created and related issues updated"
)

crew = Crew(
    agents=[issue_coordinator],
    tasks=[issue_workflow]
)

crew.kickoff()
```

### Project Analysis and Reporting

```python theme={null}
from crewai import Agent, Task, Crew

project_analyst = Agent(
    role="Project Analyst",
    goal="Analyze project data and generate insights from Jira",
    backstory="An experienced project analyst who extracts insights from project management data.",
    apps=['jira']
)

# Task to analyze project status
analysis_task = Task(
    description="""
    1. Get all projects and their issue types
    2. Search for all open issues across projects
    3. Analyze issue distribution by status and assignee
    4. Create a summary report issue with findings
    """,
    agent=project_analyst,
    expected_output="Project analysis completed with summary report created"
)

crew = Crew(
    agents=[project_analyst],
    tasks=[analysis_task]
)

crew.kickoff()
```

### Automated Issue Management

```python theme={null}
from crewai import Agent, Task, Crew

automation_manager = Agent(
    role="Automation Manager",
    goal="Automate issue management and workflow processes",
    backstory="An AI assistant that automates repetitive issue management tasks.",
    apps=['jira']
)

# Task to automate issue management
automation_task = Task(
    description="""
    1. Search for all unassigned issues using JQL
    2. Get available assignees for each project
    3. Automatically assign issues based on workload and expertise
    4. Update issue priorities based on age and type
    5. Create weekly sprint planning issues
    """,
    agent=automation_manager,
    expected_output="Issues automatically assigned and sprint planning issues created"
)

crew = Crew(
    agents=[automation_manager],
    tasks=[automation_task]
)

crew.kickoff()
```

### Advanced Schema-Based Operations

```python theme={null}
from crewai import Agent, Task, Crew

schema_specialist = Agent(
    role="Schema Specialist",
    goal="Handle complex Jira operations using dynamic schemas",
    backstory="An AI assistant that can work with dynamic Jira schemas and custom issue types.",
    apps=['jira']
)

# Task using schema-based operations
schema_task = Task(
    description="""
    1. Get all projects and their custom issue types
    2. For each custom issue type, describe the action schema
    3. Create issues using the dynamic schema for complex custom fields
    4. Update issues with custom field values based on business rules
    """,
    agent=schema_specialist,
    expected_output="Custom issues created and updated using dynamic schemas"
)

crew = Crew(
    agents=[schema_specialist],
    tasks=[schema_task]
)

crew.kickoff()
```

## Troubleshooting

### Common Issues

**Permission Errors**

* Ensure your Jira account has necessary permissions for the target projects
* Verify that the OAuth connection includes required scopes for Jira API
* Check if you have create/edit permissions for issues in the specified projects

**Invalid Project or Issue Keys**

* Double-check project keys and issue keys for correct format (e.g., "PROJ-123")
* Ensure projects exist and are accessible to your account
* Verify that issue keys reference existing issues

**Issue Type and Status Issues**

* Use JIRA\_GET\_ISSUE\_TYPES\_BY\_PROJECT to get valid issue types for a project
* Use JIRA\_GET\_ISSUE\_STATUS\_BY\_PROJECT to get valid statuses
* Ensure issue types and statuses are available in the target project

**JQL Query Problems**

* Test JQL queries in Jira's issue search before using in API calls
* Ensure field names in JQL are spelled correctly and exist in your Jira instance
* Use proper JQL syntax for complex queries

**Custom Fields and Schema Issues**

* Use JIRA\_DESCRIBE\_ACTION\_SCHEMA to get the correct schema for complex issue types
* Ensure custom field IDs are correct (e.g., "customfield\_10001")
* Verify that custom fields are available in the target project and issue type

**Filter Formula Issues**

* Ensure filter formulas follow the correct JSON structure for disjunctive normal form
* Use valid field names that exist in your Jira configuration
* Test simple filters before building complex multi-condition queries

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Jira integration setup or
  troubleshooting.
</Card>


# Linear Integration
Source: https://docs.crewai.com/en/enterprise/integrations/linear

Software project and bug tracking with Linear integration for CrewAI.

## Overview

Enable your agents to manage issues, projects, and development workflows through Linear. Create and update issues, manage project timelines, organize teams, and streamline your software development process with AI-powered automation.

## Prerequisites

Before using the Linear integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Linear account with appropriate workspace permissions
* Connected your Linear account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up Linear Integration

### 1. Connect Your Linear Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Linear** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for issue and project management
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="linear/create_issue">
    **Description:** Create a new issue in Linear.

    **Parameters:**

    * `teamId` (string, required): Team ID - Specify the Team ID of the parent for this new issue. Use Connect Portal Workflow Settings to allow users to select a Team ID. (example: "a70bdf0f-530a-4887-857d-46151b52b47c").
    * `title` (string, required): Title - Specify a title for this issue.
    * `description` (string, optional): Description - Specify a description for this issue.
    * `statusId` (string, optional): Status - Specify the state or status of this issue.
    * `priority` (string, optional): Priority - Specify the priority of this issue as an integer.
    * `dueDate` (string, optional): Due Date - Specify the due date of this issue in ISO 8601 format.
    * `cycleId` (string, optional): Cycle ID - Specify the cycle associated with this issue.
    * `additionalFields` (object, optional): Additional Fields.
      ```json theme={null}
      {
        "assigneeId": "a70bdf0f-530a-4887-857d-46151b52b47c",
        "labelIds": ["a70bdf0f-530a-4887-857d-46151b52b47c"]
      }
      ```
  </Accordion>

  <Accordion title="linear/update_issue">
    **Description:** Update an issue in Linear.

    **Parameters:**

    * `issueId` (string, required): Issue ID - Specify the Issue ID of the issue to update. (example: "90fbc706-18cd-42c9-ae66-6bd344cc8977").
    * `title` (string, optional): Title - Specify a title for this issue.
    * `description` (string, optional): Description - Specify a description for this issue.
    * `statusId` (string, optional): Status - Specify the state or status of this issue.
    * `priority` (string, optional): Priority - Specify the priority of this issue as an integer.
    * `dueDate` (string, optional): Due Date - Specify the due date of this issue in ISO 8601 format.
    * `cycleId` (string, optional): Cycle ID - Specify the cycle associated with this issue.
    * `additionalFields` (object, optional): Additional Fields.
      ```json theme={null}
      {
        "assigneeId": "a70bdf0f-530a-4887-857d-46151b52b47c",
        "labelIds": ["a70bdf0f-530a-4887-857d-46151b52b47c"]
      }
      ```
  </Accordion>

  <Accordion title="linear/get_issue_by_id">
    **Description:** Get an issue by ID in Linear.

    **Parameters:**

    * `issueId` (string, required): Issue ID - Specify the record ID of the issue to fetch. (example: "90fbc706-18cd-42c9-ae66-6bd344cc8977").
  </Accordion>

  <Accordion title="linear/get_issue_by_issue_identifier">
    **Description:** Get an issue by issue identifier in Linear.

    **Parameters:**

    * `externalId` (string, required): External ID - Specify the human-readable Issue identifier of the issue to fetch. (example: "ABC-1").
  </Accordion>

  <Accordion title="linear/search_issue">
    **Description:** Search issues in Linear.

    **Parameters:**

    * `queryTerm` (string, required): Query Term - The search term to look for.
    * `issueFilterFormula` (object, optional): A filter in disjunctive normal form - OR of AND groups of single conditions.
      ```json theme={null}
      {
        "operator": "OR",
        "conditions": [
          {
            "operator": "AND",
            "conditions": [
              {
                "field": "title",
                "operator": "$stringContains",
                "value": "bug"
              }
            ]
          }
        ]
      }
      ```
      Available fields: `title`, `number`, `project`, `createdAt`
      Available operators: `$stringExactlyMatches`, `$stringDoesNotExactlyMatch`, `$stringIsIn`, `$stringIsNotIn`, `$stringStartsWith`, `$stringDoesNotStartWith`, `$stringEndsWith`, `$stringDoesNotEndWith`, `$stringContains`, `$stringDoesNotContain`, `$stringGreaterThan`, `$stringLessThan`, `$numberGreaterThanOrEqualTo`, `$numberLessThanOrEqualTo`, `$numberGreaterThan`, `$numberLessThan`, `$dateTimeAfter`, `$dateTimeBefore`
  </Accordion>

  <Accordion title="linear/delete_issue">
    **Description:** Delete an issue in Linear.

    **Parameters:**

    * `issueId` (string, required): Issue ID - Specify the record ID of the issue to delete. (example: "90fbc706-18cd-42c9-ae66-6bd344cc8977").
  </Accordion>

  <Accordion title="linear/archive_issue">
    **Description:** Archive an issue in Linear.

    **Parameters:**

    * `issueId` (string, required): Issue ID - Specify the record ID of the issue to archive. (example: "90fbc706-18cd-42c9-ae66-6bd344cc8977").
  </Accordion>

  <Accordion title="linear/create_sub_issue">
    **Description:** Create a sub-issue in Linear.

    **Parameters:**

    * `parentId` (string, required): Parent ID - Specify the Issue ID for the parent of this new issue.
    * `teamId` (string, required): Team ID - Specify the Team ID of the parent for this new sub-issue. Use Connect Portal Workflow Settings to allow users to select a Team ID. (example: "a70bdf0f-530a-4887-857d-46151b52b47c").
    * `title` (string, required): Title - Specify a title for this issue.
    * `description` (string, optional): Description - Specify a description for this issue.
    * `additionalFields` (object, optional): Additional Fields.
      ```json theme={null}
      {
        "lead": "linear_user_id"
      }
      ```
  </Accordion>

  <Accordion title="linear/create_project">
    **Description:** Create a new project in Linear.

    **Parameters:**

    * `teamIds` (object, required): Team ID - Specify the team ID(s) this project is associated with as a string or a JSON array. Use Connect Portal User Settings to allow your user to select a Team ID.
      ```json theme={null}
      [
        "a70bdf0f-530a-4887-857d-46151b52b47c",
        "4ac7..."
      ]
      ```
    * `projectName` (string, required): Project Name - Specify the name of the project. (example: "My Linear Project").
    * `description` (string, optional): Project Description - Specify a description for this project.
    * `additionalFields` (object, optional): Additional Fields.
      ```json theme={null}
      {
        "state": "planned",
        "description": ""
      }
      ```
  </Accordion>

  <Accordion title="linear/update_project">
    **Description:** Update a project in Linear.

    **Parameters:**

    * `projectId` (string, required): Project ID - Specify the ID of the project to update. (example: "a6634484-6061-4ac7-9739-7dc5e52c796b").
    * `projectName` (string, optional): Project Name - Specify the name of the project to update. (example: "My Linear Project").
    * `description` (string, optional): Project Description - Specify a description for this project.
    * `additionalFields` (object, optional): Additional Fields.
      ```json theme={null}
      {
        "state": "planned",
        "description": ""
      }
      ```
  </Accordion>

  <Accordion title="linear/get_project_by_id">
    **Description:** Get a project by ID in Linear.

    **Parameters:**

    * `projectId` (string, required): Project ID - Specify the Project ID of the project to fetch. (example: "a6634484-6061-4ac7-9739-7dc5e52c796b").
  </Accordion>

  <Accordion title="linear/delete_project">
    **Description:** Delete a project in Linear.

    **Parameters:**

    * `projectId` (string, required): Project ID - Specify the Project ID of the project to delete. (example: "a6634484-6061-4ac7-9739-7dc5e52c796b").
  </Accordion>

  <Accordion title="linear/search_teams">
    **Description:** Search teams in Linear.

    **Parameters:**

    * `teamFilterFormula` (object, optional): A filter in disjunctive normal form - OR of AND groups of single conditions.
      ```json theme={null}
      {
        "operator": "OR",
        "conditions": [
          {
            "operator": "AND",
            "conditions": [
              {
                "field": "name",
                "operator": "$stringContains",
                "value": "Engineering"
              }
            ]
          }
        ]
      }
      ```
      Available fields: `id`, `name`
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Linear Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew
from crewai import Agent, Task, Crew

# Create an agent with Linear capabilities
linear_agent = Agent(
    role="Development Manager",
    goal="Manage Linear issues and track development progress efficiently",
    backstory="An AI assistant specialized in software development project management.",
    apps=['linear']  # All Linear actions will be available
)

# Task to create a bug report
create_bug_task = Task(
    description="Create a high-priority bug report for the authentication system and assign it to the backend team",
    agent=linear_agent,
    expected_output="Bug report created successfully with issue ID"
)

# Run the task
crew = Crew(
    agents=[linear_agent],
    tasks=[create_bug_task]
)

crew.kickoff()
```

### Filtering Specific Linear Tools

```python theme={null}

issue_manager = Agent(
    role="Issue Manager",
    goal="Create and manage Linear issues efficiently",
    backstory="An AI assistant that focuses on issue creation and lifecycle management.",
    apps=['linear/create_issue']
)

# Task to manage issue workflow
issue_workflow = Task(
    description="Create a feature request issue and update the status of related issues to reflect current progress",
    agent=issue_manager,
    expected_output="Feature request created and related issues updated"
)

crew = Crew(
    agents=[issue_manager],
    tasks=[issue_workflow]
)

crew.kickoff()
```

### Project and Team Management

```python theme={null}
from crewai import Agent, Task, Crew

project_coordinator = Agent(
    role="Project Coordinator",
    goal="Coordinate projects and teams in Linear efficiently",
    backstory="An experienced project coordinator who manages development cycles and team workflows.",
    apps=['linear']
)

# Task to coordinate project setup
project_coordination = Task(
    description="""
    1. Search for engineering teams in Linear
    2. Create a new project for Q2 feature development
    3. Associate the project with relevant teams
    4. Create initial project milestones as issues
    """,
    agent=project_coordinator,
    expected_output="Q2 project created with teams assigned and initial milestones established"
)

crew = Crew(
    agents=[project_coordinator],
    tasks=[project_coordination]
)

crew.kickoff()
```

### Issue Hierarchy and Sub-task Management

```python theme={null}
from crewai import Agent, Task, Crew

task_organizer = Agent(
    role="Task Organizer",
    goal="Organize complex issues into manageable sub-tasks",
    backstory="An AI assistant that breaks down complex development work into organized sub-tasks.",
    apps=['linear']
)

# Task to create issue hierarchy
hierarchy_task = Task(
    description="""
    1. Search for large feature issues that need to be broken down
    2. For each complex issue, create sub-issues for different components
    3. Update the parent issues with proper descriptions and links to sub-issues
    4. Assign sub-issues to appropriate team members based on expertise
    """,
    agent=task_organizer,
    expected_output="Complex issues broken down into manageable sub-tasks with proper assignments"
)

crew = Crew(
    agents=[task_organizer],
    tasks=[hierarchy_task]
)

crew.kickoff()
```

### Automated Development Workflow

```python theme={null}
from crewai import Agent, Task, Crew

workflow_automator = Agent(
    role="Workflow Automator",
    goal="Automate development workflow processes in Linear",
    backstory="An AI assistant that automates repetitive development workflow tasks.",
    apps=['linear']
)

# Complex workflow automation task
automation_task = Task(
    description="""
    1. Search for issues that have been in progress for more than 7 days
    2. Update their priorities based on due dates and project importance
    3. Create weekly sprint planning issues for each team
    4. Archive completed issues from the previous cycle
    5. Generate project status reports as new issues
    """,
    agent=workflow_automator,
    expected_output="Development workflow automated with updated priorities, sprint planning, and status reports"
)

crew = Crew(
    agents=[workflow_automator],
    tasks=[automation_task]
)

crew.kickoff()
```

## Troubleshooting

### Common Issues

**Permission Errors**

* Ensure your Linear account has necessary permissions for the target workspace
* Verify that the OAuth connection includes required scopes for Linear API
* Check if you have create/edit permissions for issues and projects in the workspace

**Invalid IDs and References**

* Double-check team IDs, issue IDs, and project IDs for correct UUID format
* Ensure referenced entities (teams, projects, cycles) exist and are accessible
* Verify that issue identifiers follow the correct format (e.g., "ABC-1")

**Team and Project Association Issues**

* Use LINEAR\_SEARCH\_TEAMS to get valid team IDs before creating issues or projects
* Ensure teams exist and are active in your workspace
* Verify that team IDs are properly formatted as UUIDs

**Issue Status and Priority Problems**

* Check that status IDs reference valid workflow states for the team
* Ensure priority values are within the valid range for your Linear configuration
* Verify that custom fields and labels exist before referencing them

**Date and Time Format Issues**

* Use ISO 8601 format for due dates and timestamps
* Ensure time zones are handled correctly for due date calculations
* Verify that date values are valid and in the future for due dates

**Search and Filter Issues**

* Ensure search queries are properly formatted and not empty
* Use valid field names in filter formulas: `title`, `number`, `project`, `createdAt`
* Test simple filters before building complex multi-condition queries
* Verify that operator types match the data types of the fields being filtered

**Sub-issue Creation Problems**

* Ensure parent issue IDs are valid and accessible
* Verify that the team ID for sub-issues matches or is compatible with the parent issue's team
* Check that parent issues are not already archived or deleted

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Linear integration setup or
  troubleshooting.
</Card>


# Microsoft Excel Integration
Source: https://docs.crewai.com/en/enterprise/integrations/microsoft_excel

Workbook and data management with Microsoft Excel integration for CrewAI.

## Overview

Enable your agents to create and manage Excel workbooks, worksheets, tables, and charts in OneDrive or SharePoint. Manipulate data ranges, create visualizations, manage tables, and streamline your spreadsheet workflows with AI-powered automation.

## Prerequisites

Before using the Microsoft Excel integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Microsoft 365 account with Excel and OneDrive/SharePoint access
* Connected your Microsoft account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up Microsoft Excel Integration

### 1. Connect Your Microsoft Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Microsoft Excel** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for files and Excel workbook access
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="microsoft_excel/create_workbook">
    **Description:** Create a new Excel workbook in OneDrive or SharePoint.

    **Parameters:**

    * `file_path` (string, required): Path where to create the workbook (e.g., 'MyWorkbook.xlsx')
    * `worksheets` (array, optional): Initial worksheets to create
      ```json theme={null}
      [
        {
          "name": "Sheet1"
        },
        {
          "name": "Data"
        }
      ]
      ```
  </Accordion>

  <Accordion title="microsoft_excel/get_workbooks">
    **Description:** Get all Excel workbooks from OneDrive or SharePoint.

    **Parameters:**

    * `select` (string, optional): Select specific properties to return
    * `filter` (string, optional): Filter results using OData syntax
    * `expand` (string, optional): Expand related resources inline
    * `top` (integer, optional): Number of items to return. Minimum: 1, Maximum: 999
    * `orderby` (string, optional): Order results by specified properties
  </Accordion>

  <Accordion title="microsoft_excel/get_worksheets">
    **Description:** Get all worksheets in an Excel workbook.

    **Parameters:**

    * `file_id` (string, required): The ID of the Excel file
    * `select` (string, optional): Select specific properties to return (e.g., 'id,name,position')
    * `filter` (string, optional): Filter results using OData syntax
    * `expand` (string, optional): Expand related resources inline
    * `top` (integer, optional): Number of items to return. Minimum: 1, Maximum: 999
    * `orderby` (string, optional): Order results by specified properties
  </Accordion>

  <Accordion title="microsoft_excel/create_worksheet">
    **Description:** Create a new worksheet in an Excel workbook.

    **Parameters:**

    * `file_id` (string, required): The ID of the Excel file
    * `name` (string, required): Name of the new worksheet
  </Accordion>

  <Accordion title="microsoft_excel/get_range_data">
    **Description:** Get data from a specific range in an Excel worksheet.

    **Parameters:**

    * `file_id` (string, required): The ID of the Excel file
    * `worksheet_name` (string, required): Name of the worksheet
    * `range` (string, required): Range address (e.g., 'A1:C10')
  </Accordion>

  <Accordion title="microsoft_excel/update_range_data">
    **Description:** Update data in a specific range in an Excel worksheet.

    **Parameters:**

    * `file_id` (string, required): The ID of the Excel file
    * `worksheet_name` (string, required): Name of the worksheet
    * `range` (string, required): Range address (e.g., 'A1:C10')
    * `values` (array, required): 2D array of values to set in the range
      ```json theme={null}
      [
        ["Name", "Age", "City"],
        ["John", 30, "New York"],
        ["Jane", 25, "Los Angeles"]
      ]
      ```
  </Accordion>

  <Accordion title="microsoft_excel/add_table">
    **Description:** Create a table in an Excel worksheet.

    **Parameters:**

    * `file_id` (string, required): The ID of the Excel file
    * `worksheet_name` (string, required): Name of the worksheet
    * `range` (string, required): Range for the table (e.g., 'A1:D10')
    * `has_headers` (boolean, optional): Whether the first row contains headers. Default: true
  </Accordion>

  <Accordion title="microsoft_excel/get_tables">
    **Description:** Get all tables in an Excel worksheet.

    **Parameters:**

    * `file_id` (string, required): The ID of the Excel file
    * `worksheet_name` (string, required): Name of the worksheet
  </Accordion>

  <Accordion title="microsoft_excel/add_table_row">
    **Description:** Add a new row to an Excel table.

    **Parameters:**

    * `file_id` (string, required): The ID of the Excel file
    * `worksheet_name` (string, required): Name of the worksheet
    * `table_name` (string, required): Name of the table
    * `values` (array, required): Array of values for the new row
      ```json theme={null}
      ["John Doe", 35, "Manager", "Sales"]
      ```
  </Accordion>

  <Accordion title="microsoft_excel/get_table_data">
    **Description:** Get data from a specific table in an Excel worksheet.

    **Parameters:**

    * `file_id` (string, required): The ID of the Excel file
    * `worksheet_name` (string, required): Name of the worksheet
    * `table_name` (string, required): Name of the table
  </Accordion>

  <Accordion title="microsoft_excel/create_chart">
    **Description:** Create a chart in an Excel worksheet.

    **Parameters:**

    * `file_id` (string, required): The ID of the Excel file
    * `worksheet_name` (string, required): Name of the worksheet
    * `chart_type` (string, required): Type of chart (e.g., 'ColumnClustered', 'Line', 'Pie')
    * `source_data` (string, required): Range of data for the chart (e.g., 'A1:B10')
    * `series_by` (string, optional): How to interpret the data ('Auto', 'Columns', or 'Rows'). Default: Auto
  </Accordion>

  <Accordion title="microsoft_excel/get_cell">
    **Description:** Get the value of a single cell in an Excel worksheet.

    **Parameters:**

    * `file_id` (string, required): The ID of the Excel file
    * `worksheet_name` (string, required): Name of the worksheet
    * `row` (integer, required): Row number (0-based)
    * `column` (integer, required): Column number (0-based)
  </Accordion>

  <Accordion title="microsoft_excel/get_used_range">
    **Description:** Get the used range of an Excel worksheet (contains all data).

    **Parameters:**

    * `file_id` (string, required): The ID of the Excel file
    * `worksheet_name` (string, required): Name of the worksheet
  </Accordion>

  <Accordion title="microsoft_excel/get_used_range_metadata">
    **Description:** Get the used range metadata (dimensions only, no data) of an Excel worksheet.

    **Parameters:**

    * `file_id` (string, required): The ID of the Excel file
    * `worksheet_name` (string, required): Name of the worksheet
  </Accordion>

  <Accordion title="microsoft_excel/list_charts">
    **Description:** Get all charts in an Excel worksheet.

    **Parameters:**

    * `file_id` (string, required): The ID of the Excel file
    * `worksheet_name` (string, required): Name of the worksheet
  </Accordion>

  <Accordion title="microsoft_excel/delete_worksheet">
    **Description:** Delete a worksheet from an Excel workbook.

    **Parameters:**

    * `file_id` (string, required): The ID of the Excel file
    * `worksheet_name` (string, required): Name of the worksheet to delete
  </Accordion>

  <Accordion title="microsoft_excel/delete_table">
    **Description:** Delete a table from an Excel worksheet.

    **Parameters:**

    * `file_id` (string, required): The ID of the Excel file
    * `worksheet_name` (string, required): Name of the worksheet
    * `table_name` (string, required): Name of the table to delete
  </Accordion>

  <Accordion title="microsoft_excel/list_names">
    **Description:** Get all named ranges in an Excel workbook.

    **Parameters:**

    * `file_id` (string, required): The ID of the Excel file
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Excel Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with Excel capabilities
excel_agent = Agent(
    role="Excel Data Manager",
    goal="Manage Excel workbooks and data efficiently",
    backstory="An AI assistant specialized in Excel data management and analysis.",
    apps=['microsoft_excel']  # All Excel actions will be available
)

# Task to create and populate a workbook
data_management_task = Task(
    description="Create a new sales report workbook with data analysis and charts",
    agent=excel_agent,
    expected_output="Excel workbook created with sales data, analysis, and visualizations"
)

# Run the task
crew = Crew(
    agents=[excel_agent],
    tasks=[data_management_task]
)

crew.kickoff()
```

### Data Analysis and Reporting

```python theme={null}
from crewai import Agent, Task, Crew

data_analyst = Agent(
    role="Data Analyst",
    goal="Analyze data in Excel and create comprehensive reports",
    backstory="An AI assistant that specializes in data analysis and Excel reporting.",
    apps=[
        'microsoft_excel/get_workbooks',
        'microsoft_excel/get_range_data',
        'microsoft_excel/create_chart',
        'microsoft_excel/add_table'
    ]
)

# Task to analyze existing data
analysis_task = Task(
    description="Analyze sales data in existing workbooks and create summary charts and tables",
    agent=data_analyst,
    expected_output="Data analyzed with summary charts and tables created"
)

crew = Crew(
    agents=[data_analyst],
    tasks=[analysis_task]
)

crew.kickoff()
```

### Workbook Creation and Structure

```python theme={null}
from crewai import Agent, Task, Crew

workbook_creator = Agent(
    role="Workbook Creator",
    goal="Create structured Excel workbooks with multiple worksheets and data organization",
    backstory="An AI assistant that creates well-organized Excel workbooks for various business needs.",
    apps=['microsoft_excel']
)

# Task to create structured workbooks
creation_task = Task(
    description="""
    1. Create a new quarterly report workbook
    2. Add multiple worksheets for different departments
    3. Create tables with headers for data organization
    4. Set up charts for key metrics visualization
    """,
    agent=workbook_creator,
    expected_output="Structured workbook created with multiple worksheets, tables, and charts"
)

crew = Crew(
    agents=[workbook_creator],
    tasks=[creation_task]
)

crew.kickoff()
```

### Data Manipulation and Updates

```python theme={null}
from crewai import Agent, Task, Crew

data_manipulator = Agent(
    role="Data Manipulator",
    goal="Update and manipulate data in Excel worksheets efficiently",
    backstory="An AI assistant that handles data updates, table management, and range operations.",
    apps=['microsoft_excel']
)

# Task to manipulate data
manipulation_task = Task(
    description="""
    1. Get data from existing worksheets
    2. Update specific ranges with new information
    3. Add new rows to existing tables
    4. Create additional charts based on updated data
    5. Organize data across multiple worksheets
    """,
    agent=data_manipulator,
    expected_output="Data updated across worksheets with new charts and organized structure"
)

crew = Crew(
    agents=[data_manipulator],
    tasks=[manipulation_task]
)

crew.kickoff()
```

### Advanced Excel Automation

```python theme={null}
from crewai import Agent, Task, Crew

excel_automator = Agent(
    role="Excel Automator",
    goal="Automate complex Excel workflows and data processing",
    backstory="An AI assistant that automates sophisticated Excel operations and data workflows.",
    apps=['microsoft_excel']
)

# Complex automation task
automation_task = Task(
    description="""
    1. Scan all Excel workbooks for specific data patterns
    2. Create consolidated reports from multiple workbooks
    3. Generate charts and tables for trend analysis
    4. Set up named ranges for easy data reference
    5. Create dashboard worksheets with key metrics
    6. Clean up unused worksheets and tables
    """,
    agent=excel_automator,
    expected_output="Automated Excel workflow completed with consolidated reports and dashboards"
)

crew = Crew(
    agents=[excel_automator],
    tasks=[automation_task]
)

crew.kickoff()
```

### Financial Modeling and Analysis

```python theme={null}
from crewai import Agent, Task, Crew

financial_modeler = Agent(
    role="Financial Modeler",
    goal="Create financial models and analysis in Excel",
    backstory="An AI assistant specialized in financial modeling and analysis using Excel.",
    apps=['microsoft_excel']
)

# Task for financial modeling
modeling_task = Task(
    description="""
    1. Create financial model workbooks with multiple scenarios
    2. Set up input tables for assumptions and variables
    3. Create calculation worksheets with formulas and logic
    4. Generate charts for financial projections and trends
    5. Add summary tables for key financial metrics
    6. Create sensitivity analysis tables
    """,
    agent=financial_modeler,
    expected_output="Financial model created with scenarios, calculations, and analysis charts"
)

crew = Crew(
    agents=[financial_modeler],
    tasks=[modeling_task]
)

crew.kickoff()
```

## Troubleshooting

### Common Issues

**Permission Errors**

* Ensure your Microsoft account has appropriate permissions for Excel and OneDrive/SharePoint
* Verify that the OAuth connection includes required scopes (Files.Read.All, Files.ReadWrite.All)
* Check that you have access to the specific workbooks you're trying to modify

**File ID and Path Issues**

* Verify that file IDs are correct and files exist in your OneDrive or SharePoint
* Ensure file paths are properly formatted when creating new workbooks
* Check that workbook files have the correct .xlsx extension

**Worksheet and Range Issues**

* Verify that worksheet names exist in the specified workbook
* Ensure range addresses are properly formatted (e.g., 'A1:C10')
* Check that ranges don't exceed worksheet boundaries

**Data Format Issues**

* Ensure data values are properly formatted for Excel (strings, numbers, integers)
* Verify that 2D arrays for ranges have consistent row and column counts
* Check that table data includes proper headers when has\_headers is true

**Chart Creation Issues**

* Verify that chart types are supported (ColumnClustered, Line, Pie, etc.)
* Ensure source data ranges contain appropriate data for the chart type
* Check that the source data range exists and contains data

**Table Management Issues**

* Ensure table names are unique within worksheets
* Verify that table ranges don't overlap with existing tables
* Check that new row data matches the table's column structure

**Cell and Range Operations**

* Verify that row and column indices are 0-based for cell operations
* Ensure ranges contain data when using get\_used\_range
* Check that named ranges exist before referencing them

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Microsoft Excel integration setup
  or troubleshooting.
</Card>


# Microsoft OneDrive Integration
Source: https://docs.crewai.com/en/enterprise/integrations/microsoft_onedrive

File and folder management with Microsoft OneDrive integration for CrewAI.

## Overview

Enable your agents to upload, download, and manage files and folders in Microsoft OneDrive. Automate file operations, organize content, create sharing links, and streamline your cloud storage workflows with AI-powered automation.

## Prerequisites

Before using the Microsoft OneDrive integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Microsoft account with OneDrive access
* Connected your Microsoft account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up Microsoft OneDrive Integration

### 1. Connect Your Microsoft Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Microsoft OneDrive** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for file access
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="microsoft_onedrive/list_files">
    **Description:** List files and folders in OneDrive.

    **Parameters:**

    * `top` (integer, optional): Number of items to retrieve (max 1000). Default is `50`.
    * `orderby` (string, optional): Order by field (e.g., "name asc", "lastModifiedDateTime desc"). Default is "name asc".
    * `filter` (string, optional): OData filter expression.
  </Accordion>

  <Accordion title="microsoft_onedrive/get_file_info">
    **Description:** Get information about a specific file or folder.

    **Parameters:**

    * `item_id` (string, required): The ID of the file or folder.
  </Accordion>

  <Accordion title="microsoft_onedrive/download_file">
    **Description:** Download a file from OneDrive.

    **Parameters:**

    * `item_id` (string, required): The ID of the file to download.
  </Accordion>

  <Accordion title="microsoft_onedrive/upload_file">
    **Description:** Upload a file to OneDrive.

    **Parameters:**

    * `file_name` (string, required): Name of the file to upload.
    * `content` (string, required): Base64 encoded file content.
  </Accordion>

  <Accordion title="microsoft_onedrive/create_folder">
    **Description:** Create a new folder in OneDrive.

    **Parameters:**

    * `folder_name` (string, required): Name of the folder to create.
  </Accordion>

  <Accordion title="microsoft_onedrive/delete_item">
    **Description:** Delete a file or folder from OneDrive.

    **Parameters:**

    * `item_id` (string, required): The ID of the file or folder to delete.
  </Accordion>

  <Accordion title="microsoft_onedrive/copy_item">
    **Description:** Copy a file or folder in OneDrive.

    **Parameters:**

    * `item_id` (string, required): The ID of the file or folder to copy.
    * `parent_id` (string, optional): The ID of the destination folder (optional, defaults to root).
    * `new_name` (string, optional): New name for the copied item (optional).
  </Accordion>

  <Accordion title="microsoft_onedrive/move_item">
    **Description:** Move a file or folder in OneDrive.

    **Parameters:**

    * `item_id` (string, required): The ID of the file or folder to move.
    * `parent_id` (string, required): The ID of the destination folder.
    * `new_name` (string, optional): New name for the item (optional).
  </Accordion>

  <Accordion title="microsoft_onedrive/search_files">
    **Description:** Search for files and folders in OneDrive.

    **Parameters:**

    * `query` (string, required): Search query string.
    * `top` (integer, optional): Number of results to return (max 1000). Default is `50`.
  </Accordion>

  <Accordion title="microsoft_onedrive/share_item">
    **Description:** Create a sharing link for a file or folder.

    **Parameters:**

    * `item_id` (string, required): The ID of the file or folder to share.
    * `type` (string, optional): Type of sharing link. Enum: `view`, `edit`, `embed`. Default is `view`.
    * `scope` (string, optional): Scope of the sharing link. Enum: `anonymous`, `organization`. Default is `anonymous`.
  </Accordion>

  <Accordion title="microsoft_onedrive/get_thumbnails">
    **Description:** Get thumbnails for a file.

    **Parameters:**

    * `item_id` (string, required): The ID of the file.
  </Accordion>

  <Accordion title="microsoft_onedrive/list_files_by_path">
    **Description:** List files and folders in a specific OneDrive path.

    **Parameters:**

    * `folder_path` (string, required): The folder path (e.g., 'Documents/Reports').
    * `top` (integer, optional): Number of items to retrieve (max 1000). Default is `50`.
    * `orderby` (string, optional): Order by field (e.g., "name asc", "lastModifiedDateTime desc"). Default is "name asc".
  </Accordion>

  <Accordion title="microsoft_onedrive/get_recent_files">
    **Description:** Get recently accessed files from OneDrive.

    **Parameters:**

    * `top` (integer, optional): Number of items to retrieve (max 200). Default is `25`.
  </Accordion>

  <Accordion title="microsoft_onedrive/get_shared_with_me">
    **Description:** Get files and folders shared with the user.

    **Parameters:**

    * `top` (integer, optional): Number of items to retrieve (max 200). Default is `50`.
    * `orderby` (string, optional): Order by field. Default is "name asc".
  </Accordion>

  <Accordion title="microsoft_onedrive/get_file_by_path">
    **Description:** Get information about a specific file or folder by path.

    **Parameters:**

    * `file_path` (string, required): The file or folder path (e.g., 'Documents/report.docx').
  </Accordion>

  <Accordion title="microsoft_onedrive/download_file_by_path">
    **Description:** Download a file from OneDrive by its path.

    **Parameters:**

    * `file_path` (string, required): The file path (e.g., 'Documents/report.docx').
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Microsoft OneDrive Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with Microsoft OneDrive capabilities
onedrive_agent = Agent(
    role="File Manager",
    goal="Manage files and folders in OneDrive efficiently",
    backstory="An AI assistant specialized in Microsoft OneDrive file operations and organization.",
    apps=['microsoft_onedrive']  # All OneDrive actions will be available
)

# Task to list files and create a folder
organize_files_task = Task(
    description="List all files in my OneDrive root directory and create a new folder called 'Project Documents'.",
    agent=onedrive_agent,
    expected_output="List of files displayed and new folder 'Project Documents' created."
)

# Run the task
crew = Crew(
    agents=[onedrive_agent],
    tasks=[organize_files_task]
)

crew.kickoff()
```

### File Upload and Management

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent focused on file operations
file_operator = Agent(
    role="File Operator",
    goal="Upload, download, and manage files with precision",
    backstory="An AI assistant skilled in file handling and content management.",
    apps=['microsoft_onedrive/upload_file', 'microsoft_onedrive/download_file', 'microsoft_onedrive/get_file_info']
)

# Task to upload and manage a file
file_management_task = Task(
    description="Upload a text file named 'report.txt' with content 'This is a sample report for the project.' Then get information about the uploaded file.",
    agent=file_operator,
    expected_output="File uploaded successfully and file information retrieved."
)

crew = Crew(
    agents=[file_operator],
    tasks=[file_management_task]
)

crew.kickoff()
```

### File Organization and Sharing

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent for file organization and sharing
file_organizer = Agent(
    role="File Organizer",
    goal="Organize files and create sharing links for collaboration",
    backstory="An AI assistant that excels at organizing files and managing sharing permissions.",
    apps=['microsoft_onedrive/search_files', 'microsoft_onedrive/move_item', 'microsoft_onedrive/share_item', 'microsoft_onedrive/create_folder']
)

# Task to organize and share files
organize_share_task = Task(
    description="Search for files containing 'presentation' in the name, create a folder called 'Presentations', move the found files to this folder, and create a view-only sharing link for the folder.",
    agent=file_organizer,
    expected_output="Files organized into 'Presentations' folder and sharing link created."
)

crew = Crew(
    agents=[file_organizer],
    tasks=[organize_share_task]
)

crew.kickoff()
```

## Troubleshooting

### Common Issues

**Authentication Errors**

* Ensure your Microsoft account has the necessary permissions for file access (e.g., `Files.Read`, `Files.ReadWrite`).
* Verify that the OAuth connection includes all required scopes.

**File Upload Issues**

* Ensure `file_name` and `content` are provided for file uploads.
* Content must be Base64 encoded for binary files.
* Check that you have write permissions to OneDrive.

**File/Folder ID Issues**

* Double-check item IDs for correctness when accessing specific files or folders.
* Item IDs are returned by other operations like `list_files` or `search_files`.
* Ensure the referenced items exist and are accessible.

**Search and Filter Operations**

* Use appropriate search terms for `search_files` operations.
* For `filter` parameters, use proper OData syntax.

**File Operations (Copy/Move)**

* For `move_item`, ensure both `item_id` and `parent_id` are provided.
* For `copy_item`, only `item_id` is required; `parent_id` defaults to root if not specified.
* Verify that destination folders exist and are accessible.

**Sharing Link Creation**

* Ensure the item exists before creating sharing links.
* Choose appropriate `type` and `scope` based on your sharing requirements.
* `anonymous` scope allows access without sign-in; `organization` requires organizational account.

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Microsoft OneDrive integration
  setup or troubleshooting.
</Card>


# Microsoft Outlook Integration
Source: https://docs.crewai.com/en/enterprise/integrations/microsoft_outlook

Email, calendar, and contact management with Microsoft Outlook integration for CrewAI.

## Overview

Enable your agents to access and manage Outlook emails, calendar events, and contacts. Send emails, retrieve messages, manage calendar events, and organize contacts with AI-powered automation.

## Prerequisites

Before using the Microsoft Outlook integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Microsoft account with Outlook access
* Connected your Microsoft account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up Microsoft Outlook Integration

### 1. Connect Your Microsoft Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Microsoft Outlook** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for mail, calendar, and contact access
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="microsoft_outlook/get_messages">
    **Description:** Get email messages from the user's mailbox.

    **Parameters:**

    * `top` (integer, optional): Number of messages to retrieve (max 1000). Default is `10`.
    * `filter` (string, optional): OData filter expression (e.g., "isRead eq false").
    * `search` (string, optional): Search query string.
    * `orderby` (string, optional): Order by field (e.g., "receivedDateTime desc"). Default is "receivedDateTime desc".
    * `select` (string, optional): Select specific properties to return.
    * `expand` (string, optional): Expand related resources inline.
  </Accordion>

  <Accordion title="microsoft_outlook/send_email">
    **Description:** Send an email message.

    **Parameters:**

    * `to_recipients` (array, required): Array of recipient email addresses.
    * `cc_recipients` (array, optional): Array of CC recipient email addresses.
    * `bcc_recipients` (array, optional): Array of BCC recipient email addresses.
    * `subject` (string, required): Email subject.
    * `body` (string, required): Email body content.
    * `body_type` (string, optional): Body content type. Enum: `Text`, `HTML`. Default is `HTML`.
    * `importance` (string, optional): Message importance level. Enum: `low`, `normal`, `high`. Default is `normal`.
    * `reply_to` (array, optional): Array of reply-to email addresses.
    * `save_to_sent_items` (boolean, optional): Whether to save the message to Sent Items folder. Default is `true`.
  </Accordion>

  <Accordion title="microsoft_outlook/get_calendar_events">
    **Description:** Get calendar events from the user's calendar.

    **Parameters:**

    * `top` (integer, optional): Number of events to retrieve (max 1000). Default is `10`.
    * `skip` (integer, optional): Number of events to skip. Default is `0`.
    * `filter` (string, optional): OData filter expression (e.g., "start/dateTime ge '2024-01-01T00:00:00Z'").
    * `orderby` (string, optional): Order by field (e.g., "start/dateTime asc"). Default is "start/dateTime asc".
  </Accordion>

  <Accordion title="microsoft_outlook/create_calendar_event">
    **Description:** Create a new calendar event.

    **Parameters:**

    * `subject` (string, required): Event subject/title.
    * `body` (string, optional): Event body/description.
    * `start_datetime` (string, required): Start date and time in ISO 8601 format (e.g., '2024-01-20T10:00:00').
    * `end_datetime` (string, required): End date and time in ISO 8601 format.
    * `timezone` (string, optional): Time zone (e.g., 'Pacific Standard Time'). Default is `UTC`.
    * `location` (string, optional): Event location.
    * `attendees` (array, optional): Array of attendee email addresses.
  </Accordion>

  <Accordion title="microsoft_outlook/get_contacts">
    **Description:** Get contacts from the user's address book.

    **Parameters:**

    * `top` (integer, optional): Number of contacts to retrieve (max 1000). Default is `10`.
    * `skip` (integer, optional): Number of contacts to skip. Default is `0`.
    * `filter` (string, optional): OData filter expression.
    * `orderby` (string, optional): Order by field (e.g., "displayName asc"). Default is "displayName asc".
  </Accordion>

  <Accordion title="microsoft_outlook/create_contact">
    **Description:** Create a new contact in the user's address book.

    **Parameters:**

    * `displayName` (string, required): Contact's display name.
    * `givenName` (string, optional): Contact's first name.
    * `surname` (string, optional): Contact's last name.
    * `emailAddresses` (array, optional): Array of email addresses. Each item is an object with `address` (string) and `name` (string).
    * `businessPhones` (array, optional): Array of business phone numbers.
    * `homePhones` (array, optional): Array of home phone numbers.
    * `jobTitle` (string, optional): Contact's job title.
    * `companyName` (string, optional): Contact's company name.
  </Accordion>

  <Accordion title="microsoft_outlook/get_message">
    **Description:** Get a specific email message by ID.

    **Parameters:**

    * `message_id` (string, required): The unique identifier of the message. Obtain from get\_messages action.
    * `select` (string, optional): Comma-separated list of properties to return. Example: "id,subject,body,from,receivedDateTime". Default is "id,subject,body,from,toRecipients,receivedDateTime".
  </Accordion>

  <Accordion title="microsoft_outlook/reply_to_email">
    **Description:** Reply to an email message.

    **Parameters:**

    * `message_id` (string, required): The unique identifier of the message to reply to. Obtain from get\_messages action.
    * `comment` (string, required): The reply message content. Can be plain text or HTML. The original message will be quoted below this content.
  </Accordion>

  <Accordion title="microsoft_outlook/forward_email">
    **Description:** Forward an email message.

    **Parameters:**

    * `message_id` (string, required): The unique identifier of the message to forward. Obtain from get\_messages action.
    * `to_recipients` (array, required): Array of recipient email addresses to forward to. Example: \["[john@example.com](mailto:john@example.com)", "[jane@example.com](mailto:jane@example.com)"].
    * `comment` (string, optional): Optional message to include above the forwarded content. Can be plain text or HTML.
  </Accordion>

  <Accordion title="microsoft_outlook/mark_message_read">
    **Description:** Mark a message as read or unread.

    **Parameters:**

    * `message_id` (string, required): The unique identifier of the message. Obtain from get\_messages action.
    * `is_read` (boolean, required): Set to true to mark as read, false to mark as unread.
  </Accordion>

  <Accordion title="microsoft_outlook/delete_message">
    **Description:** Delete an email message.

    **Parameters:**

    * `message_id` (string, required): The unique identifier of the message to delete. Obtain from get\_messages action.
  </Accordion>

  <Accordion title="microsoft_outlook/update_event">
    **Description:** Update an existing calendar event.

    **Parameters:**

    * `event_id` (string, required): The unique identifier of the event. Obtain from get\_calendar\_events action.
    * `subject` (string, optional): New subject/title for the event.
    * `start_time` (string, optional): New start time in ISO 8601 format (e.g., "2024-01-20T10:00:00"). REQUIRED: Must also provide start\_timezone when using this field.
    * `start_timezone` (string, optional): Timezone for start time. REQUIRED when updating start\_time. Examples: "Pacific Standard Time", "Eastern Standard Time", "UTC".
    * `end_time` (string, optional): New end time in ISO 8601 format. REQUIRED: Must also provide end\_timezone when using this field.
    * `end_timezone` (string, optional): Timezone for end time. REQUIRED when updating end\_time. Examples: "Pacific Standard Time", "Eastern Standard Time", "UTC".
    * `location` (string, optional): New location for the event.
    * `body` (string, optional): New body/description for the event. Supports HTML formatting.
  </Accordion>

  <Accordion title="microsoft_outlook/delete_event">
    **Description:** Delete a calendar event.

    **Parameters:**

    * `event_id` (string, required): The unique identifier of the event to delete. Obtain from get\_calendar\_events action.
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Microsoft Outlook Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with Microsoft Outlook capabilities
outlook_agent = Agent(
    role="Email Assistant",
    goal="Manage emails, calendar events, and contacts efficiently",
    backstory="An AI assistant specialized in Microsoft Outlook operations and communication management.",
    apps=['microsoft_outlook']  # All Outlook actions will be available
)

# Task to send an email
send_email_task = Task(
    description="Send an email to 'colleague@example.com' with subject 'Project Update' and body 'Hi, here is the latest project update. Best regards.'",
    agent=outlook_agent,
    expected_output="Email sent successfully to colleague@example.com"
)

# Run the task
crew = Crew(
    agents=[outlook_agent],
    tasks=[send_email_task]
)

crew.kickoff()
```

### Email Management and Search

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent focused on email management
email_manager = Agent(
    role="Email Manager",
    goal="Retrieve, search, and organize email messages",
    backstory="An AI assistant skilled in email organization and management.",
    apps=['microsoft_outlook/get_messages']
)

# Task to search and retrieve emails
search_emails_task = Task(
    description="Get the latest 20 unread emails and provide a summary of the most important ones.",
    agent=email_manager,
    expected_output="Summary of the most important unread emails with key details."
)

crew = Crew(
    agents=[email_manager],
    tasks=[search_emails_task]
)

crew.kickoff()
```

### Calendar and Contact Management

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent for calendar and contact management
scheduler = Agent(
    role="Calendar and Contact Manager",
    goal="Manage calendar events and maintain contact information",
    backstory="An AI assistant that handles scheduling and contact organization.",
    apps=['microsoft_outlook/create_calendar_event', 'microsoft_outlook/get_calendar_events', 'microsoft_outlook/create_contact']
)

# Task to create a meeting and add a contact
schedule_task = Task(
    description="Create a calendar event for tomorrow at 2 PM titled 'Team Meeting' with location 'Conference Room A', and create a new contact for 'John Smith' with email 'john.smith@example.com' and job title 'Project Manager'.",
    agent=scheduler,
    expected_output="Calendar event created and new contact added successfully."
)

crew = Crew(
    agents=[scheduler],
    tasks=[schedule_task]
)

crew.kickoff()
```

## Troubleshooting

### Common Issues

**Authentication Errors**

* Ensure your Microsoft account has the necessary permissions for mail, calendar, and contact access.
* Required scopes include: `Mail.Read`, `Mail.Send`, `Calendars.Read`, `Calendars.ReadWrite`, `Contacts.Read`, `Contacts.ReadWrite`.
* Verify that the OAuth connection includes all required scopes.

**Email Sending Issues**

* Ensure `to_recipients`, `subject`, and `body` are provided for `send_email`.
* Check that email addresses are properly formatted.
* Verify that the account has `Mail.Send` permissions.

**Calendar Event Creation**

* Ensure `subject`, `start_datetime`, and `end_datetime` are provided.
* Use proper ISO 8601 format for datetime fields (e.g., '2024-01-20T10:00:00').
* Verify timezone settings if events appear at incorrect times.

**Contact Management**

* For `create_contact`, ensure `displayName` is provided as it's required.
* When providing `emailAddresses`, use the proper object format with `address` and `name` properties.

**Search and Filter Issues**

* Use proper OData syntax for `filter` parameters.
* For date filters, use ISO 8601 format (e.g., "receivedDateTime ge '2024-01-01T00:00:00Z'").

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Microsoft Outlook integration
  setup or troubleshooting.
</Card>


# Microsoft SharePoint Integration
Source: https://docs.crewai.com/en/enterprise/integrations/microsoft_sharepoint

Site, list, and document management with Microsoft SharePoint integration for CrewAI.

## Overview

Enable your agents to access and manage SharePoint sites, lists, and document libraries. Retrieve site information, manage list items, upload and organize files, and streamline your SharePoint workflows with AI-powered automation.

## Prerequisites

Before using the Microsoft SharePoint integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Microsoft 365 account with SharePoint access
* Connected your Microsoft account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up Microsoft SharePoint Integration

### 1. Connect Your Microsoft Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Microsoft SharePoint** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for SharePoint sites and content access
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="microsoft_sharepoint/get_sites">
    **Description:** Get all SharePoint sites the user has access to.

    **Parameters:**

    * `search` (string, optional): Search query to filter sites
    * `select` (string, optional): Select specific properties to return (e.g., 'displayName,id,webUrl')
    * `filter` (string, optional): Filter results using OData syntax
    * `expand` (string, optional): Expand related resources inline
    * `top` (integer, optional): Number of items to return. Minimum: 1, Maximum: 999
    * `skip` (integer, optional): Number of items to skip. Minimum: 0
    * `orderby` (string, optional): Order results by specified properties (e.g., 'displayName desc')
  </Accordion>

  <Accordion title="microsoft_sharepoint/get_site">
    **Description:** Get information about a specific SharePoint site.

    **Parameters:**

    * `site_id` (string, required): The ID of the SharePoint site
    * `select` (string, optional): Select specific properties to return (e.g., 'displayName,id,webUrl,drives')
    * `expand` (string, optional): Expand related resources inline (e.g., 'drives,lists')
  </Accordion>

  <Accordion title="microsoft_sharepoint/get_drives">
    **Description:** List all document libraries (drives) in a SharePoint site. Use this to discover available libraries before using file operations.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `top` (integer, optional): Maximum number of drives to return per page (1-999). Default is 100
    * `skip_token` (string, optional): Pagination token from a previous response to fetch the next page of results
    * `select` (string, optional): Comma-separated list of properties to return (e.g., 'id,name,webUrl,driveType')
  </Accordion>

  <Accordion title="microsoft_sharepoint/get_site_lists">
    **Description:** Get all lists in a SharePoint site.

    **Parameters:**

    * `site_id` (string, required): The ID of the SharePoint site
  </Accordion>

  <Accordion title="microsoft_sharepoint/get_list">
    **Description:** Get information about a specific list.

    **Parameters:**

    * `site_id` (string, required): The ID of the SharePoint site
    * `list_id` (string, required): The ID of the list
  </Accordion>

  <Accordion title="microsoft_sharepoint/get_list_items">
    **Description:** Get items from a SharePoint list.

    **Parameters:**

    * `site_id` (string, required): The ID of the SharePoint site
    * `list_id` (string, required): The ID of the list
    * `expand` (string, optional): Expand related data (e.g., 'fields')
  </Accordion>

  <Accordion title="microsoft_sharepoint/create_list_item">
    **Description:** Create a new item in a SharePoint list.

    **Parameters:**

    * `site_id` (string, required): The ID of the SharePoint site
    * `list_id` (string, required): The ID of the list
    * `fields` (object, required): The field values for the new item
      ```json theme={null}
      {
        "Title": "New Item Title",
        "Description": "Item description",
        "Status": "Active"
      }
      ```
  </Accordion>

  <Accordion title="microsoft_sharepoint/update_list_item">
    **Description:** Update an item in a SharePoint list.

    **Parameters:**

    * `site_id` (string, required): The ID of the SharePoint site
    * `list_id` (string, required): The ID of the list
    * `item_id` (string, required): The ID of the item to update
    * `fields` (object, required): The field values to update
      ```json theme={null}
      {
        "Title": "Updated Title",
        "Status": "Completed"
      }
      ```
  </Accordion>

  <Accordion title="microsoft_sharepoint/delete_list_item">
    **Description:** Delete an item from a SharePoint list.

    **Parameters:**

    * `site_id` (string, required): The ID of the SharePoint site
    * `list_id` (string, required): The ID of the list
    * `item_id` (string, required): The ID of the item to delete
  </Accordion>

  <Accordion title="microsoft_sharepoint/upload_file_to_library">
    **Description:** Upload a file to a SharePoint document library.

    **Parameters:**

    * `site_id` (string, required): The ID of the SharePoint site
    * `file_path` (string, required): The path where to upload the file (e.g., 'folder/filename.txt')
    * `content` (string, required): The file content to upload
  </Accordion>

  <Accordion title="microsoft_sharepoint/list_files">
    **Description:** Retrieve files and folders from a SharePoint document library. By default lists the root folder, but you can navigate into subfolders by providing a folder\_id.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `folder_id` (string, optional): The ID of the folder to list contents from. Use 'root' for the root folder, or provide a folder ID from a previous list\_files call. Default is 'root'
    * `top` (integer, optional): Maximum number of items to return per page (1-1000). Default is 50
    * `skip_token` (string, optional): Pagination token from a previous response to fetch the next page of results
    * `orderby` (string, optional): Sort order for results (e.g., 'name asc', 'size desc', 'lastModifiedDateTime desc'). Default is 'name asc'
    * `filter` (string, optional): OData filter to narrow results (e.g., 'file ne null' for files only, 'folder ne null' for folders only)
    * `select` (string, optional): Comma-separated list of fields to return (e.g., 'id,name,size,folder,file,webUrl,lastModifiedDateTime')
  </Accordion>

  <Accordion title="microsoft_sharepoint/delete_file">
    **Description:** Delete a file or folder from a SharePoint document library. For folders, all contents are deleted recursively. Items are moved to the site recycle bin.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the file or folder to delete. Obtain from list\_files
  </Accordion>

  <Accordion title="microsoft_sharepoint/list_files_by_path">
    **Description:** List files and folders in a SharePoint document library folder by its path. More efficient than multiple list\_files calls for deep navigation.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `folder_path` (string, required): The full path to the folder without leading/trailing slashes (e.g., 'Documents', 'Reports/2024/Q1')
    * `top` (integer, optional): Maximum number of items to return per page (1-1000). Default is 50
    * `skip_token` (string, optional): Pagination token from a previous response to fetch the next page of results
    * `orderby` (string, optional): Sort order for results (e.g., 'name asc', 'size desc'). Default is 'name asc'
    * `select` (string, optional): Comma-separated list of fields to return (e.g., 'id,name,size,folder,file,webUrl,lastModifiedDateTime')
  </Accordion>

  <Accordion title="microsoft_sharepoint/download_file">
    **Description:** Download raw file content from a SharePoint document library. Use only for plain text files (.txt, .csv, .json). For Excel files, use the Excel-specific actions. For Word files, use get\_word\_document\_content.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the file to download. Obtain from list\_files or list\_files\_by\_path
  </Accordion>

  <Accordion title="microsoft_sharepoint/get_file_info">
    **Description:** Retrieve detailed metadata for a specific file or folder in a SharePoint document library, including name, size, created/modified dates, and author information.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the file or folder. Obtain from list\_files or list\_files\_by\_path
    * `select` (string, optional): Comma-separated list of properties to return (e.g., 'id,name,size,createdDateTime,lastModifiedDateTime,webUrl,createdBy,lastModifiedBy')
  </Accordion>

  <Accordion title="microsoft_sharepoint/create_folder">
    **Description:** Create a new folder in a SharePoint document library. By default creates the folder in the root; use parent\_id to create subfolders.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `folder_name` (string, required): Name for the new folder. Cannot contain: \ / : \* ? " \< > |
    * `parent_id` (string, optional): The ID of the parent folder. Use 'root' for the document library root, or provide a folder ID from list\_files. Default is 'root'
  </Accordion>

  <Accordion title="microsoft_sharepoint/search_files">
    **Description:** Search for files and folders in a SharePoint document library by keywords. Searches file names, folder names, and file contents for Office documents. Do not use wildcards or special characters.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `query` (string, required): Search keywords (e.g., 'report', 'budget 2024'). Wildcards like \*.txt are not supported
    * `top` (integer, optional): Maximum number of results to return per page (1-1000). Default is 50
    * `skip_token` (string, optional): Pagination token from a previous response to fetch the next page of results
    * `select` (string, optional): Comma-separated list of fields to return (e.g., 'id,name,size,folder,file,webUrl,lastModifiedDateTime')
  </Accordion>

  <Accordion title="microsoft_sharepoint/copy_file">
    **Description:** Copy a file or folder to a new location within SharePoint. The original item remains unchanged. The copy operation is asynchronous for large files.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the file or folder to copy. Obtain from list\_files or search\_files
    * `destination_folder_id` (string, required): The ID of the destination folder. Use 'root' for the root folder, or a folder ID from list\_files
    * `new_name` (string, optional): New name for the copy. If not provided, the original name is used
  </Accordion>

  <Accordion title="microsoft_sharepoint/move_file">
    **Description:** Move a file or folder to a new location within SharePoint. The item is removed from its original location. For folders, all contents are moved as well.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the file or folder to move. Obtain from list\_files or search\_files
    * `destination_folder_id` (string, required): The ID of the destination folder. Use 'root' for the root folder, or a folder ID from list\_files
    * `new_name` (string, optional): New name for the moved item. If not provided, the original name is kept
  </Accordion>

  <Accordion title="microsoft_sharepoint/get_excel_worksheets">
    **Description:** List all worksheets (tabs) in an Excel workbook stored in a SharePoint document library. Use the returned worksheet name with other Excel actions.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the Excel file in SharePoint. Obtain from list\_files or search\_files
    * `select` (string, optional): Comma-separated list of properties to return (e.g., 'id,name,position,visibility')
    * `filter` (string, optional): OData filter expression (e.g., "visibility eq 'Visible'" to exclude hidden sheets)
    * `top` (integer, optional): Maximum number of worksheets to return. Minimum: 1, Maximum: 999
    * `orderby` (string, optional): Sort order (e.g., 'position asc' to return sheets in tab order)
  </Accordion>

  <Accordion title="microsoft_sharepoint/create_excel_worksheet">
    **Description:** Create a new worksheet (tab) in an Excel workbook stored in a SharePoint document library. The new sheet is added at the end of the tab list.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the Excel file in SharePoint. Obtain from list\_files or search\_files
    * `name` (string, required): Name for the new worksheet. Maximum 31 characters. Cannot contain: \ / \* ? : \[ ]. Must be unique within the workbook
  </Accordion>

  <Accordion title="microsoft_sharepoint/get_excel_range_data">
    **Description:** Retrieve cell values from a specific range in an Excel worksheet stored in SharePoint. For reading all data without knowing dimensions, use get\_excel\_used\_range instead.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the Excel file in SharePoint. Obtain from list\_files or search\_files
    * `worksheet_name` (string, required): Name of the worksheet (tab) to read from. Obtain from get\_excel\_worksheets. Case-sensitive
    * `range` (string, required): Cell range in A1 notation (e.g., 'A1:C10', 'A:C', '1:5', 'A1')
    * `select` (string, optional): Comma-separated list of properties to return (e.g., 'address,values,formulas,numberFormat,text')
  </Accordion>

  <Accordion title="microsoft_sharepoint/update_excel_range_data">
    **Description:** Write values to a specific range in an Excel worksheet stored in SharePoint. Overwrites existing cell contents. The values array dimensions must match the range dimensions exactly.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the Excel file in SharePoint. Obtain from list\_files or search\_files
    * `worksheet_name` (string, required): Name of the worksheet (tab) to update. Obtain from get\_excel\_worksheets. Case-sensitive
    * `range` (string, required): Cell range in A1 notation where values will be written (e.g., 'A1:C3' for a 3x3 block)
    * `values` (array, required): 2D array of values (rows containing cells). Example for A1:B2: \[\["Header1", "Header2"], \["Value1", "Value2"]]. Use null to clear a cell
  </Accordion>

  <Accordion title="microsoft_sharepoint/get_excel_used_range_metadata">
    **Description:** Return only the metadata (address and dimensions) of the used range in a worksheet, without the actual cell values. Ideal for large files to understand spreadsheet size before reading data in chunks.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the Excel file in SharePoint. Obtain from list\_files or search\_files
    * `worksheet_name` (string, required): Name of the worksheet (tab) to read. Obtain from get\_excel\_worksheets. Case-sensitive
  </Accordion>

  <Accordion title="microsoft_sharepoint/get_excel_used_range">
    **Description:** Retrieve all cells containing data in a worksheet stored in SharePoint. Do not use for files larger than 2MB. For large files, use get\_excel\_used\_range\_metadata first, then get\_excel\_range\_data to read in smaller chunks.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the Excel file in SharePoint. Obtain from list\_files or search\_files
    * `worksheet_name` (string, required): Name of the worksheet (tab) to read. Obtain from get\_excel\_worksheets. Case-sensitive
    * `select` (string, optional): Comma-separated list of properties to return (e.g., 'address,values,formulas,numberFormat,text,rowCount,columnCount')
  </Accordion>

  <Accordion title="microsoft_sharepoint/get_excel_cell">
    **Description:** Retrieve the value of a single cell by row and column index from an Excel file in SharePoint. Indices are 0-based (row 0 = Excel row 1, column 0 = column A).

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the Excel file in SharePoint. Obtain from list\_files or search\_files
    * `worksheet_name` (string, required): Name of the worksheet (tab). Obtain from get\_excel\_worksheets. Case-sensitive
    * `row` (integer, required): 0-based row index (row 0 = Excel row 1). Valid range: 0-1048575
    * `column` (integer, required): 0-based column index (column 0 = A, column 1 = B). Valid range: 0-16383
    * `select` (string, optional): Comma-separated list of properties to return (e.g., 'address,values,formulas,numberFormat,text')
  </Accordion>

  <Accordion title="microsoft_sharepoint/add_excel_table">
    **Description:** Convert a cell range into a formatted Excel table with filtering, sorting, and structured data capabilities. Tables enable add\_excel\_table\_row for appending data.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the Excel file in SharePoint. Obtain from list\_files or search\_files
    * `worksheet_name` (string, required): Name of the worksheet containing the data range. Obtain from get\_excel\_worksheets
    * `range` (string, required): Cell range to convert into a table, including headers and data (e.g., 'A1:D10' where A1:D1 contains column headers)
    * `has_headers` (boolean, optional): Set to true if the first row contains column headers. Default is true
  </Accordion>

  <Accordion title="microsoft_sharepoint/get_excel_tables">
    **Description:** List all tables in a specific Excel worksheet stored in SharePoint. Returns table properties including id, name, showHeaders, and showTotals.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the Excel file in SharePoint. Obtain from list\_files or search\_files
    * `worksheet_name` (string, required): Name of the worksheet to get tables from. Obtain from get\_excel\_worksheets
  </Accordion>

  <Accordion title="microsoft_sharepoint/add_excel_table_row">
    **Description:** Append a new row to the end of an Excel table in a SharePoint file. The values array must have the same number of elements as the table has columns.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the Excel file in SharePoint. Obtain from list\_files or search\_files
    * `worksheet_name` (string, required): Name of the worksheet containing the table. Obtain from get\_excel\_worksheets
    * `table_name` (string, required): Name of the table to add the row to (e.g., 'Table1'). Obtain from get\_excel\_tables. Case-sensitive
    * `values` (array, required): Array of cell values for the new row, one per column in table order (e.g., \["John Doe", "[john@example.com](mailto:john@example.com)", 25])
  </Accordion>

  <Accordion title="microsoft_sharepoint/get_excel_table_data">
    **Description:** Get all rows from an Excel table in a SharePoint file as a data range. Easier than get\_excel\_range\_data when working with structured tables since you don't need to know the exact range.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the Excel file in SharePoint. Obtain from list\_files or search\_files
    * `worksheet_name` (string, required): Name of the worksheet containing the table. Obtain from get\_excel\_worksheets
    * `table_name` (string, required): Name of the table to get data from (e.g., 'Table1'). Obtain from get\_excel\_tables. Case-sensitive
    * `select` (string, optional): Comma-separated list of properties to return (e.g., 'address,values,formulas,numberFormat,text')
  </Accordion>

  <Accordion title="microsoft_sharepoint/create_excel_chart">
    **Description:** Create a chart visualization in an Excel worksheet stored in SharePoint from a data range. The chart is embedded in the worksheet.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the Excel file in SharePoint. Obtain from list\_files or search\_files
    * `worksheet_name` (string, required): Name of the worksheet where the chart will be created. Obtain from get\_excel\_worksheets
    * `chart_type` (string, required): Chart type (e.g., 'ColumnClustered', 'ColumnStacked', 'Line', 'LineMarkers', 'Pie', 'Bar', 'BarClustered', 'Area', 'Scatter', 'Doughnut')
    * `source_data` (string, required): Data range for the chart in A1 notation, including headers (e.g., 'A1:B10')
    * `series_by` (string, optional): How data series are organized: 'Auto', 'Columns', or 'Rows'. Default is 'Auto'
  </Accordion>

  <Accordion title="microsoft_sharepoint/list_excel_charts">
    **Description:** List all charts embedded in an Excel worksheet stored in SharePoint. Returns chart properties including id, name, chartType, height, width, and position.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the Excel file in SharePoint. Obtain from list\_files or search\_files
    * `worksheet_name` (string, required): Name of the worksheet to list charts from. Obtain from get\_excel\_worksheets
  </Accordion>

  <Accordion title="microsoft_sharepoint/delete_excel_worksheet">
    **Description:** Permanently remove a worksheet (tab) and all its contents from an Excel workbook stored in SharePoint. Cannot be undone. A workbook must have at least one worksheet.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the Excel file in SharePoint. Obtain from list\_files or search\_files
    * `worksheet_name` (string, required): Name of the worksheet to delete. Case-sensitive. All data, tables, and charts on this sheet will be permanently removed
  </Accordion>

  <Accordion title="microsoft_sharepoint/delete_excel_table">
    **Description:** Remove a table from an Excel worksheet in SharePoint. This deletes the table structure (filtering, formatting, table features) but preserves the underlying cell data.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the Excel file in SharePoint. Obtain from list\_files or search\_files
    * `worksheet_name` (string, required): Name of the worksheet containing the table. Obtain from get\_excel\_worksheets
    * `table_name` (string, required): Name of the table to delete (e.g., 'Table1'). Obtain from get\_excel\_tables. The data in the cells will remain after table deletion
  </Accordion>

  <Accordion title="microsoft_sharepoint/list_excel_names">
    **Description:** Retrieve all named ranges defined in an Excel workbook stored in SharePoint. Named ranges are user-defined labels for cell ranges (e.g., 'SalesData' for A1:D100).

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the Excel file in SharePoint. Obtain from list\_files or search\_files
  </Accordion>

  <Accordion title="microsoft_sharepoint/get_word_document_content">
    **Description:** Download and extract text content from a Word document (.docx) stored in a SharePoint document library. This is the recommended way to read Word documents from SharePoint.

    **Parameters:**

    * `site_id` (string, required): The full SharePoint site identifier from get\_sites
    * `drive_id` (string, required): The ID of the document library. Call get\_drives first to get valid drive IDs
    * `item_id` (string, required): The unique identifier of the Word document (.docx) in SharePoint. Obtain from list\_files or search\_files
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic SharePoint Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with SharePoint capabilities
sharepoint_agent = Agent(
    role="SharePoint Manager",
    goal="Manage SharePoint sites, lists, and documents efficiently",
    backstory="An AI assistant specialized in SharePoint content management and collaboration.",
    apps=['microsoft_sharepoint']  # All SharePoint actions will be available
)

# Task to organize SharePoint content
content_organization_task = Task(
    description="List all accessible SharePoint sites and organize content by department",
    agent=sharepoint_agent,
    expected_output="SharePoint sites listed and content organized by department"
)

# Run the task
crew = Crew(
    agents=[sharepoint_agent],
    tasks=[content_organization_task]
)

crew.kickoff()
```

### List Management and Data Operations

```python theme={null}
from crewai import Agent, Task, Crew

list_manager = Agent(
    role="List Manager",
    goal="Manage SharePoint lists and data efficiently",
    backstory="An AI assistant that focuses on SharePoint list management and data operations.",
    apps=[
        'microsoft_sharepoint/get_site_lists',
        'microsoft_sharepoint/get_list_items',
        'microsoft_sharepoint/create_list_item',
        'microsoft_sharepoint/update_list_item'
    ]
)

# Task to manage list data
list_management_task = Task(
    description="Get all lists from the project site, review items, and update status for completed tasks",
    agent=list_manager,
    expected_output="SharePoint lists reviewed and task statuses updated"
)

crew = Crew(
    agents=[list_manager],
    tasks=[list_management_task]
)

crew.kickoff()
```

### Document Library Management

```python theme={null}
from crewai import Agent, Task, Crew

document_manager = Agent(
    role="Document Manager",
    goal="Manage SharePoint document libraries and files",
    backstory="An AI assistant that specializes in document organization and file management.",
    apps=['microsoft_sharepoint']
)

# Task to manage documents
document_task = Task(
    description="""
    1. Get all files from the main document library
    2. Upload new policy documents to the appropriate folders
    3. Organize files by department and date
    4. Remove outdated documents
    """,
    agent=document_manager,
    expected_output="Document library organized with new files uploaded and outdated files removed"
)

crew = Crew(
    agents=[document_manager],
    tasks=[document_task]
)

crew.kickoff()
```

### Site Administration and Analysis

```python theme={null}
from crewai import Agent, Task, Crew

site_administrator = Agent(
    role="Site Administrator",
    goal="Administer and analyze SharePoint sites",
    backstory="An AI assistant that handles site administration and provides insights on site usage.",
    apps=['microsoft_sharepoint']
)

# Task for site administration
admin_task = Task(
    description="""
    1. Get information about all accessible SharePoint sites
    2. Analyze site structure and content organization
    3. Identify sites with low activity or outdated content
    4. Generate recommendations for site optimization
    """,
    agent=site_administrator,
    expected_output="Site analysis completed with optimization recommendations"
)

crew = Crew(
    agents=[site_administrator],
    tasks=[admin_task]
)

crew.kickoff()
```

### Automated Content Workflows

```python theme={null}
from crewai import Agent, Task, Crew

workflow_automator = Agent(
    role="Workflow Automator",
    goal="Automate SharePoint content workflows and processes",
    backstory="An AI assistant that automates complex SharePoint workflows and content management processes.",
    apps=['microsoft_sharepoint']
)

# Complex workflow automation task
automation_task = Task(
    description="""
    1. Monitor project lists across multiple sites
    2. Create status reports based on list data
    3. Upload reports to designated document libraries
    4. Update project tracking lists with completion status
    5. Archive completed project documents
    6. Send notifications for overdue items
    """,
    agent=workflow_automator,
    expected_output="Automated workflow completed with status reports generated and project tracking updated"
)

crew = Crew(
    agents=[workflow_automator],
    tasks=[automation_task]
)

crew.kickoff()
```

### Data Integration and Reporting

```python theme={null}
from crewai import Agent, Task, Crew

data_integrator = Agent(
    role="Data Integrator",
    goal="Integrate and analyze data across SharePoint sites and lists",
    backstory="An AI assistant that specializes in data integration and cross-site analysis.",
    apps=['microsoft_sharepoint']
)

# Task for data integration
integration_task = Task(
    description="""
    1. Get data from multiple SharePoint lists across different sites
    2. Consolidate information into comprehensive reports
    3. Create new list items with aggregated data
    4. Upload analytical reports to executive document library
    5. Update dashboard lists with key metrics
    """,
    agent=data_integrator,
    expected_output="Data integrated across sites with comprehensive reports and updated dashboards"
)

crew = Crew(
    agents=[data_integrator],
    tasks=[integration_task]
)

crew.kickoff()
```

## Troubleshooting

### Common Issues

**Permission Errors**

* Ensure your Microsoft account has appropriate permissions for SharePoint sites
* Verify that the OAuth connection includes required scopes (Sites.Read.All, Sites.ReadWrite.All)
* Check that you have access to the specific sites and lists you're trying to access

**Site and List ID Issues**

* Verify that site IDs and list IDs are correct and properly formatted
* Ensure that sites and lists exist and are accessible to your account
* Use the get\_sites and get\_site\_lists actions to discover valid IDs

**Field and Schema Issues**

* Ensure field names match exactly with the SharePoint list schema
* Verify that required fields are included when creating or updating list items
* Check that field types and values are compatible with the list column definitions

**File Upload Issues**

* Ensure file paths are properly formatted and don't contain invalid characters
* Verify that you have write permissions to the target document library
* Check that file content is properly encoded for upload

**OData Query Issues**

* Use proper OData syntax for filter, select, expand, and orderby parameters
* Verify that property names used in queries exist in the target resources
* Test simple queries before building complex filter expressions

**Pagination and Performance**

* Use top and skip parameters appropriately for large result sets
* Implement proper pagination for lists with many items
* Consider using select parameters to return only needed properties

**Document Library Operations**

* Ensure you have proper permissions for document library operations
* Verify that drive item IDs are correct when deleting files or folders
* Check that file paths don't conflict with existing content

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Microsoft SharePoint integration
  setup or troubleshooting.
</Card>


# Microsoft Teams Integration
Source: https://docs.crewai.com/en/enterprise/integrations/microsoft_teams

Team collaboration and communication with Microsoft Teams integration for CrewAI.

## Overview

Enable your agents to access Teams data, send messages, create meetings, and manage channels. Automate team communication, schedule meetings, retrieve messages, and streamline your collaboration workflows with AI-powered automation.

## Prerequisites

Before using the Microsoft Teams integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Microsoft account with Teams access
* Connected your Microsoft account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up Microsoft Teams Integration

### 1. Connect Your Microsoft Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Microsoft Teams** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for Teams access
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="microsoft_teams/get_teams">
    **Description:** Get all teams the user is a member of.

    **Parameters:**

    * No parameters required.
  </Accordion>

  <Accordion title="microsoft_teams/get_channels">
    **Description:** Get channels in a specific team.

    **Parameters:**

    * `team_id` (string, required): The ID of the team.
  </Accordion>

  <Accordion title="microsoft_teams/send_message">
    **Description:** Send a message to a Teams channel.

    **Parameters:**

    * `team_id` (string, required): The ID of the team.
    * `channel_id` (string, required): The ID of the channel.
    * `message` (string, required): The message content.
    * `content_type` (string, optional): Content type (html or text). Enum: `html`, `text`. Default is `text`.
  </Accordion>

  <Accordion title="microsoft_teams/get_messages">
    **Description:** Get messages from a Teams channel.

    **Parameters:**

    * `team_id` (string, required): The ID of the team.
    * `channel_id` (string, required): The ID of the channel.
    * `top` (integer, optional): Number of messages to retrieve (max 50). Default is `20`.
  </Accordion>

  <Accordion title="microsoft_teams/create_meeting">
    **Description:** Create a Teams meeting.

    **Parameters:**

    * `subject` (string, required): Meeting subject/title.
    * `startDateTime` (string, required): Meeting start time (ISO 8601 format with timezone).
    * `endDateTime` (string, required): Meeting end time (ISO 8601 format with timezone).
  </Accordion>

  <Accordion title="microsoft_teams/search_online_meetings_by_join_url">
    **Description:** Search online meetings by Join Web URL.

    **Parameters:**

    * `join_web_url` (string, required): The join web URL of the meeting to search for.
  </Accordion>

  <Accordion title="microsoft_teams/search_online_meetings_by_meeting_id">
    **Description:** Search online meetings by external Meeting ID.

    **Parameters:**

    * `join_meeting_id` (string, required): The meeting ID (numeric code) that attendees use to join. This is the joinMeetingId shown in meeting invitations, not the Graph API meeting id.
  </Accordion>

  <Accordion title="microsoft_teams/get_meeting">
    **Description:** Get details of a specific online meeting.

    **Parameters:**

    * `meeting_id` (string, required): The Graph API meeting ID (a long alphanumeric string). Obtain from create\_meeting or search\_online\_meetings actions. Different from the numeric joinMeetingId.
  </Accordion>

  <Accordion title="microsoft_teams/get_team_members">
    **Description:** Get members of a specific team.

    **Parameters:**

    * `team_id` (string, required): The unique identifier of the team. Obtain from get\_teams action.
    * `top` (integer, optional): Maximum number of members to retrieve per page (1-999). Default is `100`.
    * `skip_token` (string, optional): Pagination token from a previous response. When the response includes @odata.nextLink, extract the \$skiptoken parameter value and pass it here to get the next page of results.
  </Accordion>

  <Accordion title="microsoft_teams/create_channel">
    **Description:** Create a new channel in a team.

    **Parameters:**

    * `team_id` (string, required): The unique identifier of the team. Obtain from get\_teams action.
    * `display_name` (string, required): Name of the channel as displayed in Teams. Must be unique within the team. Max 50 characters.
    * `description` (string, optional): Optional description explaining the channel's purpose. Visible in channel details. Max 1024 characters.
    * `membership_type` (string, optional): Channel visibility. Enum: `standard`, `private`. "standard" = visible to all team members, "private" = visible only to specifically added members. Default is `standard`.
  </Accordion>

  <Accordion title="microsoft_teams/get_message_replies">
    **Description:** Get replies to a specific message in a channel.

    **Parameters:**

    * `team_id` (string, required): The unique identifier of the team. Obtain from get\_teams action.
    * `channel_id` (string, required): The unique identifier of the channel. Obtain from get\_channels action.
    * `message_id` (string, required): The unique identifier of the parent message. Obtain from get\_messages action.
    * `top` (integer, optional): Maximum number of replies to retrieve per page (1-50). Default is `50`.
    * `skip_token` (string, optional): Pagination token from a previous response. When the response includes @odata.nextLink, extract the \$skiptoken parameter value and pass it here to get the next page of results.
  </Accordion>

  <Accordion title="microsoft_teams/reply_to_message">
    **Description:** Reply to a message in a Teams channel.

    **Parameters:**

    * `team_id` (string, required): The unique identifier of the team. Obtain from get\_teams action.
    * `channel_id` (string, required): The unique identifier of the channel. Obtain from get\_channels action.
    * `message_id` (string, required): The unique identifier of the message to reply to. Obtain from get\_messages action.
    * `message` (string, required): The reply content. For HTML, include formatting tags. For text, plain text only.
    * `content_type` (string, optional): Content format. Enum: `html`, `text`. "text" for plain text, "html" for rich text with formatting. Default is `text`.
  </Accordion>

  <Accordion title="microsoft_teams/update_meeting">
    **Description:** Update an existing online meeting.

    **Parameters:**

    * `meeting_id` (string, required): The unique identifier of the meeting. Obtain from create\_meeting or search\_online\_meetings actions.
    * `subject` (string, optional): New meeting title.
    * `startDateTime` (string, optional): New start time in ISO 8601 format with timezone. Example: "2024-01-20T10:00:00-08:00".
    * `endDateTime` (string, optional): New end time in ISO 8601 format with timezone.
  </Accordion>

  <Accordion title="microsoft_teams/delete_meeting">
    **Description:** Delete an online meeting.

    **Parameters:**

    * `meeting_id` (string, required): The unique identifier of the meeting to delete. Obtain from create\_meeting or search\_online\_meetings actions.
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Microsoft Teams Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with Microsoft Teams capabilities
teams_agent = Agent(
    role="Teams Coordinator",
    goal="Manage Teams communication and meetings efficiently",
    backstory="An AI assistant specialized in Microsoft Teams operations and team collaboration.",
    apps=['microsoft_teams']  # All Teams actions will be available
)

# Task to list teams and channels
explore_teams_task = Task(
    description="List all teams I'm a member of and then get the channels for the first team.",
    agent=teams_agent,
    expected_output="List of teams and channels displayed."
)

# Run the task
crew = Crew(
    agents=[teams_agent],
    tasks=[explore_teams_task]
)

crew.kickoff()
```

### Messaging and Communication

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent focused on messaging
messenger = Agent(
    role="Teams Messenger",
    goal="Send and retrieve messages in Teams channels",
    backstory="An AI assistant skilled in team communication and message management.",
    apps=['microsoft_teams/send_message', 'microsoft_teams/get_messages']
)

# Task to send a message and retrieve recent messages
messaging_task = Task(
    description="Send a message 'Hello team! This is an automated update from our AI assistant.' to the General channel of team 'your_team_id', then retrieve the last 10 messages from that channel.",
    agent=messenger,
    expected_output="Message sent successfully and recent messages retrieved."
)

crew = Crew(
    agents=[messenger],
    tasks=[messaging_task]
)

crew.kickoff()
```

### Meeting Management

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent for meeting management
meeting_scheduler = Agent(
    role="Meeting Scheduler",
    goal="Create and manage Teams meetings",
    backstory="An AI assistant that handles meeting scheduling and organization.",
    apps=['microsoft_teams/create_meeting', 'microsoft_teams/search_online_meetings_by_join_url']
)

# Task to create a meeting
schedule_meeting_task = Task(
    description="Create a Teams meeting titled 'Weekly Team Sync' scheduled for tomorrow at 10:00 AM lasting for 1 hour (use proper ISO 8601 format with timezone).",
    agent=meeting_scheduler,
    expected_output="Teams meeting created successfully with meeting details."
)

crew = Crew(
    agents=[meeting_scheduler],
    tasks=[schedule_meeting_task]
)

crew.kickoff()
```

## Troubleshooting

### Common Issues

**Authentication Errors**

* Ensure your Microsoft account has the necessary permissions for Teams access.
* Required scopes include: `Team.ReadBasic.All`, `Channel.ReadBasic.All`, `ChannelMessage.Send`, `ChannelMessage.Read.All`, `OnlineMeetings.ReadWrite`, `OnlineMeetings.Read`.
* Verify that the OAuth connection includes all required scopes.

**Team and Channel Access**

* Ensure you are a member of the teams you're trying to access.
* Double-check team IDs and channel IDs for correctness.
* Team and channel IDs can be obtained using the `get_teams` and `get_channels` actions.

**Message Sending Issues**

* Ensure `team_id`, `channel_id`, and `message` are provided for `send_message`.
* Verify that you have permissions to send messages to the specified channel.
* Choose appropriate `content_type` (text or html) based on your message format.

**Meeting Creation**

* Ensure `subject`, `startDateTime`, and `endDateTime` are provided.
* Use proper ISO 8601 format with timezone for datetime fields (e.g., '2024-01-20T10:00:00-08:00').
* Verify that the meeting times are in the future.

**Message Retrieval Limitations**

* The `get_messages` action can retrieve a maximum of 50 messages per request.
* Messages are returned in reverse chronological order (newest first).

**Meeting Search**

* For `search_online_meetings_by_join_url`, ensure the join URL is exact and properly formatted.
* The URL should be the complete Teams meeting join URL.

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Microsoft Teams integration setup
  or troubleshooting.
</Card>


# Microsoft Word Integration
Source: https://docs.crewai.com/en/enterprise/integrations/microsoft_word

Document creation and management with Microsoft Word integration for CrewAI.

## Overview

Enable your agents to create, read, and manage Word documents and text files in OneDrive or SharePoint. Automate document creation, retrieve content, manage document properties, and streamline your document workflows with AI-powered automation.

## Prerequisites

Before using the Microsoft Word integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Microsoft account with Word and OneDrive/SharePoint access
* Connected your Microsoft account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up Microsoft Word Integration

### 1. Connect Your Microsoft Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Microsoft Word** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for file access
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="microsoft_word/get_documents">
    **Description:** Get all Word documents from OneDrive or SharePoint.

    **Parameters:**

    * `select` (string, optional): Select specific properties to return.
    * `filter` (string, optional): Filter results using OData syntax.
    * `expand` (string, optional): Expand related resources inline.
    * `top` (integer, optional): Number of items to return (min 1, max 999).
    * `orderby` (string, optional): Order results by specified properties.
  </Accordion>

  <Accordion title="microsoft_word/create_text_document">
    **Description:** Create a text document (.txt) with content. RECOMMENDED for programmatic content creation that needs to be readable and editable.

    **Parameters:**

    * `file_name` (string, required): Name of the text document (should end with .txt).
    * `content` (string, optional): Text content for the document. Default is "This is a new text document created via API."
  </Accordion>

  <Accordion title="microsoft_word/get_document_content">
    **Description:** Get the content of a document (works best with text files).

    **Parameters:**

    * `file_id` (string, required): The ID of the document.
  </Accordion>

  <Accordion title="microsoft_word/get_document_properties">
    **Description:** Get properties and metadata of a document.

    **Parameters:**

    * `file_id` (string, required): The ID of the document.
  </Accordion>

  <Accordion title="microsoft_word/delete_document">
    **Description:** Delete a document.

    **Parameters:**

    * `file_id` (string, required): The ID of the document to delete.
  </Accordion>

  <Accordion title="microsoft_word/copy_document">
    **Description:** Copy a document to a new location in OneDrive.

    **Parameters:**

    * `file_id` (string, required): The ID of the document to copy
    * `name` (string, optional): New name for the copied document
    * `parent_id` (string, optional): The ID of the destination folder (defaults to root)
  </Accordion>

  <Accordion title="microsoft_word/move_document">
    **Description:** Move a document to a new location in OneDrive.

    **Parameters:**

    * `file_id` (string, required): The ID of the document to move
    * `parent_id` (string, required): The ID of the destination folder
    * `name` (string, optional): New name for the moved document
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Microsoft Word Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with Microsoft Word capabilities
word_agent = Agent(
    role="Document Manager",
    goal="Manage Word documents and text files efficiently",
    backstory="An AI assistant specialized in Microsoft Word document operations and content management.",
    apps=['microsoft_word']  # All Word actions will be available
)

# Task to create a new text document
create_doc_task = Task(
    description="Create a new text document named 'meeting_notes.txt' with content 'Meeting Notes from January 2024: Key discussion points and action items.'",
    agent=word_agent,
    expected_output="New text document 'meeting_notes.txt' created successfully."
)

# Run the task
crew = Crew(
    agents=[word_agent],
    tasks=[create_doc_task]
)

crew.kickoff()
```

### Reading and Managing Documents

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent focused on document operations
document_reader = Agent(
    role="Document Reader",
    goal="Retrieve and analyze document content and properties",
    backstory="An AI assistant skilled in reading and analyzing document content.",
    apps=['microsoft_word/get_documents', 'microsoft_word/get_document_content', 'microsoft_word/get_document_properties']
)

# Task to list and read documents
read_docs_task = Task(
    description="List all Word documents in my OneDrive, then get the content and properties of the first document found.",
    agent=document_reader,
    expected_output="List of documents with content and properties of the first document."
)

crew = Crew(
    agents=[document_reader],
    tasks=[read_docs_task]
)

crew.kickoff()
```

### Document Cleanup and Organization

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent for document management
document_organizer = Agent(
    role="Document Organizer",
    goal="Organize and clean up document collections",
    backstory="An AI assistant that helps maintain organized document libraries.",
    apps=['microsoft_word/get_documents', 'microsoft_word/get_document_properties', 'microsoft_word/delete_document']
)

# Task to organize documents
organize_task = Task(
    description="List all documents, check their properties, and identify any documents that might be duplicates or outdated for potential cleanup.",
    agent=document_organizer,
    expected_output="Analysis of document library with recommendations for organization."
)

crew = Crew(
    agents=[document_organizer],
    tasks=[organize_task]
)

crew.kickoff()
```

## Troubleshooting

### Common Issues

**Authentication Errors**

* Ensure your Microsoft account has the necessary permissions for file access (e.g., `Files.Read.All`, `Files.ReadWrite.All`).
* Verify that the OAuth connection includes all required scopes.

**File Creation Issues**

* When creating text documents, ensure the `file_name` ends with `.txt` extension.
* Verify that you have write permissions to the target location (OneDrive/SharePoint).

**Document Access Issues**

* Double-check document IDs for correctness when accessing specific documents.
* Ensure the referenced documents exist and are accessible.
* Note that this integration works best with text files (.txt) for content operations.

**Content Retrieval Limitations**

* The `get_document_content` action works best with text files (.txt).
* For complex Word documents (.docx), consider using the document properties action to get metadata.

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Microsoft Word integration setup
  or troubleshooting.
</Card>


# Notion Integration
Source: https://docs.crewai.com/en/enterprise/integrations/notion

User management and commenting with Notion integration for CrewAI.

## Overview

Enable your agents to manage users and create comments through Notion. Access workspace user information and create comments on pages and discussions, streamlining your collaboration workflows with AI-powered automation.

## Prerequisites

Before using the Notion integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Notion account with appropriate workspace permissions
* Connected your Notion account through the [Integrations page](https://app.crewai.com/crewai_plus/connectors)

## Setting Up Notion Integration

### 1. Connect Your Notion Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Notion** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for user access and comment creation
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Actions

<AccordionGroup>
  <Accordion title="notion/list_users">
    **Description:** List all users in the workspace.

    **Parameters:**

    * `page_size` (integer, optional): Number of items returned in the response. Minimum: 1, Maximum: 100, Default: 100
    * `start_cursor` (string, optional): Cursor for pagination. Return results after this cursor.
  </Accordion>

  <Accordion title="notion/get_user">
    **Description:** Retrieve a specific user by ID.

    **Parameters:**

    * `user_id` (string, required): The ID of the user to retrieve.
  </Accordion>

  <Accordion title="notion/create_comment">
    **Description:** Create a comment on a page or discussion.

    **Parameters:**

    * `parent` (object, required): The parent page or discussion to comment on.
      ```json theme={null}
      {
        "type": "page_id",
        "page_id": "PAGE_ID_HERE"
      }
      ```
      or
      ```json theme={null}
      {
        "type": "discussion_id",
        "discussion_id": "DISCUSSION_ID_HERE"
      }
      ```
    * `rich_text` (array, required): The rich text content of the comment.
      ```json theme={null}
      [
        {
          "type": "text",
          "text": {
            "content": "This is my comment text"
          }
        }
      ]
      ```
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Notion Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with Notion capabilities
notion_agent = Agent(
    role="Workspace Manager",
    goal="Manage workspace users and facilitate collaboration through comments",
    backstory="An AI assistant specialized in user management and team collaboration.",
    apps=['notion']  # All Notion actions will be available
)

# Task to list workspace users
user_management_task = Task(
    description="List all users in the workspace and provide a summary of team members",
    agent=notion_agent,
    expected_output="Complete list of workspace users with their details"
)

# Run the task
crew = Crew(
    agents=[notion_agent],
    tasks=[user_management_task]
)

crew.kickoff()
```

### Filtering Specific Notion Tools

```python theme={null}
comment_manager = Agent(
    role="Comment Manager",
    goal="Create and manage comments on Notion pages",
    backstory="An AI assistant that focuses on facilitating discussions through comments.",
    apps=['notion/create_comment']
)

# Task to create comments on pages
comment_task = Task(
    description="Create a summary comment on the project status page with key updates",
    agent=comment_manager,
    expected_output="Comment created successfully with project status updates"
)

crew = Crew(
    agents=[comment_manager],
    tasks=[comment_task]
)

crew.kickoff()
```

### User Information and Team Management

```python theme={null}
from crewai import Agent, Task, Crew

team_coordinator = Agent(
    role="Team Coordinator",
    goal="Coordinate team activities and manage user information",
    backstory="An AI assistant that helps coordinate team activities and manages user information.",
    apps=['notion']
)

# Task to coordinate team activities
coordination_task = Task(
    description="""
    1. List all users in the workspace
    2. Get detailed information for specific team members
    3. Create comments on relevant pages to notify team members about updates
    """,
    agent=team_coordinator,
    expected_output="Team coordination completed with user information gathered and notifications sent"
)

crew = Crew(
    agents=[team_coordinator],
    tasks=[coordination_task]
)

crew.kickoff()
```

### Collaboration and Communication

```python theme={null}
from crewai import Agent, Task, Crew

collaboration_facilitator = Agent(
    role="Collaboration Facilitator",
    goal="Facilitate team collaboration through comments and user management",
    backstory="An AI assistant that specializes in team collaboration and communication.",
    apps=['notion']
)

# Task to facilitate collaboration
collaboration_task = Task(
    description="""
    1. Identify active users in the workspace
    2. Create contextual comments on project pages to facilitate discussions
    3. Provide status updates and feedback through comments
    """,
    agent=collaboration_facilitator,
    expected_output="Collaboration facilitated with comments created and team members notified"
)

crew = Crew(
    agents=[collaboration_facilitator],
    tasks=[collaboration_task]
)

crew.kickoff()
```

### Automated Team Communication

```python theme={null}
from crewai import Agent, Task, Crew

communication_automator = Agent(
    role="Communication Automator",
    goal="Automate team communication and user management workflows",
    backstory="An AI assistant that automates communication workflows and manages user interactions.",
    apps=['notion']
)

# Complex communication automation task
automation_task = Task(
    description="""
    1. List all workspace users and identify team roles
    2. Get specific user information for project stakeholders
    3. Create automated status update comments on key project pages
    4. Facilitate team communication through targeted comments
    """,
    agent=communication_automator,
    expected_output="Automated communication workflow completed with user management and comments"
)

crew = Crew(
    agents=[communication_automator],
    tasks=[automation_task]
)

crew.kickoff()
```

## Troubleshooting

### Common Issues

**Permission Errors**

* Ensure your Notion account has appropriate permissions to read user information
* Verify that the OAuth connection includes required scopes for user access and comment creation
* Check that you have permissions to comment on the target pages or discussions

**User Access Issues**

* Ensure you have workspace admin permissions to list all users
* Verify that user IDs are correct and users exist in the workspace
* Check that the workspace allows API access to user information

**Comment Creation Issues**

* Verify that page IDs or discussion IDs are correct and accessible
* Ensure that rich text content follows Notion's API format specifications
* Check that you have comment permissions on the target pages or discussions

**API Rate Limits**

* Be mindful of Notion's API rate limits when making multiple requests
* Implement appropriate delays between requests if needed
* Consider pagination for large user lists

**Parent Object Specification**

* Ensure parent object type is correctly specified (page\_id or discussion\_id)
* Verify that the parent page or discussion exists and is accessible
* Check that the parent object ID format is correct

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Notion integration setup or
  troubleshooting.
</Card>


# Salesforce Integration
Source: https://docs.crewai.com/en/enterprise/integrations/salesforce

CRM and sales automation with Salesforce integration for CrewAI.

## Overview

Enable your agents to manage customer relationships, sales processes, and data through Salesforce. Create and update records, manage leads and opportunities, execute SOQL queries, and streamline your CRM workflows with AI-powered automation.

## Prerequisites

Before using the Salesforce integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Salesforce account with appropriate permissions
* Connected your Salesforce account through the [Integrations page](https://app.crewai.com/integrations)

## Setting Up Salesforce Integration

### 1. Connect Your Salesforce Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Salesforce** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for CRM and sales management
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Tools

### **Record Management**

<AccordionGroup>
  <Accordion title="salesforce/create_record_contact">
    **Description:** Create a new Contact record in Salesforce.

    **Parameters:**

    * `FirstName` (string, optional): First Name
    * `LastName` (string, required): Last Name - This field is required
    * `accountId` (string, optional): Account ID - The Account that the Contact belongs to
    * `Email` (string, optional): Email address
    * `Title` (string, optional): Title of the contact, such as CEO or Vice President
    * `Description` (string, optional): A description of the Contact
    * `additionalFields` (object, optional): Additional fields in JSON format for custom Contact fields
  </Accordion>

  <Accordion title="salesforce/create_record_lead">
    **Description:** Create a new Lead record in Salesforce.

    **Parameters:**

    * `FirstName` (string, optional): First Name
    * `LastName` (string, required): Last Name - This field is required
    * `Company` (string, required): Company - This field is required
    * `Email` (string, optional): Email address
    * `Phone` (string, optional): Phone number
    * `Website` (string, optional): Website URL
    * `Title` (string, optional): Title of the contact, such as CEO or Vice President
    * `Status` (string, optional): Lead Status - Use Connect Portal Workflow Settings to select Lead Status
    * `Description` (string, optional): A description of the Lead
    * `additionalFields` (object, optional): Additional fields in JSON format for custom Lead fields
  </Accordion>

  <Accordion title="salesforce/create_record_opportunity">
    **Description:** Create a new Opportunity record in Salesforce.

    **Parameters:**

    * `Name` (string, required): The Opportunity name - This field is required
    * `StageName` (string, optional): Opportunity Stage - Use Connect Portal Workflow Settings to select stage
    * `CloseDate` (string, optional): Close Date in YYYY-MM-DD format - Defaults to 30 days from current date
    * `AccountId` (string, optional): The Account that the Opportunity belongs to
    * `Amount` (string, optional): Estimated total sale amount
    * `Description` (string, optional): A description of the Opportunity
    * `OwnerId` (string, optional): The Salesforce user assigned to work on this Opportunity
    * `NextStep` (string, optional): Description of next task in closing Opportunity
    * `additionalFields` (object, optional): Additional fields in JSON format for custom Opportunity fields
  </Accordion>

  <Accordion title="salesforce/create_record_task">
    **Description:** Create a new Task record in Salesforce.

    **Parameters:**

    * `whatId` (string, optional): Related to ID - The ID of the Account or Opportunity this Task is related to
    * `whoId` (string, optional): Name ID - The ID of the Contact or Lead this Task is related to
    * `subject` (string, required): Subject of the task
    * `activityDate` (string, optional): Activity Date in YYYY-MM-DD format
    * `description` (string, optional): A description of the Task
    * `taskSubtype` (string, required): Task Subtype - Options: task, email, listEmail, call
    * `Status` (string, optional): Status - Options: Not Started, In Progress, Completed
    * `ownerId` (string, optional): Assigned To ID - The Salesforce user assigned to this Task
    * `callDurationInSeconds` (string, optional): Call Duration in seconds
    * `isReminderSet` (boolean, optional): Whether reminder is set
    * `reminderDateTime` (string, optional): Reminder Date/Time in ISO format
    * `additionalFields` (object, optional): Additional fields in JSON format for custom Task fields
  </Accordion>

  <Accordion title="salesforce/create_record_account">
    **Description:** Create a new Account record in Salesforce.

    **Parameters:**

    * `Name` (string, required): The Account name - This field is required
    * `OwnerId` (string, optional): The Salesforce user assigned to this Account
    * `Website` (string, optional): Website URL
    * `Phone` (string, optional): Phone number
    * `Description` (string, optional): Account description
    * `additionalFields` (object, optional): Additional fields in JSON format for custom Account fields
  </Accordion>

  <Accordion title="salesforce/create_record_any">
    **Description:** Create a record of any object type in Salesforce.

    **Note:** This is a flexible tool for creating records of custom or unknown object types.
  </Accordion>
</AccordionGroup>

### **Record Updates**

<AccordionGroup>
  <Accordion title="salesforce/update_record_contact">
    **Description:** Update an existing Contact record in Salesforce.

    **Parameters:**

    * `recordId` (string, required): The ID of the record to update
    * `FirstName` (string, optional): First Name
    * `LastName` (string, optional): Last Name
    * `accountId` (string, optional): Account ID - The Account that the Contact belongs to
    * `Email` (string, optional): Email address
    * `Title` (string, optional): Title of the contact
    * `Description` (string, optional): A description of the Contact
    * `additionalFields` (object, optional): Additional fields in JSON format for custom Contact fields
  </Accordion>

  <Accordion title="salesforce/update_record_lead">
    **Description:** Update an existing Lead record in Salesforce.

    **Parameters:**

    * `recordId` (string, required): The ID of the record to update
    * `FirstName` (string, optional): First Name
    * `LastName` (string, optional): Last Name
    * `Company` (string, optional): Company name
    * `Email` (string, optional): Email address
    * `Phone` (string, optional): Phone number
    * `Website` (string, optional): Website URL
    * `Title` (string, optional): Title of the contact
    * `Status` (string, optional): Lead Status
    * `Description` (string, optional): A description of the Lead
    * `additionalFields` (object, optional): Additional fields in JSON format for custom Lead fields
  </Accordion>

  <Accordion title="salesforce/update_record_opportunity">
    **Description:** Update an existing Opportunity record in Salesforce.

    **Parameters:**

    * `recordId` (string, required): The ID of the record to update
    * `Name` (string, optional): The Opportunity name
    * `StageName` (string, optional): Opportunity Stage
    * `CloseDate` (string, optional): Close Date in YYYY-MM-DD format
    * `AccountId` (string, optional): The Account that the Opportunity belongs to
    * `Amount` (string, optional): Estimated total sale amount
    * `Description` (string, optional): A description of the Opportunity
    * `OwnerId` (string, optional): The Salesforce user assigned to work on this Opportunity
    * `NextStep` (string, optional): Description of next task in closing Opportunity
    * `additionalFields` (object, optional): Additional fields in JSON format for custom Opportunity fields
  </Accordion>

  <Accordion title="salesforce/update_record_task">
    **Description:** Update an existing Task record in Salesforce.

    **Parameters:**

    * `recordId` (string, required): The ID of the record to update
    * `whatId` (string, optional): Related to ID - The ID of the Account or Opportunity this Task is related to
    * `whoId` (string, optional): Name ID - The ID of the Contact or Lead this Task is related to
    * `subject` (string, optional): Subject of the task
    * `activityDate` (string, optional): Activity Date in YYYY-MM-DD format
    * `description` (string, optional): A description of the Task
    * `Status` (string, optional): Status - Options: Not Started, In Progress, Completed
    * `ownerId` (string, optional): Assigned To ID - The Salesforce user assigned to this Task
    * `callDurationInSeconds` (string, optional): Call Duration in seconds
    * `isReminderSet` (boolean, optional): Whether reminder is set
    * `reminderDateTime` (string, optional): Reminder Date/Time in ISO format
    * `additionalFields` (object, optional): Additional fields in JSON format for custom Task fields
  </Accordion>

  <Accordion title="salesforce/update_record_account">
    **Description:** Update an existing Account record in Salesforce.

    **Parameters:**

    * `recordId` (string, required): The ID of the record to update
    * `Name` (string, optional): The Account name
    * `OwnerId` (string, optional): The Salesforce user assigned to this Account
    * `Website` (string, optional): Website URL
    * `Phone` (string, optional): Phone number
    * `Description` (string, optional): Account description
    * `additionalFields` (object, optional): Additional fields in JSON format for custom Account fields
  </Accordion>

  <Accordion title="salesforce/update_record_any">
    **Description:** Update a record of any object type in Salesforce.

    **Note:** This is a flexible tool for updating records of custom or unknown object types.
  </Accordion>
</AccordionGroup>

### **Record Retrieval**

<AccordionGroup>
  <Accordion title="salesforce/get_record_by_id_contact">
    **Description:** Get a Contact record by its ID.

    **Parameters:**

    * `recordId` (string, required): Record ID of the Contact
  </Accordion>

  <Accordion title="salesforce/get_record_by_id_lead">
    **Description:** Get a Lead record by its ID.

    **Parameters:**

    * `recordId` (string, required): Record ID of the Lead
  </Accordion>

  <Accordion title="salesforce/get_record_by_id_opportunity">
    **Description:** Get an Opportunity record by its ID.

    **Parameters:**

    * `recordId` (string, required): Record ID of the Opportunity
  </Accordion>

  <Accordion title="salesforce/get_record_by_id_task">
    **Description:** Get a Task record by its ID.

    **Parameters:**

    * `recordId` (string, required): Record ID of the Task
  </Accordion>

  <Accordion title="salesforce/get_record_by_id_account">
    **Description:** Get an Account record by its ID.

    **Parameters:**

    * `recordId` (string, required): Record ID of the Account
  </Accordion>

  <Accordion title="salesforce/get_record_by_id_any">
    **Description:** Get a record of any object type by its ID.

    **Parameters:**

    * `recordType` (string, required): Record Type (e.g., "CustomObject\_\_c")
    * `recordId` (string, required): Record ID
  </Accordion>
</AccordionGroup>

### **Record Search**

<AccordionGroup>
  <Accordion title="salesforce/search_records_contact">
    **Description:** Search for Contact records with advanced filtering.

    **Parameters:**

    * `filterFormula` (object, optional): Advanced filter in disjunctive normal form with field-specific operators
    * `sortBy` (string, optional): Sort field (e.g., "CreatedDate")
    * `sortDirection` (string, optional): Sort direction - Options: ASC, DESC
    * `includeAllFields` (boolean, optional): Include all fields in results
    * `paginationParameters` (object, optional): Pagination settings with pageCursor
  </Accordion>

  <Accordion title="salesforce/search_records_lead">
    **Description:** Search for Lead records with advanced filtering.

    **Parameters:**

    * `filterFormula` (object, optional): Advanced filter in disjunctive normal form with field-specific operators
    * `sortBy` (string, optional): Sort field (e.g., "CreatedDate")
    * `sortDirection` (string, optional): Sort direction - Options: ASC, DESC
    * `includeAllFields` (boolean, optional): Include all fields in results
    * `paginationParameters` (object, optional): Pagination settings with pageCursor
  </Accordion>

  <Accordion title="salesforce/search_records_opportunity">
    **Description:** Search for Opportunity records with advanced filtering.

    **Parameters:**

    * `filterFormula` (object, optional): Advanced filter in disjunctive normal form with field-specific operators
    * `sortBy` (string, optional): Sort field (e.g., "CreatedDate")
    * `sortDirection` (string, optional): Sort direction - Options: ASC, DESC
    * `includeAllFields` (boolean, optional): Include all fields in results
    * `paginationParameters` (object, optional): Pagination settings with pageCursor
  </Accordion>

  <Accordion title="salesforce/search_records_task">
    **Description:** Search for Task records with advanced filtering.

    **Parameters:**

    * `filterFormula` (object, optional): Advanced filter in disjunctive normal form with field-specific operators
    * `sortBy` (string, optional): Sort field (e.g., "CreatedDate")
    * `sortDirection` (string, optional): Sort direction - Options: ASC, DESC
    * `includeAllFields` (boolean, optional): Include all fields in results
    * `paginationParameters` (object, optional): Pagination settings with pageCursor
  </Accordion>

  <Accordion title="salesforce/search_records_account">
    **Description:** Search for Account records with advanced filtering.

    **Parameters:**

    * `filterFormula` (object, optional): Advanced filter in disjunctive normal form with field-specific operators
    * `sortBy` (string, optional): Sort field (e.g., "CreatedDate")
    * `sortDirection` (string, optional): Sort direction - Options: ASC, DESC
    * `includeAllFields` (boolean, optional): Include all fields in results
    * `paginationParameters` (object, optional): Pagination settings with pageCursor
  </Accordion>

  <Accordion title="salesforce/search_records_any">
    **Description:** Search for records of any object type.

    **Parameters:**

    * `recordType` (string, required): Record Type to search
    * `filterFormula` (string, optional): Filter search criteria
    * `includeAllFields` (boolean, optional): Include all fields in results
    * `paginationParameters` (object, optional): Pagination settings with pageCursor
  </Accordion>
</AccordionGroup>

### **List View Retrieval**

<AccordionGroup>
  <Accordion title="salesforce/get_record_by_view_id_contact">
    **Description:** Get Contact records from a specific List View.

    **Parameters:**

    * `listViewId` (string, required): List View ID
    * `paginationParameters` (object, optional): Pagination settings with pageCursor
  </Accordion>

  <Accordion title="salesforce/get_record_by_view_id_lead">
    **Description:** Get Lead records from a specific List View.

    **Parameters:**

    * `listViewId` (string, required): List View ID
    * `paginationParameters` (object, optional): Pagination settings with pageCursor
  </Accordion>

  <Accordion title="salesforce/get_record_by_view_id_opportunity">
    **Description:** Get Opportunity records from a specific List View.

    **Parameters:**

    * `listViewId` (string, required): List View ID
    * `paginationParameters` (object, optional): Pagination settings with pageCursor
  </Accordion>

  <Accordion title="salesforce/get_record_by_view_id_task">
    **Description:** Get Task records from a specific List View.

    **Parameters:**

    * `listViewId` (string, required): List View ID
    * `paginationParameters` (object, optional): Pagination settings with pageCursor
  </Accordion>

  <Accordion title="salesforce/get_record_by_view_id_account">
    **Description:** Get Account records from a specific List View.

    **Parameters:**

    * `listViewId` (string, required): List View ID
    * `paginationParameters` (object, optional): Pagination settings with pageCursor
  </Accordion>

  <Accordion title="salesforce/get_record_by_view_id_any">
    **Description:** Get records of any object type from a specific List View.

    **Parameters:**

    * `recordType` (string, required): Record Type
    * `listViewId` (string, required): List View ID
    * `paginationParameters` (object, optional): Pagination settings with pageCursor
  </Accordion>
</AccordionGroup>

### **Custom Fields**

<AccordionGroup>
  <Accordion title="salesforce/create_custom_field_contact">
    **Description:** Deploy custom fields for Contact objects.

    **Parameters:**

    * `label` (string, required): Field Label for displays and internal reference
    * `type` (string, required): Field Type - Options: Checkbox, Currency, Date, Email, Number, Percent, Phone, Picklist, MultiselectPicklist, Text, TextArea, LongTextArea, Html, Time, Url
    * `defaultCheckboxValue` (boolean, optional): Default value for checkbox fields
    * `length` (string, required): Length for numeric/text fields
    * `decimalPlace` (string, required): Decimal places for numeric fields
    * `pickListValues` (string, required): Values for picklist fields (separated by new lines)
    * `visibleLines` (string, required): Visible lines for multiselect/text area fields
    * `description` (string, optional): Field description
    * `helperText` (string, optional): Helper text shown on hover
    * `defaultFieldValue` (string, optional): Default field value
  </Accordion>

  <Accordion title="salesforce/create_custom_field_lead">
    **Description:** Deploy custom fields for Lead objects.

    **Parameters:**

    * `label` (string, required): Field Label for displays and internal reference
    * `type` (string, required): Field Type - Options: Checkbox, Currency, Date, Email, Number, Percent, Phone, Picklist, MultiselectPicklist, Text, TextArea, LongTextArea, Html, Time, Url
    * `defaultCheckboxValue` (boolean, optional): Default value for checkbox fields
    * `length` (string, required): Length for numeric/text fields
    * `decimalPlace` (string, required): Decimal places for numeric fields
    * `pickListValues` (string, required): Values for picklist fields (separated by new lines)
    * `visibleLines` (string, required): Visible lines for multiselect/text area fields
    * `description` (string, optional): Field description
    * `helperText` (string, optional): Helper text shown on hover
    * `defaultFieldValue` (string, optional): Default field value
  </Accordion>

  <Accordion title="salesforce/create_custom_field_opportunity">
    **Description:** Deploy custom fields for Opportunity objects.

    **Parameters:**

    * `label` (string, required): Field Label for displays and internal reference
    * `type` (string, required): Field Type - Options: Checkbox, Currency, Date, Email, Number, Percent, Phone, Picklist, MultiselectPicklist, Text, TextArea, LongTextArea, Html, Time, Url
    * `defaultCheckboxValue` (boolean, optional): Default value for checkbox fields
    * `length` (string, required): Length for numeric/text fields
    * `decimalPlace` (string, required): Decimal places for numeric fields
    * `pickListValues` (string, required): Values for picklist fields (separated by new lines)
    * `visibleLines` (string, required): Visible lines for multiselect/text area fields
    * `description` (string, optional): Field description
    * `helperText` (string, optional): Helper text shown on hover
    * `defaultFieldValue` (string, optional): Default field value
  </Accordion>

  <Accordion title="salesforce/create_custom_field_task">
    **Description:** Deploy custom fields for Task objects.

    **Parameters:**

    * `label` (string, required): Field Label for displays and internal reference
    * `type` (string, required): Field Type - Options: Checkbox, Currency, Date, Email, Number, Percent, Phone, Picklist, MultiselectPicklist, Text, TextArea, Time, Url
    * `defaultCheckboxValue` (boolean, optional): Default value for checkbox fields
    * `length` (string, required): Length for numeric/text fields
    * `decimalPlace` (string, required): Decimal places for numeric fields
    * `pickListValues` (string, required): Values for picklist fields (separated by new lines)
    * `visibleLines` (string, required): Visible lines for multiselect fields
    * `description` (string, optional): Field description
    * `helperText` (string, optional): Helper text shown on hover
    * `defaultFieldValue` (string, optional): Default field value
  </Accordion>

  <Accordion title="salesforce/create_custom_field_account">
    **Description:** Deploy custom fields for Account objects.

    **Parameters:**

    * `label` (string, required): Field Label for displays and internal reference
    * `type` (string, required): Field Type - Options: Checkbox, Currency, Date, Email, Number, Percent, Phone, Picklist, MultiselectPicklist, Text, TextArea, LongTextArea, Html, Time, Url
    * `defaultCheckboxValue` (boolean, optional): Default value for checkbox fields
    * `length` (string, required): Length for numeric/text fields
    * `decimalPlace` (string, required): Decimal places for numeric fields
    * `pickListValues` (string, required): Values for picklist fields (separated by new lines)
    * `visibleLines` (string, required): Visible lines for multiselect/text area fields
    * `description` (string, optional): Field description
    * `helperText` (string, optional): Helper text shown on hover
    * `defaultFieldValue` (string, optional): Default field value
  </Accordion>

  <Accordion title="salesforce/create_custom_field_any">
    **Description:** Deploy custom fields for any object type.

    **Note:** This is a flexible tool for creating custom fields on custom or unknown object types.
  </Accordion>
</AccordionGroup>

### **Advanced Operations**

<AccordionGroup>
  <Accordion title="salesforce/write_soql_query">
    **Description:** Execute custom SOQL queries against your Salesforce data.

    **Parameters:**

    * `query` (string, required): SOQL Query (e.g., "SELECT Id, Name FROM Account WHERE Name = 'Example'")
  </Accordion>

  <Accordion title="salesforce/create_custom_object">
    **Description:** Deploy a new custom object in Salesforce.

    **Parameters:**

    * `label` (string, required): Object Label for tabs, page layouts, and reports
    * `pluralLabel` (string, required): Plural Label (e.g., "Accounts")
    * `description` (string, optional): A description of the Custom Object
    * `recordName` (string, required): Record Name that appears in layouts and searches (e.g., "Account Name")
  </Accordion>

  <Accordion title="salesforce/describe_action_schema">
    **Description:** Get the expected schema for operations on specific object types.

    **Parameters:**

    * `recordType` (string, required): Record Type to describe
    * `operation` (string, required): Operation Type (e.g., "CREATE\_RECORD" or "UPDATE\_RECORD")

    **Note:** Use this function first when working with custom objects to understand their schema before performing operations.
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Salesforce Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew
from crewai import Agent, Task, Crew

# Create an agent with Salesforce capabilities
salesforce_agent = Agent(
    role="CRM Manager",
    goal="Manage customer relationships and sales processes efficiently",
    backstory="An AI assistant specialized in CRM operations and sales automation.",
    apps=['salesforce']  # All Salesforce actions will be available
)

# Task to create a new lead
create_lead_task = Task(
    description="Create a new lead for John Doe from Example Corp with email john.doe@example.com",
    agent=salesforce_agent,
    expected_output="Lead created successfully with lead ID"
)

# Run the task
crew = Crew(
    agents=[salesforce_agent],
    tasks=[create_lead_task]
)

crew.kickoff()
```

### Filtering Specific Salesforce Tools

```python theme={null}

sales_manager = Agent(
    role="Sales Manager",
    goal="Manage leads and opportunities in the sales pipeline",
    backstory="An experienced sales manager who handles lead qualification and opportunity management.",
    apps=['salesforce/create_record_lead']
)

# Task to manage sales pipeline
pipeline_task = Task(
    description="Create a qualified lead and convert it to an opportunity with $50,000 value",
    agent=sales_manager,
    expected_output="Lead created and opportunity established successfully"
)

crew = Crew(
    agents=[sales_manager],
    tasks=[pipeline_task]
)

crew.kickoff()
```

### Contact and Account Management

```python theme={null}
from crewai import Agent, Task, Crew

account_manager = Agent(
    role="Account Manager",
    goal="Manage customer accounts and maintain strong relationships",
    backstory="An AI assistant that specializes in account management and customer relationship building.",
    apps=['salesforce']
)

# Task to manage customer accounts
account_task = Task(
    description="""
    1. Create a new account for TechCorp Inc.
    2. Add John Doe as the primary contact for this account
    3. Create a follow-up task for next week to check on their project status
    """,
    agent=account_manager,
    expected_output="Account, contact, and follow-up task created successfully"
)

crew = Crew(
    agents=[account_manager],
    tasks=[account_task]
)

crew.kickoff()
```

### Advanced SOQL Queries and Reporting

```python theme={null}
from crewai import Agent, Task, Crew

data_analyst = Agent(
    role="Sales Data Analyst",
    goal="Generate insights from Salesforce data using SOQL queries",
    backstory="An analytical AI that excels at extracting meaningful insights from CRM data.",
    apps=['salesforce']
)

# Complex task involving SOQL queries and data analysis
analysis_task = Task(
    description="""
    1. Execute a SOQL query to find all opportunities closing this quarter
    2. Search for contacts at companies with opportunities over $100K
    3. Create a summary report of the sales pipeline status
    4. Update high-value opportunities with next steps
    """,
    agent=data_analyst,
    expected_output="Comprehensive sales pipeline analysis with actionable insights"
)

crew = Crew(
    agents=[data_analyst],
    tasks=[analysis_task]
)

crew.kickoff()
```

This comprehensive documentation covers all the Salesforce tools organized by functionality, making it easy for users to find the specific operations they need for their CRM automation tasks.

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Salesforce integration setup or
  troubleshooting.
</Card>


# Shopify Integration
Source: https://docs.crewai.com/en/enterprise/integrations/shopify

E-commerce and online store management with Shopify integration for CrewAI.

## Overview

Enable your agents to manage e-commerce operations through Shopify. Handle customers, orders, products, inventory, and store analytics to streamline your online business with AI-powered automation.

## Prerequisites

Before using the Shopify integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Shopify store with appropriate admin permissions
* Connected your Shopify store through the [Integrations page](https://app.crewai.com/integrations)

## Setting Up Shopify Integration

### 1. Connect Your Shopify Store

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Shopify** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for store and product management
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Tools

### **Customer Management**

<AccordionGroup>
  <Accordion title="shopify/get_customers">
    **Description:** Retrieve a list of customers from your Shopify store.

    **Parameters:**

    * `customerIds` (string, optional): Comma-separated list of customer IDs to filter by (example: "207119551, 207119552")
    * `createdAtMin` (string, optional): Only return customers created after this date (ISO or Unix timestamp)
    * `createdAtMax` (string, optional): Only return customers created before this date (ISO or Unix timestamp)
    * `updatedAtMin` (string, optional): Only return customers updated after this date (ISO or Unix timestamp)
    * `updatedAtMax` (string, optional): Only return customers updated before this date (ISO or Unix timestamp)
    * `limit` (string, optional): Maximum number of customers to return (defaults to 250)
  </Accordion>

  <Accordion title="shopify/search_customers">
    **Description:** Search for customers using advanced filtering criteria.

    **Parameters:**

    * `filterFormula` (object, optional): Advanced filter in disjunctive normal form with field-specific operators
    * `limit` (string, optional): Maximum number of customers to return (defaults to 250)
  </Accordion>

  <Accordion title="shopify/create_customer">
    **Description:** Create a new customer in your Shopify store.

    **Parameters:**

    * `firstName` (string, required): Customer's first name
    * `lastName` (string, required): Customer's last name
    * `email` (string, required): Customer's email address
    * `company` (string, optional): Company name
    * `streetAddressLine1` (string, optional): Street address
    * `streetAddressLine2` (string, optional): Street address line 2
    * `city` (string, optional): City
    * `state` (string, optional): State or province code
    * `country` (string, optional): Country
    * `zipCode` (string, optional): Zip code
    * `phone` (string, optional): Phone number
    * `tags` (string, optional): Tags as array or comma-separated list
    * `note` (string, optional): Customer note
    * `sendEmailInvite` (boolean, optional): Whether to send email invitation
    * `metafields` (object, optional): Additional metafields in JSON format
  </Accordion>

  <Accordion title="shopify/update_customer">
    **Description:** Update an existing customer in your Shopify store.

    **Parameters:**

    * `customerId` (string, required): The ID of the customer to update
    * `firstName` (string, optional): Customer's first name
    * `lastName` (string, optional): Customer's last name
    * `email` (string, optional): Customer's email address
    * `company` (string, optional): Company name
    * `streetAddressLine1` (string, optional): Street address
    * `streetAddressLine2` (string, optional): Street address line 2
    * `city` (string, optional): City
    * `state` (string, optional): State or province code
    * `country` (string, optional): Country
    * `zipCode` (string, optional): Zip code
    * `phone` (string, optional): Phone number
    * `tags` (string, optional): Tags as array or comma-separated list
    * `note` (string, optional): Customer note
    * `sendEmailInvite` (boolean, optional): Whether to send email invitation
    * `metafields` (object, optional): Additional metafields in JSON format
  </Accordion>
</AccordionGroup>

### **Order Management**

<AccordionGroup>
  <Accordion title="shopify/get_orders">
    **Description:** Retrieve a list of orders from your Shopify store.

    **Parameters:**

    * `orderIds` (string, optional): Comma-separated list of order IDs to filter by (example: "450789469, 450789470")
    * `createdAtMin` (string, optional): Only return orders created after this date (ISO or Unix timestamp)
    * `createdAtMax` (string, optional): Only return orders created before this date (ISO or Unix timestamp)
    * `updatedAtMin` (string, optional): Only return orders updated after this date (ISO or Unix timestamp)
    * `updatedAtMax` (string, optional): Only return orders updated before this date (ISO or Unix timestamp)
    * `limit` (string, optional): Maximum number of orders to return (defaults to 250)
  </Accordion>

  <Accordion title="shopify/create_order">
    **Description:** Create a new order in your Shopify store.

    **Parameters:**

    * `email` (string, required): Customer email address
    * `lineItems` (object, required): Order line items in JSON format with title, price, quantity, and variant\_id
    * `sendReceipt` (boolean, optional): Whether to send order receipt
    * `fulfillmentStatus` (string, optional): Fulfillment status - Options: fulfilled, null, partial, restocked
    * `financialStatus` (string, optional): Financial status - Options: pending, authorized, partially\_paid, paid, partially\_refunded, refunded, voided
    * `inventoryBehaviour` (string, optional): Inventory behavior - Options: bypass, decrement\_ignoring\_policy, decrement\_obeying\_policy
    * `note` (string, optional): Order note
  </Accordion>

  <Accordion title="shopify/update_order">
    **Description:** Update an existing order in your Shopify store.

    **Parameters:**

    * `orderId` (string, required): The ID of the order to update
    * `email` (string, optional): Customer email address
    * `lineItems` (object, optional): Updated order line items in JSON format
    * `sendReceipt` (boolean, optional): Whether to send order receipt
    * `fulfillmentStatus` (string, optional): Fulfillment status - Options: fulfilled, null, partial, restocked
    * `financialStatus` (string, optional): Financial status - Options: pending, authorized, partially\_paid, paid, partially\_refunded, refunded, voided
    * `inventoryBehaviour` (string, optional): Inventory behavior - Options: bypass, decrement\_ignoring\_policy, decrement\_obeying\_policy
    * `note` (string, optional): Order note
  </Accordion>

  <Accordion title="shopify/get_abandoned_carts">
    **Description:** Retrieve abandoned carts from your Shopify store.

    **Parameters:**

    * `createdWithInLast` (string, optional): Restrict results to checkouts created within specified time
    * `createdAfterId` (string, optional): Restrict results to after the specified ID
    * `status` (string, optional): Show checkouts with given status - Options: open, closed (defaults to open)
    * `createdAtMin` (string, optional): Only return carts created after this date (ISO or Unix timestamp)
    * `createdAtMax` (string, optional): Only return carts created before this date (ISO or Unix timestamp)
    * `limit` (string, optional): Maximum number of carts to return (defaults to 250)
  </Accordion>
</AccordionGroup>

### **Product Management (REST API)**

<AccordionGroup>
  <Accordion title="shopify/get_products">
    **Description:** Retrieve a list of products from your Shopify store using REST API.

    **Parameters:**

    * `productIds` (string, optional): Comma-separated list of product IDs to filter by (example: "632910392, 632910393")
    * `title` (string, optional): Filter by product title
    * `productType` (string, optional): Filter by product type
    * `vendor` (string, optional): Filter by vendor
    * `status` (string, optional): Filter by status - Options: active, archived, draft
    * `createdAtMin` (string, optional): Only return products created after this date (ISO or Unix timestamp)
    * `createdAtMax` (string, optional): Only return products created before this date (ISO or Unix timestamp)
    * `updatedAtMin` (string, optional): Only return products updated after this date (ISO or Unix timestamp)
    * `updatedAtMax` (string, optional): Only return products updated before this date (ISO or Unix timestamp)
    * `limit` (string, optional): Maximum number of products to return (defaults to 250)
  </Accordion>

  <Accordion title="shopify/create_product">
    **Description:** Create a new product in your Shopify store using REST API.

    **Parameters:**

    * `title` (string, required): Product title
    * `productType` (string, required): Product type/category
    * `vendor` (string, required): Product vendor
    * `productDescription` (string, optional): Product description (accepts plain text or HTML)
    * `tags` (string, optional): Product tags as array or comma-separated list
    * `price` (string, optional): Product price
    * `inventoryPolicy` (string, optional): Inventory policy - Options: deny, continue
    * `imageUrl` (string, optional): Product image URL
    * `isPublished` (boolean, optional): Whether product is published
    * `publishToPointToSale` (boolean, optional): Whether to publish to point of sale
  </Accordion>

  <Accordion title="shopify/update_product">
    **Description:** Update an existing product in your Shopify store using REST API.

    **Parameters:**

    * `productId` (string, required): The ID of the product to update
    * `title` (string, optional): Product title
    * `productType` (string, optional): Product type/category
    * `vendor` (string, optional): Product vendor
    * `productDescription` (string, optional): Product description (accepts plain text or HTML)
    * `tags` (string, optional): Product tags as array or comma-separated list
    * `price` (string, optional): Product price
    * `inventoryPolicy` (string, optional): Inventory policy - Options: deny, continue
    * `imageUrl` (string, optional): Product image URL
    * `isPublished` (boolean, optional): Whether product is published
    * `publishToPointToSale` (boolean, optional): Whether to publish to point of sale
  </Accordion>
</AccordionGroup>

### **Product Management (GraphQL)**

<AccordionGroup>
  <Accordion title="shopify/get_products_graphql">
    **Description:** Retrieve products using advanced GraphQL filtering capabilities.

    **Parameters:**

    * `productFilterFormula` (object, optional): Advanced filter in disjunctive normal form with support for fields like id, title, vendor, status, handle, tag, created\_at, updated\_at, published\_at
  </Accordion>

  <Accordion title="shopify/create_product_graphql">
    **Description:** Create a new product using GraphQL API with enhanced media support.

    **Parameters:**

    * `title` (string, required): Product title
    * `productType` (string, required): Product type/category
    * `vendor` (string, required): Product vendor
    * `productDescription` (string, optional): Product description (accepts plain text or HTML)
    * `tags` (string, optional): Product tags as array or comma-separated list
    * `media` (object, optional): Media objects with alt text, content type, and source URL
    * `additionalFields` (object, optional): Additional product fields like status, requiresSellingPlan, giftCard
  </Accordion>

  <Accordion title="shopify/update_product_graphql">
    **Description:** Update an existing product using GraphQL API with enhanced media support.

    **Parameters:**

    * `productId` (string, required): The GraphQL ID of the product to update (e.g., "gid://shopify/Product/913144112")
    * `title` (string, optional): Product title
    * `productType` (string, optional): Product type/category
    * `vendor` (string, optional): Product vendor
    * `productDescription` (string, optional): Product description (accepts plain text or HTML)
    * `tags` (string, optional): Product tags as array or comma-separated list
    * `media` (object, optional): Updated media objects with alt text, content type, and source URL
    * `additionalFields` (object, optional): Additional product fields like status, requiresSellingPlan, giftCard
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Shopify Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew
from crewai import Agent, Task, Crew

# Create an agent with Shopify capabilities
shopify_agent = Agent(
    role="E-commerce Manager",
    goal="Manage online store operations and customer relationships efficiently",
    backstory="An AI assistant specialized in e-commerce operations and online store management.",
    apps=['shopify']  # All Shopify actions will be available
)

# Task to create a new customer
create_customer_task = Task(
    description="Create a new VIP customer Jane Smith with email jane.smith@example.com and phone +1-555-0123",
    agent=shopify_agent,
    expected_output="Customer created successfully with customer ID"
)

# Run the task
crew = Crew(
    agents=[shopify_agent],
    tasks=[create_customer_task]
)

crew.kickoff()
```

### Filtering Specific Shopify Tools

```python theme={null}

store_manager = Agent(
    role="Store Manager",
    goal="Manage customer orders and product catalog",
    backstory="An experienced store manager who handles customer relationships and inventory management.",
    apps=['shopify/create_customer']
)

# Task to manage store operations
store_task = Task(
    description="Create a new customer and process their order for 2 Premium Coffee Mugs",
    agent=store_manager,
    expected_output="Customer created and order processed successfully"
)

crew = Crew(
    agents=[store_manager],
    tasks=[store_task]
)

crew.kickoff()
```

### Product Management with GraphQL

```python theme={null}
from crewai import Agent, Task, Crew

product_manager = Agent(
    role="Product Manager",
    goal="Manage product catalog and inventory with advanced GraphQL capabilities",
    backstory="An AI assistant that specializes in product management and catalog optimization.",
    apps=['shopify']
)

# Task to manage product catalog
catalog_task = Task(
    description="""
    1. Create a new product "Premium Coffee Mug" from Coffee Co vendor
    2. Add high-quality product images and descriptions
    3. Search for similar products from the same vendor
    4. Update product tags and pricing strategy
    """,
    agent=product_manager,
    expected_output="Product created and catalog optimized successfully"
)

crew = Crew(
    agents=[product_manager],
    tasks=[catalog_task]
)

crew.kickoff()
```

### Order and Customer Analytics

```python theme={null}
from crewai import Agent, Task, Crew

analytics_agent = Agent(
    role="E-commerce Analyst",
    goal="Analyze customer behavior and order patterns to optimize store performance",
    backstory="An analytical AI that excels at extracting insights from e-commerce data.",
    apps=['shopify']
)

# Complex task involving multiple operations
analytics_task = Task(
    description="""
    1. Retrieve recent customer data and order history
    2. Identify abandoned carts from the last 7 days
    3. Analyze product performance and inventory levels
    4. Generate recommendations for customer retention
    """,
    agent=analytics_agent,
    expected_output="Comprehensive e-commerce analytics report with actionable insights"
)

crew = Crew(
    agents=[analytics_agent],
    tasks=[analytics_task]
)

crew.kickoff()
```

### Getting Help

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Shopify integration setup or
  troubleshooting.
</Card>


# Slack Integration
Source: https://docs.crewai.com/en/enterprise/integrations/slack

Team communication and collaboration with Slack integration for CrewAI.

## Overview

Enable your agents to manage team communication through Slack. Send messages, search conversations, manage channels, and coordinate team activities to streamline your collaboration workflows with AI-powered automation.

## Prerequisites

Before using the Slack integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Slack workspace with appropriate permissions
* Connected your Slack workspace through the [Integrations page](https://app.crewai.com/integrations)

## Setting Up Slack Integration

### 1. Connect Your Slack Workspace

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Slack** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for team communication
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Tools

### **User Management**

<AccordionGroup>
  <Accordion title="slack/list_members">
    **Description:** List all members in a Slack channel.

    **Parameters:**

    * No parameters required - retrieves all channel members
  </Accordion>

  <Accordion title="slack/get_user_by_email">
    **Description:** Find a user in your Slack workspace by their email address.

    **Parameters:**

    * `email` (string, required): The email address of a user in the workspace
  </Accordion>

  <Accordion title="slack/get_users_by_name">
    **Description:** Search for users by their name or display name.

    **Parameters:**

    * `name` (string, required): User's real name to search for
    * `displayName` (string, required): User's display name to search for
    * `paginationParameters` (object, optional): Pagination settings
      * `pageCursor` (string, optional): Page cursor for pagination
  </Accordion>
</AccordionGroup>

### **Channel Management**

<AccordionGroup>
  <Accordion title="slack/list_channels">
    **Description:** List all channels in your Slack workspace.

    **Parameters:**

    * No parameters required - retrieves all accessible channels
  </Accordion>
</AccordionGroup>

### **Messaging**

<AccordionGroup>
  <Accordion title="slack/send_message">
    **Description:** Send a message to a Slack channel.

    **Parameters:**

    * `channel` (string, required): Channel name or ID - Use Connect Portal Workflow Settings to allow users to select a channel, or enter a channel name to create a new channel
    * `message` (string, required): The message text to send
    * `botName` (string, required): The name of the bot that sends this message
    * `botIcon` (string, required): Bot icon - Can be either an image URL or an emoji (e.g., ":dog:")
    * `blocks` (object, optional): Slack Block Kit JSON for rich message formatting with attachments and interactive elements
    * `authenticatedUser` (boolean, optional): If true, message appears to come from your authenticated Slack user instead of the application (defaults to false)
  </Accordion>

  <Accordion title="slack/send_direct_message">
    **Description:** Send a direct message to a specific user in Slack.

    **Parameters:**

    * `memberId` (string, required): Recipient user ID - Use Connect Portal Workflow Settings to allow users to select a workspace member
    * `message` (string, required): The message text to send
    * `botName` (string, required): The name of the bot that sends this message
    * `botIcon` (string, required): Bot icon - Can be either an image URL or an emoji (e.g., ":dog:")
    * `blocks` (object, optional): Slack Block Kit JSON for rich message formatting with attachments and interactive elements
    * `authenticatedUser` (boolean, optional): If true, message appears to come from your authenticated Slack user instead of the application (defaults to false)
  </Accordion>
</AccordionGroup>

### **Search & Discovery**

<AccordionGroup>
  <Accordion title="slack/search_messages">
    **Description:** Search for messages across your Slack workspace.

    **Parameters:**

    * `query` (string, required): Search query using Slack search syntax to find messages that match specified criteria

    **Search Query Examples:**

    * `"project update"` - Search for messages containing "project update"
    * `from:@john in:#general` - Search for messages from John in the #general channel
    * `has:link after:2023-01-01` - Search for messages with links after January 1, 2023
    * `in:@channel before:yesterday` - Search for messages in a specific channel before yesterday
  </Accordion>
</AccordionGroup>

## Block Kit Integration

Slack's Block Kit allows you to create rich, interactive messages. Here are some examples of how to use the `blocks` parameter:

### Simple Text with Attachment

```json theme={null}
[
  {
    "text": "I am a test message",
    "attachments": [
      {
        "text": "And here's an attachment!"
      }
    ]
  }
]
```

### Rich Formatting with Sections

```json theme={null}
[
  {
    "type": "section",
    "text": {
      "type": "mrkdwn",
      "text": "*Project Update*\nStatus: ✅ Complete"
    }
  },
  {
    "type": "divider"
  },
  {
    "type": "section",
    "text": {
      "type": "plain_text",
      "text": "All tasks have been completed successfully."
    }
  }
]
```

## Usage Examples

### Basic Slack Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew

# Create an agent with Slack capabilities
slack_agent = Agent(
    role="Team Communication Manager",
    goal="Facilitate team communication and coordinate collaboration efficiently",
    backstory="An AI assistant specialized in team communication and workspace coordination.",
    apps=['slack']  # All Slack actions will be available
)

# Task to send project updates
update_task = Task(
    description="Send a project status update to the #general channel with current progress",
    agent=slack_agent,
    expected_output="Project update message sent successfully to team channel"
)

# Run the task
crew = Crew(
    agents=[slack_agent],
    tasks=[update_task]
)

crew.kickoff()
```

### Filtering Specific Slack Tools

```python theme={null}
from crewai import Agent, Task, Crew

# Create agent with specific Slack actions only
communication_manager = Agent(
    role="Communication Coordinator",
    goal="Manage team communications and ensure important messages reach the right people",
    backstory="An experienced communication coordinator who handles team messaging and notifications.",
    apps=[
        'slack/send_message',
        'slack/send_direct_message',
        'slack/search_messages'
    ]  # Using canonical action names from canonical_integrations.yml
)

# Task to coordinate team communication
coordination_task = Task(
    description="Send task completion notifications to team members and update project channels",
    agent=communication_manager,
    expected_output="Team notifications sent and project channels updated successfully"
)

crew = Crew(
    agents=[communication_manager],
    tasks=[coordination_task]
)

crew.kickoff()
```

### Advanced Messaging with Block Kit

```python theme={null}
from crewai import Agent, Task, Crew

# Create agent with Slack messaging capabilities
notification_agent = Agent(
    role="Notification Manager",
    goal="Create rich, interactive notifications and manage workspace communication",
    backstory="An AI assistant that specializes in creating engaging team notifications and updates.",
    apps=['slack/send_message']  # Specific action for sending messages
)

# Task to send rich notifications
notification_task = Task(
    description="""
    1. Send a formatted project completion message to #general with progress charts
    2. Send direct messages to team leads with task summaries
    3. Create interactive notification with action buttons for team feedback
    """,
    agent=notification_agent,
    expected_output="Rich notifications sent with interactive elements and formatted content"
)

crew = Crew(
    agents=[notification_agent],
    tasks=[notification_task]
)

crew.kickoff()
```

### Message Search and Analytics

```python theme={null}
from crewai import Agent, Task, Crew

# Create agent with Slack search and user management capabilities
analytics_agent = Agent(
    role="Communication Analyst",
    goal="Analyze team communication patterns and extract insights from conversations",
    backstory="An analytical AI that excels at understanding team dynamics through communication data.",
    apps=[
        'slack/search_messages',
        'slack/get_user_by_email',
        'slack/list_members'
    ]  # Using canonical action names from canonical_integrations.yml
)

# Complex task involving search and analysis
analysis_task = Task(
    description="""
    1. Search for recent project-related messages across all channels
    2. Find users by email to identify team members
    3. Analyze communication patterns and response times
    4. Generate weekly team communication summary
    """,
    agent=analytics_agent,
    expected_output="Comprehensive communication analysis with team insights and recommendations"
)

crew = Crew(
    agents=[analytics_agent],
    tasks=[analysis_task]
)

crew.kickoff()
```

## Contact Support

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Slack integration setup or
  troubleshooting.
</Card>


# Stripe Integration
Source: https://docs.crewai.com/en/enterprise/integrations/stripe

Payment processing and subscription management with Stripe integration for CrewAI.

## Overview

Enable your agents to manage payments, subscriptions, and customer billing through Stripe. Handle customer data, process subscriptions, manage products, and track financial transactions to streamline your payment workflows with AI-powered automation.

## Prerequisites

Before using the Stripe integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Stripe account with appropriate API permissions
* Connected your Stripe account through the [Integrations page](https://app.crewai.com/integrations)

## Setting Up Stripe Integration

### 1. Connect Your Stripe Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Stripe** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for payment processing
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Tools

### **Customer Management**

<AccordionGroup>
  <Accordion title="stripe/create_customer">
    **Description:** Create a new customer in your Stripe account.

    **Parameters:**

    * `emailCreateCustomer` (string, required): Customer's email address
    * `name` (string, optional): Customer's full name
    * `description` (string, optional): Customer description for internal reference
    * `metadataCreateCustomer` (object, optional): Additional metadata as key-value pairs (e.g., `{"field1": 1, "field2": 2}`)
  </Accordion>

  <Accordion title="stripe/get_customer_by_id">
    **Description:** Retrieve a specific customer by their Stripe customer ID.

    **Parameters:**

    * `idGetCustomer` (string, required): The Stripe customer ID to retrieve
  </Accordion>

  <Accordion title="stripe/get_customers">
    **Description:** Retrieve a list of customers with optional filtering.

    **Parameters:**

    * `emailGetCustomers` (string, optional): Filter customers by email address
    * `createdAfter` (string, optional): Filter customers created after this date (Unix timestamp)
    * `createdBefore` (string, optional): Filter customers created before this date (Unix timestamp)
    * `limitGetCustomers` (string, optional): Maximum number of customers to return (defaults to 10)
  </Accordion>

  <Accordion title="stripe/update_customer">
    **Description:** Update an existing customer's information.

    **Parameters:**

    * `customerId` (string, required): The ID of the customer to update
    * `emailUpdateCustomer` (string, optional): Updated email address
    * `name` (string, optional): Updated customer name
    * `description` (string, optional): Updated customer description
    * `metadataUpdateCustomer` (object, optional): Updated metadata as key-value pairs
  </Accordion>
</AccordionGroup>

### **Subscription Management**

<AccordionGroup>
  <Accordion title="stripe/create_subscription">
    **Description:** Create a new subscription for a customer.

    **Parameters:**

    * `customerIdCreateSubscription` (string, required): The customer ID for whom the subscription will be created
    * `plan` (string, required): The plan ID for the subscription - Use Connect Portal Workflow Settings to allow users to select a plan
    * `metadataCreateSubscription` (object, optional): Additional metadata for the subscription
  </Accordion>

  <Accordion title="stripe/get_subscriptions">
    **Description:** Retrieve subscriptions with optional filtering.

    **Parameters:**

    * `customerIdGetSubscriptions` (string, optional): Filter subscriptions by customer ID
    * `subscriptionStatus` (string, optional): Filter by subscription status - Options: incomplete, incomplete\_expired, trialing, active, past\_due, canceled, unpaid
    * `limitGetSubscriptions` (string, optional): Maximum number of subscriptions to return (defaults to 10)
  </Accordion>
</AccordionGroup>

### **Product Management**

<AccordionGroup>
  <Accordion title="stripe/create_product">
    **Description:** Create a new product in your Stripe catalog.

    **Parameters:**

    * `productName` (string, required): The product name
    * `description` (string, optional): Product description
    * `metadataProduct` (object, optional): Additional product metadata as key-value pairs
  </Accordion>

  <Accordion title="stripe/get_product_by_id">
    **Description:** Retrieve a specific product by its Stripe product ID.

    **Parameters:**

    * `productId` (string, required): The Stripe product ID to retrieve
  </Accordion>

  <Accordion title="stripe/get_products">
    **Description:** Retrieve a list of products with optional filtering.

    **Parameters:**

    * `createdAfter` (string, optional): Filter products created after this date (Unix timestamp)
    * `createdBefore` (string, optional): Filter products created before this date (Unix timestamp)
    * `limitGetProducts` (string, optional): Maximum number of products to return (defaults to 10)
  </Accordion>
</AccordionGroup>

### **Financial Operations**

<AccordionGroup>
  <Accordion title="stripe/get_balance_transactions">
    **Description:** Retrieve balance transactions from your Stripe account.

    **Parameters:**

    * `balanceTransactionType` (string, optional): Filter by transaction type - Options: charge, refund, payment, payment\_refund
    * `paginationParameters` (object, optional): Pagination settings
      * `pageCursor` (string, optional): Page cursor for pagination
  </Accordion>

  <Accordion title="stripe/get_plans">
    **Description:** Retrieve subscription plans from your Stripe account.

    **Parameters:**

    * `isPlanActive` (boolean, optional): Filter by plan status - true for active plans, false for inactive plans
    * `paginationParameters` (object, optional): Pagination settings
      * `pageCursor` (string, optional): Page cursor for pagination
  </Accordion>
</AccordionGroup>

## Usage Examples

### Basic Stripe Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew
from crewai import Agent, Task, Crew

# Create an agent with Stripe capabilities
stripe_agent = Agent(
    role="Payment Manager",
    goal="Manage customer payments, subscriptions, and billing operations efficiently",
    backstory="An AI assistant specialized in payment processing and subscription management.",
    apps=['stripe']  # All Stripe actions will be available
)

# Task to create a new customer
create_customer_task = Task(
    description="Create a new premium customer John Doe with email john.doe@example.com",
    agent=stripe_agent,
    expected_output="Customer created successfully with customer ID"
)

# Run the task
crew = Crew(
    agents=[stripe_agent],
    tasks=[create_customer_task]
)

crew.kickoff()
```

### Filtering Specific Stripe Tools

```python theme={null}

billing_manager = Agent(
    role="Billing Manager",
    goal="Handle customer billing, subscriptions, and payment processing",
    backstory="An experienced billing manager who handles subscription lifecycle and payment operations.",
    apps=['stripe']
)

# Task to manage billing operations
billing_task = Task(
    description="Create a new customer and set up their premium subscription plan",
    agent=billing_manager,
    expected_output="Customer created and subscription activated successfully"
)

crew = Crew(
    agents=[billing_manager],
    tasks=[billing_task]
)

crew.kickoff()
```

### Subscription Management

```python theme={null}
from crewai import Agent, Task, Crew

subscription_manager = Agent(
    role="Subscription Manager",
    goal="Manage customer subscriptions and optimize recurring revenue",
    backstory="An AI assistant that specializes in subscription lifecycle management and customer retention.",
    apps=['stripe']
)

# Task to manage subscription operations
subscription_task = Task(
    description="""
    1. Create a new product "Premium Service Plan" with advanced features
    2. Set up subscription plans with different tiers
    3. Create customers and assign them to appropriate plans
    4. Monitor subscription status and handle billing issues
    """,
    agent=subscription_manager,
    expected_output="Subscription management system configured with customers and active plans"
)

crew = Crew(
    agents=[subscription_manager],
    tasks=[subscription_task]
)

crew.kickoff()
```

### Financial Analytics and Reporting

```python theme={null}
from crewai import Agent, Task, Crew

financial_analyst = Agent(
    role="Financial Analyst",
    goal="Analyze payment data and generate financial insights",
    backstory="An analytical AI that excels at extracting insights from payment and subscription data.",
    apps=['stripe']
)

# Complex task involving financial analysis
analytics_task = Task(
    description="""
    1. Retrieve balance transactions for the current month
    2. Analyze customer payment patterns and subscription trends
    3. Identify high-value customers and subscription performance
    4. Generate monthly financial performance report
    """,
    agent=financial_analyst,
    expected_output="Comprehensive financial analysis with payment insights and recommendations"
)

crew = Crew(
    agents=[financial_analyst],
    tasks=[analytics_task]
)

crew.kickoff()
```

## Subscription Status Reference

Understanding subscription statuses:

* **incomplete** - Subscription requires payment method or payment confirmation
* **incomplete\_expired** - Subscription expired before payment was confirmed
* **trialing** - Subscription is in trial period
* **active** - Subscription is active and current
* **past\_due** - Payment failed but subscription is still active
* **canceled** - Subscription has been canceled
* **unpaid** - Payment failed and subscription is no longer active

## Metadata Usage

Metadata allows you to store additional information about customers, subscriptions, and products:

```json theme={null}
{
  "customer_segment": "enterprise",
  "acquisition_source": "google_ads",
  "lifetime_value": "high",
  "custom_field_1": "value1"
}
```

This integration enables comprehensive payment and subscription management automation, allowing your AI agents to handle billing operations seamlessly within your Stripe ecosystem.


# Zendesk Integration
Source: https://docs.crewai.com/en/enterprise/integrations/zendesk

Customer support and helpdesk management with Zendesk integration for CrewAI.

## Overview

Enable your agents to manage customer support operations through Zendesk. Create and update tickets, manage users, track support metrics, and streamline your customer service workflows with AI-powered automation.

## Prerequisites

Before using the Zendesk integration, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account with an active subscription
* A Zendesk account with appropriate API permissions
* Connected your Zendesk account through the [Integrations page](https://app.crewai.com/integrations)

## Setting Up Zendesk Integration

### 1. Connect Your Zendesk Account

1. Navigate to [CrewAI AMP Integrations](https://app.crewai.com/crewai_plus/connectors)
2. Find **Zendesk** in the Authentication Integrations section
3. Click **Connect** and complete the OAuth flow
4. Grant the necessary permissions for ticket and user management
5. Copy your Enterprise Token from [Integration Settings](https://app.crewai.com/crewai_plus/settings/integrations)

### 2. Install Required Package

```bash theme={null}
uv add crewai-tools
```

### 3. Environment Variable Setup

<Note>
  To use integrations with `Agent(apps=[])`, you must set the
  `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
  Token.
</Note>

```bash theme={null}
export CREWAI_PLATFORM_INTEGRATION_TOKEN="your_enterprise_token"
```

Or add it to your `.env` file:

```
CREWAI_PLATFORM_INTEGRATION_TOKEN=your_enterprise_token
```

## Available Tools

### **Ticket Management**

<AccordionGroup>
  <Accordion title="zendesk/create_ticket">
    **Description:** Create a new support ticket in Zendesk.

    **Parameters:**

    * `ticketSubject` (string, required): Ticket subject line (e.g., "Help, my printer is on fire!")
    * `ticketDescription` (string, required): First comment that appears on the ticket (e.g., "The smoke is very colorful.")
    * `requesterName` (string, required): Name of the user requesting support (e.g., "Jane Customer")
    * `requesterEmail` (string, required): Email of the user requesting support (e.g., "[jane@example.com](mailto:jane@example.com)")
    * `assigneeId` (string, optional): Zendesk Agent ID assigned to this ticket - Use Connect Portal Workflow Settings to allow users to select an assignee
    * `ticketType` (string, optional): Ticket type - Options: problem, incident, question, task
    * `ticketPriority` (string, optional): Priority level - Options: urgent, high, normal, low
    * `ticketStatus` (string, optional): Ticket status - Options: new, open, pending, hold, solved, closed
    * `ticketDueAt` (string, optional): Due date for task-type tickets (ISO 8601 timestamp)
    * `ticketTags` (string, optional): Array of tags to apply (e.g., `["enterprise", "other_tag"]`)
    * `ticketExternalId` (string, optional): External ID to link tickets to local records
    * `ticketCustomFields` (object, optional): Custom field values in JSON format
  </Accordion>

  <Accordion title="zendesk/update_ticket">
    **Description:** Update an existing support ticket in Zendesk.

    **Parameters:**

    * `ticketId` (string, required): ID of the ticket to update (e.g., "35436")
    * `ticketSubject` (string, optional): Updated ticket subject
    * `requesterName` (string, required): Name of the user who requested this ticket
    * `requesterEmail` (string, required): Email of the user who requested this ticket
    * `assigneeId` (string, optional): Updated assignee ID - Use Connect Portal Workflow Settings
    * `ticketType` (string, optional): Updated ticket type - Options: problem, incident, question, task
    * `ticketPriority` (string, optional): Updated priority - Options: urgent, high, normal, low
    * `ticketStatus` (string, optional): Updated status - Options: new, open, pending, hold, solved, closed
    * `ticketDueAt` (string, optional): Updated due date (ISO 8601 timestamp)
    * `ticketTags` (string, optional): Updated tags array
    * `ticketExternalId` (string, optional): Updated external ID
    * `ticketCustomFields` (object, optional): Updated custom field values
  </Accordion>

  <Accordion title="zendesk/get_ticket_by_id">
    **Description:** Retrieve a specific ticket by its ID.

    **Parameters:**

    * `ticketId` (string, required): The ticket ID to retrieve (e.g., "35436")
  </Accordion>

  <Accordion title="zendesk/add_comment_to_ticket">
    **Description:** Add a comment or internal note to an existing ticket.

    **Parameters:**

    * `ticketId` (string, required): ID of the ticket to add comment to (e.g., "35436")
    * `commentBody` (string, required): Comment message (accepts plain text or HTML, e.g., "Thanks for your help!")
    * `isInternalNote` (boolean, optional): Set to true for internal notes instead of public replies (defaults to false)
    * `isPublic` (boolean, optional): True for public comments, false for internal notes
  </Accordion>

  <Accordion title="zendesk/search_tickets">
    **Description:** Search for tickets using various filters and criteria.

    **Parameters:**

    * `ticketSubject` (string, optional): Filter by text in ticket subject
    * `ticketDescription` (string, optional): Filter by text in ticket description and comments
    * `ticketStatus` (string, optional): Filter by status - Options: new, open, pending, hold, solved, closed
    * `ticketType` (string, optional): Filter by type - Options: problem, incident, question, task, no\_type
    * `ticketPriority` (string, optional): Filter by priority - Options: urgent, high, normal, low, no\_priority
    * `requesterId` (string, optional): Filter by requester user ID
    * `assigneeId` (string, optional): Filter by assigned agent ID
    * `recipientEmail` (string, optional): Filter by original recipient email address
    * `ticketTags` (string, optional): Filter by ticket tags
    * `ticketExternalId` (string, optional): Filter by external ID
    * `createdDate` (object, optional): Filter by creation date with operator (EQUALS, LESS\_THAN\_EQUALS, GREATER\_THAN\_EQUALS) and value
    * `updatedDate` (object, optional): Filter by update date with operator and value
    * `dueDate` (object, optional): Filter by due date with operator and value
    * `sort_by` (string, optional): Sort field - Options: created\_at, updated\_at, priority, status, ticket\_type
    * `sort_order` (string, optional): Sort direction - Options: asc, desc
  </Accordion>
</AccordionGroup>

### **User Management**

<AccordionGroup>
  <Accordion title="zendesk/create_user">
    **Description:** Create a new user in Zendesk.

    **Parameters:**

    * `name` (string, required): User's full name
    * `email` (string, optional): User's email address (e.g., "[jane@example.com](mailto:jane@example.com)")
    * `phone` (string, optional): User's phone number
    * `role` (string, optional): User role - Options: admin, agent, end-user
    * `externalId` (string, optional): Unique identifier from another system
    * `details` (string, optional): Additional user details
    * `notes` (string, optional): Internal notes about the user
  </Accordion>

  <Accordion title="zendesk/update_user">
    **Description:** Update an existing user's information.

    **Parameters:**

    * `userId` (string, required): ID of the user to update
    * `name` (string, optional): Updated user name
    * `email` (string, optional): Updated email (adds as secondary email on update)
    * `phone` (string, optional): Updated phone number
    * `role` (string, optional): Updated role - Options: admin, agent, end-user
    * `externalId` (string, optional): Updated external ID
    * `details` (string, optional): Updated user details
    * `notes` (string, optional): Updated internal notes
  </Accordion>

  <Accordion title="zendesk/get_user_by_id">
    **Description:** Retrieve a specific user by their ID.

    **Parameters:**

    * `userId` (string, required): The user ID to retrieve
  </Accordion>

  <Accordion title="zendesk/search_users">
    **Description:** Search for users using various criteria.

    **Parameters:**

    * `name` (string, optional): Filter by user name
    * `email` (string, optional): Filter by user email (e.g., "[jane@example.com](mailto:jane@example.com)")
    * `role` (string, optional): Filter by role - Options: admin, agent, end-user
    * `externalId` (string, optional): Filter by external ID
    * `sort_by` (string, optional): Sort field - Options: created\_at, updated\_at
    * `sort_order` (string, optional): Sort direction - Options: asc, desc
  </Accordion>
</AccordionGroup>

### **Administrative Tools**

<AccordionGroup>
  <Accordion title="zendesk/get_ticket_fields">
    **Description:** Retrieve all standard and custom fields available for tickets.

    **Parameters:**

    * `paginationParameters` (object, optional): Pagination settings
      * `pageCursor` (string, optional): Page cursor for pagination
  </Accordion>

  <Accordion title="zendesk/get_ticket_audits">
    **Description:** Get audit records (read-only history) for tickets.

    **Parameters:**

    * `ticketId` (string, optional): Get audits for specific ticket (if empty, retrieves audits for all non-archived tickets, e.g., "1234")
    * `paginationParameters` (object, optional): Pagination settings
      * `pageCursor` (string, optional): Page cursor for pagination
  </Accordion>
</AccordionGroup>

## Custom Fields

Custom fields allow you to store additional information specific to your organization:

```json theme={null}
[
  { "id": 27642, "value": "745" },
  { "id": 27648, "value": "yes" }
]
```

## Ticket Priority Levels

Understanding priority levels:

* **urgent** - Critical issues requiring immediate attention
* **high** - Important issues that should be addressed quickly
* **normal** - Standard priority for most tickets
* **low** - Minor issues that can be addressed when convenient

## Ticket Status Workflow

Standard ticket status progression:

* **new** - Recently created, not yet assigned
* **open** - Actively being worked on
* **pending** - Waiting for customer response or external action
* **hold** - Temporarily paused
* **solved** - Issue resolved, awaiting customer confirmation
* **closed** - Ticket completed and closed

## Usage Examples

### Basic Zendesk Agent Setup

```python theme={null}
from crewai import Agent, Task, Crew
from crewai import Agent, Task, Crew

# Create an agent with Zendesk capabilities
zendesk_agent = Agent(
    role="Support Manager",
    goal="Manage customer support tickets and provide excellent customer service",
    backstory="An AI assistant specialized in customer support operations and ticket management.",
    apps=['zendesk']  # All Zendesk actions will be available
)

# Task to create a new support ticket
create_ticket_task = Task(
    description="Create a high-priority support ticket for John Smith who is unable to access his account after password reset",
    agent=zendesk_agent,
    expected_output="Support ticket created successfully with ticket ID"
)

# Run the task
crew = Crew(
    agents=[zendesk_agent],
    tasks=[create_ticket_task]
)

crew.kickoff()
```

### Filtering Specific Zendesk Tools

```python theme={null}
from crewai import Agent, Task, Crew

# Create agent with specific Zendesk actions only
support_agent = Agent(
    role="Customer Support Agent",
    goal="Handle customer inquiries and resolve support issues efficiently",
    backstory="An experienced support agent who specializes in ticket resolution and customer communication.",
    apps=['zendesk/create_ticket']  # Specific Zendesk actions
)

# Task to manage support workflow
support_task = Task(
    description="Create a ticket for login issues, add troubleshooting comments, and update status to resolved",
    agent=support_agent,
    expected_output="Support ticket managed through complete resolution workflow"
)

crew = Crew(
    agents=[support_agent],
    tasks=[support_task]
)

crew.kickoff()
```

### Advanced Ticket Management

```python theme={null}
from crewai import Agent, Task, Crew

ticket_manager = Agent(
    role="Ticket Manager",
    goal="Manage support ticket workflows and ensure timely resolution",
    backstory="An AI assistant that specializes in support ticket triage and workflow optimization.",
    apps=['zendesk']
)

# Task to manage ticket lifecycle
ticket_workflow = Task(
    description="""
    1. Create a new support ticket for account access issues
    2. Add internal notes with troubleshooting steps
    3. Update ticket priority based on customer tier
    4. Add resolution comments and close the ticket
    """,
    agent=ticket_manager,
    expected_output="Complete ticket lifecycle managed from creation to resolution"
)

crew = Crew(
    agents=[ticket_manager],
    tasks=[ticket_workflow]
)

crew.kickoff()
```

### Support Analytics and Reporting

```python theme={null}
from crewai import Agent, Task, Crew

support_analyst = Agent(
    role="Support Analyst",
    goal="Analyze support metrics and generate insights for team performance",
    backstory="An analytical AI that excels at extracting insights from support data and ticket patterns.",
    apps=['zendesk']
)

# Complex task involving analytics and reporting
analytics_task = Task(
    description="""
    1. Search for all open tickets from the last 30 days
    2. Analyze ticket resolution times and customer satisfaction
    3. Identify common issues and support patterns
    4. Generate weekly support performance report
    """,
    agent=support_analyst,
    expected_output="Comprehensive support analytics report with performance insights and recommendations"
)

crew = Crew(
    agents=[support_analyst],
    tasks=[analytics_task]
)

crew.kickoff()
```


# CrewAI AMP
Source: https://docs.crewai.com/en/enterprise/introduction

Deploy, monitor, and scale your AI agent workflows

## Introduction

CrewAI AMP(Agent Management Platform) provides a platform for deploying, monitoring, and scaling your crews and agents in a production environment.

<Frame>
  <img alt="CrewAI AMP Dashboard" />
</Frame>

CrewAI AMP extends the power of the open-source framework with features designed for production deployments, collaboration, and scalability. Deploy your crews to a managed infrastructure and monitor their execution in real-time.

## Key Features

<CardGroup>
  <Card title="Crew Deployments" icon="rocket">
    Deploy your crews to a managed infrastructure with a few clicks
  </Card>

  <Card title="API Access" icon="code">
    Access your deployed crews via REST API for integration with existing
    systems
  </Card>

  <Card title="Observability" icon="chart-line">
    Monitor your crews with detailed execution traces and logs
  </Card>

  <Card title="Tool Repository" icon="toolbox">
    Publish and install tools to enhance your crews' capabilities
  </Card>

  <Card title="Webhook Streaming" icon="webhook">
    Stream real-time events and updates to your systems
  </Card>

  <Card title="Crew Studio" icon="paintbrush">
    Create and customize crews using a no-code/low-code interface
  </Card>
</CardGroup>

## Deployment Options

<CardGroup>
  <Card title="GitHub Integration" icon="github">
    Connect directly to your GitHub repositories to deploy code
  </Card>

  <Card title="Crew Studio" icon="palette">
    Deploy crews created through the no-code Crew Studio interface
  </Card>

  <Card title="CLI Deployment" icon="terminal">
    Use the CrewAI CLI for more advanced deployment workflows
  </Card>
</CardGroup>

## Getting Started

<Steps>
  <Step title="Sign up for an account">
    Create your account at [app.crewai.com](https://app.crewai.com)

    <Card title="Sign Up" icon="user" href="https://app.crewai.com/signup">
      Sign Up
    </Card>
  </Step>

  <Step title="Build your first crew">
    Use code or Crew Studio to build your crew

    <Card title="Build Crew" icon="paintbrush" href="/en/enterprise/guides/build-crew">
      Build Crew
    </Card>
  </Step>

  <Step title="Deploy your crew">
    Deploy your crew to the Enterprise platform

    <Card title="Deploy Crew" icon="rocket" href="/en/enterprise/guides/deploy-crew">
      Deploy Crew
    </Card>
  </Step>

  <Step title="Access your crew">
    Integrate with your crew via the generated API endpoints

    <Card title="API Access" icon="code" href="/en/enterprise/guides/kickoff-crew">
      Use the Crew API
    </Card>
  </Step>
</Steps>

For detailed instructions, check out our [deployment guide](/en/enterprise/guides/deploy-crew) or click the button below to get started.


# Coding Agents
Source: https://docs.crewai.com/en/learn/coding-agents

Learn how to enable your CrewAI Agents to write and execute code, and explore advanced features for enhanced functionality.

## Introduction

CrewAI Agents now have the powerful ability to write and execute code, significantly enhancing their problem-solving capabilities. This feature is particularly useful for tasks that require computational or programmatic solutions.

## Enabling Code Execution

To enable code execution for an agent, set the `allow_code_execution` parameter to `True` when creating the agent.

Here's an example:

```python Code theme={null}
from crewai import Agent

coding_agent = Agent(
    role="Senior Python Developer",
    goal="Craft well-designed and thought-out code",
    backstory="You are a senior Python developer with extensive experience in software architecture and best practices.",
    allow_code_execution=True
)
```

<Note>
  Note that `allow_code_execution` parameter defaults to `False`.
</Note>

## Important Considerations

1. **Model Selection**: It is strongly recommended to use more capable models like Claude 3.5 Sonnet and GPT-4 when enabling code execution.
   These models have a better understanding of programming concepts and are more likely to generate correct and efficient code.

2. **Error Handling**: The code execution feature includes error handling. If executed code raises an exception, the agent will receive the error message and can attempt to correct the code or
   provide alternative solutions. The `max_retry_limit` parameter, which defaults to 2, controls the maximum number of retries for a task.

3. **Dependencies**: To use the code execution feature, you need to install the `crewai_tools` package. If not installed, the agent will log an info message:
   "Coding tools not available. Install crewai\_tools."

## Code Execution Process

When an agent with code execution enabled encounters a task requiring programming:

<Steps>
  <Step title="Task Analysis">
    The agent analyzes the task and determines that code execution is necessary.
  </Step>

  <Step title="Code Formulation">
    It formulates the Python code needed to solve the problem.
  </Step>

  <Step title="Code Execution">
    The code is sent to the internal code execution tool (`CodeInterpreterTool`).
  </Step>

  <Step title="Result Interpretation">
    The agent interprets the result and incorporates it into its response or uses it for further problem-solving.
  </Step>
</Steps>

## Example Usage

Here's a detailed example of creating an agent with code execution capabilities and using it in a task:

```python Code theme={null}
from crewai import Agent, Task, Crew

# Create an agent with code execution enabled
coding_agent = Agent(
    role="Python Data Analyst",
    goal="Analyze data and provide insights using Python",
    backstory="You are an experienced data analyst with strong Python skills.",
    allow_code_execution=True
)

# Create a task that requires code execution
data_analysis_task = Task(
    description="Analyze the given dataset and calculate the average age of participants.",
    agent=coding_agent
)

# Create a crew and add the task
analysis_crew = Crew(
    agents=[coding_agent],
    tasks=[data_analysis_task]
)

# Execute the crew
result = analysis_crew.kickoff()

print(result)
```

In this example, the `coding_agent` can write and execute Python code to perform data analysis tasks.


# Conditional Tasks
Source: https://docs.crewai.com/en/learn/conditional-tasks

Learn how to use conditional tasks in a crewAI kickoff

## Introduction

Conditional Tasks in crewAI allow for dynamic workflow adaptation based on the outcomes of previous tasks.
This powerful feature enables crews to make decisions and execute tasks selectively, enhancing the flexibility and efficiency of your AI-driven processes.

## Example Usage

```python Code theme={null}
from typing import List
from pydantic import BaseModel
from crewai import Agent, Crew
from crewai.tasks.conditional_task import ConditionalTask
from crewai.tasks.task_output import TaskOutput
from crewai.task import Task
from crewai_tools import SerperDevTool

# Define a condition function for the conditional task
# If false, the task will be skipped, if true, then execute the task.
def is_data_missing(output: TaskOutput) -> bool:
    return len(output.pydantic.events) < 10  # this will skip this task

# Define the agents
data_fetcher_agent = Agent(
    role="Data Fetcher",
    goal="Fetch data online using Serper tool",
    backstory="Backstory 1",
    verbose=True,
    tools=[SerperDevTool()]
)

data_processor_agent = Agent(
    role="Data Processor",
    goal="Process fetched data",
    backstory="Backstory 2",
    verbose=True
)

summary_generator_agent = Agent(
    role="Summary Generator",
    goal="Generate summary from fetched data",
    backstory="Backstory 3",
    verbose=True
)

class EventOutput(BaseModel):
    events: List[str]

task1 = Task(
    description="Fetch data about events in San Francisco using Serper tool",
    expected_output="List of 10 things to do in SF this week",
    agent=data_fetcher_agent,
    output_pydantic=EventOutput,
)

conditional_task = ConditionalTask(
    description="""
        Check if data is missing. If we have less than 10 events,
        fetch more events using Serper tool so that
        we have a total of 10 events in SF this week..
        """,
    expected_output="List of 10 Things to do in SF this week",
    condition=is_data_missing,
    agent=data_processor_agent,
)

task3 = Task(
    description="Generate summary of events in San Francisco from fetched data",
    expected_output="A complete report on the customer and their customers and competitors, including their demographics, preferences, market positioning and audience engagement.",
    agent=summary_generator_agent,
)

# Create a crew with the tasks
crew = Crew(
    agents=[data_fetcher_agent, data_processor_agent, summary_generator_agent],
    tasks=[task1, conditional_task, task3],
    verbose=True,
    planning=True
)

# Run the crew
result = crew.kickoff()
print("results", result)
```


# Create Custom Tools
Source: https://docs.crewai.com/en/learn/create-custom-tools

Comprehensive guide on crafting, using, and managing custom tools within the CrewAI framework, including new functionalities and error handling.

## Creating and Utilizing Tools in CrewAI

This guide provides detailed instructions on creating custom tools for the CrewAI framework and how to efficiently manage and utilize these tools,
incorporating the latest functionalities such as tool delegation, error handling, and dynamic tool calling. It also highlights the importance of collaboration tools,
enabling agents to perform a wide range of actions.

### Subclassing `BaseTool`

To create a personalized tool, inherit from `BaseTool` and define the necessary attributes, including the `args_schema` for input validation, and the `_run` method.

```python Code theme={null}
from typing import Type
from crewai.tools import BaseTool
from pydantic import BaseModel, Field

class MyToolInput(BaseModel):
    """Input schema for MyCustomTool."""
    argument: str = Field(..., description="Description of the argument.")

class MyCustomTool(BaseTool):
    name: str = "Name of my tool"
    description: str = "What this tool does. It's vital for effective utilization."
    args_schema: Type[BaseModel] = MyToolInput

    def _run(self, argument: str) -> str:
        # Your tool's logic here
        return "Tool's result"
```

### Using the `tool` Decorator

Alternatively, you can use the tool decorator `@tool`. This approach allows you to define the tool's attributes and functionality directly within a function,
offering a concise and efficient way to create specialized tools tailored to your needs.

```python Code theme={null}
from crewai.tools import tool

@tool("Tool Name")
def my_simple_tool(question: str) -> str:
    """Tool description for clarity."""
    # Tool logic here
    return "Tool output"
```

### Defining a Cache Function for the Tool

To optimize tool performance with caching, define custom caching strategies using the `cache_function` attribute.

```python Code theme={null}
@tool("Tool with Caching")
def cached_tool(argument: str) -> str:
    """Tool functionality description."""
    return "Cacheable result"

def my_cache_strategy(arguments: dict, result: str) -> bool:
    # Define custom caching logic
    return True if some_condition else False

cached_tool.cache_function = my_cache_strategy
```

### Creating Async Tools

CrewAI supports async tools for non-blocking I/O operations. This is useful when your tool needs to make HTTP requests, database queries, or other I/O-bound operations.

#### Using the `@tool` Decorator with Async Functions

The simplest way to create an async tool is using the `@tool` decorator with an async function:

```python Code theme={null}
import aiohttp
from crewai.tools import tool

@tool("Async Web Fetcher")
async def fetch_webpage(url: str) -> str:
    """Fetch content from a webpage asynchronously."""
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()
```

#### Subclassing `BaseTool` with Async Support

For more control, subclass `BaseTool` and implement both `_run` (sync) and `_arun` (async) methods:

```python Code theme={null}
import requests
import aiohttp
from crewai.tools import BaseTool
from pydantic import BaseModel, Field

class WebFetcherInput(BaseModel):
    """Input schema for WebFetcher."""
    url: str = Field(..., description="The URL to fetch")

class WebFetcherTool(BaseTool):
    name: str = "Web Fetcher"
    description: str = "Fetches content from a URL"
    args_schema: type[BaseModel] = WebFetcherInput

    def _run(self, url: str) -> str:
        """Synchronous implementation."""
        return requests.get(url).text

    async def _arun(self, url: str) -> str:
        """Asynchronous implementation for non-blocking I/O."""
        async with aiohttp.ClientSession() as session:
            async with session.get(url) as response:
                return await response.text()
```

By adhering to these guidelines and incorporating new functionalities and collaboration tools into your tool creation and management processes,
you can leverage the full capabilities of the CrewAI framework, enhancing both the development experience and the efficiency of your AI agents.


# Custom LLM Implementation
Source: https://docs.crewai.com/en/learn/custom-llm

Learn how to create custom LLM implementations in CrewAI.

## Overview

CrewAI supports custom LLM implementations through the `BaseLLM` abstract base class. This allows you to integrate any LLM provider that doesn't have built-in support in LiteLLM, or implement custom authentication mechanisms.

## Quick Start

Here's a minimal custom LLM implementation:

```python theme={null}
from crewai import BaseLLM
from typing import Any, Dict, List, Optional, Union
import requests

class CustomLLM(BaseLLM):
    def __init__(self, model: str, api_key: str, endpoint: str, temperature: Optional[float] = None):
        # IMPORTANT: Call super().__init__() with required parameters
        super().__init__(model=model, temperature=temperature)
        
        self.api_key = api_key
        self.endpoint = endpoint
        
    def call(
        self,
        messages: Union[str, List[Dict[str, str]]],
        tools: Optional[List[dict]] = None,
        callbacks: Optional[List[Any]] = None,
        available_functions: Optional[Dict[str, Any]] = None,
    ) -> Union[str, Any]:
        """Call the LLM with the given messages."""
        # Convert string to message format if needed
        if isinstance(messages, str):
            messages = [{"role": "user", "content": messages}]
        
        # Prepare request
        payload = {
            "model": self.model,
            "messages": messages,
            "temperature": self.temperature,
        }
        
        # Add tools if provided and supported
        if tools and self.supports_function_calling():
            payload["tools"] = tools
        
        # Make API call
        response = requests.post(
            self.endpoint,
            headers={
                "Authorization": f"Bearer {self.api_key}",
                "Content-Type": "application/json"
            },
            json=payload,
            timeout=30
        )
        response.raise_for_status()
        
        result = response.json()
        return result["choices"][0]["message"]["content"]
        
    def supports_function_calling(self) -> bool:
        """Override if your LLM supports function calling."""
        return True  # Change to False if your LLM doesn't support tools
        
    def get_context_window_size(self) -> int:
        """Return the context window size of your LLM."""
        return 8192  # Adjust based on your model's actual context window
```

## Using Your Custom LLM

```python theme={null}
from crewai import Agent, Task, Crew

# Assuming you have the CustomLLM class defined above
# Create your custom LLM
custom_llm = CustomLLM(
    model="my-custom-model",
    api_key="your-api-key",
    endpoint="https://api.example.com/v1/chat/completions",
    temperature=0.7
)

# Use with an agent
agent = Agent(
    role="Research Assistant",
    goal="Find and analyze information",
    backstory="You are a research assistant.",
    llm=custom_llm
)

# Create and execute tasks
task = Task(
    description="Research the latest developments in AI",
    expected_output="A comprehensive summary",
    agent=agent
)

crew = Crew(agents=[agent], tasks=[task])
result = crew.kickoff()
```

## Required Methods

### Constructor: `__init__()`

**Critical**: You must call `super().__init__(model, temperature)` with the required parameters:

```python theme={null}
def __init__(self, model: str, api_key: str, temperature: Optional[float] = None):
    # REQUIRED: Call parent constructor with model and temperature
    super().__init__(model=model, temperature=temperature)
    
    # Your custom initialization
    self.api_key = api_key
```

### Abstract Method: `call()`

The `call()` method is the heart of your LLM implementation. It must:

* Accept messages (string or list of dicts with 'role' and 'content')
* Return a string response
* Handle tools and function calling if supported
* Raise appropriate exceptions for errors

### Optional Methods

```python theme={null}
def supports_function_calling(self) -> bool:
    """Return True if your LLM supports function calling."""
    return True  # Default is True

def supports_stop_words(self) -> bool:
    """Return True if your LLM supports stop sequences."""
    return True  # Default is True

def get_context_window_size(self) -> int:
    """Return the context window size."""
    return 4096  # Default is 4096
```

## Common Patterns

### Error Handling

```python theme={null}
import requests

def call(self, messages, tools=None, callbacks=None, available_functions=None):
    try:
        response = requests.post(
            self.endpoint,
            headers={"Authorization": f"Bearer {self.api_key}"},
            json=payload,
            timeout=30
        )
        response.raise_for_status()
        return response.json()["choices"][0]["message"]["content"]
        
    except requests.Timeout:
        raise TimeoutError("LLM request timed out")
    except requests.RequestException as e:
        raise RuntimeError(f"LLM request failed: {str(e)}")
    except (KeyError, IndexError) as e:
        raise ValueError(f"Invalid response format: {str(e)}")
```

### Custom Authentication

```python theme={null}
from crewai import BaseLLM
from typing import Optional

class CustomAuthLLM(BaseLLM):
    def __init__(self, model: str, auth_token: str, endpoint: str, temperature: Optional[float] = None):
        super().__init__(model=model, temperature=temperature)
        self.auth_token = auth_token
        self.endpoint = endpoint
    
    def call(self, messages, tools=None, callbacks=None, available_functions=None):
        headers = {
            "Authorization": f"Custom {self.auth_token}",  # Custom auth format
            "Content-Type": "application/json"
        }
        # Rest of implementation...
```

### Stop Words Support

CrewAI automatically adds `"\nObservation:"` as a stop word to control agent behavior. If your LLM supports stop words:

```python theme={null}
def call(self, messages, tools=None, callbacks=None, available_functions=None):
    payload = {
        "model": self.model,
        "messages": messages,
        "stop": self.stop  # Include stop words in API call
    }
    # Make API call...

def supports_stop_words(self) -> bool:
    return True  # Your LLM supports stop sequences
```

If your LLM doesn't support stop words natively:

```python theme={null}
def call(self, messages, tools=None, callbacks=None, available_functions=None):
    response = self._make_api_call(messages, tools)
    content = response["choices"][0]["message"]["content"]
    
    # Manually truncate at stop words
    if self.stop:
        for stop_word in self.stop:
            if stop_word in content:
                content = content.split(stop_word)[0]
                break
    
    return content

def supports_stop_words(self) -> bool:
    return False  # Tell CrewAI we handle stop words manually
```

## Function Calling

If your LLM supports function calling, implement the complete flow:

```python theme={null}
import json

def call(self, messages, tools=None, callbacks=None, available_functions=None):
    # Convert string to message format
    if isinstance(messages, str):
        messages = [{"role": "user", "content": messages}]
    
    # Make API call
    response = self._make_api_call(messages, tools)
    message = response["choices"][0]["message"]
    
    # Check for function calls
    if "tool_calls" in message and available_functions:
        return self._handle_function_calls(
            message["tool_calls"], messages, tools, available_functions
        )
    
    return message["content"]

def _handle_function_calls(self, tool_calls, messages, tools, available_functions):
    """Handle function calling with proper message flow."""
    for tool_call in tool_calls:
        function_name = tool_call["function"]["name"]
        
        if function_name in available_functions:
            # Parse and execute function
            function_args = json.loads(tool_call["function"]["arguments"])
            function_result = available_functions[function_name](**function_args)
            
            # Add function call and result to message history
            messages.append({
                "role": "assistant",
                "content": None,
                "tool_calls": [tool_call]
            })
            messages.append({
                "role": "tool",
                "tool_call_id": tool_call["id"],
                "name": function_name,
                "content": str(function_result)
            })
            
            # Call LLM again with updated context
            return self.call(messages, tools, None, available_functions)
    
    return "Function call failed"
```

## Troubleshooting

### Common Issues

**Constructor Errors**

```python theme={null}
# ❌ Wrong - missing required parameters
def __init__(self, api_key: str):
    super().__init__()

# ✅ Correct
def __init__(self, model: str, api_key: str, temperature: Optional[float] = None):
    super().__init__(model=model, temperature=temperature)
```

**Function Calling Not Working**

* Ensure `supports_function_calling()` returns `True`
* Check that you handle `tool_calls` in the response
* Verify `available_functions` parameter is used correctly

**Authentication Failures**

* Verify API key format and permissions
* Check authentication header format
* Ensure endpoint URLs are correct

**Response Parsing Errors**

* Validate response structure before accessing nested fields
* Handle cases where content might be None
* Add proper error handling for malformed responses

## Testing Your Custom LLM

```python theme={null}
from crewai import Agent, Task, Crew

def test_custom_llm():
    llm = CustomLLM(
        model="test-model",
        api_key="test-key",
        endpoint="https://api.test.com"
    )
    
    # Test basic call
    result = llm.call("Hello, world!")
    assert isinstance(result, str)
    assert len(result) > 0
    
    # Test with CrewAI agent
    agent = Agent(
        role="Test Agent",
        goal="Test custom LLM",
        backstory="A test agent.",
        llm=llm
    )
    
    task = Task(
        description="Say hello",
        expected_output="A greeting",
        agent=agent
    )
    
    crew = Crew(agents=[agent], tasks=[task])
    result = crew.kickoff()
    assert "hello" in result.raw.lower()
```

This guide covers the essentials of implementing custom LLMs in CrewAI.


# Custom Manager Agent
Source: https://docs.crewai.com/en/learn/custom-manager-agent

Learn how to set a custom agent as the manager in CrewAI, providing more control over task management and coordination.

# Setting a Specific Agent as Manager in CrewAI

CrewAI allows users to set a specific agent as the manager of the crew, providing more control over the management and coordination of tasks.
This feature enables the customization of the managerial role to better fit your project's requirements.

## Using the `manager_agent` Attribute

### Custom Manager Agent

The `manager_agent` attribute allows you to define a custom agent to manage the crew. This agent will oversee the entire process, ensuring that tasks are completed efficiently and to the highest standard.

### Example

```python Code theme={null}
import os
from crewai import Agent, Task, Crew, Process

# Define your agents
researcher = Agent(
    role="Researcher",
    goal="Conduct thorough research and analysis on AI and AI agents",
    backstory="You're an expert researcher, specialized in technology, software engineering, AI, and startups. You work as a freelancer and are currently researching for a new client.",
    allow_delegation=False,
)

writer = Agent(
    role="Senior Writer",
    goal="Create compelling content about AI and AI agents",
    backstory="You're a senior writer, specialized in technology, software engineering, AI, and startups. You work as a freelancer and are currently writing content for a new client.",
    allow_delegation=False,
)

# Define your task
task = Task(
    description="Generate a list of 5 interesting ideas for an article, then write one captivating paragraph for each idea that showcases the potential of a full article on this topic. Return the list of ideas with their paragraphs and your notes.",
    expected_output="5 bullet points, each with a paragraph and accompanying notes.",
)

# Define the manager agent
manager = Agent(
    role="Project Manager",
    goal="Efficiently manage the crew and ensure high-quality task completion",
    backstory="You're an experienced project manager, skilled in overseeing complex projects and guiding teams to success. Your role is to coordinate the efforts of the crew members, ensuring that each task is completed on time and to the highest standard.",
    allow_delegation=True,
)

# Instantiate your crew with a custom manager
crew = Crew(
    agents=[researcher, writer],
    tasks=[task],
    manager_agent=manager,
    process=Process.hierarchical,
)

# Start the crew's work
result = crew.kickoff()
```

## Benefits of a Custom Manager Agent

* **Enhanced Control**: Tailor the management approach to fit the specific needs of your project.
* **Improved Coordination**: Ensure efficient task coordination and management by an experienced agent.
* **Customizable Management**: Define managerial roles and responsibilities that align with your project's goals.

## Setting a Manager LLM

If you're using the hierarchical process and don't want to set a custom manager agent, you can specify the language model for the manager:

```python Code theme={null}
from crewai import LLM

manager_llm = LLM(model="gpt-4o")

crew = Crew(
    agents=[researcher, writer],
    tasks=[task],
    process=Process.hierarchical,
    manager_llm=manager_llm
)
```

<Note>
  Either `manager_agent` or `manager_llm` must be set when using the hierarchical process.
</Note>


# Customize Agents
Source: https://docs.crewai.com/en/learn/customizing-agents

A comprehensive guide to tailoring agents for specific roles, tasks, and advanced customizations within the CrewAI framework.

## Customizable Attributes

Crafting an efficient CrewAI team hinges on the ability to dynamically tailor your AI agents to meet the unique requirements of any project. This section covers the foundational attributes you can customize.

### Key Attributes for Customization

| Attribute                           | Description                                                                                                         |
| :---------------------------------- | :------------------------------------------------------------------------------------------------------------------ |
| **Role**                            | Specifies the agent's job within the crew, such as 'Analyst' or 'Customer Service Rep'.                             |
| **Goal**                            | Defines the agent’s objectives, aligned with its role and the crew’s overarching mission.                           |
| **Backstory**                       | Provides depth to the agent's persona, enhancing motivations and engagements within the crew.                       |
| **Tools** *(Optional)*              | Represents the capabilities or methods the agent uses for tasks, from simple functions to complex integrations.     |
| **Cache** *(Optional)*              | Determines if the agent should use a cache for tool usage.                                                          |
| **Max RPM**                         | Sets the maximum requests per minute (`max_rpm`). Can be set to `None` for unlimited requests to external services. |
| **Verbose** *(Optional)*            | Enables detailed logging for debugging and optimization, providing insights into execution processes.               |
| **Allow Delegation** *(Optional)*   | Controls task delegation to other agents, default is `False`.                                                       |
| **Max Iter** *(Optional)*           | Limits the maximum number of iterations (`max_iter`) for a task to prevent infinite loops, with a default of 25.    |
| **Max Execution Time** *(Optional)* | Sets the maximum time allowed for an agent to complete a task.                                                      |
| **System Template** *(Optional)*    | Defines the system format for the agent.                                                                            |
| **Prompt Template** *(Optional)*    | Defines the prompt format for the agent.                                                                            |
| **Response Template** *(Optional)*  | Defines the response format for the agent.                                                                          |
| **Use System Prompt** *(Optional)*  | Controls whether the agent will use a system prompt during task execution.                                          |
| **Respect Context Window**          | Enables a sliding context window by default, maintaining context size.                                              |
| **Max Retry Limit**                 | Sets the maximum number of retries (`max_retry_limit`) for an agent in case of errors.                              |

## Advanced Customization Options

Beyond the basic attributes, CrewAI allows for deeper customization to enhance an agent's behavior and capabilities significantly.

### Language Model Customization

Agents can be customized with specific language models (`llm`) and function-calling language models (`function_calling_llm`), offering advanced control over their processing and decision-making abilities.
It's important to note that setting the `function_calling_llm` allows for overriding the default crew function-calling language model, providing a greater degree of customization.

## Performance and Debugging Settings

Adjusting an agent's performance and monitoring its operations are crucial for efficient task execution.

### Verbose Mode and RPM Limit

* **Verbose Mode**: Enables detailed logging of an agent's actions, useful for debugging and optimization. Specifically, it provides insights into agent execution processes, aiding in the optimization of performance.
* **RPM Limit**: Sets the maximum number of requests per minute (`max_rpm`). This attribute is optional and can be set to `None` for no limit, allowing for unlimited queries to external services if needed.

### Maximum Iterations for Task Execution

The `max_iter` attribute allows users to define the maximum number of iterations an agent can perform for a single task, preventing infinite loops or excessively long executions.
The default value is set to 25, providing a balance between thoroughness and efficiency. Once the agent approaches this number, it will try its best to give a good answer.

## Customizing Agents and Tools

Agents are customized by defining their attributes and tools during initialization. Tools are critical for an agent's functionality, enabling them to perform specialized tasks.
The `tools` attribute should be an array of tools the agent can utilize, and it's initialized as an empty list by default. Tools can be added or modified post-agent initialization to adapt to new requirements.

```shell theme={null}
pip install 'crewai[tools]'
```

### Example: Assigning Tools to an Agent

```python Code theme={null}
import os
from crewai import Agent
from crewai_tools import SerperDevTool

# Set API keys for tool initialization
os.environ["OPENAI_API_KEY"] = "Your Key"
os.environ["SERPER_API_KEY"] = "Your Key"

# Initialize a search tool
search_tool = SerperDevTool()

# Initialize the agent with advanced options
agent = Agent(
  role='Research Analyst',
  goal='Provide up-to-date market analysis',
  backstory='An expert analyst with a keen eye for market trends.',
  tools=[search_tool],
  memory=True, # Enable memory
  verbose=True,
  max_rpm=None, # No limit on requests per minute
  max_iter=25, # Default value for maximum iterations
)
```

## Delegation and Autonomy

Controlling an agent's ability to delegate tasks or ask questions is vital for tailoring its autonomy and collaborative dynamics within the CrewAI framework. By default,
the `allow_delegation` attribute is now set to `False`, disabling agents to seek assistance or delegate tasks as needed. This default behavior can be changed to promote collaborative problem-solving and
efficiency within the CrewAI ecosystem. If needed, delegation can be enabled to suit specific operational requirements.

### Example: Disabling Delegation for an Agent

```python Code theme={null}
agent = Agent(
  role='Content Writer',
  goal='Write engaging content on market trends',
  backstory='A seasoned writer with expertise in market analysis.',
  allow_delegation=True # Enabling delegation
)
```

## Conclusion

Customizing agents in CrewAI by setting their roles, goals, backstories, and tools, alongside advanced options like language model customization, memory, performance settings, and delegation preferences,
equips a nuanced and capable AI team ready for complex challenges.


# Image Generation with DALL-E
Source: https://docs.crewai.com/en/learn/dalle-image-generation

Learn how to use DALL-E for AI-powered image generation in your CrewAI projects

CrewAI supports integration with OpenAI's DALL-E, allowing your AI agents to generate images as part of their tasks. This guide will walk you through how to set up and use the DALL-E tool in your CrewAI projects.

## Prerequisites

* crewAI installed (latest version)
* OpenAI API key with access to DALL-E

## Setting Up the DALL-E Tool

<Steps>
  <Step title="Import the DALL-E tool">
    ```python theme={null}
    from crewai_tools import DallETool
    ```
  </Step>

  <Step title="Add the DALL-E tool to your agent configuration">
    ```python theme={null}
    @agent
    def researcher(self) -> Agent:
        return Agent(
            config=self.agents_config['researcher'],
            tools=[SerperDevTool(), DallETool()],  # Add DallETool to the list of tools
            allow_delegation=False,
            verbose=True
        )
    ```
  </Step>
</Steps>

## Using the DALL-E Tool

Once you've added the DALL-E tool to your agent, it can generate images based on text prompts. The tool will return a URL to the generated image, which can be used in the agent's output or passed to other agents for further processing.

### Example Agent Configuration

```yaml theme={null}
role: >
    LinkedIn Profile Senior Data Researcher
goal: >
    Uncover detailed LinkedIn profiles based on provided name {name} and domain {domain}
    Generate a Dall-e image based on domain {domain}
backstory: >
    You're a seasoned researcher with a knack for uncovering the most relevant LinkedIn profiles.
    Known for your ability to navigate LinkedIn efficiently, you excel at gathering and presenting
    professional information clearly and concisely.
```

### Expected Output

The agent with the DALL-E tool will be able to generate the image and provide a URL in its response. You can then download the image.

<Frame>
  <img alt="DALL-E Image" />
</Frame>

## Best Practices

1. **Be specific in your image generation prompts** to get the best results.
2. **Consider generation time** - Image generation can take some time, so factor this into your task planning.
3. **Follow usage policies** - Always comply with OpenAI's usage policies when generating images.

## Troubleshooting

1. **Check API access** - Ensure your OpenAI API key has access to DALL-E.
2. **Version compatibility** - Check that you're using the latest version of crewAI and crewai-tools.
3. **Tool configuration** - Verify that the DALL-E tool is correctly added to the agent's tool list.


# Execution Hooks Overview
Source: https://docs.crewai.com/en/learn/execution-hooks

Understanding and using execution hooks in CrewAI for fine-grained control over agent operations

Execution Hooks provide fine-grained control over the runtime behavior of your CrewAI agents. Unlike kickoff hooks that run before and after crew execution, execution hooks intercept specific operations during agent execution, allowing you to modify behavior, implement safety checks, and add comprehensive monitoring.

## Types of Execution Hooks

CrewAI provides two main categories of execution hooks:

### 1. [LLM Call Hooks](/learn/llm-hooks)

Control and monitor language model interactions:

* **Before LLM Call**: Modify prompts, validate inputs, implement approval gates
* **After LLM Call**: Transform responses, sanitize outputs, update conversation history

**Use Cases:**

* Iteration limiting
* Cost tracking and token usage monitoring
* Response sanitization and content filtering
* Human-in-the-loop approval for LLM calls
* Adding safety guidelines or context
* Debug logging and request/response inspection

[View LLM Hooks Documentation →](/learn/llm-hooks)

### 2. [Tool Call Hooks](/learn/tool-hooks)

Control and monitor tool execution:

* **Before Tool Call**: Modify inputs, validate parameters, block dangerous operations
* **After Tool Call**: Transform results, sanitize outputs, log execution details

**Use Cases:**

* Safety guardrails for destructive operations
* Human approval for sensitive actions
* Input validation and sanitization
* Result caching and rate limiting
* Tool usage analytics
* Debug logging and monitoring

[View Tool Hooks Documentation →](/learn/tool-hooks)

## Hook Registration Methods

### 1. Decorator-Based Hooks (Recommended)

The cleanest and most Pythonic way to register hooks:

```python theme={null}
from crewai.hooks import before_llm_call, after_llm_call, before_tool_call, after_tool_call

@before_llm_call
def limit_iterations(context):
    """Prevent infinite loops by limiting iterations."""
    if context.iterations > 10:
        return False  # Block execution
    return None

@after_llm_call
def sanitize_response(context):
    """Remove sensitive data from LLM responses."""
    if "API_KEY" in context.response:
        return context.response.replace("API_KEY", "[REDACTED]")
    return None

@before_tool_call
def block_dangerous_tools(context):
    """Block destructive operations."""
    if context.tool_name == "delete_database":
        return False  # Block execution
    return None

@after_tool_call
def log_tool_result(context):
    """Log tool execution."""
    print(f"Tool {context.tool_name} completed")
    return None
```

### 2. Crew-Scoped Hooks

Apply hooks only to specific crew instances:

```python theme={null}
from crewai import CrewBase
from crewai.project import crew
from crewai.hooks import before_llm_call_crew, after_tool_call_crew

@CrewBase
class MyProjCrew:
    @before_llm_call_crew
    def validate_inputs(self, context):
        # Only applies to this crew
        print(f"LLM call in {self.__class__.__name__}")
        return None

    @after_tool_call_crew
    def log_results(self, context):
        # Crew-specific logging
        print(f"Tool result: {context.tool_result[:50]}...")
        return None

    @crew
    def crew(self) -> Crew:
        return Crew(
            agents=self.agents,
            tasks=self.tasks,
            process=Process.sequential
        )
```

## Hook Execution Flow

### LLM Call Flow

```
Agent needs to call LLM
    ↓
[Before LLM Call Hooks Execute]
    ├→ Hook 1: Validate iteration count
    ├→ Hook 2: Add safety context
    └→ Hook 3: Log request
    ↓
If any hook returns False:
    ├→ Block LLM call
    └→ Raise ValueError
    ↓
If all hooks return True/None:
    ├→ LLM call proceeds
    └→ Response generated
    ↓
[After LLM Call Hooks Execute]
    ├→ Hook 1: Sanitize response
    ├→ Hook 2: Log response
    └→ Hook 3: Update metrics
    ↓
Final response returned
```

### Tool Call Flow

```
Agent needs to execute tool
    ↓
[Before Tool Call Hooks Execute]
    ├→ Hook 1: Check if tool is allowed
    ├→ Hook 2: Validate inputs
    └→ Hook 3: Request approval if needed
    ↓
If any hook returns False:
    ├→ Block tool execution
    └→ Return error message
    ↓
If all hooks return True/None:
    ├→ Tool execution proceeds
    └→ Result generated
    ↓
[After Tool Call Hooks Execute]
    ├→ Hook 1: Sanitize result
    ├→ Hook 2: Cache result
    └→ Hook 3: Log metrics
    ↓
Final result returned
```

## Hook Context Objects

### LLMCallHookContext

Provides access to LLM execution state:

```python theme={null}
class LLMCallHookContext:
    executor: CrewAgentExecutor  # Full executor access
    messages: list               # Mutable message list
    agent: Agent                 # Current agent
    task: Task                   # Current task
    crew: Crew                   # Crew instance
    llm: BaseLLM                 # LLM instance
    iterations: int              # Current iteration
    response: str | None         # LLM response (after hooks)
```

### ToolCallHookContext

Provides access to tool execution state:

```python theme={null}
class ToolCallHookContext:
    tool_name: str               # Tool being called
    tool_input: dict             # Mutable input parameters
    tool: CrewStructuredTool     # Tool instance
    agent: Agent | None          # Agent executing
    task: Task | None            # Current task
    crew: Crew | None            # Crew instance
    tool_result: str | None      # Tool result (after hooks)
```

## Common Patterns

### Safety and Validation

```python theme={null}
@before_tool_call
def safety_check(context):
    """Block destructive operations."""
    dangerous = ['delete_file', 'drop_table', 'system_shutdown']
    if context.tool_name in dangerous:
        print(f"🛑 Blocked: {context.tool_name}")
        return False
    return None

@before_llm_call
def iteration_limit(context):
    """Prevent infinite loops."""
    if context.iterations > 15:
        print("⛔ Maximum iterations exceeded")
        return False
    return None
```

### Human-in-the-Loop

```python theme={null}
@before_tool_call
def require_approval(context):
    """Require approval for sensitive operations."""
    sensitive = ['send_email', 'make_payment', 'post_message']

    if context.tool_name in sensitive:
        response = context.request_human_input(
            prompt=f"Approve {context.tool_name}?",
            default_message="Type 'yes' to approve:"
        )

        if response.lower() != 'yes':
            return False

    return None
```

### Monitoring and Analytics

```python theme={null}
from collections import defaultdict
import time

metrics = defaultdict(lambda: {'count': 0, 'total_time': 0})

@before_tool_call
def start_timer(context):
    context.tool_input['_start'] = time.time()
    return None

@after_tool_call
def track_metrics(context):
    start = context.tool_input.get('_start', time.time())
    duration = time.time() - start

    metrics[context.tool_name]['count'] += 1
    metrics[context.tool_name]['total_time'] += duration

    return None

# View metrics
def print_metrics():
    for tool, data in metrics.items():
        avg = data['total_time'] / data['count']
        print(f"{tool}: {data['count']} calls, {avg:.2f}s avg")
```

### Response Sanitization

```python theme={null}
import re

@after_llm_call
def sanitize_llm_response(context):
    """Remove sensitive data from LLM responses."""
    if not context.response:
        return None

    result = context.response
    result = re.sub(r'(api[_-]?key)["\']?\s*[:=]\s*["\']?[\w-]+',
                   r'\1: [REDACTED]', result, flags=re.IGNORECASE)
    return result

@after_tool_call
def sanitize_tool_result(context):
    """Remove sensitive data from tool results."""
    if not context.tool_result:
        return None

    result = context.tool_result
    result = re.sub(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b',
                   '[EMAIL-REDACTED]', result)
    return result
```

## Hook Management

### Clearing All Hooks

```python theme={null}
from crewai.hooks import clear_all_global_hooks

# Clear all hooks at once
result = clear_all_global_hooks()
print(f"Cleared {result['total']} hooks")
# Output: {'llm_hooks': (2, 1), 'tool_hooks': (1, 2), 'total': (3, 3)}
```

### Clearing Specific Hook Types

```python theme={null}
from crewai.hooks import (
    clear_before_llm_call_hooks,
    clear_after_llm_call_hooks,
    clear_before_tool_call_hooks,
    clear_after_tool_call_hooks
)

# Clear specific types
llm_before_count = clear_before_llm_call_hooks()
tool_after_count = clear_after_tool_call_hooks()
```

### Unregistering Individual Hooks

```python theme={null}
from crewai.hooks import (
    unregister_before_llm_call_hook,
    unregister_after_tool_call_hook
)

def my_hook(context):
    ...

# Register
register_before_llm_call_hook(my_hook)

# Later, unregister
success = unregister_before_llm_call_hook(my_hook)
print(f"Unregistered: {success}")
```

## Best Practices

### 1. Keep Hooks Focused

Each hook should have a single, clear responsibility:

```python theme={null}
# ✅ Good - focused responsibility
@before_tool_call
def validate_file_path(context):
    if context.tool_name == 'read_file':
        if '..' in context.tool_input.get('path', ''):
            return False
    return None

# ❌ Bad - too many responsibilities
@before_tool_call
def do_everything(context):
    # Validation + logging + metrics + approval...
    ...
```

### 2. Handle Errors Gracefully

```python theme={null}
@before_llm_call
def safe_hook(context):
    try:
        # Your logic
        if some_condition:
            return False
    except Exception as e:
        print(f"Hook error: {e}")
        return None  # Allow execution despite error
```

### 3. Modify Context In-Place

```python theme={null}
# ✅ Correct - modify in-place
@before_llm_call
def add_context(context):
    context.messages.append({"role": "system", "content": "Be concise"})

# ❌ Wrong - replaces reference
@before_llm_call
def wrong_approach(context):
    context.messages = [{"role": "system", "content": "Be concise"}]
```

### 4. Use Type Hints

```python theme={null}
from crewai.hooks import LLMCallHookContext, ToolCallHookContext

def my_llm_hook(context: LLMCallHookContext) -> bool | None:
    # IDE autocomplete and type checking
    return None

def my_tool_hook(context: ToolCallHookContext) -> str | None:
    return None
```

### 5. Clean Up in Tests

```python theme={null}
import pytest
from crewai.hooks import clear_all_global_hooks

@pytest.fixture(autouse=True)
def clean_hooks():
    """Reset hooks before each test."""
    yield
    clear_all_global_hooks()
```

## When to Use Which Hook

### Use LLM Hooks When:

* Implementing iteration limits
* Adding context or safety guidelines to prompts
* Tracking token usage and costs
* Sanitizing or transforming responses
* Implementing approval gates for LLM calls
* Debugging prompt/response interactions

### Use Tool Hooks When:

* Blocking dangerous or destructive operations
* Validating tool inputs before execution
* Implementing approval gates for sensitive actions
* Caching tool results
* Tracking tool usage and performance
* Sanitizing tool outputs
* Rate limiting tool calls

### Use Both When:

Building comprehensive observability, safety, or approval systems that need to monitor all agent operations.

## Alternative Registration Methods

### Programmatic Registration (Advanced)

For dynamic hook registration or when you need to register hooks programmatically:

```python theme={null}
from crewai.hooks import (
    register_before_llm_call_hook,
    register_after_tool_call_hook
)

def my_hook(context):
    return None

# Register programmatically
register_before_llm_call_hook(my_hook)

# Useful for:
# - Loading hooks from configuration
# - Conditional hook registration
# - Plugin systems
```

**Note:** For most use cases, decorators are cleaner and more maintainable.

## Performance Considerations

1. **Keep Hooks Fast**: Hooks execute on every call - avoid heavy computation
2. **Cache When Possible**: Store expensive validations or lookups
3. **Be Selective**: Use crew-scoped hooks when global hooks aren't needed
4. **Monitor Hook Overhead**: Profile hook execution time in production
5. **Lazy Import**: Import heavy dependencies only when needed

## Debugging Hooks

### Enable Debug Logging

```python theme={null}
import logging

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

@before_llm_call
def debug_hook(context):
    logger.debug(f"LLM call: {context.agent.role}, iteration {context.iterations}")
    return None
```

### Hook Execution Order

Hooks execute in registration order. If a before hook returns `False`, subsequent hooks don't execute:

```python theme={null}
# Register order matters!
register_before_tool_call_hook(hook1)  # Executes first
register_before_tool_call_hook(hook2)  # Executes second
register_before_tool_call_hook(hook3)  # Executes third

# If hook2 returns False:
# - hook1 executed
# - hook2 executed and returned False
# - hook3 NOT executed
# - Tool call blocked
```

## Related Documentation

* [LLM Call Hooks →](/learn/llm-hooks) - Detailed LLM hook documentation
* [Tool Call Hooks →](/learn/tool-hooks) - Detailed tool hook documentation
* [Before and After Kickoff Hooks →](/learn/before-and-after-kickoff-hooks) - Crew lifecycle hooks
* [Human-in-the-Loop →](/learn/human-in-the-loop) - Human input patterns

## Conclusion

Execution hooks provide powerful control over agent runtime behavior. Use them to implement safety guardrails, approval workflows, comprehensive monitoring, and custom business logic. Combined with proper error handling, type safety, and performance considerations, hooks enable production-ready, secure, and observable agent systems.


# Force Tool Output as Result
Source: https://docs.crewai.com/en/learn/force-tool-output-as-result

Learn how to force tool output as the result in an Agent's task in CrewAI.

## Introduction

In CrewAI, you can force the output of a tool as the result of an agent's task.
This feature is useful when you want to ensure that the tool output is captured and returned as the task result, avoiding any agent modification during the task execution.

## Forcing Tool Output as Result

To force the tool output as the result of an agent's task, you need to set the `result_as_answer` parameter to `True` when adding a tool to the agent.
This parameter ensures that the tool output is captured and returned as the task result, without any modifications by the agent.

Here's an example of how to force the tool output as the result of an agent's task:

```python Code theme={null}
from crewai.agent import Agent
from my_tool import MyCustomTool

# Create a coding agent with the custom tool
coding_agent = Agent(
        role="Data Scientist",
        goal="Produce amazing reports on AI",
        backstory="You work with data and AI",
        tools=[MyCustomTool(result_as_answer=True)],
    )

# Assuming the tool's execution and result population occurs within the system
task_result = coding_agent.execute_task(task)
```

## Workflow in Action

<Steps>
  <Step title="Task Execution">
    The agent executes the task using the tool provided.
  </Step>

  <Step title="Tool Output">
    The tool generates the output, which is captured as the task result.
  </Step>

  <Step title="Agent Interaction">
    The agent may reflect and take learnings from the tool but the output is not modified.
  </Step>

  <Step title="Result Return">
    The tool output is returned as the task result without any modifications.
  </Step>
</Steps>


# Hierarchical Process
Source: https://docs.crewai.com/en/learn/hierarchical-process

A comprehensive guide to understanding and applying the hierarchical process within your CrewAI projects, updated to reflect the latest coding practices and functionalities.

## Introduction

The hierarchical process in CrewAI introduces a structured approach to task management, simulating traditional organizational hierarchies for efficient task delegation and execution.
This systematic workflow enhances project outcomes by ensuring tasks are handled with optimal efficiency and accuracy.

<Tip>
  The hierarchical process is designed to leverage advanced models like GPT-4, optimizing token usage while handling complex tasks with greater efficiency.
</Tip>

## Hierarchical Process Overview

By default, tasks in CrewAI are managed through a sequential process. However, adopting a hierarchical approach allows for a clear hierarchy in task management,
where a 'manager' agent coordinates the workflow, delegates tasks, and validates outcomes for streamlined and effective execution. This manager agent can now be either
automatically created by CrewAI or explicitly set by the user.

### Key Features

* **Task Delegation**: A manager agent allocates tasks among crew members based on their roles and capabilities.
* **Result Validation**: The manager evaluates outcomes to ensure they meet the required standards.
* **Efficient Workflow**: Emulates corporate structures, providing an organized approach to task management.
* **System Prompt Handling**: Optionally specify whether the system should use predefined prompts.
* **Stop Words Control**: Optionally specify whether stop words should be used, supporting various models including the o1 models.
* **Context Window Respect**: Prioritize important context by enabling respect of the context window, which is now the default behavior.
* **Delegation Control**: Delegation is now disabled by default to give users explicit control.
* **Max Requests Per Minute**: Configurable option to set the maximum number of requests per minute.
* **Max Iterations**: Limit the maximum number of iterations for obtaining a final answer.

## Implementing the Hierarchical Process

To utilize the hierarchical process, it's essential to explicitly set the process attribute to `Process.hierarchical`, as the default behavior is `Process.sequential`.
Define a crew with a designated manager and establish a clear chain of command.

<Tip>
  Assign tools at the agent level to facilitate task delegation and execution by the designated agents under the manager's guidance.
  Tools can also be specified at the task level for precise control over tool availability during task execution.
</Tip>

<Tip>
  Configuring the `manager_llm` parameter is crucial for the hierarchical process.
  The system requires a manager LLM to be set up for proper function, ensuring tailored decision-making.
</Tip>

```python Code theme={null}
from crewai import Crew, Process, Agent

# Agents are defined with attributes for backstory, cache, and verbose mode
researcher = Agent(
    role='Researcher',
    goal='Conduct in-depth analysis',
    backstory='Experienced data analyst with a knack for uncovering hidden trends.',
)
writer = Agent(
    role='Writer',
    goal='Create engaging content',
    backstory='Creative writer passionate about storytelling in technical domains.',
)

# Establishing the crew with a hierarchical process and additional configurations
project_crew = Crew(
    tasks=[...],  # Tasks to be delegated and executed under the manager's supervision
    agents=[researcher, writer],
    manager_llm="gpt-4o",  # Specify which LLM the manager should use
    process=Process.hierarchical,  
    planning=True, 
)
```

### Using a Custom Manager Agent

Alternatively, you can create a custom manager agent with specific attributes tailored to your project's management needs. This gives you more control over the manager's behavior and capabilities.

```python theme={null}
# Define a custom manager agent
manager = Agent(
    role="Project Manager",
    goal="Efficiently manage the crew and ensure high-quality task completion",
    backstory="You're an experienced project manager, skilled in overseeing complex projects and guiding teams to success.",
    allow_delegation=True,
)

# Use the custom manager in your crew
project_crew = Crew(
    tasks=[...],
    agents=[researcher, writer],
    manager_agent=manager,  # Use your custom manager agent
    process=Process.hierarchical,
    planning=True,
)
```

<Tip>
  For more details on creating and customizing a manager agent, check out the [Custom Manager Agent documentation](/en/learn/custom-manager-agent).
</Tip>

### Workflow in Action

1. **Task Assignment**: The manager assigns tasks strategically, considering each agent's capabilities and available tools.
2. **Execution and Review**: Agents complete their tasks with the option for asynchronous execution and callback functions for streamlined workflows.
3. **Sequential Task Progression**: Despite being a hierarchical process, tasks follow a logical order for smooth progression, facilitated by the manager's oversight.

## Conclusion

Adopting the hierarchical process in CrewAI, with the correct configurations and understanding of the system's capabilities, facilitates an organized and efficient approach to project management.
Utilize the advanced features and customizations to tailor the workflow to your specific needs, ensuring optimal task execution and project success.


# Human Feedback in Flows
Source: https://docs.crewai.com/en/learn/human-feedback-in-flows

Learn how to integrate human feedback directly into your CrewAI Flows using the @human_feedback decorator

## Overview

<Note>
  The `@human_feedback` decorator requires **CrewAI version 1.8.0 or higher**. Make sure to update your installation before using this feature.
</Note>

The `@human_feedback` decorator enables human-in-the-loop (HITL) workflows directly within CrewAI Flows. It allows you to pause flow execution, present output to a human for review, collect their feedback, and optionally route to different listeners based on the feedback outcome.

This is particularly valuable for:

* **Quality assurance**: Review AI-generated content before it's used downstream
* **Decision gates**: Let humans make critical decisions in automated workflows
* **Approval workflows**: Implement approve/reject/revise patterns
* **Interactive refinement**: Collect feedback to improve outputs iteratively

```mermaid theme={null}
flowchart LR
    A[Flow Method] --> B[Output Generated]
    B --> C[Human Reviews]
    C --> D{Feedback}
    D -->|emit specified| E[LLM Collapses to Outcome]
    D -->|no emit| F[HumanFeedbackResult]
    E --> G["@listen('approved')"]
    E --> H["@listen('rejected')"]
    F --> I[Next Listener]
```

## Quick Start

Here's the simplest way to add human feedback to a flow:

```python Code theme={null}
from crewai.flow.flow import Flow, start, listen
from crewai.flow.human_feedback import human_feedback

class SimpleReviewFlow(Flow):
    @start()
    @human_feedback(message="Please review this content:")
    def generate_content(self):
        return "This is AI-generated content that needs review."

    @listen(generate_content)
    def process_feedback(self, result):
        print(f"Content: {result.output}")
        print(f"Human said: {result.feedback}")

flow = SimpleReviewFlow()
flow.kickoff()
```

When this flow runs, it will:

1. Execute `generate_content` and return the string
2. Display the output to the user with the request message
3. Wait for the user to type feedback (or press Enter to skip)
4. Pass a `HumanFeedbackResult` object to `process_feedback`

## The @human\_feedback Decorator

### Parameters

| Parameter         | Type                    | Required              | Description                                                                                                                                              |
| ----------------- | ----------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `message`         | `str`                   | Yes                   | The message shown to the human alongside the method output                                                                                               |
| `emit`            | `Sequence[str]`         | No                    | List of possible outcomes. Feedback is collapsed to one of these, which triggers `@listen` decorators                                                    |
| `llm`             | `str \| BaseLLM`        | When `emit` specified | LLM used to interpret feedback and map to an outcome                                                                                                     |
| `default_outcome` | `str`                   | No                    | Outcome to use if no feedback provided. Must be in `emit`                                                                                                |
| `metadata`        | `dict`                  | No                    | Additional data for enterprise integrations                                                                                                              |
| `provider`        | `HumanFeedbackProvider` | No                    | Custom provider for async/non-blocking feedback. See [Async Human Feedback](#async-human-feedback-non-blocking)                                          |
| `learn`           | `bool`                  | No                    | Enable HITL learning: distill lessons from feedback and pre-review future output. Default `False`. See [Learning from Feedback](#learning-from-feedback) |
| `learn_limit`     | `int`                   | No                    | Max past lessons to recall for pre-review. Default `5`                                                                                                   |

### Basic Usage (No Routing)

When you don't specify `emit`, the decorator simply collects feedback and passes a `HumanFeedbackResult` to the next listener:

```python Code theme={null}
@start()
@human_feedback(message="What do you think of this analysis?")
def analyze_data(self):
    return "Analysis results: Revenue up 15%, costs down 8%"

@listen(analyze_data)
def handle_feedback(self, result):
    # result is a HumanFeedbackResult
    print(f"Analysis: {result.output}")
    print(f"Feedback: {result.feedback}")
```

### Routing with emit

When you specify `emit`, the decorator becomes a router. The human's free-form feedback is interpreted by an LLM and collapsed into one of the specified outcomes:

```python Code theme={null}
from crewai.flow.flow import Flow, start, listen, or_
from crewai.flow.human_feedback import human_feedback

class ReviewFlow(Flow):
    @start()
    def generate_content(self):
        return "Draft blog post content here..."

    @human_feedback(
        message="Do you approve this content for publication?",
        emit=["approved", "rejected", "needs_revision"],
        llm="gpt-4o-mini",
        default_outcome="needs_revision",
    )
    @listen(or_("generate_content", "needs_revision"))
    def review_content(self):
        return "Draft blog post content here..."

    @listen("approved")
    def publish(self, result):
        print(f"Publishing! User said: {result.feedback}")

    @listen("rejected")
    def discard(self, result):
        print(f"Discarding. Reason: {result.feedback}")
```

When the human says something like "needs more detail", the LLM collapses that to `"needs_revision"`, which triggers `review_content` again via `or_()` — creating a revision loop. The loop continues until the outcome is `"approved"` or `"rejected"`.

<Tip>
  The LLM uses structured outputs (function calling) when available to guarantee the response is one of your specified outcomes. This makes routing reliable and predictable.
</Tip>

<Warning>
  A `@start()` method only runs once at the beginning of the flow. If you need a revision loop, separate the start method from the review method and use `@listen(or_("trigger", "revision_outcome"))` on the review method to enable the self-loop.
</Warning>

## HumanFeedbackResult

The `HumanFeedbackResult` dataclass contains all information about a human feedback interaction:

```python Code theme={null}
from crewai.flow.human_feedback import HumanFeedbackResult

@dataclass
class HumanFeedbackResult:
    output: Any              # The original method output shown to the human
    feedback: str            # The raw feedback text from the human
    outcome: str | None      # The collapsed outcome (if emit was specified)
    timestamp: datetime      # When the feedback was received
    method_name: str         # Name of the decorated method
    metadata: dict           # Any metadata passed to the decorator
```

### Accessing in Listeners

When a listener is triggered by a `@human_feedback` method with `emit`, it receives the `HumanFeedbackResult`:

```python Code theme={null}
@listen("approved")
def on_approval(self, result: HumanFeedbackResult):
    print(f"Original output: {result.output}")
    print(f"User feedback: {result.feedback}")
    print(f"Outcome: {result.outcome}")  # "approved"
    print(f"Received at: {result.timestamp}")
```

## Accessing Feedback History

The `Flow` class provides two attributes for accessing human feedback:

### last\_human\_feedback

Returns the most recent `HumanFeedbackResult`:

```python Code theme={null}
@listen(some_method)
def check_feedback(self):
    if self.last_human_feedback:
        print(f"Last feedback: {self.last_human_feedback.feedback}")
```

### human\_feedback\_history

A list of all `HumanFeedbackResult` objects collected during the flow:

```python Code theme={null}
@listen(final_step)
def summarize(self):
    print(f"Total feedback collected: {len(self.human_feedback_history)}")
    for i, fb in enumerate(self.human_feedback_history):
        print(f"{i+1}. {fb.method_name}: {fb.outcome or 'no routing'}")
```

<Warning>
  Each `HumanFeedbackResult` is appended to `human_feedback_history`, so multiple feedback steps won't overwrite each other. Use this list to access all feedback collected during the flow.
</Warning>

## Complete Example: Content Approval Workflow

Here's a full example implementing a content review and approval workflow with a revision loop:

<CodeGroup>
  ```python Code theme={null}
  from crewai.flow.flow import Flow, start, listen, or_
  from crewai.flow.human_feedback import human_feedback, HumanFeedbackResult
  from pydantic import BaseModel


  class ContentState(BaseModel):
      draft: str = ""
      revision_count: int = 0
      status: str = "pending"


  class ContentApprovalFlow(Flow[ContentState]):
      """A flow that generates content and loops until the human approves."""

      @start()
      def generate_draft(self):
          self.state.draft = "# AI Safety\n\nThis is a draft about AI Safety..."
          return self.state.draft

      @human_feedback(
          message="Please review this draft. Approve, reject, or describe what needs changing:",
          emit=["approved", "rejected", "needs_revision"],
          llm="gpt-4o-mini",
          default_outcome="needs_revision",
      )
      @listen(or_("generate_draft", "needs_revision"))
      def review_draft(self):
          self.state.revision_count += 1
          return f"{self.state.draft} (v{self.state.revision_count})"

      @listen("approved")
      def publish_content(self, result: HumanFeedbackResult):
          self.state.status = "published"
          print(f"Content approved and published! Reviewer said: {result.feedback}")
          return "published"

      @listen("rejected")
      def handle_rejection(self, result: HumanFeedbackResult):
          self.state.status = "rejected"
          print(f"Content rejected. Reason: {result.feedback}")
          return "rejected"


  flow = ContentApprovalFlow()
  result = flow.kickoff()
  print(f"\nFlow completed. Status: {flow.state.status}, Reviews: {flow.state.revision_count}")
  ```

  ```text Output theme={null}
  ==================================================
  OUTPUT FOR REVIEW:
  ==================================================
  # AI Safety

  This is a draft about AI Safety... (v1)
  ==================================================

  Please review this draft. Approve, reject, or describe what needs changing:
  (Press Enter to skip, or type your feedback)

  Your feedback: Needs more detail on alignment research

  ==================================================
  OUTPUT FOR REVIEW:
  ==================================================
  # AI Safety

  This is a draft about AI Safety... (v2)
  ==================================================

  Please review this draft. Approve, reject, or describe what needs changing:
  (Press Enter to skip, or type your feedback)

  Your feedback: Looks good, approved!

  Content approved and published! Reviewer said: Looks good, approved!

  Flow completed. Status: published, Reviews: 2
  ```
</CodeGroup>

The key pattern is `@listen(or_("generate_draft", "needs_revision"))` — the review method listens to both the initial trigger and its own revision outcome, creating a self-loop that repeats until the human approves or rejects.

## Combining with Other Decorators

The `@human_feedback` decorator works with `@start()`, `@listen()`, and `or_()`. Both decorator orderings work — the framework propagates attributes in both directions — but the recommended patterns are:

```python Code theme={null}
# One-shot review at the start of a flow (no self-loop)
@start()
@human_feedback(message="Review this:", emit=["approved", "rejected"], llm="gpt-4o-mini")
def my_start_method(self):
    return "content"

# Linear review on a listener (no self-loop)
@listen(other_method)
@human_feedback(message="Review this too:", emit=["good", "bad"], llm="gpt-4o-mini")
def my_listener(self, data):
    return f"processed: {data}"

# Self-loop: review that can loop back for revisions
@human_feedback(message="Approve or revise?", emit=["approved", "revise"], llm="gpt-4o-mini")
@listen(or_("upstream_method", "revise"))
def review_with_loop(self):
    return "content for review"
```

### Self-loop pattern

To create a revision loop, the review method must listen to **both** an upstream trigger and its own revision outcome using `or_()`:

```python Code theme={null}
@start()
def generate(self):
    return "initial draft"

@human_feedback(
    message="Approve or request changes?",
    emit=["revise", "approved"],
    llm="gpt-4o-mini",
    default_outcome="approved",
)
@listen(or_("generate", "revise"))
def review(self):
    return "content"

@listen("approved")
def publish(self):
    return "published"
```

When the outcome is `"revise"`, the flow routes back to `review` (because it listens to `"revise"` via `or_()`). When the outcome is `"approved"`, the flow continues to `publish`. This works because the flow engine exempts routers from the "fire once" rule, allowing them to re-execute on each loop iteration.

### Chained routers

A listener triggered by one router's outcome can itself be a router:

```python Code theme={null}
@start()
def generate(self):
    return "draft content"

@human_feedback(message="First review:", emit=["approved", "rejected"], llm="gpt-4o-mini")
@listen("generate")
def first_review(self):
    return "draft content"

@human_feedback(message="Final review:", emit=["publish", "hold"], llm="gpt-4o-mini")
@listen("approved")
def final_review(self, prev):
    return "final content"

@listen("publish")
def on_publish(self, prev):
    return "published"

@listen("hold")
def on_hold(self, prev):
    return "held for later"
```

### Limitations

* **`@start()` methods run once**: A `@start()` method cannot self-loop. If you need a revision cycle, use a separate `@start()` method as the entry point and put the `@human_feedback` on a `@listen()` method.
* **No `@start()` + `@listen()` on the same method**: This is a Flow framework constraint. A method is either a start point or a listener, not both.

## Best Practices

### 1. Write Clear Request Messages

The `message` parameter is what the human sees. Make it actionable:

```python Code theme={null}
# ✅ Good - clear and actionable
@human_feedback(message="Does this summary accurately capture the key points? Reply 'yes' or explain what's missing:")

# ❌ Bad - vague
@human_feedback(message="Review this:")
```

### 2. Choose Meaningful Outcomes

When using `emit`, pick outcomes that map naturally to human responses:

```python Code theme={null}
# ✅ Good - natural language outcomes
emit=["approved", "rejected", "needs_more_detail"]

# ❌ Bad - technical or unclear
emit=["state_1", "state_2", "state_3"]
```

### 3. Always Provide a Default Outcome

Use `default_outcome` to handle cases where users press Enter without typing:

```python Code theme={null}
@human_feedback(
    message="Approve? (press Enter to request revision)",
    emit=["approved", "needs_revision"],
    llm="gpt-4o-mini",
    default_outcome="needs_revision",  # Safe default
)
```

### 4. Use Feedback History for Audit Trails

Access `human_feedback_history` to create audit logs:

```python Code theme={null}
@listen(final_step)
def create_audit_log(self):
    log = []
    for fb in self.human_feedback_history:
        log.append({
            "step": fb.method_name,
            "outcome": fb.outcome,
            "feedback": fb.feedback,
            "timestamp": fb.timestamp.isoformat(),
        })
    return log
```

### 5. Handle Both Routed and Non-Routed Feedback

When designing flows, consider whether you need routing:

| Scenario                                            | Use        |
| --------------------------------------------------- | ---------- |
| Simple review, just need the feedback text          | No `emit`  |
| Need to branch to different paths based on response | Use `emit` |
| Approval gates with approve/reject/revise           | Use `emit` |
| Collecting comments for logging only                | No `emit`  |

## Async Human Feedback (Non-Blocking)

By default, `@human_feedback` blocks execution waiting for console input. For production applications, you may need **async/non-blocking** feedback that integrates with external systems like Slack, email, webhooks, or APIs.

### The Provider Abstraction

Use the `provider` parameter to specify a custom feedback collection strategy:

```python Code theme={null}
from crewai.flow import Flow, start, human_feedback, HumanFeedbackProvider, HumanFeedbackPending, PendingFeedbackContext

class WebhookProvider(HumanFeedbackProvider):
    """Provider that pauses flow and waits for webhook callback."""

    def __init__(self, webhook_url: str):
        self.webhook_url = webhook_url

    def request_feedback(self, context: PendingFeedbackContext, flow: Flow) -> str:
        # Notify external system (e.g., send Slack message, create ticket)
        self.send_notification(context)

        # Pause execution - framework handles persistence automatically
        raise HumanFeedbackPending(
            context=context,
            callback_info={"webhook_url": f"{self.webhook_url}/{context.flow_id}"}
        )

class ReviewFlow(Flow):
    @start()
    @human_feedback(
        message="Review this content:",
        emit=["approved", "rejected"],
        llm="gpt-4o-mini",
        provider=WebhookProvider("https://myapp.com/api"),
    )
    def generate_content(self):
        return "AI-generated content..."

    @listen("approved")
    def publish(self, result):
        return "Published!"
```

<Tip>
  The flow framework **automatically persists state** when `HumanFeedbackPending` is raised. Your provider only needs to notify the external system and raise the exception—no manual persistence calls required.
</Tip>

### Handling Paused Flows

When using an async provider, `kickoff()` returns a `HumanFeedbackPending` object instead of raising an exception:

```python Code theme={null}
flow = ReviewFlow()
result = flow.kickoff()

if isinstance(result, HumanFeedbackPending):
    # Flow is paused, state is automatically persisted
    print(f"Waiting for feedback at: {result.callback_info['webhook_url']}")
    print(f"Flow ID: {result.context.flow_id}")
else:
    # Normal completion
    print(f"Flow completed: {result}")
```

### Resuming a Paused Flow

When feedback arrives (e.g., via webhook), resume the flow:

```python Code theme={null}
# Sync handler:
def handle_feedback_webhook(flow_id: str, feedback: str):
    flow = ReviewFlow.from_pending(flow_id)
    result = flow.resume(feedback)
    return result

# Async handler (FastAPI, aiohttp, etc.):
async def handle_feedback_webhook(flow_id: str, feedback: str):
    flow = ReviewFlow.from_pending(flow_id)
    result = await flow.resume_async(feedback)
    return result
```

### Key Types

| Type                     | Description                                              |
| ------------------------ | -------------------------------------------------------- |
| `HumanFeedbackProvider`  | Protocol for custom feedback providers                   |
| `PendingFeedbackContext` | Contains all info needed to resume a paused flow         |
| `HumanFeedbackPending`   | Returned by `kickoff()` when flow is paused for feedback |
| `ConsoleProvider`        | Default blocking console input provider                  |

### PendingFeedbackContext

The context contains everything needed to resume:

```python Code theme={null}
@dataclass
class PendingFeedbackContext:
    flow_id: str           # Unique identifier for this flow execution
    flow_class: str        # Fully qualified class name
    method_name: str       # Method that triggered feedback
    method_output: Any     # Output shown to the human
    message: str           # The request message
    emit: list[str] | None # Possible outcomes for routing
    default_outcome: str | None
    metadata: dict         # Custom metadata
    llm: str | None        # LLM for outcome collapsing
    requested_at: datetime
```

### Complete Async Flow Example

```python Code theme={null}
from crewai.flow import (
    Flow, start, listen, human_feedback,
    HumanFeedbackProvider, HumanFeedbackPending, PendingFeedbackContext
)

class SlackNotificationProvider(HumanFeedbackProvider):
    """Provider that sends Slack notifications and pauses for async feedback."""

    def __init__(self, channel: str):
        self.channel = channel

    def request_feedback(self, context: PendingFeedbackContext, flow: Flow) -> str:
        # Send Slack notification (implement your own)
        slack_thread_id = self.post_to_slack(
            channel=self.channel,
            message=f"Review needed:\n\n{context.method_output}\n\n{context.message}",
        )

        # Pause execution - framework handles persistence automatically
        raise HumanFeedbackPending(
            context=context,
            callback_info={
                "slack_channel": self.channel,
                "thread_id": slack_thread_id,
            }
        )

class ContentPipeline(Flow):
    @start()
    @human_feedback(
        message="Approve this content for publication?",
        emit=["approved", "rejected"],
        llm="gpt-4o-mini",
        default_outcome="rejected",
        provider=SlackNotificationProvider("#content-reviews"),
    )
    def generate_content(self):
        return "AI-generated blog post content..."

    @listen("approved")
    def publish(self, result):
        print(f"Publishing! Reviewer said: {result.feedback}")
        return {"status": "published"}

    @listen("rejected")
    def archive(self, result):
        print(f"Archived. Reason: {result.feedback}")
        return {"status": "archived"}


# Starting the flow (will pause and wait for Slack response)
def start_content_pipeline():
    flow = ContentPipeline()
    result = flow.kickoff()

    if isinstance(result, HumanFeedbackPending):
        return {"status": "pending", "flow_id": result.context.flow_id}

    return result


# Resuming when Slack webhook fires (sync handler)
def on_slack_feedback(flow_id: str, slack_message: str):
    flow = ContentPipeline.from_pending(flow_id)
    result = flow.resume(slack_message)
    return result


# If your handler is async (FastAPI, aiohttp, Slack Bolt async, etc.)
async def on_slack_feedback_async(flow_id: str, slack_message: str):
    flow = ContentPipeline.from_pending(flow_id)
    result = await flow.resume_async(slack_message)
    return result
```

<Warning>
  If you're using an async web framework (FastAPI, aiohttp, Slack Bolt async mode), use `await flow.resume_async()` instead of `flow.resume()`. Calling `resume()` from within a running event loop will raise a `RuntimeError`.
</Warning>

### Best Practices for Async Feedback

1. **Check the return type**: `kickoff()` returns `HumanFeedbackPending` when paused—no try/except needed
2. **Use the right resume method**: Use `resume()` in sync code, `await resume_async()` in async code
3. **Store callback info**: Use `callback_info` to store webhook URLs, ticket IDs, etc.
4. **Implement idempotency**: Your resume handler should be idempotent for safety
5. **Automatic persistence**: State is automatically saved when `HumanFeedbackPending` is raised and uses `SQLiteFlowPersistence` by default
6. **Custom persistence**: Pass a custom persistence instance to `from_pending()` if needed

## Learning from Feedback

The `learn=True` parameter enables a feedback loop between human reviewers and the memory system. When enabled, the system progressively improves its outputs by learning from past human corrections.

### How It Works

1. **After feedback**: The LLM extracts generalizable lessons from the output + feedback and stores them in memory with `source="hitl"`. If the feedback is just approval (e.g. "looks good"), nothing is stored.
2. **Before next review**: Past HITL lessons are recalled from memory and applied by the LLM to improve the output before the human sees it.

Over time, the human sees progressively better pre-reviewed output because each correction informs future reviews.

### Example

```python Code theme={null}
class ArticleReviewFlow(Flow):
    @start()
    def generate_article(self):
        return self.crew.kickoff(inputs={"topic": "AI Safety"}).raw

    @human_feedback(
        message="Review this article draft:",
        emit=["approved", "needs_revision"],
        llm="gpt-4o-mini",
        learn=True,  # enable HITL learning
    )
    @listen(or_("generate_article", "needs_revision"))
    def review_article(self):
        return self.last_human_feedback.output if self.last_human_feedback else "article draft"

    @listen("approved")
    def publish(self):
        print(f"Publishing: {self.last_human_feedback.output}")
```

**First run**: The human sees the raw output and says "Always include citations for factual claims." The lesson is distilled and stored in memory.

**Second run**: The system recalls the citation lesson, pre-reviews the output to add citations, then shows the improved version. The human's job shifts from "fix everything" to "catch what the system missed."

### Configuration

| Parameter     | Default | Description                               |
| ------------- | ------- | ----------------------------------------- |
| `learn`       | `False` | Enable HITL learning                      |
| `learn_limit` | `5`     | Max past lessons to recall for pre-review |

### Key Design Decisions

* **Same LLM for everything**: The `llm` parameter on the decorator is shared by outcome collapsing, lesson distillation, and pre-review. No need to configure multiple models.
* **Structured output**: Both distillation and pre-review use function calling with Pydantic models when the LLM supports it, falling back to text parsing otherwise.
* **Non-blocking storage**: Lessons are stored via `remember_many()` which runs in a background thread -- the flow continues immediately.
* **Graceful degradation**: If the LLM fails during distillation, nothing is stored. If it fails during pre-review, the raw output is shown. Neither failure blocks the flow.
* **No scope/categories needed**: When storing lessons, only `source` is passed. The encoding pipeline infers scope, categories, and importance automatically.

<Note>
  `learn=True` requires the Flow to have memory available. Flows get memory automatically by default, but if you've disabled it with `_skip_auto_memory`, HITL learning will be silently skipped.
</Note>

## Related Documentation

* [Flows Overview](/en/concepts/flows) - Learn about CrewAI Flows
* [Flow State Management](/en/guides/flows/mastering-flow-state) - Managing state in flows
* [Flow Persistence](/en/concepts/flows#persistence) - Persisting flow state
* [Routing with @router](/en/concepts/flows#router) - More about conditional routing
* [Human Input on Execution](/en/learn/human-input-on-execution) - Task-level human input
* [Memory](/en/concepts/memory) - The unified memory system used by HITL learning


# Human-in-the-Loop (HITL) Workflows
Source: https://docs.crewai.com/en/learn/human-in-the-loop

Learn how to implement Human-in-the-Loop workflows in CrewAI for enhanced decision-making

Human-in-the-Loop (HITL) is a powerful approach that combines artificial intelligence with human expertise to enhance decision-making and improve task outcomes. CrewAI provides multiple ways to implement HITL depending on your needs.

## Choosing Your HITL Approach

CrewAI offers two main approaches for implementing human-in-the-loop workflows:

| Approach                                     | Best For                                                                            | Integration                                                  | Version    |
| -------------------------------------------- | ----------------------------------------------------------------------------------- | ------------------------------------------------------------ | ---------- |
| **Flow-based** (`@human_feedback` decorator) | Local development, console-based review, synchronous workflows                      | [Human Feedback in Flows](/en/learn/human-feedback-in-flows) | **1.8.0+** |
| **Webhook-based** (Enterprise)               | Production deployments, async workflows, external integrations (Slack, Teams, etc.) | This guide                                                   | -          |

<Tip>
  If you're building flows and want to add human review steps with routing based on feedback, check out the [Human Feedback in Flows](/en/learn/human-feedback-in-flows) guide for the `@human_feedback` decorator.
</Tip>

## Setting Up Webhook-Based HITL Workflows

<Steps>
  <Step title="Configure Your Task">
    Set up your task with human input enabled:

    <Frame>
      <img alt="Crew Human Input" />
    </Frame>
  </Step>

  <Step title="Provide Webhook URL">
    When kicking off your crew, include a webhook URL for human input:

    <Frame>
      <img alt="Crew Webhook URL" />
    </Frame>

    Example with Bearer authentication:

    ```bash theme={null}
    curl -X POST {BASE_URL}/kickoff \
      -H "Authorization: Bearer YOUR_API_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "inputs": {
          "topic": "AI Research"
        },
        "humanInputWebhook": {
          "url": "https://your-webhook.com/hitl",
          "authentication": {
            "strategy": "bearer",
            "token": "your-webhook-secret-token"
          }
        }
      }'
    ```

    Or with Basic authentication:

    ```bash theme={null}
    curl -X POST {BASE_URL}/kickoff \
      -H "Authorization: Bearer YOUR_API_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "inputs": {
          "topic": "AI Research"
        },
        "humanInputWebhook": {
          "url": "https://your-webhook.com/hitl",
          "authentication": {
            "strategy": "basic",
            "username": "your-username",
            "password": "your-password"
          }
        }
      }'
    ```
  </Step>

  <Step title="Receive Webhook Notification">
    Once the crew completes the task requiring human input, you'll receive a webhook notification containing:

    * Execution ID
    * Task ID
    * Task output
  </Step>

  <Step title="Review Task Output">
    The system will pause in the `Pending Human Input` state. Review the task output carefully.
  </Step>

  <Step title="Submit Human Feedback">
    Call the resume endpoint of your crew with the following information:

    <Frame>
      <img alt="Crew Resume Endpoint" />
    </Frame>

    <Warning>
      **Critical: Webhook URLs Must Be Provided Again**:
      You **must** provide the same webhook URLs (`taskWebhookUrl`, `stepWebhookUrl`, `crewWebhookUrl`) in the resume call that you used in the kickoff call. Webhook configurations are **NOT** automatically carried over from kickoff - they must be explicitly included in the resume request to continue receiving notifications for task completion, agent steps, and crew completion.
    </Warning>

    Example resume call with webhooks:

    ```bash theme={null}
    curl -X POST {BASE_URL}/resume \
      -H "Authorization: Bearer YOUR_API_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "execution_id": "abcd1234-5678-90ef-ghij-klmnopqrstuv",
        "task_id": "research_task",
        "human_feedback": "Great work! Please add more details.",
        "is_approve": true,
        "taskWebhookUrl": "https://your-server.com/webhooks/task",
        "stepWebhookUrl": "https://your-server.com/webhooks/step",
        "crewWebhookUrl": "https://your-server.com/webhooks/crew"
      }'
    ```

    <Warning>
      **Feedback Impact on Task Execution**:
      It's crucial to exercise care when providing feedback, as the entire feedback content will be incorporated as additional context for further task executions.
    </Warning>

    This means:

    * All information in your feedback becomes part of the task's context.
    * Irrelevant details may negatively influence it.
    * Concise, relevant feedback helps maintain task focus and efficiency.
    * Always review your feedback carefully before submission to ensure it contains only pertinent information that will positively guide the task's execution.
  </Step>

  <Step title="Handle Negative Feedback">
    If you provide negative feedback:

    * The crew will retry the task with added context from your feedback.
    * You'll receive another webhook notification for further review.
    * Repeat steps 4-6 until satisfied.
  </Step>

  <Step title="Execution Continuation">
    When you submit positive feedback, the execution will proceed to the next steps.
  </Step>
</Steps>

## Best Practices

* **Be Specific**: Provide clear, actionable feedback that directly addresses the task at hand
* **Stay Relevant**: Only include information that will help improve the task execution
* **Be Timely**: Respond to HITL prompts promptly to avoid workflow delays
* **Review Carefully**: Double-check your feedback before submitting to ensure accuracy

## Common Use Cases

HITL workflows are particularly valuable for:

* Quality assurance and validation
* Complex decision-making scenarios
* Sensitive or high-stakes operations
* Creative tasks requiring human judgment
* Compliance and regulatory reviews

## Enterprise Features

<Card title="Flow HITL Management Platform" icon="users-gear" href="/en/enterprise/features/flow-hitl-management">
  CrewAI Enterprise provides a comprehensive HITL management system for Flows with in-platform review, responder assignment, permissions, escalation policies, SLA management, dynamic routing, and full analytics. [Learn more →](/en/enterprise/features/flow-hitl-management)
</Card>


# Human Input on Execution
Source: https://docs.crewai.com/en/learn/human-input-on-execution

Integrating CrewAI with human input during execution in complex decision-making processes and leveraging the full capabilities of the agent's attributes and tools.

## Human input in agent execution

Human input is critical in several agent execution scenarios, allowing agents to request additional information or clarification when necessary.
This feature is especially useful in complex decision-making processes or when agents require more details to complete a task effectively.

## Using human input with CrewAI

To integrate human input into agent execution, set the `human_input` flag in the task definition. When enabled, the agent prompts the user for input before delivering its final answer.
This input can provide extra context, clarify ambiguities, or validate the agent's output.

### Example:

```shell theme={null}
pip install crewai
```

```python Code theme={null}
import os
from crewai import Agent, Task, Crew
from crewai_tools import SerperDevTool

os.environ["SERPER_API_KEY"] = "Your Key"  # serper.dev API key
os.environ["OPENAI_API_KEY"] = "Your Key"

# Loading Tools
search_tool = SerperDevTool()

# Define your agents with roles, goals, tools, and additional attributes
researcher = Agent(
    role='Senior Research Analyst',
    goal='Uncover cutting-edge developments in AI and data science',
    backstory=(
        "You are a Senior Research Analyst at a leading tech think tank. "
        "Your expertise lies in identifying emerging trends and technologies in AI and data science. "
        "You have a knack for dissecting complex data and presenting actionable insights."
    ),
    verbose=True,
    allow_delegation=False,
    tools=[search_tool]
)
writer = Agent(
    role='Tech Content Strategist',
    goal='Craft compelling content on tech advancements',
    backstory=(
        "You are a renowned Tech Content Strategist, known for your insightful and engaging articles on technology and innovation. "
        "With a deep understanding of the tech industry, you transform complex concepts into compelling narratives."
    ),
    verbose=True,
    allow_delegation=True,
    tools=[search_tool],
    cache=False,  # Disable cache for this agent
)

# Create tasks for your agents
task1 = Task(
    description=(
        "Conduct a comprehensive analysis of the latest advancements in AI in 2025. "
        "Identify key trends, breakthrough technologies, and potential industry impacts. "
        "Compile your findings in a detailed report. "
        "Make sure to check with a human if the draft is good before finalizing your answer."
    ),
    expected_output='A comprehensive full report on the latest AI advancements in 2025, leave nothing out',
    agent=researcher,
    human_input=True
)

task2 = Task(
    description=(
        "Using the insights from the researcher\'s report, develop an engaging blog post that highlights the most significant AI advancements. "
        "Your post should be informative yet accessible, catering to a tech-savvy audience. "
        "Aim for a narrative that captures the essence of these breakthroughs and their implications for the future."
    ),
    expected_output='A compelling 3 paragraphs blog post formatted as markdown about the latest AI advancements in 2025',
    agent=writer,
    human_input=True
)

# Instantiate your crew with a sequential process
crew = Crew(
    agents=[researcher, writer],
    tasks=[task1, task2],
    verbose=True,
    memory=True,
    planning=True  # Enable planning feature for the crew
)

# Get your crew to work!
result = crew.kickoff()

print("######################")
print(result)
```


# Kickoff Crew Asynchronously
Source: https://docs.crewai.com/en/learn/kickoff-async

Kickoff a Crew Asynchronously

## Introduction

CrewAI provides the ability to kickoff a crew asynchronously, allowing you to start the crew execution in a non-blocking manner.
This feature is particularly useful when you want to run multiple crews concurrently or when you need to perform other tasks while the crew is executing.

CrewAI offers two approaches for async execution:

| Method            | Type         | Description                                            |
| ----------------- | ------------ | ------------------------------------------------------ |
| `akickoff()`      | Native async | True async/await throughout the entire execution chain |
| `kickoff_async()` | Thread-based | Wraps synchronous execution in `asyncio.to_thread`     |

<Note>
  For high-concurrency workloads, `akickoff()` is recommended as it uses native async for task execution, memory operations, and knowledge retrieval.
</Note>

## Native Async Execution with `akickoff()`

The `akickoff()` method provides true native async execution, using async/await throughout the entire execution chain including task execution, memory operations, and knowledge queries.

### Method Signature

```python Code theme={null}
async def akickoff(self, inputs: dict) -> CrewOutput:
```

### Parameters

* `inputs` (dict): A dictionary containing the input data required for the tasks.

### Returns

* `CrewOutput`: An object representing the result of the crew execution.

### Example: Native Async Crew Execution

```python Code theme={null}
import asyncio
from crewai import Crew, Agent, Task

# Create an agent
coding_agent = Agent(
    role="Python Data Analyst",
    goal="Analyze data and provide insights using Python",
    backstory="You are an experienced data analyst with strong Python skills.",
    allow_code_execution=True
)

# Create a task
data_analysis_task = Task(
    description="Analyze the given dataset and calculate the average age of participants. Ages: {ages}",
    agent=coding_agent,
    expected_output="The average age of the participants."
)

# Create a crew
analysis_crew = Crew(
    agents=[coding_agent],
    tasks=[data_analysis_task]
)

# Native async execution
async def main():
    result = await analysis_crew.akickoff(inputs={"ages": [25, 30, 35, 40, 45]})
    print("Crew Result:", result)

asyncio.run(main())
```

### Example: Multiple Native Async Crews

Run multiple crews concurrently using `asyncio.gather()` with native async:

```python Code theme={null}
import asyncio
from crewai import Crew, Agent, Task

coding_agent = Agent(
    role="Python Data Analyst",
    goal="Analyze data and provide insights using Python",
    backstory="You are an experienced data analyst with strong Python skills.",
    allow_code_execution=True
)

task_1 = Task(
    description="Analyze the first dataset and calculate the average age. Ages: {ages}",
    agent=coding_agent,
    expected_output="The average age of the participants."
)

task_2 = Task(
    description="Analyze the second dataset and calculate the average age. Ages: {ages}",
    agent=coding_agent,
    expected_output="The average age of the participants."
)

crew_1 = Crew(agents=[coding_agent], tasks=[task_1])
crew_2 = Crew(agents=[coding_agent], tasks=[task_2])

async def main():
    results = await asyncio.gather(
        crew_1.akickoff(inputs={"ages": [25, 30, 35, 40, 45]}),
        crew_2.akickoff(inputs={"ages": [20, 22, 24, 28, 30]})
    )

    for i, result in enumerate(results, 1):
        print(f"Crew {i} Result:", result)

asyncio.run(main())
```

### Example: Native Async for Multiple Inputs

Use `akickoff_for_each()` to execute your crew against multiple inputs concurrently with native async:

```python Code theme={null}
import asyncio
from crewai import Crew, Agent, Task

coding_agent = Agent(
    role="Python Data Analyst",
    goal="Analyze data and provide insights using Python",
    backstory="You are an experienced data analyst with strong Python skills.",
    allow_code_execution=True
)

data_analysis_task = Task(
    description="Analyze the dataset and calculate the average age. Ages: {ages}",
    agent=coding_agent,
    expected_output="The average age of the participants."
)

analysis_crew = Crew(
    agents=[coding_agent],
    tasks=[data_analysis_task]
)

async def main():
    datasets = [
        {"ages": [25, 30, 35, 40, 45]},
        {"ages": [20, 22, 24, 28, 30]},
        {"ages": [30, 35, 40, 45, 50]}
    ]

    results = await analysis_crew.akickoff_for_each(datasets)

    for i, result in enumerate(results, 1):
        print(f"Dataset {i} Result:", result)

asyncio.run(main())
```

## Thread-Based Async with `kickoff_async()`

The `kickoff_async()` method provides async execution by wrapping the synchronous `kickoff()` in a thread. This is useful for simpler async integration or backward compatibility.

### Method Signature

```python Code theme={null}
async def kickoff_async(self, inputs: dict) -> CrewOutput:
```

### Parameters

* `inputs` (dict): A dictionary containing the input data required for the tasks.

### Returns

* `CrewOutput`: An object representing the result of the crew execution.

### Example: Thread-Based Async Execution

```python Code theme={null}
import asyncio
from crewai import Crew, Agent, Task

coding_agent = Agent(
    role="Python Data Analyst",
    goal="Analyze data and provide insights using Python",
    backstory="You are an experienced data analyst with strong Python skills.",
    allow_code_execution=True
)

data_analysis_task = Task(
    description="Analyze the given dataset and calculate the average age of participants. Ages: {ages}",
    agent=coding_agent,
    expected_output="The average age of the participants."
)

analysis_crew = Crew(
    agents=[coding_agent],
    tasks=[data_analysis_task]
)

async def async_crew_execution():
    result = await analysis_crew.kickoff_async(inputs={"ages": [25, 30, 35, 40, 45]})
    print("Crew Result:", result)

asyncio.run(async_crew_execution())
```

### Example: Multiple Thread-Based Async Crews

```python Code theme={null}
import asyncio
from crewai import Crew, Agent, Task

coding_agent = Agent(
    role="Python Data Analyst",
    goal="Analyze data and provide insights using Python",
    backstory="You are an experienced data analyst with strong Python skills.",
    allow_code_execution=True
)

task_1 = Task(
    description="Analyze the first dataset and calculate the average age of participants. Ages: {ages}",
    agent=coding_agent,
    expected_output="The average age of the participants."
)

task_2 = Task(
    description="Analyze the second dataset and calculate the average age of participants. Ages: {ages}",
    agent=coding_agent,
    expected_output="The average age of the participants."
)

crew_1 = Crew(agents=[coding_agent], tasks=[task_1])
crew_2 = Crew(agents=[coding_agent], tasks=[task_2])

async def async_multiple_crews():
    result_1 = crew_1.kickoff_async(inputs={"ages": [25, 30, 35, 40, 45]})
    result_2 = crew_2.kickoff_async(inputs={"ages": [20, 22, 24, 28, 30]})

    results = await asyncio.gather(result_1, result_2)

    for i, result in enumerate(results, 1):
        print(f"Crew {i} Result:", result)

asyncio.run(async_multiple_crews())
```

## Async Streaming

Both async methods support streaming when `stream=True` is set on the crew:

```python Code theme={null}
import asyncio
from crewai import Crew, Agent, Task

agent = Agent(
    role="Researcher",
    goal="Research and summarize topics",
    backstory="You are an expert researcher."
)

task = Task(
    description="Research the topic: {topic}",
    agent=agent,
    expected_output="A comprehensive summary of the topic."
)

crew = Crew(
    agents=[agent],
    tasks=[task],
    stream=True  # Enable streaming
)

async def main():
    streaming_output = await crew.akickoff(inputs={"topic": "AI trends in 2024"})

    # Async iteration over streaming chunks
    async for chunk in streaming_output:
        print(f"Chunk: {chunk.content}")

    # Access final result after streaming completes
    result = streaming_output.result
    print(f"Final result: {result.raw}")

asyncio.run(main())
```

## Potential Use Cases

* **Parallel Content Generation**: Kickoff multiple independent crews asynchronously, each responsible for generating content on different topics. For example, one crew might research and draft an article on AI trends, while another crew generates social media posts about a new product launch.

* **Concurrent Market Research Tasks**: Launch multiple crews asynchronously to conduct market research in parallel. One crew might analyze industry trends, while another examines competitor strategies, and yet another evaluates consumer sentiment.

* **Independent Travel Planning Modules**: Execute separate crews to independently plan different aspects of a trip. One crew might handle flight options, another handles accommodation, and a third plans activities.

## Choosing Between `akickoff()` and `kickoff_async()`

| Feature             | `akickoff()`                          | `kickoff_async()`        |
| ------------------- | ------------------------------------- | ------------------------ |
| Execution model     | Native async/await                    | Thread-based wrapper     |
| Task execution      | Async with `aexecute_sync()`          | Sync in thread pool      |
| Memory operations   | Async                                 | Sync in thread pool      |
| Knowledge retrieval | Async                                 | Sync in thread pool      |
| Best for            | High-concurrency, I/O-bound workloads | Simple async integration |
| Streaming support   | Yes                                   | Yes                      |


# Kickoff Crew for Each
Source: https://docs.crewai.com/en/learn/kickoff-for-each

Kickoff Crew for Each Item in a List

## Introduction

CrewAI provides the ability to kickoff a crew for each item in a list, allowing you to execute the crew for each item in the list.
This feature is particularly useful when you need to perform the same set of tasks for multiple items.

## Kicking Off a Crew for Each Item

To kickoff a crew for each item in a list, use the `kickoff_for_each()` method.
This method executes the crew for each item in the list, allowing you to process multiple items efficiently.

Here's an example of how to kickoff a crew for each item in a list:

```python Code theme={null}
from crewai import Crew, Agent, Task

# Create an agent with code execution enabled
coding_agent = Agent(
    role="Python Data Analyst",
    goal="Analyze data and provide insights using Python",
    backstory="You are an experienced data analyst with strong Python skills.",
    allow_code_execution=True
)

# Create a task that requires code execution
data_analysis_task = Task(
    description="Analyze the given dataset and calculate the average age of participants. Ages: {ages}",
    agent=coding_agent,
    expected_output="The average age calculated from the dataset"
)

# Create a crew and add the task
analysis_crew = Crew(
    agents=[coding_agent],
    tasks=[data_analysis_task],
    verbose=True,
    memory=False
)

datasets = [
  { "ages": [25, 30, 35, 40, 45] },
  { "ages": [20, 25, 30, 35, 40] },
  { "ages": [30, 35, 40, 45, 50] }
]

# Execute the crew
result = analysis_crew.kickoff_for_each(inputs=datasets)
```


# Connect to any LLM
Source: https://docs.crewai.com/en/learn/llm-connections

Comprehensive guide on integrating CrewAI with various Large Language Models (LLMs) using LiteLLM, including supported providers and configuration options.

## Connect CrewAI to LLMs

CrewAI connects to LLMs through native SDK integrations for the most popular providers (OpenAI, Anthropic, Google Gemini, Azure, and AWS Bedrock), and uses LiteLLM as a flexible fallback for all other providers.

<Note>
  By default, CrewAI uses the `gpt-4o-mini` model. This is determined by the `OPENAI_MODEL_NAME` environment variable, which defaults to "gpt-4o-mini" if not set.
  You can easily configure your agents to use a different model or provider as described in this guide.
</Note>

## Supported Providers

LiteLLM supports a wide range of providers, including but not limited to:

* OpenAI
* Anthropic
* Google (Vertex AI, Gemini)
* Azure OpenAI
* AWS (Bedrock, SageMaker)
* Cohere
* VoyageAI
* Hugging Face
* Ollama
* Mistral AI
* Replicate
* Together AI
* AI21
* Cloudflare Workers AI
* DeepInfra
* Groq
* SambaNova
* Nebius AI Studio
* [NVIDIA NIMs](https://docs.api.nvidia.com/nim/reference/models-1)
* And many more!

For a complete and up-to-date list of supported providers, please refer to the [LiteLLM Providers documentation](https://docs.litellm.ai/docs/providers).

<Info>
  To use any provider not covered by a native integration, add LiteLLM as a dependency to your project:

  ```bash theme={null}
  uv add 'crewai[litellm]'
  ```

  Native providers (OpenAI, Anthropic, Google Gemini, Azure, AWS Bedrock) use their own SDK extras — see the [Provider Configuration Examples](/en/concepts/llms#provider-configuration-examples).
</Info>

## Changing the LLM

To use a different LLM with your CrewAI agents, you have several options:

<Tabs>
  <Tab title="Using a String Identifier">
    Pass the model name as a string when initializing the agent:

    <CodeGroup>
      ```python Code theme={null}
      from crewai import Agent

      # Using OpenAI's GPT-4
      openai_agent = Agent(
          role='OpenAI Expert',
          goal='Provide insights using GPT-4',
          backstory="An AI assistant powered by OpenAI's latest model.",
          llm='gpt-4'
      )

      # Using Anthropic's Claude
      claude_agent = Agent(
          role='Anthropic Expert',
          goal='Analyze data using Claude',
          backstory="An AI assistant leveraging Anthropic's language model.",
          llm='claude-2'
      )
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Using the LLM Class">
    For more detailed configuration, use the LLM class:

    <CodeGroup>
      ```python Code theme={null}
      from crewai import Agent, LLM

      llm = LLM(
          model="gpt-4",
          temperature=0.7,
          base_url="https://api.openai.com/v1",
          api_key="your-api-key-here"
      )

      agent = Agent(
          role='Customized LLM Expert',
          goal='Provide tailored responses',
          backstory="An AI assistant with custom LLM settings.",
          llm=llm
      )
      ```
    </CodeGroup>
  </Tab>
</Tabs>

## Configuration Options

When configuring an LLM for your agent, you have access to a wide range of parameters:

| Parameter              |        Type        | Description                                                      |
| :--------------------- | :----------------: | :--------------------------------------------------------------- |
| **model**              |        `str`       | The name of the model to use (e.g., "gpt-4", "claude-2")         |
| **temperature**        |       `float`      | Controls randomness in output (0.0 to 1.0)                       |
| **max\_tokens**        |        `int`       | Maximum number of tokens to generate                             |
| **top\_p**             |       `float`      | Controls diversity of output (0.0 to 1.0)                        |
| **frequency\_penalty** |       `float`      | Penalizes new tokens based on their frequency in the text so far |
| **presence\_penalty**  |       `float`      | Penalizes new tokens based on their presence in the text so far  |
| **stop**               | `str`, `List[str]` | Sequence(s) to stop generation                                   |
| **base\_url**          |        `str`       | The base URL for the API endpoint                                |
| **api\_key**           |        `str`       | Your API key for authentication                                  |

For a complete list of parameters and their descriptions, refer to the LLM class documentation.

## Connecting to OpenAI-Compatible LLMs

You can connect to OpenAI-compatible LLMs using either environment variables or by setting specific attributes on the LLM class:

<Tabs>
  <Tab title="Using Environment Variables">
    <CodeGroup>
      ```python Generic theme={null}
      import os

      os.environ["OPENAI_API_KEY"] = "your-api-key"
      os.environ["OPENAI_API_BASE"] = "https://api.your-provider.com/v1"
      os.environ["OPENAI_MODEL_NAME"] = "your-model-name"
      ```

      ```python Google theme={null}
      import os

      # Example using Gemini's OpenAI-compatible API.
      os.environ["OPENAI_API_KEY"] = "your-gemini-key"  # Should start with AIza...
      os.environ["OPENAI_API_BASE"] = "https://generativelanguage.googleapis.com/v1beta/openai/"
      os.environ["OPENAI_MODEL_NAME"] = "openai/gemini-2.0-flash"  # Add your Gemini model here, under openai/
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Using LLM Class Attributes">
    <CodeGroup>
      ```python Generic theme={null}
      llm = LLM(
          model="custom-model-name",
          api_key="your-api-key",
          base_url="https://api.your-provider.com/v1"
      )
      agent = Agent(llm=llm, ...)
      ```

      ```python Google theme={null}
      # Example using Gemini's OpenAI-compatible API
      llm = LLM(
          model="openai/gemini-2.0-flash",
          base_url="https://generativelanguage.googleapis.com/v1beta/openai/",
          api_key="your-gemini-key",  # Should start with AIza...
      )
      agent = Agent(llm=llm, ...)
      ```
    </CodeGroup>
  </Tab>
</Tabs>

## Using Local Models with Ollama

For local models like those provided by Ollama:

<Steps>
  <Step title="Download and install Ollama">
    [Click here to download and install Ollama](https://ollama.com/download)
  </Step>

  <Step title="Pull the desired model">
    For example, run `ollama pull llama3.2` to download the model.
  </Step>

  <Step title="Configure your agent">
    <CodeGroup>
      ```python Code theme={null}
          agent = Agent(
              role='Local AI Expert',
              goal='Process information using a local model',
              backstory="An AI assistant running on local hardware.",
              llm=LLM(model="ollama/llama3.2", base_url="http://localhost:11434")
          )
      ```
    </CodeGroup>
  </Step>
</Steps>

## Changing the Base API URL

You can change the base API URL for any LLM provider by setting the `base_url` parameter:

```python Code theme={null}
llm = LLM(
    model="custom-model-name",
    base_url="https://api.your-provider.com/v1",
    api_key="your-api-key"
)
agent = Agent(llm=llm, ...)
```

This is particularly useful when working with OpenAI-compatible APIs or when you need to specify a different endpoint for your chosen provider.

## Conclusion

By leveraging LiteLLM, CrewAI offers seamless integration with a vast array of LLMs. This flexibility allows you to choose the most suitable model for your specific needs, whether you prioritize performance, cost-efficiency, or local deployment. Remember to consult the [LiteLLM documentation](https://docs.litellm.ai/docs/) for the most up-to-date information on supported models and configuration options.


# LLM Call Hooks
Source: https://docs.crewai.com/en/learn/llm-hooks

Learn how to use LLM call hooks to intercept, modify, and control language model interactions in CrewAI

LLM Call Hooks provide fine-grained control over language model interactions during agent execution. These hooks allow you to intercept LLM calls, modify prompts, transform responses, implement approval gates, and add custom logging or monitoring.

## Overview

LLM hooks are executed at two critical points:

* **Before LLM Call**: Modify messages, validate inputs, or block execution
* **After LLM Call**: Transform responses, sanitize outputs, or modify conversation history

## Hook Types

### Before LLM Call Hooks

Executed before every LLM call, these hooks can:

* Inspect and modify messages sent to the LLM
* Block LLM execution based on conditions
* Implement rate limiting or approval gates
* Add context or system messages
* Log request details

**Signature:**

```python theme={null}
def before_hook(context: LLMCallHookContext) -> bool | None:
    # Return False to block execution
    # Return True or None to allow execution
    ...
```

### After LLM Call Hooks

Executed after every LLM call, these hooks can:

* Modify or sanitize LLM responses
* Add metadata or formatting
* Log response details
* Update conversation history
* Implement content filtering

**Signature:**

```python theme={null}
def after_hook(context: LLMCallHookContext) -> str | None:
    # Return modified response string
    # Return None to keep original response
    ...
```

## LLM Hook Context

The `LLMCallHookContext` object provides comprehensive access to execution state:

```python theme={null}
class LLMCallHookContext:
    executor: CrewAgentExecutor  # Full executor reference
    messages: list               # Mutable message list
    agent: Agent                 # Current agent
    task: Task                   # Current task
    crew: Crew                   # Crew instance
    llm: BaseLLM                 # LLM instance
    iterations: int              # Current iteration count
    response: str | None         # LLM response (after hooks only)
```

### Modifying Messages

**Important:** Always modify messages in-place:

```python theme={null}
# ✅ Correct - modify in-place
def add_context(context: LLMCallHookContext) -> None:
    context.messages.append({"role": "system", "content": "Be concise"})

# ❌ Wrong - replaces list reference
def wrong_approach(context: LLMCallHookContext) -> None:
    context.messages = [{"role": "system", "content": "Be concise"}]
```

## Registration Methods

### 1. Global Hook Registration

Register hooks that apply to all LLM calls across all crews:

```python theme={null}
from crewai.hooks import register_before_llm_call_hook, register_after_llm_call_hook

def log_llm_call(context):
    print(f"LLM call by {context.agent.role} at iteration {context.iterations}")
    return None  # Allow execution

register_before_llm_call_hook(log_llm_call)
```

### 2. Decorator-Based Registration

Use decorators for cleaner syntax:

```python theme={null}
from crewai.hooks import before_llm_call, after_llm_call

@before_llm_call
def validate_iteration_count(context):
    if context.iterations > 10:
        print("⚠️ Exceeded maximum iterations")
        return False  # Block execution
    return None

@after_llm_call
def sanitize_response(context):
    if context.response and "API_KEY" in context.response:
        return context.response.replace("API_KEY", "[REDACTED]")
    return None
```

### 3. Crew-Scoped Hooks

Register hooks for a specific crew instance:

```python theme={null}
@CrewBase
class MyProjCrew:
    @before_llm_call_crew
    def validate_inputs(self, context):
        # Only applies to this crew
        if context.iterations == 0:
            print(f"Starting task: {context.task.description}")
        return None

    @after_llm_call_crew
    def log_responses(self, context):
        # Crew-specific response logging
        print(f"Response length: {len(context.response)}")
        return None

    @crew
    def crew(self) -> Crew:
        return Crew(
            agents=self.agents,
            tasks=self.tasks,
            process=Process.sequential,
            verbose=True
        )
```

## Common Use Cases

### 1. Iteration Limiting

```python theme={null}
@before_llm_call
def limit_iterations(context: LLMCallHookContext) -> bool | None:
    max_iterations = 15
    if context.iterations > max_iterations:
        print(f"⛔ Blocked: Exceeded {max_iterations} iterations")
        return False  # Block execution
    return None
```

### 2. Human Approval Gate

```python theme={null}
@before_llm_call
def require_approval(context: LLMCallHookContext) -> bool | None:
    if context.iterations > 5:
        response = context.request_human_input(
            prompt=f"Iteration {context.iterations}: Approve LLM call?",
            default_message="Press Enter to approve, or type 'no' to block:"
        )
        if response.lower() == "no":
            print("🚫 LLM call blocked by user")
            return False
    return None
```

### 3. Adding System Context

```python theme={null}
@before_llm_call
def add_guardrails(context: LLMCallHookContext) -> None:
    # Add safety guidelines to every LLM call
    context.messages.append({
        "role": "system",
        "content": "Ensure responses are factual and cite sources when possible."
    })
    return None
```

### 4. Response Sanitization

```python theme={null}
@after_llm_call
def sanitize_sensitive_data(context: LLMCallHookContext) -> str | None:
    if not context.response:
        return None

    # Remove sensitive patterns
    import re
    sanitized = context.response
    sanitized = re.sub(r'\b\d{3}-\d{2}-\d{4}\b', '[SSN-REDACTED]', sanitized)
    sanitized = re.sub(r'\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b', '[CARD-REDACTED]', sanitized)

    return sanitized
```

### 5. Cost Tracking

```python theme={null}
import tiktoken

@before_llm_call
def track_token_usage(context: LLMCallHookContext) -> None:
    encoding = tiktoken.get_encoding("cl100k_base")
    total_tokens = sum(
        len(encoding.encode(msg.get("content", "")))
        for msg in context.messages
    )
    print(f"📊 Input tokens: ~{total_tokens}")
    return None

@after_llm_call
def track_response_tokens(context: LLMCallHookContext) -> None:
    if context.response:
        encoding = tiktoken.get_encoding("cl100k_base")
        tokens = len(encoding.encode(context.response))
        print(f"📊 Response tokens: ~{tokens}")
    return None
```

### 6. Debug Logging

```python theme={null}
@before_llm_call
def debug_request(context: LLMCallHookContext) -> None:
    print(f"""
    🔍 LLM Call Debug:
    - Agent: {context.agent.role}
    - Task: {context.task.description[:50]}...
    - Iteration: {context.iterations}
    - Message Count: {len(context.messages)}
    - Last Message: {context.messages[-1] if context.messages else 'None'}
    """)
    return None

@after_llm_call
def debug_response(context: LLMCallHookContext) -> None:
    if context.response:
        print(f"✅ Response Preview: {context.response[:100]}...")
    return None
```

## Hook Management

### Unregistering Hooks

```python theme={null}
from crewai.hooks import (
    unregister_before_llm_call_hook,
    unregister_after_llm_call_hook
)

# Unregister specific hook
def my_hook(context):
    ...

register_before_llm_call_hook(my_hook)
# Later...
unregister_before_llm_call_hook(my_hook)  # Returns True if found
```

### Clearing Hooks

```python theme={null}
from crewai.hooks import (
    clear_before_llm_call_hooks,
    clear_after_llm_call_hooks,
    clear_all_llm_call_hooks
)

# Clear specific hook type
count = clear_before_llm_call_hooks()
print(f"Cleared {count} before hooks")

# Clear all LLM hooks
before_count, after_count = clear_all_llm_call_hooks()
print(f"Cleared {before_count} before and {after_count} after hooks")
```

### Listing Registered Hooks

```python theme={null}
from crewai.hooks import (
    get_before_llm_call_hooks,
    get_after_llm_call_hooks
)

# Get current hooks
before_hooks = get_before_llm_call_hooks()
after_hooks = get_after_llm_call_hooks()

print(f"Registered: {len(before_hooks)} before, {len(after_hooks)} after")
```

## Advanced Patterns

### Conditional Hook Execution

```python theme={null}
@before_llm_call
def conditional_blocking(context: LLMCallHookContext) -> bool | None:
    # Only block for specific agents
    if context.agent.role == "researcher" and context.iterations > 10:
        return False

    # Only block for specific tasks
    if "sensitive" in context.task.description.lower() and context.iterations > 5:
        return False

    return None
```

### Context-Aware Modifications

```python theme={null}
@before_llm_call
def adaptive_prompting(context: LLMCallHookContext) -> None:
    # Add different context based on iteration
    if context.iterations == 0:
        context.messages.append({
            "role": "system",
            "content": "Start with a high-level overview."
        })
    elif context.iterations > 3:
        context.messages.append({
            "role": "system",
            "content": "Focus on specific details and provide examples."
        })
    return None
```

### Chaining Hooks

```python theme={null}
# Multiple hooks execute in registration order

@before_llm_call
def first_hook(context):
    print("1. First hook executed")
    return None

@before_llm_call
def second_hook(context):
    print("2. Second hook executed")
    return None

@before_llm_call
def blocking_hook(context):
    if context.iterations > 10:
        print("3. Blocking hook - execution stopped")
        return False  # Subsequent hooks won't execute
    print("3. Blocking hook - execution allowed")
    return None
```

## Best Practices

1. **Keep Hooks Focused**: Each hook should have a single responsibility
2. **Avoid Heavy Computation**: Hooks execute on every LLM call
3. **Handle Errors Gracefully**: Use try-except to prevent hook failures from breaking execution
4. **Use Type Hints**: Leverage `LLMCallHookContext` for better IDE support
5. **Document Hook Behavior**: Especially for blocking conditions
6. **Test Hooks Independently**: Unit test hooks before using in production
7. **Clear Hooks in Tests**: Use `clear_all_llm_call_hooks()` between test runs
8. **Modify In-Place**: Always modify `context.messages` in-place, never replace

## Error Handling

```python theme={null}
@before_llm_call
def safe_hook(context: LLMCallHookContext) -> bool | None:
    try:
        # Your hook logic
        if some_condition:
            return False
    except Exception as e:
        print(f"⚠️ Hook error: {e}")
        # Decide: allow or block on error
        return None  # Allow execution despite error
```

## Type Safety

```python theme={null}
from crewai.hooks import LLMCallHookContext, BeforeLLMCallHookType, AfterLLMCallHookType

# Explicit type annotations
def my_before_hook(context: LLMCallHookContext) -> bool | None:
    return None

def my_after_hook(context: LLMCallHookContext) -> str | None:
    return None

# Type-safe registration
register_before_llm_call_hook(my_before_hook)
register_after_llm_call_hook(my_after_hook)
```

## Troubleshooting

### Hook Not Executing

* Verify hook is registered before crew execution
* Check if previous hook returned `False` (blocks subsequent hooks)
* Ensure hook signature matches expected type

### Message Modifications Not Persisting

* Use in-place modifications: `context.messages.append()`
* Don't replace the list: `context.messages = []`

### Response Modifications Not Working

* Return the modified string from after hooks
* Returning `None` keeps the original response

## Conclusion

LLM Call Hooks provide powerful capabilities for controlling and monitoring language model interactions in CrewAI. Use them to implement safety guardrails, approval gates, logging, cost tracking, and response sanitization. Combined with proper error handling and type safety, hooks enable robust and production-ready agent systems.


# Strategic LLM Selection Guide
Source: https://docs.crewai.com/en/learn/llm-selection-guide

Strategic framework for choosing the right LLM for your CrewAI AI agents and writing effective task and agent definitions

## The CrewAI Approach to LLM Selection

Rather than prescriptive model recommendations, we advocate for a **thinking framework** that helps you make informed decisions based on your specific use case, constraints, and requirements. The LLM landscape evolves rapidly, with new models emerging regularly and existing ones being updated frequently. What matters most is developing a systematic approach to evaluation that remains relevant regardless of which specific models are available.

<Note>
  This guide focuses on strategic thinking rather than specific model
  recommendations, as the LLM landscape evolves rapidly.
</Note>

## Quick Decision Framework

<Steps>
  <Step title="Analyze Your Tasks">
    Begin by deeply understanding what your tasks actually require. Consider the
    cognitive complexity involved, the depth of reasoning needed, the format of
    expected outputs, and the amount of context the model will need to process.
    This foundational analysis will guide every subsequent decision.
  </Step>

  <Step title="Map Model Capabilities">
    Once you understand your requirements, map them to model strengths.
    Different model families excel at different types of work; some are
    optimized for reasoning and analysis, others for creativity and content
    generation, and others for speed and efficiency.
  </Step>

  <Step title="Consider Constraints">
    Factor in your real-world operational constraints including budget
    limitations, latency requirements, data privacy needs, and infrastructure
    capabilities. The theoretically best model may not be the practically best
    choice for your situation.
  </Step>

  <Step title="Test and Iterate">
    Start with reliable, well-understood models and optimize based on actual
    performance in your specific use case. Real-world results often differ from
    theoretical benchmarks, so empirical testing is crucial.
  </Step>
</Steps>

## Core Selection Framework

### a. Task-First Thinking

The most critical step in LLM selection is understanding what your task actually demands. Too often, teams select models based on general reputation or benchmark scores without carefully analyzing their specific requirements. This approach leads to either over-engineering simple tasks with expensive, complex models, or under-powering sophisticated work with models that lack the necessary capabilities.

<Tabs>
  <Tab title="Reasoning Complexity">
    * **Simple Tasks** represent the majority of everyday AI work and include basic instruction following, straightforward data processing, and simple formatting operations. These tasks typically have clear inputs and outputs with minimal ambiguity. The cognitive load is low, and the model primarily needs to follow explicit instructions rather than engage in complex reasoning.

    * **Complex Tasks** require multi-step reasoning, strategic thinking, and the ability to handle ambiguous or incomplete information. These might involve analyzing multiple data sources, developing comprehensive strategies, or solving problems that require breaking down into smaller components. The model needs to maintain context across multiple reasoning steps and often must make inferences that aren't explicitly stated.

    * **Creative Tasks** demand a different type of cognitive capability focused on generating novel, engaging, and contextually appropriate content. This includes storytelling, marketing copy creation, and creative problem-solving. The model needs to understand nuance, tone, and audience while producing content that feels authentic and engaging rather than formulaic.
  </Tab>

  <Tab title="Output Requirements">
    * **Structured Data** tasks require precision and consistency in format adherence. When working with JSON, XML, or database formats, the model must reliably produce syntactically correct output that can be programmatically processed. These tasks often have strict validation requirements and little tolerance for format errors, making reliability more important than creativity.

    * **Creative Content** outputs demand a balance of technical competence and creative flair. The model needs to understand audience, tone, and brand voice while producing content that engages readers and achieves specific communication goals. Quality here is often subjective and requires models that can adapt their writing style to different contexts and purposes.

    * **Technical Content** sits between structured data and creative content, requiring both precision and clarity. Documentation, code generation, and technical analysis need to be accurate and comprehensive while remaining accessible to the intended audience. The model must understand complex technical concepts and communicate them effectively.
  </Tab>

  <Tab title="Context Needs">
    * **Short Context** scenarios involve focused, immediate tasks where the model needs to process limited information quickly. These are often transactional interactions where speed and efficiency matter more than deep understanding. The model doesn't need to maintain extensive conversation history or process large documents.

    * **Long Context** requirements emerge when working with substantial documents, extended conversations, or complex multi-part tasks. The model needs to maintain coherence across thousands of tokens while referencing earlier information accurately. This capability becomes crucial for document analysis, comprehensive research, and sophisticated dialogue systems.

    * **Very Long Context** scenarios push the boundaries of what's currently possible, involving massive document processing, extensive research synthesis, or complex multi-session interactions. These use cases require models specifically designed for extended context handling and often involve trade-offs between context length and processing speed.
  </Tab>
</Tabs>

### b. Model Capability Mapping

Understanding model capabilities requires looking beyond marketing claims and benchmark scores to understand the fundamental strengths and limitations of different model architectures and training approaches.

<AccordionGroup>
  <Accordion title="Reasoning Models" icon="brain">
    Reasoning models represent a specialized category designed specifically for complex, multi-step thinking tasks. These models excel when problems require careful analysis, strategic planning, or systematic problem decomposition. They typically employ techniques like chain-of-thought reasoning or tree-of-thought processing to work through complex problems step by step.

    The strength of reasoning models lies in their ability to maintain logical consistency across extended reasoning chains and to break down complex problems into manageable components. They're particularly valuable for strategic planning, complex analysis, and situations where the quality of reasoning matters more than speed of response.

    However, reasoning models often come with trade-offs in terms of speed and cost. They may also be less suitable for creative tasks or simple operations where their sophisticated reasoning capabilities aren't needed. Consider these models when your tasks involve genuine complexity that benefits from systematic, step-by-step analysis.
  </Accordion>

  <Accordion title="General Purpose Models" icon="microchip">
    General purpose models offer the most balanced approach to LLM selection, providing solid performance across a wide range of tasks without extreme specialization in any particular area. These models are trained on diverse datasets and optimized for versatility rather than peak performance in specific domains.

    The primary advantage of general purpose models is their reliability and predictability across different types of work. They handle most standard business tasks competently, from research and analysis to content creation and data processing. This makes them excellent choices for teams that need consistent performance across varied workflows.

    While general purpose models may not achieve the peak performance of specialized alternatives in specific domains, they offer operational simplicity and reduced complexity in model management. They're often the best starting point for new projects, allowing teams to understand their specific needs before potentially optimizing with more specialized models.
  </Accordion>

  <Accordion title="Fast & Efficient Models" icon="bolt">
    Fast and efficient models prioritize speed, cost-effectiveness, and resource efficiency over sophisticated reasoning capabilities. These models are optimized for high-throughput scenarios where quick responses and low operational costs are more important than nuanced understanding or complex reasoning.

    These models excel in scenarios involving routine operations, simple data processing, function calling, and high-volume tasks where the cognitive requirements are relatively straightforward. They're particularly valuable for applications that need to process many requests quickly or operate within tight budget constraints.

    The key consideration with efficient models is ensuring that their capabilities align with your task requirements. While they can handle many routine operations effectively, they may struggle with tasks requiring nuanced understanding, complex reasoning, or sophisticated content generation. They're best used for well-defined, routine operations where speed and cost matter more than sophistication.
  </Accordion>

  <Accordion title="Creative Models" icon="pen">
    Creative models are specifically optimized for content generation, writing quality, and creative thinking tasks. These models typically excel at understanding nuance, tone, and style while producing engaging, contextually appropriate content that feels natural and authentic.

    The strength of creative models lies in their ability to adapt writing style to different audiences, maintain consistent voice and tone, and generate content that engages readers effectively. They often perform better on tasks involving storytelling, marketing copy, brand communications, and other content where creativity and engagement are primary goals.

    When selecting creative models, consider not just their ability to generate text, but their understanding of audience, context, and purpose. The best creative models can adapt their output to match specific brand voices, target different audience segments, and maintain consistency across extended content pieces.
  </Accordion>

  <Accordion title="Open Source Models" icon="code">
    Open source models offer unique advantages in terms of cost control, customization potential, data privacy, and deployment flexibility. These models can be run locally or on private infrastructure, providing complete control over data handling and model behavior.

    The primary benefits of open source models include elimination of per-token costs, ability to fine-tune for specific use cases, complete data privacy, and independence from external API providers. They're particularly valuable for organizations with strict data privacy requirements, budget constraints, or specific customization needs.

    However, open source models require more technical expertise to deploy and maintain effectively. Teams need to consider infrastructure costs, model management complexity, and the ongoing effort required to keep models updated and optimized. The total cost of ownership may be higher than cloud-based alternatives when factoring in technical overhead.
  </Accordion>
</AccordionGroup>

## Strategic Configuration Patterns

### a. Multi-Model Approach

<Tip>
  Use different models for different purposes within the same crew to optimize
  both performance and cost.
</Tip>

The most sophisticated CrewAI implementations often employ multiple models strategically, assigning different models to different agents based on their specific roles and requirements. This approach allows teams to optimize for both performance and cost by using the most appropriate model for each type of work.

Planning agents benefit from reasoning models that can handle complex strategic thinking and multi-step analysis. These agents often serve as the "brain" of the operation, developing strategies and coordinating other agents' work. Content agents, on the other hand, perform best with creative models that excel at writing quality and audience engagement. Processing agents handling routine operations can use efficient models that prioritize speed and cost-effectiveness.

**Example: Research and Analysis Crew**

```python theme={null}
from crewai import Agent, Task, Crew, LLM

# High-capability reasoning model for strategic planning
manager_llm = LLM(model="gemini-2.5-flash-preview-05-20", temperature=0.1)

# Creative model for content generation
content_llm = LLM(model="claude-3-5-sonnet-20241022", temperature=0.7)

# Efficient model for data processing
processing_llm = LLM(model="gpt-4o-mini", temperature=0)

research_manager = Agent(
    role="Research Strategy Manager",
    goal="Develop comprehensive research strategies and coordinate team efforts",
    backstory="Expert research strategist with deep analytical capabilities",
    llm=manager_llm,  # High-capability model for complex reasoning
    verbose=True
)

content_writer = Agent(
    role="Research Content Writer",
    goal="Transform research findings into compelling, well-structured reports",
    backstory="Skilled writer who excels at making complex topics accessible",
    llm=content_llm,  # Creative model for engaging content
    verbose=True
)

data_processor = Agent(
    role="Data Analysis Specialist",
    goal="Extract and organize key data points from research sources",
    backstory="Detail-oriented analyst focused on accuracy and efficiency",
    llm=processing_llm,  # Fast, cost-effective model for routine tasks
    verbose=True
)

crew = Crew(
    agents=[research_manager, content_writer, data_processor],
    tasks=[...],  # Your specific tasks
    manager_llm=manager_llm,  # Manager uses the reasoning model
    verbose=True
)
```

The key to successful multi-model implementation is understanding how different agents interact and ensuring that model capabilities align with agent responsibilities. This requires careful planning but can result in significant improvements in both output quality and operational efficiency.

### b. Component-Specific Selection

<Tabs>
  <Tab title="Manager LLM">
    The manager LLM plays a crucial role in hierarchical CrewAI processes, serving as the coordination point for multiple agents and tasks. This model needs to excel at delegation, task prioritization, and maintaining context across multiple concurrent operations.

    Effective manager LLMs require strong reasoning capabilities to make good delegation decisions, consistent performance to ensure predictable coordination, and excellent context management to track the state of multiple agents simultaneously. The model needs to understand the capabilities and limitations of different agents while optimizing task allocation for efficiency and quality.

    Cost considerations are particularly important for manager LLMs since they're involved in every operation. The model needs to provide sufficient capability for effective coordination while remaining cost-effective for frequent use. This often means finding models that offer good reasoning capabilities without the premium pricing of the most sophisticated options.
  </Tab>

  <Tab title="Function Calling LLM">
    Function calling LLMs handle tool usage across all agents, making them critical for crews that rely heavily on external tools and APIs. These models need to excel at understanding tool capabilities, extracting parameters accurately, and handling tool responses effectively.

    The most important characteristics for function calling LLMs are precision and reliability rather than creativity or sophisticated reasoning. The model needs to consistently extract the correct parameters from natural language requests and handle tool responses appropriately. Speed is also important since tool usage often involves multiple round trips that can impact overall performance.

    Many teams find that specialized function calling models or general purpose models with strong tool support work better than creative or reasoning-focused models for this role. The key is ensuring that the model can reliably bridge the gap between natural language instructions and structured tool calls.
  </Tab>

  <Tab title="Agent-Specific Overrides">
    Individual agents can override crew-level LLM settings when their specific needs differ significantly from the general crew requirements. This capability allows for fine-tuned optimization while maintaining operational simplicity for most agents.

    Consider agent-specific overrides when an agent's role requires capabilities that differ substantially from other crew members. For example, a creative writing agent might benefit from a model optimized for content generation, while a data analysis agent might perform better with a reasoning-focused model.

    The challenge with agent-specific overrides is balancing optimization with operational complexity. Each additional model adds complexity to deployment, monitoring, and cost management. Teams should focus overrides on agents where the performance improvement justifies the additional complexity.
  </Tab>
</Tabs>

## Task Definition Framework

### a. Focus on Clarity Over Complexity

Effective task definition is often more important than model selection in determining the quality of CrewAI outputs. Well-defined tasks provide clear direction and context that enable even modest models to perform well, while poorly defined tasks can cause even sophisticated models to produce unsatisfactory results.

<AccordionGroup>
  <Accordion title="Effective Task Descriptions" icon="list-check">
    The best task descriptions strike a balance between providing sufficient detail and maintaining clarity. They should define the specific objective clearly enough that there's no ambiguity about what success looks like, while explaining the approach or methodology in enough detail that the agent understands how to proceed.

    Effective task descriptions include relevant context and constraints that help the agent understand the broader purpose and any limitations they need to work within. They break complex work into focused steps that can be executed systematically, rather than presenting overwhelming, multi-faceted objectives that are difficult to approach systematically.

    Common mistakes include being too vague about objectives, failing to provide necessary context, setting unclear success criteria, or combining multiple unrelated tasks into a single description. The goal is to provide enough information for the agent to succeed while maintaining focus on a single, clear objective.
  </Accordion>

  <Accordion title="Expected Output Guidelines" icon="bullseye">
    Expected output guidelines serve as a contract between the task definition and the agent, clearly specifying what the deliverable should look like and how it will be evaluated. These guidelines should describe both the format and structure needed, as well as the key elements that must be included for the output to be considered complete.

    The best output guidelines provide concrete examples of quality indicators and define completion criteria clearly enough that both the agent and human reviewers can assess whether the task has been completed successfully. This reduces ambiguity and helps ensure consistent results across multiple task executions.

    Avoid generic output descriptions that could apply to any task, missing format specifications that leave agents guessing about structure, unclear quality standards that make evaluation difficult, or failing to provide examples or templates that help agents understand expectations.
  </Accordion>
</AccordionGroup>

### b. Task Sequencing Strategy

<Tabs>
  <Tab title="Sequential Dependencies">
    Sequential task dependencies are essential when tasks build upon previous outputs, information flows from one task to another, or quality depends on the completion of prerequisite work. This approach ensures that each task has access to the information and context it needs to succeed.

    Implementing sequential dependencies effectively requires using the context parameter to chain related tasks, building complexity gradually through task progression, and ensuring that each task produces outputs that serve as meaningful inputs for subsequent tasks. The goal is to maintain logical flow between dependent tasks while avoiding unnecessary bottlenecks.

    Sequential dependencies work best when there's a clear logical progression from one task to another and when the output of one task genuinely improves the quality or feasibility of subsequent tasks. However, they can create bottlenecks if not managed carefully, so it's important to identify which dependencies are truly necessary versus those that are merely convenient.
  </Tab>

  <Tab title="Parallel Execution">
    Parallel execution becomes valuable when tasks are independent of each other, time efficiency is important, or different expertise areas are involved that don't require coordination. This approach can significantly reduce overall execution time while allowing specialized agents to work on their areas of strength simultaneously.

    Successful parallel execution requires identifying tasks that can truly run independently, grouping related but separate work streams effectively, and planning for result integration when parallel tasks need to be combined into a final deliverable. The key is ensuring that parallel tasks don't create conflicts or redundancies that reduce overall quality.

    Consider parallel execution when you have multiple independent research streams, different types of analysis that don't depend on each other, or content creation tasks that can be developed simultaneously. However, be mindful of resource allocation and ensure that parallel execution doesn't overwhelm your available model capacity or budget.
  </Tab>
</Tabs>

## Optimizing Agent Configuration for LLM Performance

### a. Role-Driven LLM Selection

<Warning>
  Generic agent roles make it impossible to select the right LLM. Specific roles
  enable targeted model optimization.
</Warning>

The specificity of your agent roles directly determines which LLM capabilities matter most for optimal performance. This creates a strategic opportunity to match precise model strengths with agent responsibilities.

**Generic vs. Specific Role Impact on LLM Choice:**

When defining roles, think about the specific domain knowledge, working style, and decision-making frameworks that would be most valuable for the tasks the agent will handle. The more specific and contextual the role definition, the better the model can embody that role effectively.

```python theme={null}
# ✅ Specific role - clear LLM requirements
specific_agent = Agent(
    role="SaaS Revenue Operations Analyst",  # Clear domain expertise needed
    goal="Analyze recurring revenue metrics and identify growth opportunities",
    backstory="Specialist in SaaS business models with deep understanding of ARR, churn, and expansion revenue",
    llm=LLM(model="gpt-4o")  # Reasoning model justified for complex analysis
)
```

**Role-to-Model Mapping Strategy:**

* **"Research Analyst"** → Reasoning model (GPT-4o, Claude Sonnet) for complex analysis
* **"Content Editor"** → Creative model (Claude, GPT-4o) for writing quality
* **"Data Processor"** → Efficient model (GPT-4o-mini, Gemini Flash) for structured tasks
* **"API Coordinator"** → Function-calling optimized model (GPT-4o, Claude) for tool usage

### b. Backstory as Model Context Amplifier

<Info>
  Strategic backstories multiply your chosen LLM's effectiveness by providing
  domain-specific context that generic prompting cannot achieve.
</Info>

A well-crafted backstory transforms your LLM choice from generic capability to specialized expertise. This is especially crucial for cost optimization - a well-contextualized efficient model can outperform a premium model without proper context.

**Context-Driven Performance Example:**

```python theme={null}
# Context amplifies model effectiveness
domain_expert = Agent(
    role="B2B SaaS Marketing Strategist",
    goal="Develop comprehensive go-to-market strategies for enterprise software",
    backstory="""
    You have 10+ years of experience scaling B2B SaaS companies from Series A to IPO.
    You understand the nuances of enterprise sales cycles, the importance of product-market
    fit in different verticals, and how to balance growth metrics with unit economics.
    You've worked with companies like Salesforce, HubSpot, and emerging unicorns, giving
    you perspective on both established and disruptive go-to-market strategies.
    """,
    llm=LLM(model="claude-3-5-sonnet", temperature=0.3)  # Balanced creativity with domain knowledge
)

# This context enables Claude to perform like a domain expert
# Without it, even it would produce generic marketing advice
```

**Backstory Elements That Enhance LLM Performance:**

* **Domain Experience**: "10+ years in enterprise SaaS sales"
* **Specific Expertise**: "Specializes in technical due diligence for Series B+ rounds"
* **Working Style**: "Prefers data-driven decisions with clear documentation"
* **Quality Standards**: "Insists on citing sources and showing analytical work"

### c. Holistic Agent-LLM Optimization

The most effective agent configurations create synergy between role specificity, backstory depth, and LLM selection. Each element reinforces the others to maximize model performance.

**Optimization Framework:**

```python theme={null}
# Example: Technical Documentation Agent
tech_writer = Agent(
    role="API Documentation Specialist",  # Specific role for clear LLM requirements
    goal="Create comprehensive, developer-friendly API documentation",
    backstory="""
    You're a technical writer with 8+ years documenting REST APIs, GraphQL endpoints,
    and SDK integration guides. You've worked with developer tools companies and
    understand what developers need: clear examples, comprehensive error handling,
    and practical use cases. You prioritize accuracy and usability over marketing fluff.
    """,
    llm=LLM(
        model="claude-3-5-sonnet",  # Excellent for technical writing
        temperature=0.1  # Low temperature for accuracy
    ),
    tools=[code_analyzer_tool, api_scanner_tool],
    verbose=True
)
```

**Alignment Checklist:**

* ✅ **Role Specificity**: Clear domain and responsibilities
* ✅ **LLM Match**: Model strengths align with role requirements
* ✅ **Backstory Depth**: Provides domain context the LLM can leverage
* ✅ **Tool Integration**: Tools support the agent's specialized function
* ✅ **Parameter Tuning**: Temperature and settings optimize for role needs

The key is creating agents where every configuration choice reinforces your LLM selection strategy, maximizing performance while optimizing costs.

## Practical Implementation Checklist

Rather than repeating the strategic framework, here's a tactical checklist for implementing your LLM selection decisions in CrewAI:

<Steps>
  <Step title="Audit Your Current Setup" icon="clipboard-check">
    **What to Review:**

    * Are all agents using the same LLM by default?
    * Which agents handle the most complex reasoning tasks?
    * Which agents primarily do data processing or formatting?
    * Are any agents heavily tool-dependent?

    **Action**: Document current agent roles and identify optimization opportunities.
  </Step>

  <Step title="Implement Crew-Level Strategy" icon="users-gear">
    **Set Your Baseline:**

    ```python theme={null}
    # Start with a reliable default for the crew
    default_crew_llm = LLM(model="gpt-4o-mini")  # Cost-effective baseline

    crew = Crew(
        agents=[...],
        tasks=[...],
        memory=True
    )
    ```

    **Action**: Establish your crew's default LLM before optimizing individual agents.
  </Step>

  <Step title="Optimize High-Impact Agents" icon="star">
    **Identify and Upgrade Key Agents:**

    ```python theme={null}
    # Manager or coordination agents
    manager_agent = Agent(
        role="Project Manager",
        llm=LLM(model="gemini-2.5-flash-preview-05-20"),  # Premium for coordination
        # ... rest of config
    )

    # Creative or customer-facing agents
    content_agent = Agent(
        role="Content Creator",
        llm=LLM(model="claude-3-5-sonnet"),  # Best for writing
        # ... rest of config
    )
    ```

    **Action**: Upgrade 20% of your agents that handle 80% of the complexity.
  </Step>

  <Step title="Validate with Enterprise Testing" icon="test-tube">
    **Once you deploy your agents to production:**

    * Use [CrewAI AMP platform](https://app.crewai.com) to A/B test your model selections
    * Run multiple iterations with real inputs to measure consistency and performance
    * Compare cost vs. performance across your optimized setup
    * Share results with your team for collaborative decision-making

    **Action**: Replace guesswork with data-driven validation using the testing platform.
  </Step>
</Steps>

### When to Use Different Model Types

<Tabs>
  <Tab title="Reasoning Models">
    Reasoning models become essential when tasks require genuine multi-step logical thinking, strategic planning, or high-level decision making that benefits from systematic analysis. These models excel when problems need to be broken down into components and analyzed systematically rather than handled through pattern matching or simple instruction following.

    Consider reasoning models for business strategy development, complex data analysis that requires drawing insights from multiple sources, multi-step problem solving where each step depends on previous analysis, and strategic planning tasks that require considering multiple variables and their interactions.

    However, reasoning models often come with higher costs and slower response times, so they're best reserved for tasks where their sophisticated capabilities provide genuine value rather than being used for simple operations that don't require complex reasoning.
  </Tab>

  <Tab title="Creative Models">
    Creative models become valuable when content generation is the primary output and the quality, style, and engagement level of that content directly impact success. These models excel when writing quality and style matter significantly, creative ideation or brainstorming is needed, or brand voice and tone are important considerations.

    Use creative models for blog post writing and article creation, marketing copy that needs to engage and persuade, creative storytelling and narrative development, and brand communications where voice and tone are crucial. These models often understand nuance and context better than general purpose alternatives.

    Creative models may be less suitable for technical or analytical tasks where precision and factual accuracy are more important than engagement and style. They're best used when the creative and communicative aspects of the output are primary success factors.
  </Tab>

  <Tab title="Efficient Models">
    Efficient models are ideal for high-frequency, routine operations where speed and cost optimization are priorities. These models work best when tasks have clear, well-defined parameters and don't require sophisticated reasoning or creative capabilities.

    Consider efficient models for data processing and transformation tasks, simple formatting and organization operations, function calling and tool usage where precision matters more than sophistication, and high-volume operations where cost per operation is a significant factor.

    The key with efficient models is ensuring that their capabilities align with task requirements. They can handle many routine operations effectively but may struggle with tasks requiring nuanced understanding, complex reasoning, or sophisticated content generation.
  </Tab>

  <Tab title="Open Source Models">
    Open source models become attractive when budget constraints are significant, data privacy requirements exist, customization needs are important, or local deployment is required for operational or compliance reasons.

    Consider open source models for internal company tools where data privacy is paramount, privacy-sensitive applications that can't use external APIs, cost-optimized deployments where per-token pricing is prohibitive, and situations requiring custom model modifications or fine-tuning.

    However, open source models require more technical expertise to deploy and maintain effectively. Consider the total cost of ownership including infrastructure, technical overhead, and ongoing maintenance when evaluating open source options.
  </Tab>
</Tabs>

## Common CrewAI Model Selection Pitfalls

<AccordionGroup>
  <Accordion title="The 'One Model Fits All' Trap" icon="triangle-exclamation">
    **The Problem**: Using the same LLM for all agents in a crew, regardless of their specific roles and responsibilities. This is often the default approach but rarely optimal.

    **Real Example**: Using GPT-4o for both a strategic planning manager and a data extraction agent. The manager needs reasoning capabilities worth the premium cost, but the data extractor could perform just as well with GPT-4o-mini at a fraction of the price.

    **CrewAI Solution**: Leverage agent-specific LLM configuration to match model capabilities with agent roles:

    ```python theme={null}
    # Strategic agent gets premium model
    manager = Agent(role="Strategy Manager", llm=LLM(model="gpt-4o"))

    # Processing agent gets efficient model
    processor = Agent(role="Data Processor", llm=LLM(model="gpt-4o-mini"))
    ```
  </Accordion>

  <Accordion title="Ignoring Crew-Level vs Agent-Level LLM Hierarchy" icon="shuffle">
    **The Problem**: Not understanding how CrewAI's LLM hierarchy works - crew LLM, manager LLM, and agent LLM settings can conflict or be poorly coordinated.

    **Real Example**: Setting a crew to use Claude, but having agents configured with GPT models, creating inconsistent behavior and unnecessary model switching overhead.

    **CrewAI Solution**: Plan your LLM hierarchy strategically:

    ```python theme={null}
    crew = Crew(
        agents=[agent1, agent2],
        tasks=[task1, task2],
        manager_llm=LLM(model="gpt-4o"),  # For crew coordination
        process=Process.hierarchical  # When using manager_llm
    )

    # Agents inherit crew LLM unless specifically overridden
    agent1 = Agent(llm=LLM(model="claude-3-5-sonnet"))  # Override for specific needs
    ```
  </Accordion>

  <Accordion title="Function Calling Model Mismatch" icon="screwdriver-wrench">
    **The Problem**: Choosing models based on general capabilities while ignoring function calling performance for tool-heavy CrewAI workflows.

    **Real Example**: Selecting a creative-focused model for an agent that primarily needs to call APIs, search tools, or process structured data. The agent struggles with tool parameter extraction and reliable function calls.

    **CrewAI Solution**: Prioritize function calling capabilities for tool-heavy agents:

    ```python theme={null}
    # For agents that use many tools
    tool_agent = Agent(
        role="API Integration Specialist",
        tools=[search_tool, api_tool, data_tool],
        llm=LLM(model="gpt-4o"),  # Excellent function calling
        # OR
        llm=LLM(model="claude-3-5-sonnet")  # Also strong with tools
    )
    ```
  </Accordion>

  <Accordion title="Premature Optimization Without Testing" icon="gear">
    **The Problem**: Making complex model selection decisions based on theoretical performance without validating with actual CrewAI workflows and tasks.

    **Real Example**: Implementing elaborate model switching logic based on task types without testing if the performance gains justify the operational complexity.

    **CrewAI Solution**: Start simple, then optimize based on real performance data:

    ```python theme={null}
    # Start with this
    crew = Crew(agents=[...], tasks=[...], llm=LLM(model="gpt-4o-mini"))

    # Test performance, then optimize specific agents as needed
    # Use Enterprise platform testing to validate improvements
    ```
  </Accordion>

  <Accordion title="Overlooking Context and Memory Limitations" icon="brain">
    **The Problem**: Not considering how model context windows interact with CrewAI's memory and context sharing between agents.

    **Real Example**: Using a short-context model for agents that need to maintain conversation history across multiple task iterations, or in crews with extensive agent-to-agent communication.

    **CrewAI Solution**: Match context capabilities to crew communication patterns.
  </Accordion>
</AccordionGroup>

## Testing and Iteration Strategy

<Steps>
  <Step title="Start Simple" icon="play">
    Begin with reliable, general-purpose models that are well-understood and
    widely supported. This provides a stable foundation for understanding your
    specific requirements and performance expectations before optimizing for
    specialized needs.
  </Step>

  <Step title="Measure What Matters" icon="chart-line">
    Develop metrics that align with your specific use case and business
    requirements rather than relying solely on general benchmarks. Focus on
    measuring outcomes that directly impact your success rather than theoretical
    performance indicators.
  </Step>

  <Step title="Iterate Based on Results" icon="arrows-rotate">
    Make model changes based on observed performance in your specific context
    rather than theoretical considerations or general recommendations.
    Real-world performance often differs significantly from benchmark results or
    general reputation.
  </Step>

  <Step title="Consider Total Cost" icon="calculator">
    Evaluate the complete cost of ownership including model costs, development
    time, maintenance overhead, and operational complexity. The cheapest model
    per token may not be the most cost-effective choice when considering all
    factors.
  </Step>
</Steps>

<Tip>
  Focus on understanding your requirements first, then select models that best
  match those needs. The best LLM choice is the one that consistently delivers
  the results you need within your operational constraints.
</Tip>

### Enterprise-Grade Model Validation

For teams serious about optimizing their LLM selection, the **CrewAI AMP platform** provides sophisticated testing capabilities that go far beyond basic CLI testing. The platform enables comprehensive model evaluation that helps you make data-driven decisions about your LLM strategy.

<Frame>
  <img alt="Enterprise Testing Interface" />
</Frame>

**Advanced Testing Features:**

* **Multi-Model Comparison**: Test multiple LLMs simultaneously across the same tasks and inputs. Compare performance between GPT-4o, Claude, Llama, Groq, Cerebras, and other leading models in parallel to identify the best fit for your specific use case.

* **Statistical Rigor**: Configure multiple iterations with consistent inputs to measure reliability and performance variance. This helps identify models that not only perform well but do so consistently across runs.

* **Real-World Validation**: Use your actual crew inputs and scenarios rather than synthetic benchmarks. The platform allows you to test with your specific industry context, company information, and real use cases for more accurate evaluation.

* **Comprehensive Analytics**: Access detailed performance metrics, execution times, and cost analysis across all tested models. This enables data-driven decision making rather than relying on general model reputation or theoretical capabilities.

* **Team Collaboration**: Share testing results and model performance data across your team, enabling collaborative decision-making and consistent model selection strategies across projects.

Go to [app.crewai.com](https://app.crewai.com) to get started!

<Info>
  The Enterprise platform transforms model selection from guesswork into a
  data-driven process, enabling you to validate the principles in this guide
  with your actual use cases and requirements.
</Info>

## Key Principles Summary

<CardGroup>
  <Card title="Task-Driven Selection" icon="bullseye">
    Choose models based on what the task actually requires, not theoretical capabilities or general reputation.
  </Card>

  <Card title="Capability Matching" icon="puzzle-piece">
    Align model strengths with agent roles and responsibilities for optimal
    performance.
  </Card>

  <Card title="Strategic Consistency" icon="link">
    Maintain coherent model selection strategy across related components and
    workflows.
  </Card>

  <Card title="Practical Testing" icon="flask">
    Validate choices through real-world usage rather than benchmarks alone.
  </Card>

  <Card title="Iterative Improvement" icon="arrow-up">
    Start simple and optimize based on actual performance and needs.
  </Card>

  <Card title="Operational Balance" icon="scale-balanced">
    Balance performance requirements with cost and complexity constraints.
  </Card>
</CardGroup>

<Check>
  Remember: The best LLM choice is the one that consistently delivers the
  results you need within your operational constraints. Focus on understanding
  your requirements first, then select models that best match those needs.
</Check>

## Current Model Landscape (June 2025)

<Warning>
  **Snapshot in Time**: The following model rankings represent current
  leaderboard standings as of June 2025, compiled from [LMSys
  Arena](https://arena.lmsys.org/), [Artificial
  Analysis](https://artificialanalysis.ai/), and other leading benchmarks. LLM
  performance, availability, and pricing change rapidly. Always conduct your own
  evaluations with your specific use cases and data.
</Warning>

### Leading Models by Category

The tables below show a representative sample of current top-performing models across different categories, with guidance on their suitability for CrewAI agents:

<Note>
  These tables/metrics showcase selected leading models in each category and are
  not exhaustive. Many excellent models exist beyond those listed here. The goal
  is to illustrate the types of capabilities to look for rather than provide a
  complete catalog.
</Note>

<Tabs>
  <Tab title="Reasoning & Planning">
    **Best for Manager LLMs and Complex Analysis**

    | Model                      | Intelligence Score | Cost (\$/M tokens) | Speed    | Best Use in CrewAI                                  |
    | :------------------------- | :----------------- | :----------------- | :------- | :-------------------------------------------------- |
    | **o3**                     | 70                 | \$17.50            | Fast     | Manager LLM for complex multi-agent coordination    |
    | **Gemini 2.5 Pro**         | 69                 | \$3.44             | Fast     | Strategic planning agents, research coordination    |
    | **DeepSeek R1**            | 68                 | \$0.96             | Moderate | Cost-effective reasoning for budget-conscious crews |
    | **Claude 4 Sonnet**        | 53                 | \$6.00             | Fast     | Analysis agents requiring nuanced understanding     |
    | **Qwen3 235B (Reasoning)** | 62                 | \$2.63             | Moderate | Open-source alternative for reasoning tasks         |

    These models excel at multi-step reasoning and are ideal for agents that need to develop strategies, coordinate other agents, or analyze complex information.
  </Tab>

  <Tab title="Coding & Technical">
    **Best for Development and Tool-Heavy Workflows**

    | Model                 | Coding Performance | Tool Use Score | Cost (\$/M tokens) | Best Use in CrewAI                            |
    | :-------------------- | :----------------- | :------------- | :----------------- | :-------------------------------------------- |
    | **Claude 4 Sonnet**   | Excellent          | 72.7%          | \$6.00             | Primary coding agent, technical documentation |
    | **Claude 4 Opus**     | Excellent          | 72.5%          | \$30.00            | Complex software architecture, code review    |
    | **DeepSeek V3**       | Very Good          | High           | \$0.48             | Cost-effective coding for routine development |
    | **Qwen2.5 Coder 32B** | Very Good          | Medium         | \$0.15             | Budget-friendly coding agent                  |
    | **Llama 3.1 405B**    | Good               | 81.1%          | \$3.50             | Function calling LLM for tool-heavy workflows |

    These models are optimized for code generation, debugging, and technical problem-solving, making them ideal for development-focused crews.
  </Tab>

  <Tab title="Speed & Efficiency">
    **Best for High-Throughput and Real-Time Applications**

    | Model                   | Speed (tokens/s) | Latency (TTFT) | Cost (\$/M tokens) | Best Use in CrewAI                   |
    | :---------------------- | :--------------- | :------------- | :----------------- | :----------------------------------- |
    | **Llama 4 Scout**       | 2,600            | 0.33s          | \$0.27             | High-volume processing agents        |
    | **Gemini 2.5 Flash**    | 376              | 0.30s          | \$0.26             | Real-time response agents            |
    | **DeepSeek R1 Distill** | 383              | Variable       | \$0.04             | Cost-optimized high-speed processing |
    | **Llama 3.3 70B**       | 2,500            | 0.52s          | \$0.60             | Balanced speed and capability        |
    | **Nova Micro**          | High             | 0.30s          | \$0.04             | Simple, fast task execution          |

    These models prioritize speed and efficiency, perfect for agents handling routine operations or requiring quick responses. **Pro tip**: Pairing these models with fast inference providers like Groq can achieve even better performance, especially for open-source models like Llama.
  </Tab>

  <Tab title="Balanced Performance">
    **Best All-Around Models for General Crews**

    | Model                 | Overall Score | Versatility | Cost (\$/M tokens) | Best Use in CrewAI                |
    | :-------------------- | :------------ | :---------- | :----------------- | :-------------------------------- |
    | **GPT-4.1**           | 53            | Excellent   | \$3.50             | General-purpose crew LLM          |
    | **Claude 3.7 Sonnet** | 48            | Very Good   | \$6.00             | Balanced reasoning and creativity |
    | **Gemini 2.0 Flash**  | 48            | Good        | \$0.17             | Cost-effective general use        |
    | **Llama 4 Maverick**  | 51            | Good        | \$0.37             | Open-source general purpose       |
    | **Qwen3 32B**         | 44            | Good        | \$1.23             | Budget-friendly versatility       |

    These models offer good performance across multiple dimensions, suitable for crews with diverse task requirements.
  </Tab>
</Tabs>

### Selection Framework for Current Models

<AccordionGroup>
  <Accordion title="High-Performance Crews" icon="rocket">
    **When performance is the priority**: Use top-tier models like **o3**, **Gemini 2.5 Pro**, or **Claude 4 Sonnet** for manager LLMs and critical agents. These models excel at complex reasoning and coordination but come with higher costs.

    **Strategy**: Implement a multi-model approach where premium models handle strategic thinking while efficient models handle routine operations.
  </Accordion>

  <Accordion title="Cost-Conscious Crews" icon="dollar-sign">
    **When budget is a primary constraint**: Focus on models like **DeepSeek R1**, **Llama 4 Scout**, or **Gemini 2.0 Flash**. These provide strong performance at significantly lower costs.

    **Strategy**: Use cost-effective models for most agents, reserving premium models only for the most critical decision-making roles.
  </Accordion>

  <Accordion title="Specialized Workflows" icon="screwdriver-wrench">
    **For specific domain expertise**: Choose models optimized for your primary use case. **Claude 4** series for coding, **Gemini 2.5 Pro** for research, **Llama 405B** for function calling.

    **Strategy**: Select models based on your crew's primary function, ensuring the core capability aligns with model strengths.
  </Accordion>

  <Accordion title="Enterprise & Privacy" icon="shield">
    **For data-sensitive operations**: Consider open-source models like **Llama 4** series, **DeepSeek V3**, or **Qwen3** that can be deployed locally while maintaining competitive performance.

    **Strategy**: Deploy open-source models on private infrastructure, accepting potential performance trade-offs for data control.
  </Accordion>
</AccordionGroup>

### Key Considerations for Model Selection

* **Performance Trends**: The current landscape shows strong competition between reasoning-focused models (o3, Gemini 2.5 Pro) and balanced models (Claude 4, GPT-4.1). Specialized models like DeepSeek R1 offer excellent cost-performance ratios.

* **Speed vs. Intelligence Trade-offs**: Models like Llama 4 Scout prioritize speed (2,600 tokens/s) while maintaining reasonable intelligence, whereas models like o3 maximize reasoning capability at the cost of speed and price.

* **Open Source Viability**: The gap between open-source and proprietary models continues to narrow, with models like Llama 4 Maverick and DeepSeek V3 offering competitive performance at attractive price points. Fast inference providers particularly shine with open-source models, often delivering better speed-to-cost ratios than proprietary alternatives.

<Info>
  **Testing is Essential**: Leaderboard rankings provide general guidance, but
  your specific use case, prompting style, and evaluation criteria may produce
  different results. Always test candidate models with your actual tasks and
  data before making final decisions.
</Info>

### Practical Implementation Strategy

<Steps>
  <Step title="Start with Proven Models">
    Begin with well-established models like **GPT-4.1**, **Claude 3.7 Sonnet**, or **Gemini 2.0 Flash** that offer good performance across multiple dimensions and have extensive real-world validation.
  </Step>

  <Step title="Identify Specialized Needs">
    Determine if your crew has specific requirements (coding, reasoning, speed)
    that would benefit from specialized models like **Claude 4 Sonnet** for
    development or **o3** for complex analysis. For speed-critical applications,
    consider fast inference providers like **Groq** alongside model selection.
  </Step>

  <Step title="Implement Multi-Model Strategy">
    Use different models for different agents based on their roles.
    High-capability models for managers and complex tasks, efficient models for
    routine operations.
  </Step>

  <Step title="Monitor and Optimize">
    Track performance metrics relevant to your use case and be prepared to adjust model selections as new models are released or pricing changes.
  </Step>
</Steps>


# Using Multimodal Agents
Source: https://docs.crewai.com/en/learn/multimodal-agents

Learn how to enable and use multimodal capabilities in your agents for processing images and other non-text content within the CrewAI framework.

## Using Multimodal Agents

CrewAI supports multimodal agents that can process both text and non-text content like images. This guide will show you how to enable and use multimodal capabilities in your agents.

### Enabling Multimodal Capabilities

To create a multimodal agent, simply set the `multimodal` parameter to `True` when initializing your agent:

```python theme={null}
from crewai import Agent

agent = Agent(
    role="Image Analyst",
    goal="Analyze and extract insights from images",
    backstory="An expert in visual content interpretation with years of experience in image analysis",
    multimodal=True  # This enables multimodal capabilities
)
```

When you set `multimodal=True`, the agent is automatically configured with the necessary tools for handling non-text content, including the `AddImageTool`.

### Working with Images

The multimodal agent comes pre-configured with the `AddImageTool`, which allows it to process images. You don't need to manually add this tool - it's automatically included when you enable multimodal capabilities.

Here's a complete example showing how to use a multimodal agent to analyze an image:

```python theme={null}
from crewai import Agent, Task, Crew

# Create a multimodal agent
image_analyst = Agent(
    role="Product Analyst",
    goal="Analyze product images and provide detailed descriptions",
    backstory="Expert in visual product analysis with deep knowledge of design and features",
    multimodal=True
)

# Create a task for image analysis
task = Task(
    description="Analyze the product image at https://example.com/product.jpg and provide a detailed description",
    expected_output="A detailed description of the product image",
    agent=image_analyst
)

# Create and run the crew
crew = Crew(
    agents=[image_analyst],
    tasks=[task]
)

result = crew.kickoff()
```

### Advanced Usage with Context

You can provide additional context or specific questions about the image when creating tasks for multimodal agents. The task description can include specific aspects you want the agent to focus on:

```python theme={null}
from crewai import Agent, Task, Crew

# Create a multimodal agent for detailed analysis
expert_analyst = Agent(
    role="Visual Quality Inspector",
    goal="Perform detailed quality analysis of product images",
    backstory="Senior quality control expert with expertise in visual inspection",
    multimodal=True  # AddImageTool is automatically included
)

# Create a task with specific analysis requirements
inspection_task = Task(
    description="""
    Analyze the product image at https://example.com/product.jpg with focus on:
    1. Quality of materials
    2. Manufacturing defects
    3. Compliance with standards
    Provide a detailed report highlighting any issues found.
    """,
    expected_output="A detailed report highlighting any issues found",
    agent=expert_analyst
)

# Create and run the crew
crew = Crew(
    agents=[expert_analyst],
    tasks=[inspection_task]
)

result = crew.kickoff()
```

### Tool Details

When working with multimodal agents, the `AddImageTool` is automatically configured with the following schema:

```python theme={null}
class AddImageToolSchema:
    image_url: str  # Required: The URL or path of the image to process
    action: Optional[str] = None  # Optional: Additional context or specific questions about the image
```

The multimodal agent will automatically handle the image processing through its built-in tools, allowing it to:

* Access images via URLs or local file paths
* Process image content with optional context or specific questions
* Provide analysis and insights based on the visual information and task requirements

### Best Practices

When working with multimodal agents, keep these best practices in mind:

1. **Image Access**
   * Ensure your images are accessible via URLs that the agent can reach
   * For local images, consider hosting them temporarily or using absolute file paths
   * Verify that image URLs are valid and accessible before running tasks

2. **Task Description**
   * Be specific about what aspects of the image you want the agent to analyze
   * Include clear questions or requirements in the task description
   * Consider using the optional `action` parameter for focused analysis

3. **Resource Management**
   * Image processing may require more computational resources than text-only tasks
   * Some language models may require base64 encoding for image data
   * Consider batch processing for multiple images to optimize performance

4. **Environment Setup**
   * Verify that your environment has the necessary dependencies for image processing
   * Ensure your language model supports multimodal capabilities
   * Test with small images first to validate your setup

5. **Error Handling**
   * Implement proper error handling for image loading failures
   * Have fallback strategies for when image processing fails
   * Monitor and log image processing operations for debugging


# Overview
Source: https://docs.crewai.com/en/learn/overview

Learn how to build, customize, and optimize your CrewAI applications with comprehensive guides and tutorials

## Learn CrewAI

This section provides comprehensive guides and tutorials to help you master CrewAI, from basic concepts to advanced techniques. Whether you're just getting started or looking to optimize your existing implementations, these resources will guide you through every aspect of building powerful AI agent workflows.

## Getting Started Guides

### Core Concepts

<CardGroup>
  <Card title="Sequential Process" icon="list-ol" href="/en/learn/sequential-process">
    Learn how to execute tasks in a sequential order for structured workflows.
  </Card>

  <Card title="Hierarchical Process" icon="sitemap" href="/en/learn/hierarchical-process">
    Implement hierarchical task execution with manager agents overseeing workflows.
  </Card>

  <Card title="Conditional Tasks" icon="code-branch" href="/en/learn/conditional-tasks">
    Create dynamic workflows with conditional task execution based on outcomes.
  </Card>

  <Card title="Async Kickoff" icon="bolt" href="/en/learn/kickoff-async">
    Execute crews asynchronously for improved performance and concurrency.
  </Card>
</CardGroup>

### Agent Development

<CardGroup>
  <Card title="Customizing Agents" icon="user-gear" href="/en/learn/customizing-agents">
    Learn how to customize agent behavior, roles, and capabilities.
  </Card>

  <Card title="Coding Agents" icon="code" href="/en/learn/coding-agents">
    Build agents that can write, execute, and debug code automatically.
  </Card>

  <Card title="Multimodal Agents" icon="images" href="/en/learn/multimodal-agents">
    Create agents that can process text, images, and other media types.
  </Card>

  <Card title="Custom Manager Agent" icon="user-tie" href="/en/learn/custom-manager-agent">
    Implement custom manager agents for complex hierarchical workflows.
  </Card>
</CardGroup>

## Advanced Features

### Workflow Control

<CardGroup>
  <Card title="Human in the Loop" icon="user-check" href="/en/learn/human-in-the-loop">
    Integrate human oversight and intervention into agent workflows.
  </Card>

  <Card title="Human Input on Execution" icon="hand-paper" href="/en/learn/human-input-on-execution">
    Allow human input during task execution for dynamic decision making.
  </Card>

  <Card title="Replay Tasks" icon="rotate-left" href="/en/learn/replay-tasks-from-latest-crew-kickoff">
    Replay and resume tasks from previous crew executions.
  </Card>

  <Card title="Kickoff for Each" icon="repeat" href="/en/learn/kickoff-for-each">
    Execute crews multiple times with different inputs efficiently.
  </Card>
</CardGroup>

### Customization & Integration

<CardGroup>
  <Card title="Custom LLM" icon="brain" href="/en/learn/custom-llm">
    Integrate custom language models and providers with CrewAI.
  </Card>

  <Card title="LLM Connections" icon="link" href="/en/learn/llm-connections">
    Configure and manage connections to various LLM providers.
  </Card>

  <Card title="Create Custom Tools" icon="wrench" href="/en/learn/create-custom-tools">
    Build custom tools to extend agent capabilities.
  </Card>

  <Card title="Using Annotations" icon="at" href="/en/learn/using-annotations">
    Use Python annotations for cleaner, more maintainable code.
  </Card>
</CardGroup>

## Specialized Applications

### Content & Media

<CardGroup>
  <Card title="DALL-E Image Generation" icon="image" href="/en/learn/dalle-image-generation">
    Generate images using DALL-E integration with your agents.
  </Card>

  <Card title="Bring Your Own Agent" icon="user-plus" href="/en/learn/bring-your-own-agent">
    Integrate existing agents and models into CrewAI workflows.
  </Card>
</CardGroup>

### Tool Management

<CardGroup>
  <Card title="Force Tool Output as Result" icon="hammer" href="/en/learn/force-tool-output-as-result">
    Configure tools to return their output directly as task results.
  </Card>
</CardGroup>

## Learning Path Recommendations

### For Beginners

1. Start with **Sequential Process** to understand basic workflow execution
2. Learn **Customizing Agents** to create effective agent configurations
3. Explore **Create Custom Tools** to extend functionality
4. Try **Human in the Loop** for interactive workflows

### For Intermediate Users

1. Master **Hierarchical Process** for complex multi-agent systems
2. Implement **Conditional Tasks** for dynamic workflows
3. Use **Async Kickoff** for performance optimization
4. Integrate **Custom LLM** for specialized models

### For Advanced Users

1. Build **Multimodal Agents** for complex media processing
2. Create **Custom Manager Agents** for sophisticated orchestration
3. Implement **Bring Your Own Agent** for hybrid systems
4. Use **Replay Tasks** for robust error recovery

## Best Practices

### Development

* **Start Simple**: Begin with basic sequential workflows before adding complexity
* **Test Incrementally**: Test each component before integrating into larger systems
* **Use Annotations**: Leverage Python annotations for cleaner, more maintainable code
* **Custom Tools**: Build reusable tools that can be shared across different agents

### Production

* **Error Handling**: Implement robust error handling and recovery mechanisms
* **Performance**: Use async execution and optimize LLM calls for better performance
* **Monitoring**: Integrate observability tools to track agent performance
* **Human Oversight**: Include human checkpoints for critical decisions

### Optimization

* **Resource Management**: Monitor and optimize token usage and API costs
* **Workflow Design**: Design workflows that minimize unnecessary LLM calls
* **Tool Efficiency**: Create efficient tools that provide maximum value with minimal overhead
* **Iterative Improvement**: Use feedback and metrics to continuously improve agent performance

## Getting Help

* **Documentation**: Each guide includes detailed examples and explanations
* **Community**: Join the [CrewAI Forum](https://community.crewai.com) for discussions and support
* **Examples**: Check the Examples section for complete working implementations
* **Support**: Contact [support@crewai.com](mailto:support@crewai.com) for technical assistance

Start with the guides that match your current needs and gradually explore more advanced topics as you become comfortable with the fundamentals.


# Replay Tasks from Latest Crew Kickoff
Source: https://docs.crewai.com/en/learn/replay-tasks-from-latest-crew-kickoff

Replay tasks from the latest crew.kickoff(...)

## Introduction

CrewAI provides the ability to replay from a task specified from the latest crew kickoff. This feature is particularly useful when you've finished a kickoff and may want to retry certain tasks or don't need to refetch data over and your agents already have the context saved from the kickoff execution so you just need to replay the tasks you want to.

<Note>
  You must run `crew.kickoff()` before you can replay a task.
  Currently, only the latest kickoff is supported, so if you use `kickoff_for_each`, it will only allow you to replay from the most recent crew run.
</Note>

Here's an example of how to replay from a task:

### Replaying from Specific Task Using the CLI

To use the replay feature, follow these steps:

<Steps>
  <Step title="Open your terminal or command prompt." />

  <Step title="Navigate to the directory where your CrewAI project is located." />

  <Step title="Run the following commands:">
    To view the latest kickoff task\_ids use:

    ```shell theme={null}
    crewai log-tasks-outputs
    ```

    Once you have your `task_id` to replay, use:

    ```shell theme={null}
    crewai replay -t <task_id>
    ```
  </Step>
</Steps>

<Note>
  Ensure `crewai` is installed and configured correctly in your development environment.
</Note>

### Replaying from a Task Programmatically

To replay from a task programmatically, use the following steps:

<Steps>
  <Step title="Specify the `task_id` and input parameters for the replay process.">
    Specify the `task_id` and input parameters for the replay process.
  </Step>

  <Step title="Execute the replay command within a try-except block to handle potential errors.">
    Execute the replay command within a try-except block to handle potential errors.

    <CodeGroup>
      ```python Code theme={null}
        def replay():
        """
        Replay the crew execution from a specific task.
        """
        task_id = '<task_id>'
        inputs = {"topic": "CrewAI Training"}  # This is optional; you can pass in the inputs you want to replay; otherwise, it uses the previous kickoff's inputs.
        try:
            YourCrewName_Crew().crew().replay(task_id=task_id, inputs=inputs)

        except subprocess.CalledProcessError as e:
            raise Exception(f"An error occurred while replaying the crew: {e}")

        except Exception as e:
            raise Exception(f"An unexpected error occurred: {e}")
      ```
    </CodeGroup>
  </Step>
</Steps>

## Conclusion

With the above enhancements and detailed functionality, replaying specific tasks in CrewAI has been made more efficient and robust.
Ensure you follow the commands and steps precisely to make the most of these features.


# Sequential Processes
Source: https://docs.crewai.com/en/learn/sequential-process

A comprehensive guide to utilizing the sequential processes for task execution in CrewAI projects.

## Introduction

CrewAI offers a flexible framework for executing tasks in a structured manner, supporting both sequential and hierarchical processes.
This guide outlines how to effectively implement these processes to ensure efficient task execution and project completion.

## Sequential Process Overview

The sequential process ensures tasks are executed one after the other, following a linear progression.
This approach is ideal for projects requiring tasks to be completed in a specific order.

### Key Features

* **Linear Task Flow**: Ensures orderly progression by handling tasks in a predetermined sequence.
* **Simplicity**: Best suited for projects with clear, step-by-step tasks.
* **Easy Monitoring**: Facilitates easy tracking of task completion and project progress.

## Implementing the Sequential Process

To use the sequential process, assemble your crew and define tasks in the order they need to be executed.

```python Code theme={null}
from crewai import Crew, Process, Agent, Task, TaskOutput, CrewOutput

# Define your agents
researcher = Agent(
  role='Researcher',
  goal='Conduct foundational research',
  backstory='An experienced researcher with a passion for uncovering insights'
)
analyst = Agent(
  role='Data Analyst',
  goal='Analyze research findings',
  backstory='A meticulous analyst with a knack for uncovering patterns'
)
writer = Agent(
  role='Writer',
  goal='Draft the final report',
  backstory='A skilled writer with a talent for crafting compelling narratives'
)

# Define your tasks
research_task = Task(
  description='Gather relevant data...', 
  agent=researcher, 
  expected_output='Raw Data'
)
analysis_task = Task(
  description='Analyze the data...', 
  agent=analyst, 
  expected_output='Data Insights'
)
writing_task = Task(
  description='Compose the report...', 
  agent=writer, 
  expected_output='Final Report'
)

# Form the crew with a sequential process
report_crew = Crew(
  agents=[researcher, analyst, writer],
  tasks=[research_task, analysis_task, writing_task],
  process=Process.sequential
)

# Execute the crew
result = report_crew.kickoff()

# Accessing the type-safe output
task_output: TaskOutput = result.tasks[0].output
crew_output: CrewOutput = result.output
```

### Note:

Each task in a sequential process **must** have an agent assigned. Ensure that every `Task` includes an `agent` parameter.

### Workflow in Action

1. **Initial Task**: In a sequential process, the first agent completes their task and signals completion.
2. **Subsequent Tasks**: Agents pick up their tasks based on the process type, with outcomes of preceding tasks or directives guiding their execution.
3. **Completion**: The process concludes once the final task is executed, leading to project completion.

## Advanced Features

### Task Delegation

In sequential processes, if an agent has `allow_delegation` set to `True`, they can delegate tasks to other agents in the crew.
This feature is automatically set up when there are multiple agents in the crew.

### Asynchronous Execution

Tasks can be executed asynchronously, allowing for parallel processing when appropriate.
To create an asynchronous task, set `async_execution=True` when defining the task.

### Memory and Caching

CrewAI supports both memory and caching features:

* **Memory**: Enable by setting `memory=True` when creating the Crew. This allows agents to retain information across tasks.
* **Caching**: By default, caching is enabled. Set `cache=False` to disable it.

### Callbacks

You can set callbacks at both the task and step level:

* `task_callback`: Executed after each task completion.
* `step_callback`: Executed after each step in an agent's execution.

### Usage Metrics

CrewAI tracks token usage across all tasks and agents. You can access these metrics after execution.

## Best Practices for Sequential Processes

1. **Order Matters**: Arrange tasks in a logical sequence where each task builds upon the previous one.
2. **Clear Task Descriptions**: Provide detailed descriptions for each task to guide the agents effectively.
3. **Appropriate Agent Selection**: Match agents' skills and roles to the requirements of each task.
4. **Use Context**: Leverage the context from previous tasks to inform subsequent ones.

This updated documentation ensures that details accurately reflect the latest changes in the codebase and clearly describes how to leverage new features and configurations.
The content is kept simple and direct to ensure easy understanding.


# Tool Call Hooks
Source: https://docs.crewai.com/en/learn/tool-hooks

Learn how to use tool call hooks to intercept, modify, and control tool execution in CrewAI

Tool Call Hooks provide fine-grained control over tool execution during agent operations. These hooks allow you to intercept tool calls, modify inputs, transform outputs, implement safety checks, and add comprehensive logging or monitoring.

## Overview

Tool hooks are executed at two critical points:

* **Before Tool Call**: Modify inputs, validate parameters, or block execution
* **After Tool Call**: Transform results, sanitize outputs, or log execution details

## Hook Types

### Before Tool Call Hooks

Executed before every tool execution, these hooks can:

* Inspect and modify tool inputs
* Block tool execution based on conditions
* Implement approval gates for dangerous operations
* Validate parameters
* Log tool invocations

**Signature:**

```python theme={null}
def before_hook(context: ToolCallHookContext) -> bool | None:
    # Return False to block execution
    # Return True or None to allow execution
    ...
```

### After Tool Call Hooks

Executed after every tool execution, these hooks can:

* Modify or sanitize tool results
* Add metadata or formatting
* Log execution results
* Implement result validation
* Transform output formats

**Signature:**

```python theme={null}
def after_hook(context: ToolCallHookContext) -> str | None:
    # Return modified result string
    # Return None to keep original result
    ...
```

## Tool Hook Context

The `ToolCallHookContext` object provides comprehensive access to tool execution state:

```python theme={null}
class ToolCallHookContext:
    tool_name: str                    # Name of the tool being called
    tool_input: dict[str, Any]        # Mutable tool input parameters
    tool: CrewStructuredTool          # Tool instance reference
    agent: Agent | BaseAgent | None   # Agent executing the tool
    task: Task | None                 # Current task
    crew: Crew | None                 # Crew instance
    tool_result: str | None           # Tool result (after hooks only)
```

### Modifying Tool Inputs

**Important:** Always modify tool inputs in-place:

```python theme={null}
# ✅ Correct - modify in-place
def sanitize_input(context: ToolCallHookContext) -> None:
    context.tool_input['query'] = context.tool_input['query'].lower()

# ❌ Wrong - replaces dict reference
def wrong_approach(context: ToolCallHookContext) -> None:
    context.tool_input = {'query': 'new query'}
```

## Registration Methods

### 1. Global Hook Registration

Register hooks that apply to all tool calls across all crews:

```python theme={null}
from crewai.hooks import register_before_tool_call_hook, register_after_tool_call_hook

def log_tool_call(context):
    print(f"Tool: {context.tool_name}")
    print(f"Input: {context.tool_input}")
    return None  # Allow execution

register_before_tool_call_hook(log_tool_call)
```

### 2. Decorator-Based Registration

Use decorators for cleaner syntax:

```python theme={null}
from crewai.hooks import before_tool_call, after_tool_call

@before_tool_call
def block_dangerous_tools(context):
    dangerous_tools = ['delete_database', 'drop_table', 'rm_rf']
    if context.tool_name in dangerous_tools:
        print(f"⛔ Blocked dangerous tool: {context.tool_name}")
        return False  # Block execution
    return None

@after_tool_call
def sanitize_results(context):
    if context.tool_result and "password" in context.tool_result.lower():
        return context.tool_result.replace("password", "[REDACTED]")
    return None
```

### 3. Crew-Scoped Hooks

Register hooks for a specific crew instance:

```python theme={null}
@CrewBase
class MyProjCrew:
    @before_tool_call_crew
    def validate_tool_inputs(self, context):
        # Only applies to this crew
        if context.tool_name == "web_search":
            if not context.tool_input.get('query'):
                print("❌ Invalid search query")
                return False
        return None

    @after_tool_call_crew
    def log_tool_results(self, context):
        # Crew-specific tool logging
        print(f"✅ {context.tool_name} completed")
        return None

    @crew
    def crew(self) -> Crew:
        return Crew(
            agents=self.agents,
            tasks=self.tasks,
            process=Process.sequential,
            verbose=True
        )
```

## Common Use Cases

### 1. Safety Guardrails

```python theme={null}
@before_tool_call
def safety_check(context: ToolCallHookContext) -> bool | None:
    # Block tools that could cause harm
    destructive_tools = [
        'delete_file',
        'drop_table',
        'remove_user',
        'system_shutdown'
    ]

    if context.tool_name in destructive_tools:
        print(f"🛑 Blocked destructive tool: {context.tool_name}")
        return False

    # Warn on sensitive operations
    sensitive_tools = ['send_email', 'post_to_social_media', 'charge_payment']
    if context.tool_name in sensitive_tools:
        print(f"⚠️  Executing sensitive tool: {context.tool_name}")

    return None
```

### 2. Human Approval Gate

```python theme={null}
@before_tool_call
def require_approval_for_actions(context: ToolCallHookContext) -> bool | None:
    approval_required = [
        'send_email',
        'make_purchase',
        'delete_file',
        'post_message'
    ]

    if context.tool_name in approval_required:
        response = context.request_human_input(
            prompt=f"Approve {context.tool_name}?",
            default_message=f"Input: {context.tool_input}\nType 'yes' to approve:"
        )

        if response.lower() != 'yes':
            print(f"❌ Tool execution denied: {context.tool_name}")
            return False

    return None
```

### 3. Input Validation and Sanitization

```python theme={null}
@before_tool_call
def validate_and_sanitize_inputs(context: ToolCallHookContext) -> bool | None:
    # Validate search queries
    if context.tool_name == 'web_search':
        query = context.tool_input.get('query', '')
        if len(query) < 3:
            print("❌ Search query too short")
            return False

        # Sanitize query
        context.tool_input['query'] = query.strip().lower()

    # Validate file paths
    if context.tool_name == 'read_file':
        path = context.tool_input.get('path', '')
        if '..' in path or path.startswith('/'):
            print("❌ Invalid file path")
            return False

    return None
```

### 4. Result Sanitization

```python theme={null}
@after_tool_call
def sanitize_sensitive_data(context: ToolCallHookContext) -> str | None:
    if not context.tool_result:
        return None

    import re
    result = context.tool_result

    # Remove API keys
    result = re.sub(
        r'(api[_-]?key|token)["\']?\s*[:=]\s*["\']?[\w-]+',
        r'\1: [REDACTED]',
        result,
        flags=re.IGNORECASE
    )

    # Remove email addresses
    result = re.sub(
        r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b',
        '[EMAIL-REDACTED]',
        result
    )

    # Remove credit card numbers
    result = re.sub(
        r'\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b',
        '[CARD-REDACTED]',
        result
    )

    return result
```

### 5. Tool Usage Analytics

```python theme={null}
import time
from collections import defaultdict

tool_stats = defaultdict(lambda: {'count': 0, 'total_time': 0, 'failures': 0})

@before_tool_call
def start_timer(context: ToolCallHookContext) -> None:
    context.tool_input['_start_time'] = time.time()
    return None

@after_tool_call
def track_tool_usage(context: ToolCallHookContext) -> None:
    start_time = context.tool_input.get('_start_time', time.time())
    duration = time.time() - start_time

    tool_stats[context.tool_name]['count'] += 1
    tool_stats[context.tool_name]['total_time'] += duration

    if not context.tool_result or 'error' in context.tool_result.lower():
        tool_stats[context.tool_name]['failures'] += 1

    print(f"""
    📊 Tool Stats for {context.tool_name}:
    - Executions: {tool_stats[context.tool_name]['count']}
    - Avg Time: {tool_stats[context.tool_name]['total_time'] / tool_stats[context.tool_name]['count']:.2f}s
    - Failures: {tool_stats[context.tool_name]['failures']}
    """)

    return None
```

### 6. Rate Limiting

```python theme={null}
from collections import defaultdict
from datetime import datetime, timedelta

tool_call_history = defaultdict(list)

@before_tool_call
def rate_limit_tools(context: ToolCallHookContext) -> bool | None:
    tool_name = context.tool_name
    now = datetime.now()

    # Clean old entries (older than 1 minute)
    tool_call_history[tool_name] = [
        call_time for call_time in tool_call_history[tool_name]
        if now - call_time < timedelta(minutes=1)
    ]

    # Check rate limit (max 10 calls per minute)
    if len(tool_call_history[tool_name]) >= 10:
        print(f"🚫 Rate limit exceeded for {tool_name}")
        return False

    # Record this call
    tool_call_history[tool_name].append(now)
    return None
```

### 7. Caching Tool Results

```python theme={null}
import hashlib
import json

tool_cache = {}

def cache_key(tool_name: str, tool_input: dict) -> str:
    """Generate cache key from tool name and input."""
    input_str = json.dumps(tool_input, sort_keys=True)
    return hashlib.md5(f"{tool_name}:{input_str}".encode()).hexdigest()

@before_tool_call
def check_cache(context: ToolCallHookContext) -> bool | None:
    key = cache_key(context.tool_name, context.tool_input)
    if key in tool_cache:
        print(f"💾 Cache hit for {context.tool_name}")
        # Note: Can't return cached result from before hook
        # Would need to implement this differently
    return None

@after_tool_call
def cache_result(context: ToolCallHookContext) -> None:
    if context.tool_result:
        key = cache_key(context.tool_name, context.tool_input)
        tool_cache[key] = context.tool_result
        print(f"💾 Cached result for {context.tool_name}")
    return None
```

### 8. Debug Logging

```python theme={null}
@before_tool_call
def debug_tool_call(context: ToolCallHookContext) -> None:
    print(f"""
    🔍 Tool Call Debug:
    - Tool: {context.tool_name}
    - Agent: {context.agent.role if context.agent else 'Unknown'}
    - Task: {context.task.description[:50] if context.task else 'Unknown'}...
    - Input: {context.tool_input}
    """)
    return None

@after_tool_call
def debug_tool_result(context: ToolCallHookContext) -> None:
    if context.tool_result:
        result_preview = context.tool_result[:200]
        print(f"✅ Result Preview: {result_preview}...")
    else:
        print("⚠️  No result returned")
    return None
```

## Hook Management

### Unregistering Hooks

```python theme={null}
from crewai.hooks import (
    unregister_before_tool_call_hook,
    unregister_after_tool_call_hook
)

# Unregister specific hook
def my_hook(context):
    ...

register_before_tool_call_hook(my_hook)
# Later...
success = unregister_before_tool_call_hook(my_hook)
print(f"Unregistered: {success}")
```

### Clearing Hooks

```python theme={null}
from crewai.hooks import (
    clear_before_tool_call_hooks,
    clear_after_tool_call_hooks,
    clear_all_tool_call_hooks
)

# Clear specific hook type
count = clear_before_tool_call_hooks()
print(f"Cleared {count} before hooks")

# Clear all tool hooks
before_count, after_count = clear_all_tool_call_hooks()
print(f"Cleared {before_count} before and {after_count} after hooks")
```

### Listing Registered Hooks

```python theme={null}
from crewai.hooks import (
    get_before_tool_call_hooks,
    get_after_tool_call_hooks
)

# Get current hooks
before_hooks = get_before_tool_call_hooks()
after_hooks = get_after_tool_call_hooks()

print(f"Registered: {len(before_hooks)} before, {len(after_hooks)} after")
```

## Advanced Patterns

### Conditional Hook Execution

```python theme={null}
@before_tool_call
def conditional_blocking(context: ToolCallHookContext) -> bool | None:
    # Only block for specific agents
    if context.agent and context.agent.role == "junior_agent":
        if context.tool_name in ['delete_file', 'send_email']:
            print(f"❌ Junior agents cannot use {context.tool_name}")
            return False

    # Only block during specific tasks
    if context.task and "sensitive" in context.task.description.lower():
        if context.tool_name == 'web_search':
            print("❌ Web search blocked for sensitive tasks")
            return False

    return None
```

### Context-Aware Input Modification

```python theme={null}
@before_tool_call
def enhance_tool_inputs(context: ToolCallHookContext) -> None:
    # Add context based on agent role
    if context.agent and context.agent.role == "researcher":
        if context.tool_name == 'web_search':
            # Add domain restrictions for researchers
            context.tool_input['domains'] = ['edu', 'gov', 'org']

    # Add context based on task
    if context.task and "urgent" in context.task.description.lower():
        if context.tool_name == 'send_email':
            context.tool_input['priority'] = 'high'

    return None
```

### Tool Chain Monitoring

```python theme={null}
tool_call_chain = []

@before_tool_call
def track_tool_chain(context: ToolCallHookContext) -> None:
    tool_call_chain.append({
        'tool': context.tool_name,
        'timestamp': time.time(),
        'agent': context.agent.role if context.agent else 'Unknown'
    })

    # Detect potential infinite loops
    recent_calls = tool_call_chain[-5:]
    if len(recent_calls) == 5 and all(c['tool'] == context.tool_name for c in recent_calls):
        print(f"⚠️  Warning: {context.tool_name} called 5 times in a row")

    return None
```

## Best Practices

1. **Keep Hooks Focused**: Each hook should have a single responsibility
2. **Avoid Heavy Computation**: Hooks execute on every tool call
3. **Handle Errors Gracefully**: Use try-except to prevent hook failures
4. **Use Type Hints**: Leverage `ToolCallHookContext` for better IDE support
5. **Document Blocking Conditions**: Make it clear when/why tools are blocked
6. **Test Hooks Independently**: Unit test hooks before using in production
7. **Clear Hooks in Tests**: Use `clear_all_tool_call_hooks()` between test runs
8. **Modify In-Place**: Always modify `context.tool_input` in-place, never replace
9. **Log Important Decisions**: Especially when blocking tool execution
10. **Consider Performance**: Cache expensive validations when possible

## Error Handling

```python theme={null}
@before_tool_call
def safe_validation(context: ToolCallHookContext) -> bool | None:
    try:
        # Your validation logic
        if not validate_input(context.tool_input):
            return False
    except Exception as e:
        print(f"⚠️ Hook error: {e}")
        # Decide: allow or block on error
        return None  # Allow execution despite error
```

## Type Safety

```python theme={null}
from crewai.hooks import ToolCallHookContext, BeforeToolCallHookType, AfterToolCallHookType

# Explicit type annotations
def my_before_hook(context: ToolCallHookContext) -> bool | None:
    return None

def my_after_hook(context: ToolCallHookContext) -> str | None:
    return None

# Type-safe registration
register_before_tool_call_hook(my_before_hook)
register_after_tool_call_hook(my_after_hook)
```

## Integration with Existing Tools

### Wrapping Existing Validation

```python theme={null}
def existing_validator(tool_name: str, inputs: dict) -> bool:
    """Your existing validation function."""
    # Your validation logic
    return True

@before_tool_call
def integrate_validator(context: ToolCallHookContext) -> bool | None:
    if not existing_validator(context.tool_name, context.tool_input):
        print(f"❌ Validation failed for {context.tool_name}")
        return False
    return None
```

### Logging to External Systems

```python theme={null}
import logging

logger = logging.getLogger(__name__)

@before_tool_call
def log_to_external_system(context: ToolCallHookContext) -> None:
    logger.info(f"Tool call: {context.tool_name}", extra={
        'tool_name': context.tool_name,
        'tool_input': context.tool_input,
        'agent': context.agent.role if context.agent else None
    })
    return None
```

## Troubleshooting

### Hook Not Executing

* Verify hook is registered before crew execution
* Check if previous hook returned `False` (blocks execution and subsequent hooks)
* Ensure hook signature matches expected type

### Input Modifications Not Working

* Use in-place modifications: `context.tool_input['key'] = value`
* Don't replace the dict: `context.tool_input = {}`

### Result Modifications Not Working

* Return the modified string from after hooks
* Returning `None` keeps the original result
* Ensure the tool actually returned a result

### Tool Blocked Unexpectedly

* Check all before hooks for blocking conditions
* Verify hook execution order
* Add debug logging to identify which hook is blocking

## Conclusion

Tool Call Hooks provide powerful capabilities for controlling and monitoring tool execution in CrewAI. Use them to implement safety guardrails, approval gates, input validation, result sanitization, logging, and analytics. Combined with proper error handling and type safety, hooks enable secure and production-ready agent systems with comprehensive observability.


# Using Annotations in crew.py
Source: https://docs.crewai.com/en/learn/using-annotations

Learn how to use annotations to properly structure agents, tasks, and components in CrewAI

This guide explains how to use annotations to properly reference **agents**, **tasks**, and other components in the `crew.py` file.

## Introduction

Annotations in the CrewAI framework are used to decorate classes and methods, providing metadata and functionality to various components of your crew. These annotations help in organizing and structuring your code, making it more readable and maintainable.

## Available Annotations

The CrewAI framework provides the following annotations:

* `@CrewBase`: Used to decorate the main crew class.
* `@agent`: Decorates methods that define and return Agent objects.
* `@task`: Decorates methods that define and return Task objects.
* `@crew`: Decorates the method that creates and returns the Crew object.
* `@llm`: Decorates methods that initialize and return Language Model objects.
* `@tool`: Decorates methods that initialize and return Tool objects.
* `@callback`: Used for defining callback methods.
* `@output_json`: Used for methods that output JSON data.
* `@output_pydantic`: Used for methods that output Pydantic models.
* `@cache_handler`: Used for defining cache handling methods.

## Usage Examples

Let's go through examples of how to use these annotations:

### 1. Crew Base Class

```python theme={null}
@CrewBase
class LinkedinProfileCrew():
    """LinkedinProfile crew"""
    agents_config = 'config/agents.yaml'
    tasks_config = 'config/tasks.yaml'
```

The `@CrewBase` annotation is used to decorate the main crew class. This class typically contains configurations and methods for creating agents, tasks, and the crew itself.

<Tip>
  `@CrewBase` does more than register the class:

  * **Configuration bootstrapping:** looks for `agents_config` and `tasks_config` (defaulting to `config/agents.yaml` and `config/tasks.yaml`) beside the class file, loads them at instantiation, and safely falls back to empty dicts if files are missing.
  * **Decorator orchestration:** keeps memoized references to every method marked with `@agent`, `@task`, `@before_kickoff`, or `@after_kickoff` so they are instantiated once per crew and executed in declaration order.
  * **Hook wiring:** automatically attaches the preserved kickoff hooks to the `Crew` object returned by the `@crew` method, making them run before and after `.kickoff()`.
  * **MCP integration:** when the class defines `mcp_server_params`, `get_mcp_tools()` lazily starts an MCP server adapter, hydrates the declared tools, and an internal after-kickoff hook stops the adapter. See [MCP overview](/en/mcp/overview) for adapter configuration details.
</Tip>

### 2. Tool Definition

```python theme={null}
@tool
def myLinkedInProfileTool(self):
    return LinkedInProfileTool()
```

The `@tool` annotation is used to decorate methods that return tool objects. These tools can be used by agents to perform specific tasks.

### 3. LLM Definition

```python theme={null}
@llm
def groq_llm(self):
    api_key = os.getenv('api_key')
    return ChatGroq(api_key=api_key, temperature=0, model_name="mixtral-8x7b-32768")
```

The `@llm` annotation is used to decorate methods that initialize and return Language Model objects. These LLMs are used by agents for natural language processing tasks.

### 4. Agent Definition

```python theme={null}
@agent
def researcher(self) -> Agent:
    return Agent(
        config=self.agents_config['researcher']
    )
```

The `@agent` annotation is used to decorate methods that define and return Agent objects.

### 5. Task Definition

```python theme={null}
@task
def research_task(self) -> Task:
    return Task(
        config=self.tasks_config['research_linkedin_task'],
        agent=self.researcher()
    )
```

The `@task` annotation is used to decorate methods that define and return Task objects. These methods specify the task configuration and the agent responsible for the task.

### 6. Crew Creation

```python theme={null}
@crew
def crew(self) -> Crew:
    """Creates the LinkedinProfile crew"""
    return Crew(
        agents=self.agents,
        tasks=self.tasks,
        process=Process.sequential,
        verbose=True
    )
```

The `@crew` annotation is used to decorate the method that creates and returns the `Crew` object. This method assembles all the components (agents and tasks) into a functional crew.

## YAML Configuration

The agent configurations are typically stored in a YAML file. Here's an example of how the `agents.yaml` file might look for the researcher agent:

```yaml theme={null}
researcher:
    role: >
        LinkedIn Profile Senior Data Researcher
    goal: >
        Uncover detailed LinkedIn profiles based on provided name {name} and domain {domain}
        Generate a Dall-E image based on domain {domain}
    backstory: >
        You're a seasoned researcher with a knack for uncovering the most relevant LinkedIn profiles.
        Known for your ability to navigate LinkedIn efficiently, you excel at gathering and presenting
        professional information clearly and concisely.
    allow_delegation: False
    verbose: True
    llm: groq_llm
    tools:
        - myLinkedInProfileTool
        - mySerperDevTool
        - myDallETool
```

This YAML configuration corresponds to the researcher agent defined in the `LinkedinProfileCrew` class. The configuration specifies the agent's role, goal, backstory, and other properties such as the LLM and tools it uses.

Note how the `llm` and `tools` in the YAML file correspond to the methods decorated with `@llm` and `@tool` in the Python class.

## Best Practices

* **Consistent Naming**: Use clear and consistent naming conventions for your methods. For example, agent methods could be named after their roles (e.g., researcher, reporting\_analyst).
* **Environment Variables**: Use environment variables for sensitive information like API keys.
* **Flexibility**: Design your crew to be flexible by allowing easy addition or removal of agents and tasks.
* **YAML-Code Correspondence**: Ensure that the names and structures in your YAML files correspond correctly to the decorated methods in your Python code.

By following these guidelines and properly using annotations, you can create well-structured and maintainable crews using the CrewAI framework.


# Arize Phoenix
Source: https://docs.crewai.com/en/observability/arize-phoenix

Arize Phoenix integration for CrewAI with OpenTelemetry and OpenInference

# Arize Phoenix Integration

This guide demonstrates how to integrate **Arize Phoenix** with **CrewAI** using OpenTelemetry via the [OpenInference](https://github.com/openinference/openinference) SDK. By the end of this guide, you will be able to trace your CrewAI agents and easily debug your agents.

> **What is Arize Phoenix?** [Arize Phoenix](https://phoenix.arize.com) is an LLM observability platform that provides tracing and evaluation for AI applications.

[![Watch a Video Demo of Our Integration with Phoenix](https://storage.googleapis.com/arize-assets/fixtures/setup_crewai.png)](https://www.youtube.com/watch?v=Yc5q3l6F7Ww)

## Get Started

We'll walk through a simple example of using CrewAI and integrating it with Arize Phoenix via OpenTelemetry using OpenInference.

You can also access this guide on [Google Colab](https://colab.research.google.com/github/Arize-ai/phoenix/blob/main/tutorials/tracing/crewai_tracing_tutorial.ipynb).

### Step 1: Install Dependencies

```bash theme={null}
pip install openinference-instrumentation-crewai crewai crewai-tools arize-phoenix-otel
```

### Step 2: Set Up Environment Variables

Setup Phoenix Cloud API keys and configure OpenTelemetry to send traces to Phoenix. Phoenix Cloud is a hosted version of Arize Phoenix, but it is not required to use this integration.

You can get your free Serper API key [here](https://serper.dev/).

```python theme={null}
import os
from getpass import getpass

# Get your Phoenix Cloud credentials
PHOENIX_API_KEY = getpass("🔑 Enter your Phoenix Cloud API Key: ")

# Get API keys for services
OPENAI_API_KEY = getpass("🔑 Enter your OpenAI API key: ")
SERPER_API_KEY = getpass("🔑 Enter your Serper API key: ")

# Set environment variables
os.environ["PHOENIX_CLIENT_HEADERS"] = f"api_key={PHOENIX_API_KEY}"
os.environ["PHOENIX_COLLECTOR_ENDPOINT"] = "https://app.phoenix.arize.com" # Phoenix Cloud, change this to your own endpoint if you are using a self-hosted instance
os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
os.environ["SERPER_API_KEY"] = SERPER_API_KEY
```

### Step 3: Initialize OpenTelemetry with Phoenix

Initialize the OpenInference OpenTelemetry instrumentation SDK to start capturing traces and send them to Phoenix.

```python theme={null}
from phoenix.otel import register

tracer_provider = register(
    project_name="crewai-tracing-demo",
    auto_instrument=True,
)
```

### Step 4: Create a CrewAI Application

We'll create a CrewAI application where two agents collaborate to research and write a blog post about AI advancements.

```python theme={null}
from crewai import Agent, Crew, Process, Task
from crewai_tools import SerperDevTool
from openinference.instrumentation.crewai import CrewAIInstrumentor
from phoenix.otel import register

# setup monitoring for your crew
tracer_provider = register(
    endpoint="http://localhost:6006/v1/traces")
CrewAIInstrumentor().instrument(skip_dep_check=True, tracer_provider=tracer_provider)
search_tool = SerperDevTool()

# Define your agents with roles and goals
researcher = Agent(
    role="Senior Research Analyst",
    goal="Uncover cutting-edge developments in AI and data science",
    backstory="""You work at a leading tech think tank.
    Your expertise lies in identifying emerging trends.
    You have a knack for dissecting complex data and presenting actionable insights.""",
    verbose=True,
    allow_delegation=False,
    # You can pass an optional llm attribute specifying what model you wanna use.
    # llm=ChatOpenAI(model_name="gpt-3.5", temperature=0.7),
    tools=[search_tool],
)
writer = Agent(
    role="Tech Content Strategist",
    goal="Craft compelling content on tech advancements",
    backstory="""You are a renowned Content Strategist, known for your insightful and engaging articles.
    You transform complex concepts into compelling narratives.""",
    verbose=True,
    allow_delegation=True,
)

# Create tasks for your agents
task1 = Task(
    description="""Conduct a comprehensive analysis of the latest advancements in AI in 2024.
    Identify key trends, breakthrough technologies, and potential industry impacts.""",
    expected_output="Full analysis report in bullet points",
    agent=researcher,
)

task2 = Task(
    description="""Using the insights provided, develop an engaging blog
    post that highlights the most significant AI advancements.
    Your post should be informative yet accessible, catering to a tech-savvy audience.
    Make it sound cool, avoid complex words so it doesn't sound like AI.""",
    expected_output="Full blog post of at least 4 paragraphs",
    agent=writer,
)

# Instantiate your crew with a sequential process
crew = Crew(
    agents=[researcher, writer], tasks=[task1, task2], verbose=1, process=Process.sequential
)

# Get your crew to work!
result = crew.kickoff()

print("######################")
print(result)
```

### Step 5: View Traces in Phoenix

After running the agent, you can view the traces generated by your CrewAI application in Phoenix. You should see detailed steps of the agent interactions and LLM calls, which can help you debug and optimize your AI agents.

Log into your Phoenix Cloud account and navigate to the project you specified in the `project_name` parameter. You'll see a timeline view of your trace with all the agent interactions, tool usages, and LLM calls.

![Example trace in Phoenix showing agent interactions](https://storage.googleapis.com/arize-assets/fixtures/crewai_traces.png)

### Version Compatibility Information

* Python 3.8+
* CrewAI >= 0.86.0
* Arize Phoenix >= 7.0.1
* OpenTelemetry SDK >= 1.31.0

### References

* [Phoenix Documentation](https://docs.arize.com/phoenix/) - Overview of the Phoenix platform.
* [CrewAI Documentation](https://docs.crewai.com/) - Overview of the CrewAI framework.
* [OpenTelemetry Docs](https://opentelemetry.io/docs/) - OpenTelemetry guide
* [OpenInference GitHub](https://github.com/openinference/openinference) - Source code for OpenInference SDK.


# Braintrust
Source: https://docs.crewai.com/en/observability/braintrust

Braintrust integration for CrewAI with OpenTelemetry tracing and evaluation

# Braintrust Integration

This guide demonstrates how to integrate **Braintrust** with **CrewAI** using OpenTelemetry for comprehensive tracing and evaluation. By the end of this guide, you will be able to trace your CrewAI agents, monitor their performance, and evaluate their outputs using Braintrust's powerful observability platform.

> **What is Braintrust?** [Braintrust](https://www.braintrust.dev) is an AI evaluation and observability platform that provides comprehensive tracing, evaluation, and monitoring for AI applications with built-in experiment tracking and performance analytics.

## Get Started

We'll walk through a simple example of using CrewAI and integrating it with Braintrust via OpenTelemetry for comprehensive observability and evaluation.

### Step 1: Install Dependencies

```bash theme={null}
uv add braintrust[otel] crewai crewai-tools opentelemetry-instrumentation-openai opentelemetry-instrumentation-crewai python-dotenv
```

### Step 2: Set Up Environment Variables

Setup Braintrust API keys and configure OpenTelemetry to send traces to Braintrust. You'll need a Braintrust API key and your OpenAI API key.

```python theme={null}
import os
from getpass import getpass

# Get your Braintrust credentials
BRAINTRUST_API_KEY = getpass("🔑 Enter your Braintrust API Key: ")

# Get API keys for services
OPENAI_API_KEY = getpass("🔑 Enter your OpenAI API key: ")

# Set environment variables
os.environ["BRAINTRUST_API_KEY"] = BRAINTRUST_API_KEY
os.environ["BRAINTRUST_PARENT"] = "project_name:crewai-demo"
os.environ["OPENAI_API_KEY"] = OPENAI_API_KEY
```

### Step 3: Initialize OpenTelemetry with Braintrust

Initialize the Braintrust OpenTelemetry instrumentation to start capturing traces and send them to Braintrust.

```python theme={null}
import os
from typing import Any, Dict

from braintrust.otel import BraintrustSpanProcessor
from crewai import Agent, Crew, Task
from crewai.llm import LLM
from opentelemetry import trace
from opentelemetry.instrumentation.crewai import CrewAIInstrumentor
from opentelemetry.instrumentation.openai import OpenAIInstrumentor
from opentelemetry.sdk.trace import TracerProvider

def setup_tracing() -> None:
    """Setup OpenTelemetry tracing with Braintrust."""
    current_provider = trace.get_tracer_provider()
    if isinstance(current_provider, TracerProvider):
        provider = current_provider
    else:
        provider = TracerProvider()
        trace.set_tracer_provider(provider)

    provider.add_span_processor(BraintrustSpanProcessor())
    CrewAIInstrumentor().instrument(tracer_provider=provider)
    OpenAIInstrumentor().instrument(tracer_provider=provider)


setup_tracing()
```

### Step 4: Create a CrewAI Application

We'll create a CrewAI application where two agents collaborate to research and write a blog post about AI advancements, with comprehensive tracing enabled.

```python theme={null}
from crewai import Agent, Crew, Process, Task
from crewai_tools import SerperDevTool

def create_crew() -> Crew:
    """Create a crew with multiple agents for comprehensive tracing."""
    llm = LLM(model="gpt-4o-mini")
    search_tool = SerperDevTool()

    # Define agents with specific roles
    researcher = Agent(
        role="Senior Research Analyst",
        goal="Uncover cutting-edge developments in AI and data science",
        backstory="""You work at a leading tech think tank.
        Your expertise lies in identifying emerging trends.
        You have a knack for dissecting complex data and presenting actionable insights.""",
        verbose=True,
        allow_delegation=False,
        llm=llm,
        tools=[search_tool],
    )

    writer = Agent(
        role="Tech Content Strategist",
        goal="Craft compelling content on tech advancements",
        backstory="""You are a renowned Content Strategist, known for your insightful and engaging articles.
        You transform complex concepts into compelling narratives.""",
        verbose=True,
        allow_delegation=True,
        llm=llm,
    )

    # Create tasks for your agents
    research_task = Task(
        description="""Conduct a comprehensive analysis of the latest advancements in {topic}.
        Identify key trends, breakthrough technologies, and potential industry impacts.""",
        expected_output="Full analysis report in bullet points",
        agent=researcher,
    )

    writing_task = Task(
        description="""Using the insights provided, develop an engaging blog
        post that highlights the most significant {topic} advancements.
        Your post should be informative yet accessible, catering to a tech-savvy audience.
        Make it sound cool, avoid complex words so it doesn't sound like AI.""",
        expected_output="Full blog post of at least 4 paragraphs",
        agent=writer,
        context=[research_task],
    )

    # Instantiate your crew with a sequential process
    crew = Crew(
        agents=[researcher, writer], 
        tasks=[research_task, writing_task], 
        verbose=True, 
        process=Process.sequential
    )

    return crew

def run_crew():
    """Run the crew and return results."""
    crew = create_crew()
    result = crew.kickoff(inputs={"topic": "AI developments"})
    return result

# Run your crew
if __name__ == "__main__":
    # Instrumentation is already initialized above in this module
    result = run_crew()
    print(result)
```

### Step 5: View Traces in Braintrust

After running your crew, you can view comprehensive traces in Braintrust through different perspectives:

<Tabs>
  <Tab title="Trace">
    <Frame>
      <img alt="Braintrust Trace View" />
    </Frame>
  </Tab>

  <Tab title="Timeline">
    <Frame>
      <img alt="Braintrust Timeline View" />
    </Frame>
  </Tab>

  <Tab title="Thread">
    <Frame>
      <img alt="Braintrust Thread View" />
    </Frame>
  </Tab>
</Tabs>

### Step 6: Evaluate via SDK (Experiments)

You can also run evaluations using Braintrust's Eval SDK. This is useful for comparing versions or scoring outputs offline. Below is a Python example using the `Eval` class with the crew we created above:

```python theme={null}
# eval_crew.py
from braintrust import Eval
from autoevals import Levenshtein

def evaluate_crew_task(input_data):
    """Task function that wraps our crew for evaluation."""
    crew = create_crew()
    result = crew.kickoff(inputs={"topic": input_data["topic"]})
    return str(result)

Eval(
    "AI Research Crew",  # Project name
    {
        "data": lambda: [
            {"topic": "artificial intelligence trends 2024"},
            {"topic": "machine learning breakthroughs"},
            {"topic": "AI ethics and governance"},
        ],
        "task": evaluate_crew_task,
        "scores": [Levenshtein],
    },
)
```

Setup your API key and run:

```bash theme={null}
export BRAINTRUST_API_KEY="YOUR_API_KEY"
braintrust eval eval_crew.py
```

See the [Braintrust Eval SDK guide](https://www.braintrust.dev/docs/start/eval-sdk) for more details.

### Key Features of Braintrust Integration

* **Comprehensive Tracing**: Track all agent interactions, tool usage, and LLM calls
* **Performance Monitoring**: Monitor execution times, token usage, and success rates
* **Experiment Tracking**: Compare different crew configurations and models
* **Automated Evaluation**: Set up custom evaluation metrics for crew outputs
* **Error Tracking**: Monitor and debug failures across your crew executions
* **Cost Analysis**: Track token usage and associated costs

### Version Compatibility Information

* Python 3.8+
* CrewAI >= 0.86.0
* Braintrust >= 0.1.0
* OpenTelemetry SDK >= 1.31.0

### References

* [Braintrust Documentation](https://www.braintrust.dev/docs) - Overview of the Braintrust platform
* [Braintrust CrewAI Integration](https://www.braintrust.dev/docs/integrations/crew-ai) - Official CrewAI integration guide
* [Braintrust Eval SDK](https://www.braintrust.dev/docs/start/eval-sdk) - Run experiments via the SDK
* [CrewAI Documentation](https://docs.crewai.com/) - Overview of the CrewAI framework
* [OpenTelemetry Docs](https://opentelemetry.io/docs/) - OpenTelemetry guide
* [Braintrust GitHub](https://github.com/braintrustdata/braintrust) - Source code for Braintrust SDK


# Datadog Integration
Source: https://docs.crewai.com/en/observability/datadog

Learn how to integrate Datadog with CrewAI to submit LLM Observability traces to Datadog.

# Integrate Datadog with CrewAI

This guide will demonstrate how to integrate **[Datadog LLM Observability](https://docs.datadoghq.com/llm_observability/)** with **CrewAI** using [Datadog auto-instrumentation](https://docs.datadoghq.com/llm_observability/instrumentation/auto_instrumentation?tab=python). By the end of this guide, you will be able to submit LLM Observability traces to Datadog and view your CrewAI agent runs in Datadog LLM Observability's [Agentic Execution View](https://docs.datadoghq.com/llm_observability/monitoring/agent_monitoring).

## What is Datadog LLM Observability?

[Datadog LLM Observability](https://www.datadoghq.com/product/llm-observability/) helps AI engineers, data scientists, and application developers quickly develop, evaluate, and monitor LLM applications. Confidently improve output quality, performance, costs, and overall risk with structured experiments, end-to-end tracing across AI agents, and evaluations.

## Getting Started

### Install Dependencies

```shell theme={null}
pip install ddtrace crewai crewai-tools
```

### Set Environment Variables

If you do not have a Datadog API key, you can [create an account](https://www.datadoghq.com/) and [get your API key](https://docs.datadoghq.com/account_management/api-app-keys/#api-keys).

You will also need to specify an ML Application name in the following environment variables. An ML Application is a grouping of LLM Observability traces associated with a specific LLM-based application. See [ML Application Naming Guidelines](https://docs.datadoghq.com/llm_observability/instrumentation/sdk?tab=python#application-naming-guidelines) for more information on limitations with ML Application names.

```shell theme={null}
export DD_API_KEY=<YOUR_DD_API_KEY>
export DD_SITE=<YOUR_DD_SITE>
export DD_LLMOBS_ENABLED=true
export DD_LLMOBS_ML_APP=<YOUR_ML_APP_NAME>
export DD_LLMOBS_AGENTLESS_ENABLED=true
export DD_APM_TRACING_ENABLED=false
```

Additionally, configure any LLM provider API keys

```shell theme={null}
export OPENAI_API_KEY=<YOUR_OPENAI_API_KEY>
export ANTHROPIC_API_KEY=<YOUR_ANTHROPIC_API_KEY>
export GEMINI_API_KEY=<YOUR_GEMINI_API_KEY>
...
```

### Create a CrewAI Agent Application

```python theme={null}
# crewai_agent.py
from crewai import Agent, Task, Crew

from crewai_tools import (
    WebsiteSearchTool
)

web_rag_tool = WebsiteSearchTool()

writer = Agent(
    role="Writer",
    goal="You make math engaging and understandable for young children through poetry",
    backstory="You're an expert in writing haikus but you know nothing of math.",
    tools=[web_rag_tool],
)

task = Task(
    description=("What is {multiplication}?"),
    expected_output=("Compose a haiku that includes the answer."),
    agent=writer
)

crew = Crew(
    agents=[writer],
    tasks=[task],
    share_crew=False
)

output = crew.kickoff(dict(multiplication="2 * 2"))
```

### Run the Application with Datadog Auto-Instrumentation

With the [environment variables](#set-environment-variables) set, you can now run the application with Datadog auto-instrumentation.

```shell theme={null}
ddtrace-run python crewai_agent.py
```

### View the Traces in Datadog

After running the application, you can view the traces in [Datadog LLM Observability's Traces View](https://app.datadoghq.com/llm/traces), selecting the ML Application name you chose from the top-left dropdown.

Clicking on a trace will show you the details of the trace, including total tokens used, number of LLM calls, models used, and estimated cost. Clicking into a specific span will narrow down these details, and show related input, output, and metadata.

<Frame>
  <img alt="Datadog LLM Observability Trace View" />
</Frame>

Additionally, you can view the execution graph view of the trace, which shows the control and data flow of the trace, which will scale with larger agents to show handoffs and relationships between LLM calls, tool calls, and agent interactions.

<Frame>
  <img alt="Datadog LLM Observability Agent Execution Flow View" />
</Frame>

## References

* [Datadog LLM Observability](https://www.datadoghq.com/product/llm-observability/)
* [Datadog LLM Observability CrewAI Auto-Instrumentation](https://docs.datadoghq.com/llm_observability/instrumentation/auto_instrumentation?tab=python#crew-ai)


# Galileo
Source: https://docs.crewai.com/en/observability/galileo

Galileo integration for CrewAI tracing and evaluation

## Overview

This guide demonstrates how to integrate **Galileo** with **CrewAI**
for comprehensive tracing and Evaluation Engineering.
By the end of this guide, you will be able to trace your CrewAI agents,
monitor their performance, and evaluate their behaviour with
Galileo's powerful observability platform.

> **What is Galileo?** [Galileo](https://galileo.ai) is AI evaluation and observability
> platform that delivers end-to-end tracing, evaluation,
> and monitoring for AI applications. It enables teams to capture ground truth,
> create robust guardrails, and run systematic experiments with
> built-in experiment tracking and performance analytics—ensuring reliability,
> transparency, and continuous improvement across the AI lifecycle.

## Getting started

This tutorial follows the [CrewAI quickstart](/en/quickstart) and shows how to add
Galileo's [CrewAIEventListener](https://v2docs.galileo.ai/sdk-api/python/reference/handlers/crewai/handler),
an event handler.
For more information, see Galileo’s
[Add Galileo to a CrewAI Application](https://v2docs.galileo.ai/how-to-guides/third-party-integrations/add-galileo-to-crewai/add-galileo-to-crewai)
how-to guide.

> **Note** This tutorial assumes you have completed the [CrewAI quickstart](/en/quickstart).
> If you want a completed comprehensive example, see the Galileo
> [CrewAI sdk-example repo](https://github.com/rungalileo/sdk-examples/tree/main/python/agent/crew-ai).

### Step 1: Install dependencies

Install the required dependencies for your app.
Create a virtual environment using your preferred method,
then install dependencies inside that environment using your
preferred tool:

```bash theme={null}
uv add galileo 
```

### Step 2: Add to the .env file from the [CrewAI quickstart](/en/quickstart)

```bash theme={null}
# Your Galileo API key
GALILEO_API_KEY="your-galileo-api-key"

# Your Galileo project name
GALILEO_PROJECT="your-galileo-project-name"

# The name of the Log stream you want to use for logging
GALILEO_LOG_STREAM="your-galileo-log-stream "
```

### Step 3: Add the Galileo event listener

To enable logging with Galileo, you need to create an instance of the `CrewAIEventListener`.
Import the Galileo CrewAI handler package by
adding the following code at the top of your main.py file:

```python theme={null}
from galileo.handlers.crewai.handler import CrewAIEventListener
```

At the start of your run function, create the event listener:

```python theme={null}
def run():
    # Create the event listener
    CrewAIEventListener()
    # The rest of your existing code goes here
```

When you create the listener instance, it is automatically
registered with CrewAI.

### Step 4: Run your crew

Run your crew with the CrewAI CLI:

```bash theme={null}
crewai run
```

### Step 5: View the traces in Galileo

Once your crew has finished, the traces will be flushed and appear in Galileo.

<img alt="Galileo trace view" />

## Understanding the Galileo Integration

Galileo integrates with CrewAI by registering an event listener
that captures Crew execution events (e.g., agent actions, tool calls, model responses)
and forwards them to Galileo for observability and evaluation.

### Understanding the event listener

Creating a `CrewAIEventListener()` instance is all that’s
required to enable Galileo for a CrewAI run. When instantiated, the listener:

* Automatically registers itself with CrewAI
* Reads Galileo configuration from environment variables
* Logs all run data to the Galileo project and log stream specified by
  `GALILEO_PROJECT` and `GALILEO_LOG_STREAM`

No additional configuration or code changes are required.
All data from this run is logged to the Galileo project and
log stream specified by your environment configuration
(for example, GALILEO\_PROJECT and GALILEO\_LOG\_STREAM).


# LangDB Integration
Source: https://docs.crewai.com/en/observability/langdb

Govern, secure, and optimize your CrewAI workflows with LangDB AI Gateway—access 350+ models, automatic routing, cost optimization, and full observability.

# Introduction

[LangDB AI Gateway](https://langdb.ai) provides OpenAI-compatible APIs to connect with multiple Large Language Models and serves as an observability platform that makes it effortless to trace CrewAI workflows end-to-end while providing access to 350+ language models. With a single `init()` call, all agent interactions, task executions, and LLM calls are captured, providing comprehensive observability and production-ready AI infrastructure for your applications.

<Frame>
  <img alt="LangDB CrewAI trace example" />
</Frame>

**Checkout:** [View the live trace example](https://app.langdb.ai/sharing/threads/3becbfed-a1be-ae84-ea3c-4942867a3e22)

## Features

### AI Gateway Capabilities

* **Access to 350+ LLMs**: Connect to all major language models through a single integration
* **Virtual Models**: Create custom model configurations with specific parameters and routing rules
* **Virtual MCP**: Enable compatibility and integration with MCP (Model Context Protocol) systems for enhanced agent communication
* **Guardrails**: Implement safety measures and compliance controls for agent behavior

### Observability & Tracing

* **Automatic Tracing**: Single `init()` call captures all CrewAI interactions
* **End-to-End Visibility**: Monitor agent workflows from start to finish
* **Tool Usage Tracking**: Track which tools agents use and their outcomes
* **Model Call Monitoring**: Detailed insights into LLM interactions
* **Performance Analytics**: Monitor latency, token usage, and costs
* **Debugging Support**: Step-through execution for troubleshooting
* **Real-time Monitoring**: Live traces and metrics dashboard

## Setup Instructions

<Steps>
  <Step title="Install LangDB">
    Install the LangDB client with CrewAI feature flag:

    ```bash theme={null}
    pip install 'pylangdb[crewai]'
    ```
  </Step>

  <Step title="Set Environment Variables">
    Configure your LangDB credentials:

    ```bash theme={null}
    export LANGDB_API_KEY="<your_langdb_api_key>"
    export LANGDB_PROJECT_ID="<your_langdb_project_id>"
    export LANGDB_API_BASE_URL='https://api.us-east-1.langdb.ai'
    ```
  </Step>

  <Step title="Initialize Tracing">
    Import and initialize LangDB before configuring your CrewAI code:

    ```python theme={null}
    from pylangdb.crewai import init
    # Initialize LangDB
    init()
    ```
  </Step>

  <Step title="Configure CrewAI with LangDB">
    Set up your LLM with LangDB headers:

    ```python theme={null}
    from crewai import Agent, Task, Crew, LLM
    import os

    # Configure LLM with LangDB headers
    llm = LLM(
        model="openai/gpt-4o", # Replace with the model you want to use
        api_key=os.getenv("LANGDB_API_KEY"),
        base_url=os.getenv("LANGDB_API_BASE_URL"),
        extra_headers={"x-project-id": os.getenv("LANGDB_PROJECT_ID")}
    )
    ```
  </Step>
</Steps>

## Quick Start Example

Here's a simple example to get you started with LangDB and CrewAI:

```python theme={null}
import os
from pylangdb.crewai import init
from crewai import Agent, Task, Crew, LLM

# Initialize LangDB before any CrewAI imports
init()

def create_llm(model):
    return LLM(
        model=model,
        api_key=os.environ.get("LANGDB_API_KEY"),
        base_url=os.environ.get("LANGDB_API_BASE_URL"),
        extra_headers={"x-project-id": os.environ.get("LANGDB_PROJECT_ID")}
    )

# Define your agent
researcher = Agent(
    role="Research Specialist",
    goal="Research topics thoroughly",
    backstory="Expert researcher with skills in finding information",
    llm=create_llm("openai/gpt-4o"), # Replace with the model you want to use
    verbose=True
)

# Create a task
task = Task(
    description="Research the given topic and provide a comprehensive summary",
    agent=researcher,
    expected_output="Detailed research summary with key findings"
)

# Create and run the crew
crew = Crew(agents=[researcher], tasks=[task])
result = crew.kickoff()
print(result)
```

## Complete Example: Research and Planning Agent

This comprehensive example demonstrates a multi-agent workflow with research and planning capabilities.

### Prerequisites

```bash theme={null}
pip install crewai 'pylangdb[crewai]' crewai_tools setuptools python-dotenv
```

### Environment Setup

```bash theme={null}
# LangDB credentials
export LANGDB_API_KEY="<your_langdb_api_key>"
export LANGDB_PROJECT_ID="<your_langdb_project_id>"
export LANGDB_API_BASE_URL='https://api.us-east-1.langdb.ai'

# Additional API keys (optional)
export SERPER_API_KEY="<your_serper_api_key>"  # For web search capabilities
```

### Complete Implementation

```python theme={null}
#!/usr/bin/env python3

import os
import sys
from pylangdb.crewai import init
init()  # Initialize LangDB before any CrewAI imports
from dotenv import load_dotenv
from crewai import Agent, Task, Crew, Process, LLM
from crewai_tools import SerperDevTool

load_dotenv()

def create_llm(model):
    return LLM(
        model=model,
        api_key=os.environ.get("LANGDB_API_KEY"),
        base_url=os.environ.get("LANGDB_API_BASE_URL"),
        extra_headers={"x-project-id": os.environ.get("LANGDB_PROJECT_ID")}
    )

class ResearchPlanningCrew:
    def researcher(self) -> Agent:
        return Agent(
            role="Research Specialist",
            goal="Research topics thoroughly and compile comprehensive information",
            backstory="Expert researcher with skills in finding and analyzing information from various sources",
            tools=[SerperDevTool()],
            llm=create_llm("openai/gpt-4o"),
            verbose=True
        )
    
    def planner(self) -> Agent:
        return Agent(
            role="Strategic Planner",
            goal="Create actionable plans based on research findings",
            backstory="Strategic planner who breaks down complex challenges into executable plans",
            reasoning=True,
            max_reasoning_attempts=3,
            llm=create_llm("openai/anthropic/claude-3.7-sonnet"),
            verbose=True
        )
    
    def research_task(self) -> Task:
        return Task(
            description="Research the topic thoroughly and compile comprehensive information",
            agent=self.researcher(),
            expected_output="Comprehensive research report with key findings and insights"
        )
    
    def planning_task(self) -> Task:
        return Task(
            description="Create a strategic plan based on the research findings",
            agent=self.planner(),
            expected_output="Strategic execution plan with phases, goals, and actionable steps",
            context=[self.research_task()]
        )
    
    def crew(self) -> Crew:
        return Crew(
            agents=[self.researcher(), self.planner()],
            tasks=[self.research_task(), self.planning_task()],
            verbose=True,
            process=Process.sequential
        )

def main():
        topic = sys.argv[1] if len(sys.argv) > 1 else "Artificial Intelligence in Healthcare"
        
        crew_instance = ResearchPlanningCrew()
        
        # Update task descriptions with the specific topic
        crew_instance.research_task().description = f"Research {topic} thoroughly and compile comprehensive information"
    crew_instance.planning_task().description = f"Create a strategic plan for {topic} based on the research findings"
    
    result = crew_instance.crew().kickoff()
    print(result)

if __name__ == "__main__":
    main()
```

### Running the Example

```bash theme={null}
python main.py "Sustainable Energy Solutions"
```

## Viewing Traces in LangDB

After running your CrewAI application, you can view detailed traces in the LangDB dashboard:

<Frame>
  <img alt="LangDB trace dashboard showing CrewAI workflow" />
</Frame>

### What You'll See

* **Agent Interactions**: Complete flow of agent conversations and task handoffs
* **Tool Usage**: Which tools were called, their inputs, and outputs
* **Model Calls**: Detailed LLM interactions with prompts image.pngand responses
* **Performance Metrics**: Latency, token usage, and cost tracking
* **Execution Timeline**: Step-by-step view of the entire workflow

## Troubleshooting

### Common Issues

* **No traces appearing**: Ensure `init()` is called before any CrewAI imports
* **Authentication errors**: Verify your LangDB API key and project ID

## Resources

<CardGroup>
  <Card title="LangDB Documentation" icon="book" href="https://docs.langdb.ai">
    Official LangDB documentation and guides
  </Card>

  <Card title="LangDB Guides" icon="graduation-cap" href="https://docs.langdb.ai/guides">
    Step-by-step tutorials for building AI agents
  </Card>

  <Card title="GitHub Examples" icon="github" href="https://github.com/langdb/langdb-samples/tree/main/examples/crewai">
    Complete CrewAI integration examples
  </Card>

  <Card title="LangDB Dashboard" icon="chart-line" href="https://app.langdb.ai">
    Access your traces and analytics
  </Card>

  <Card title="Model Catalog" icon="list" href="https://app.langdb.ai/models">
    Browse 350+ available language models
  </Card>

  <Card title="Enterprise Features" icon="building" href="https://docs.langdb.ai/enterprise">
    Self-hosted options and enterprise capabilities
  </Card>
</CardGroup>

## Next Steps

This guide covered the basics of integrating LangDB AI Gateway with CrewAI. To further enhance your AI workflows, explore:

* **Virtual Models**: Create custom model configurations with routing strategies
* **Guardrails & Safety**: Implement content filtering and compliance controls
* **Production Deployment**: Configure fallbacks, retries, and load balancing

For more advanced features and use cases, visit the [LangDB Documentation](https://docs.langdb.ai) or explore the [Model Catalog](https://app.langdb.ai/models) to discover all available models.


# Langfuse Integration
Source: https://docs.crewai.com/en/observability/langfuse

Learn how to integrate Langfuse with CrewAI via OpenTelemetry using OpenLit

# Integrate Langfuse with CrewAI

This notebook demonstrates how to integrate **Langfuse** with **CrewAI** using OpenTelemetry via the **OpenLit** SDK. By the end of this notebook, you will be able to trace your CrewAI applications with Langfuse for improved observability and debugging.

> **What is Langfuse?** [Langfuse](https://langfuse.com) is an open-source LLM engineering platform. It provides tracing and monitoring capabilities for LLM applications, helping developers debug, analyze, and optimize their AI systems. Langfuse integrates with various tools and frameworks via native integrations, OpenTelemetry, and APIs/SDKs.

[![Langfuse Overview Video](https://github.com/user-attachments/assets/3926b288-ff61-4b95-8aa1-45d041c70866)](https://langfuse.com/watch-demo)

## Get Started

We'll walk through a simple example of using CrewAI and integrating it with Langfuse via OpenTelemetry using OpenLit.

### Step 1: Install Dependencies

```python theme={null}
%pip install langfuse openlit crewai crewai_tools
```

### Step 2: Set Up Environment Variables

Set your Langfuse API keys and configure OpenTelemetry export settings to send traces to Langfuse. Please refer to the [Langfuse OpenTelemetry Docs](https://langfuse.com/docs/opentelemetry/get-started) for more information on the Langfuse OpenTelemetry endpoint `/api/public/otel` and authentication.

```python theme={null}
import os
 
# Get keys for your project from the project settings page: https://cloud.langfuse.com
os.environ["LANGFUSE_PUBLIC_KEY"] = "pk-lf-..." 
os.environ["LANGFUSE_SECRET_KEY"] = "sk-lf-..."
os.environ["LANGFUSE_HOST"] = "https://cloud.langfuse.com" # 🇪🇺 EU region
# os.environ["LANGFUSE_HOST"] = "https://us.cloud.langfuse.com" # 🇺🇸 US region
 
 
# Your OpenAI key
os.environ["OPENAI_API_KEY"] = "sk-proj-..."
```

With the environment variables set, we can now initialize the Langfuse client. get\_client() initializes the Langfuse client using the credentials provided in the environment variables.

```python theme={null}
from langfuse import get_client
 
langfuse = get_client()
 
# Verify connection
if langfuse.auth_check():
    print("Langfuse client is authenticated and ready!")
else:
    print("Authentication failed. Please check your credentials and host.")
```

### Step 3: Initialize OpenLit

Initialize the OpenLit OpenTelemetry instrumentation SDK to start capturing OpenTelemetry traces.

```python theme={null}
import openlit

openlit.init()
```

### Step 4: Create a Simple CrewAI Application

We'll create a simple CrewAI application where multiple agents collaborate to answer a user's question.

```python theme={null}
from crewai import Agent, Task, Crew

from crewai_tools import (
    WebsiteSearchTool
)

web_rag_tool = WebsiteSearchTool()

writer = Agent(
        role="Writer",
        goal="You make math engaging and understandable for young children through poetry",
        backstory="You're an expert in writing haikus but you know nothing of math.",
        tools=[web_rag_tool],  
    )

task = Task(description=("What is {multiplication}?"),
            expected_output=("Compose a haiku that includes the answer."),
            agent=writer)

crew = Crew(
  agents=[writer],
  tasks=[task],
  share_crew=False
)
```

### Step 5: See Traces in Langfuse

After running the agent, you can view the traces generated by your CrewAI application in [Langfuse](https://cloud.langfuse.com). You should see detailed steps of the LLM interactions, which can help you debug and optimize your AI agent.

![CrewAI example trace in Langfuse](https://langfuse.com/images/cookbook/integration_crewai/crewai-example-trace.png)

*[Public example trace in Langfuse](https://cloud.langfuse.com/project/cloramnkj0002jz088vzn1ja4/traces/e2cf380ffc8d47d28da98f136140642b?timestamp=2025-02-05T15%3A12%3A02.717Z\&observation=3b32338ee6a5d9af)*

## References

* [Langfuse OpenTelemetry Docs](https://langfuse.com/docs/opentelemetry/get-started)


# Langtrace Integration
Source: https://docs.crewai.com/en/observability/langtrace

How to monitor cost, latency, and performance of CrewAI Agents using Langtrace, an external observability tool.

# Langtrace Overview

Langtrace is an open-source, external tool that helps you set up observability and evaluations for Large Language Models (LLMs), LLM frameworks, and Vector Databases.
While not built directly into CrewAI, Langtrace can be used alongside CrewAI to gain deep visibility into the cost, latency, and performance of your CrewAI Agents.
This integration allows you to log hyperparameters, monitor performance regressions, and establish a process for continuous improvement of your Agents.

<img alt="Overview of a select series of agent session runs" />

<img alt="Overview of agent traces" />

<img alt="Overview of llm traces in details" />

## Setup Instructions

<Steps>
  <Step title="Sign up for Langtrace">
    Sign up by visiting [https://langtrace.ai/signup](https://langtrace.ai/signup).
  </Step>

  <Step title="Create a project">
    Set the project type to `CrewAI` and generate an API key.
  </Step>

  <Step title="Install Langtrace in your CrewAI project">
    Use the following command:

    ```bash theme={null}
    pip install langtrace-python-sdk
    ```
  </Step>

  <Step title="Import Langtrace">
    Import and initialize Langtrace at the beginning of your script, before any CrewAI imports:

    ```python theme={null}
    from langtrace_python_sdk import langtrace
    langtrace.init(api_key='<LANGTRACE_API_KEY>')

    # Now import CrewAI modules
    from crewai import Agent, Task, Crew
    ```
  </Step>
</Steps>

### Features and Their Application to CrewAI

1. **LLM Token and Cost Tracking**

   * Monitor the token usage and associated costs for each CrewAI agent interaction.

2. **Trace Graph for Execution Steps**

   * Visualize the execution flow of your CrewAI tasks, including latency and logs.
   * Useful for identifying bottlenecks in your agent workflows.

3. **Dataset Curation with Manual Annotation**

   * Create datasets from your CrewAI task outputs for future training or evaluation.

4. **Prompt Versioning and Management**

   * Keep track of different versions of prompts used in your CrewAI agents.
   * Useful for A/B testing and optimizing agent performance.

5. **Prompt Playground with Model Comparisons**

   * Test and compare different prompts and models for your CrewAI agents before deployment.

6. **Testing and Evaluations**

   * Set up automated tests for your CrewAI agents and tasks.


# Maxim Integration
Source: https://docs.crewai.com/en/observability/maxim

Start Agent monitoring, evaluation, and observability

# Maxim Overview

Maxim AI provides comprehensive agent monitoring, evaluation, and observability for your CrewAI applications. With Maxim's one-line integration, you can easily trace and analyse agent interactions, performance metrics, and more.

## Features

### Prompt Management

Maxim's Prompt Management capabilities enable you to create, organize, and optimize prompts for your CrewAI agents. Rather than hardcoding instructions, leverage Maxim’s SDK to dynamically retrieve and apply version-controlled prompts.

<Tabs>
  <Tab title="Prompt Playground">
    Create, refine, experiment and deploy your prompts via the playground. Organize of your prompts using folders and versions, experimenting with the real world cases by linking tools and context, and deploying based on custom logic.

    Easily experiment across models by [**configuring models**](https://www.getmaxim.ai/docs/introduction/quickstart/setting-up-workspace#add-model-api-keys) and selecting the relevant model from the dropdown at the top of the prompt playground.

    <img />
  </Tab>

  <Tab title="Prompt Versions">
    As teams build their AI applications, a big part of experimentation is iterating on the prompt structure. In order to collaborate effectively and organize your changes clearly, Maxim allows prompt versioning and comparison runs across versions.

    <img />
  </Tab>

  <Tab title="Prompt Comparisons">
    Iterating on Prompts as you evolve your AI application would need experiments across models, prompt structures, etc. In order to compare versions and make informed decisions about changes, the comparison playground allows a side by side view of results.

    ## **Why use Prompt comparison?**

    Prompt comparison combines multiple single Prompts into one view, enabling a streamlined approach for various workflows:

    1. **Model comparison**: Evaluate the performance of different models on the same Prompt.
    2. **Prompt optimization**: Compare different versions of a Prompt to identify the most effective formulation.
    3. **Cross-Model consistency**: Ensure consistent outputs across various models for the same Prompt.
    4. **Performance benchmarking**: Analyze metrics like latency, cost, and token count across different models and Prompts.
  </Tab>
</Tabs>

### Observability & Evals

Maxim AI provides comprehensive observability & evaluation for your CrewAI agents, helping you understand exactly what's happening during each execution.

<Tabs>
  <Tab title="Agent Tracing">
    Track your agent’s complete lifecycle, including tool calls, agent trajectories, and decision flows effortlessly.

    <img />
  </Tab>

  <Tab title="Analytics + Evals">
    Run detailed evaluations on full traces or individual nodes with support for:

    * Multi-step interactions and granular trace analysis
    * Session Level Evaluations
    * Simulations for real-world testing

    <img />

    <CardGroup>
      <Card title="Auto Evals on Logs" icon="e" href="https://www.getmaxim.ai/docs/observe/how-to/evaluate-logs/auto-evaluation">
        <p>
          Evaluate captured logs automatically from the UI based on filters and sampling
        </p>
      </Card>

      <Card title="Human Evals on Logs" icon="hand" href="https://www.getmaxim.ai/docs/observe/how-to/evaluate-logs/human-evaluation">
        <p>
          Use human evaluation or rating to assess the quality of your logs and evaluate them.
        </p>
      </Card>

      <Card title="Node Level Evals" icon="road" href="https://www.getmaxim.ai/docs/observe/how-to/evaluate-logs/node-level-evaluation">
        <p>
          Evaluate any component of your trace or log to gain insights into your agent’s behavior.
        </p>
      </Card>
    </CardGroup>

    ***
  </Tab>

  <Tab title="Alerting">
    Set thresholds on **error**, **cost, token usage, user feedback, latency** and get real-time alerts via Slack or PagerDuty.

    <img />
  </Tab>

  <Tab title="Dashboards">
    Visualize Traces over time, usage metrics, latency & error rates with ease.

    <img />
  </Tab>
</Tabs>

## Getting Started

### Prerequisites

* Python version >=3.10
* A Maxim account ([sign up here](https://getmaxim.ai/))
* Generate Maxim API Key
* A CrewAI project

### Installation

Install the Maxim SDK via pip:

```python theme={null}
pip install maxim-py
```

Or add it to your `requirements.txt`:

```
maxim-py
```

### Basic Setup

### 1. Set up environment variables

```python theme={null}
### Environment Variables Setup

# Create a `.env` file in your project root:

# Maxim API Configuration
MAXIM_API_KEY=your_api_key_here
MAXIM_LOG_REPO_ID=your_repo_id_here
```

### 2. Import the required packages

```python theme={null}
from crewai import Agent, Task, Crew, Process
from maxim import Maxim
from maxim.logger.crewai import instrument_crewai
```

### 3. Initialise Maxim with your API key

```python {8} theme={null}
# Instrument CrewAI with just one line
instrument_crewai(Maxim().logger())
```

### 4. Create and run your CrewAI application as usual

```python theme={null}
# Create your agent
researcher = Agent(
    role='Senior Research Analyst',
    goal='Uncover cutting-edge developments in AI',
    backstory="You are an expert researcher at a tech think tank...",
    verbose=True,
    llm=llm
)

# Define the task
research_task = Task(
    description="Research the latest AI advancements...",
    expected_output="",
    agent=researcher
)

# Configure and run the crew
crew = Crew(
    agents=[researcher],
    tasks=[research_task],
    verbose=True
)

try:
    result = crew.kickoff()
finally:
    maxim.cleanup()  # Ensure cleanup happens even if errors occur
```

That's it! All your CrewAI agent interactions will now be logged and available in your Maxim dashboard.

Check this Google Colab Notebook for a quick reference - [Notebook](https://colab.research.google.com/drive/1ZKIZWsmgQQ46n8TH9zLsT1negKkJA6K8?usp=sharing)

## Viewing Your Traces

After running your CrewAI application:

1. Log in to your [Maxim Dashboard](https://app.getmaxim.ai/login)
2. Navigate to your repository
3. View detailed agent traces, including:

   * Agent conversations
   * Tool usage patterns
   * Performance metrics
   * Cost analytics

   <img />

## Troubleshooting

### Common Issues

* **No traces appearing**: Ensure your API key and repository ID are correct
* Ensure you've **`called instrument_crewai()`** ***before*** running your crew. This initializes logging hooks correctly.
* Set `debug=True` in your `instrument_crewai()` call to surface any internal errors:

  ```python theme={null}
  instrument_crewai(logger, debug=True)
  ```
* Configure your agents with `verbose=True` to capture detailed logs:

  ```python theme={null}
  agent = CrewAgent(..., verbose=True)
  ```
* Double-check that `instrument_crewai()` is called **before** creating or executing agents. This might be obvious, but it's a common oversight.

## Resources

<CardGroup>
  <Card title="CrewAI Docs" icon="book" href="https://docs.crewai.com/">
    Official CrewAI documentation
  </Card>

  <Card title="Maxim Docs" icon="book" href="https://getmaxim.ai/docs">
    Official Maxim documentation
  </Card>

  <Card title="Maxim Github" icon="github" href="https://github.com/maximhq">
    Maxim Github
  </Card>
</CardGroup>


# MLflow Integration
Source: https://docs.crewai.com/en/observability/mlflow

Quickly start monitoring your Agents with MLflow.

# MLflow Overview

[MLflow](https://mlflow.org/) is an open-source platform to assist machine learning practitioners and teams in handling the complexities of the machine learning process.

It provides a tracing feature that enhances LLM observability in your Generative AI applications by capturing detailed information about the execution of your application’s services.
Tracing provides a way to record the inputs, outputs, and metadata associated with each intermediate step of a request, enabling you to easily pinpoint the source of bugs and unexpected behaviors.

<img alt="Overview of MLflow crewAI tracing usage" />

### Features

* **Tracing Dashboard**: Monitor activities of your crewAI agents with detailed dashboards that include inputs, outputs and metadata of spans.
* **Automated Tracing**: A fully automated integration with crewAI, which can be enabled by running `mlflow.crewai.autolog()`.
* **Manual Trace Instrumentation with minor efforts**: Customize trace instrumentation through MLflow's high-level fluent APIs such as decorators, function wrappers and context managers.
* **OpenTelemetry Compatibility**: MLflow Tracing supports exporting traces to an OpenTelemetry Collector, which can then be used to export traces to various backends such as Jaeger, Zipkin, and AWS X-Ray.
* **Package and Deploy Agents**: Package and deploy your crewAI agents to an inference server with a variety of deployment targets.
* **Securely Host LLMs**: Host multiple LLM from various providers in one unified endpoint through MFflow gateway.
* **Evaluation**: Evaluate your crewAI agents with a wide range of metrics using a convenient API `mlflow.evaluate()`.

## Setup Instructions

<Steps>
  <Step title="Install MLflow package">
    ```shell theme={null}
    # The crewAI integration is available in mlflow>=2.19.0
    pip install mlflow
    ```
  </Step>

  <Step title="Start MFflow tracking server">
    ```shell theme={null}
    # This process is optional, but it is recommended to use MLflow tracking server for better visualization and broader features.
    mlflow server
    ```
  </Step>

  <Step title="Initialize MLflow in Your Application">
    Add the following two lines to your application code:

    ```python theme={null}
    import mlflow

    mlflow.crewai.autolog()

    # Optional: Set a tracking URI and an experiment name if you have a tracking server
    mlflow.set_tracking_uri("http://localhost:5000")
    mlflow.set_experiment("CrewAI")
    ```

    Example Usage for tracing CrewAI Agents:

    ```python theme={null}
    from crewai import Agent, Crew, Task
    from crewai.knowledge.source.string_knowledge_source import StringKnowledgeSource
    from crewai_tools import SerperDevTool, WebsiteSearchTool

    from textwrap import dedent

    content = "Users name is John. He is 30 years old and lives in San Francisco."
    string_source = StringKnowledgeSource(
        content=content, metadata={"preference": "personal"}
    )

    search_tool = WebsiteSearchTool()


    class TripAgents:
        def city_selection_agent(self):
            return Agent(
                role="City Selection Expert",
                goal="Select the best city based on weather, season, and prices",
                backstory="An expert in analyzing travel data to pick ideal destinations",
                tools=[
                    search_tool,
                ],
                verbose=True,
            )

        def local_expert(self):
            return Agent(
                role="Local Expert at this city",
                goal="Provide the BEST insights about the selected city",
                backstory="""A knowledgeable local guide with extensive information
            about the city, it's attractions and customs""",
                tools=[search_tool],
                verbose=True,
            )


    class TripTasks:
        def identify_task(self, agent, origin, cities, interests, range):
            return Task(
                description=dedent(
                    f"""
                    Analyze and select the best city for the trip based
                    on specific criteria such as weather patterns, seasonal
                    events, and travel costs. This task involves comparing
                    multiple cities, considering factors like current weather
                    conditions, upcoming cultural or seasonal events, and
                    overall travel expenses.
                    Your final answer must be a detailed
                    report on the chosen city, and everything you found out
                    about it, including the actual flight costs, weather
                    forecast and attractions.

                    Traveling from: {origin}
                    City Options: {cities}
                    Trip Date: {range}
                    Traveler Interests: {interests}
                """
                ),
                agent=agent,
                expected_output="Detailed report on the chosen city including flight costs, weather forecast, and attractions",
            )

        def gather_task(self, agent, origin, interests, range):
            return Task(
                description=dedent(
                    f"""
                    As a local expert on this city you must compile an
                    in-depth guide for someone traveling there and wanting
                    to have THE BEST trip ever!
                    Gather information about key attractions, local customs,
                    special events, and daily activity recommendations.
                    Find the best spots to go to, the kind of place only a
                    local would know.
                    This guide should provide a thorough overview of what
                    the city has to offer, including hidden gems, cultural
                    hotspots, must-visit landmarks, weather forecasts, and
                    high level costs.
                    The final answer must be a comprehensive city guide,
                    rich in cultural insights and practical tips,
                    tailored to enhance the travel experience.

                    Trip Date: {range}
                    Traveling from: {origin}
                    Traveler Interests: {interests}
                """
                ),
                agent=agent,
                expected_output="Comprehensive city guide including hidden gems, cultural hotspots, and practical travel tips",
            )


    class TripCrew:
        def __init__(self, origin, cities, date_range, interests):
            self.cities = cities
            self.origin = origin
            self.interests = interests
            self.date_range = date_range

        def run(self):
            agents = TripAgents()
            tasks = TripTasks()

            city_selector_agent = agents.city_selection_agent()
            local_expert_agent = agents.local_expert()

            identify_task = tasks.identify_task(
                city_selector_agent,
                self.origin,
                self.cities,
                self.interests,
                self.date_range,
            )
            gather_task = tasks.gather_task(
                local_expert_agent, self.origin, self.interests, self.date_range
            )

            crew = Crew(
                agents=[city_selector_agent, local_expert_agent],
                tasks=[identify_task, gather_task],
                verbose=True,
                memory=True,
                knowledge={
                    "sources": [string_source],
                    "metadata": {"preference": "personal"},
                },
            )

            result = crew.kickoff()
            return result


    trip_crew = TripCrew("California", "Tokyo", "Dec 12 - Dec 20", "sports")
    result = trip_crew.run()

    print(result)
    ```

    Refer to [MLflow Tracing Documentation](https://mlflow.org/docs/latest/llms/tracing/index.html) for more configurations and use cases.
  </Step>

  <Step title="Visualize Activities of Agents">
    Now traces for your crewAI agents are captured by MLflow.
    Let's visit MLflow tracking server to view the traces and get insights into your Agents.

    Open `127.0.0.1:5000` on your browser to visit MLflow tracking server.

    <Frame>
      <img alt="MLflow tracing example with crewai" />
    </Frame>
  </Step>
</Steps>


# Neatlogs Integration
Source: https://docs.crewai.com/en/observability/neatlogs

Understand, debug, and share your CrewAI agent runs

# Introduction

Neatlogs helps you **see what your agent did**, **why**, and **share it**.

It captures every step: thoughts, tool calls, responses, evaluations. No raw logs. Just clear, structured traces. Great for debugging and collaboration.

## Why use Neatlogs?

CrewAI agents use multiple tools and reasoning steps. When something goes wrong, you need context — not just errors.

Neatlogs lets you:

* Follow the full decision path
* Add feedback directly on steps
* Chat with the trace using AI assistant
* Share runs publicly for feedback
* Turn insights into tasks

All in one place.

Manage your traces effortlessly

<img alt="Traces" />

<img alt="Trace Response" />

The best UX to view a CrewAI trace. Post comments anywhere you want. Use AI to debug.

<img alt="Trace Details" />

<img alt="Ai Chat Bot With A Trace" />

<img alt="Comments Drawer" />

## Core Features

* **Trace Viewer**: Track thoughts, tools, and decisions in sequence
* **Inline Comments**: Tag teammates on any trace step
* **Feedback & Evaluation**: Mark outputs as correct or incorrect
* **Error Highlighting**: Automatic flagging of API/tool failures
* **Task Conversion**: Convert comments into assigned tasks
* **Ask the Trace (AI)**: Chat with your trace using Neatlogs AI bot
* **Public Sharing**: Publish trace links to your community

## Quick Setup with CrewAI

<Steps>
  <Step title="Sign Up & Get API Key">
    Visit [neatlogs.com](https://neatlogs.com/?utm_source=crewAI-docs), create a project, copy the API key.
  </Step>

  <Step title="Install SDK">
    ```bash theme={null}
    pip install neatlogs
    ```

    (Latest version 0.8.0, Python 3.8+; MIT license)
  </Step>

  <Step title="Initialize Neatlogs">
    Before starting Crew agents, add:

    ```python theme={null}
    import neatlogs
    neatlogs.init("YOUR_PROJECT_API_KEY")
    ```

    Agents run as usual. Neatlogs captures everything automatically.
  </Step>
</Steps>

## Under the Hood

According to GitHub, Neatlogs:

* Captures thoughts, tool calls, responses, errors, and token stats
* Supports AI-powered task generation and robust evaluation workflows

All with just two lines of code.

## Watch It Work

### 🔍 Full Demo (4 min)

<iframe title="NeatLogs overview" />

### ⚙️ CrewAI Integration (30 s)

<iframe title="Loom video player" />

## Links & Support

* 📘 [Neatlogs Docs](https://docs.neatlogs.com/)
* 🔐 [Dashboard & API Key](https://app.neatlogs.com/)
* 🐦 [Follow on Twitter](https://twitter.com/neatlogs)
* 📧 Contact: [hello@neatlogs.com](mailto:hello@neatlogs.com)
* 🛠 [GitHub SDK](https://github.com/NeatLogs/neatlogs)

## TL;DR

With just:

```bash theme={null}
pip install neatlogs

import neatlogs
neatlogs.init("YOUR_API_KEY")

You can now capture, understand, share, and act on your CrewAI agent runs in seconds.
No setup overhead. Full trace transparency. Full team collaboration.
```


# OpenLIT Integration
Source: https://docs.crewai.com/en/observability/openlit

Quickly start monitoring your Agents in just a single line of code with OpenTelemetry.

# OpenLIT Overview

[OpenLIT](https://github.com/openlit/openlit?src=crewai-docs) is an open-source tool that makes it simple to monitor the performance of AI agents, LLMs, VectorDBs, and GPUs with just **one** line of code.

It provides OpenTelemetry-native tracing and metrics to track important parameters like cost, latency, interactions and task sequences.
This setup enables you to track hyperparameters and monitor for performance issues, helping you find ways to enhance and fine-tune your agents over time.

<Frame>
  <img alt="Overview Agent usage including cost and tokens" />

  <img alt="Overview of agent otel traces and metrics" />

  <img alt="Overview of agent traces in details" />
</Frame>

### Features

* **Analytics Dashboard**: Monitor your Agents health and performance with detailed dashboards that track metrics, costs, and user interactions.
* **OpenTelemetry-native Observability SDK**: Vendor-neutral SDKs to send traces and metrics to your existing observability tools like Grafana, DataDog and more.
* **Cost Tracking for Custom and Fine-Tuned Models**: Tailor cost estimations for specific models using custom pricing files for precise budgeting.
* **Exceptions Monitoring Dashboard**: Quickly spot and resolve issues by tracking common exceptions and errors with a monitoring dashboard.
* **Compliance and Security**: Detect potential threats such as profanity and PII leaks.
* **Prompt Injection Detection**: Identify potential code injection and secret leaks.
* **API Keys and Secrets Management**: Securely handle your LLM API keys and secrets centrally, avoiding insecure practices.
* **Prompt Management**: Manage and version Agent prompts using PromptHub for consistent and easy access across Agents.
* **Model Playground** Test and compare different models for your CrewAI agents before deployment.

## Setup Instructions

<Steps>
  <Step title="Deploy OpenLIT">
    <Steps>
      <Step title="Git Clone OpenLIT Repository">
        ```shell theme={null}
        git clone git@github.com:openlit/openlit.git
        ```
      </Step>

      <Step title="Start Docker Compose">
        From the root directory of the [OpenLIT Repo](https://github.com/openlit/openlit), Run the below command:

        ```shell theme={null}
        docker compose up -d
        ```
      </Step>
    </Steps>
  </Step>

  <Step title="Install OpenLIT SDK">
    ```shell theme={null}
    pip install openlit
    ```
  </Step>

  <Step title="Initialize OpenLIT in Your Application">
    Add the following two lines to your application code:

    <Tabs>
      <Tab title="Setup using function arguments">
        ```python theme={null}
        import openlit
        openlit.init(otlp_endpoint="http://127.0.0.1:4318")
        ```

        Example Usage for monitoring a CrewAI Agent:

        ```python theme={null}
        from crewai import Agent, Task, Crew, Process
        import openlit

        openlit.init(disable_metrics=True)
        # Define your agents
        researcher = Agent(
            role="Researcher",
            goal="Conduct thorough research and analysis on AI and AI agents",
            backstory="You're an expert researcher, specialized in technology, software engineering, AI, and startups. You work as a freelancer and are currently researching for a new client.",
            allow_delegation=False,
            llm='command-r'
        )


        # Define your task
        task = Task(
            description="Generate a list of 5 interesting ideas for an article, then write one captivating paragraph for each idea that showcases the potential of a full article on this topic. Return the list of ideas with their paragraphs and your notes.",
            expected_output="5 bullet points, each with a paragraph and accompanying notes.",
        )

        # Define the manager agent
        manager = Agent(
            role="Project Manager",
            goal="Efficiently manage the crew and ensure high-quality task completion",
            backstory="You're an experienced project manager, skilled in overseeing complex projects and guiding teams to success. Your role is to coordinate the efforts of the crew members, ensuring that each task is completed on time and to the highest standard.",
            allow_delegation=True,
            llm='command-r'
        )

        # Instantiate your crew with a custom manager
        crew = Crew(
            agents=[researcher],
            tasks=[task],
            manager_agent=manager,
            process=Process.hierarchical,
        )

        # Start the crew's work
        result = crew.kickoff()

        print(result)
        ```
      </Tab>

      <Tab title="Setup using Environment Variables">
        Add the following two lines to your application code:

        ```python theme={null}
        import openlit

        openlit.init()
        ```

        Run the following command to configure the OTEL export endpoint:

        ```shell theme={null}
        export OTEL_EXPORTER_OTLP_ENDPOINT = "http://127.0.0.1:4318"
        ```

        Example Usage for monitoring a CrewAI Async Agent:

        ```python theme={null}
        import asyncio
        from crewai import Crew, Agent, Task
        import openlit

        openlit.init(otlp_endpoint="http://127.0.0.1:4318")

        # Create an agent with code execution enabled
        coding_agent = Agent(
          role="Python Data Analyst",
          goal="Analyze data and provide insights using Python",
          backstory="You are an experienced data analyst with strong Python skills.",
          allow_code_execution=True,
          llm="command-r"
        )

        # Create a task that requires code execution
        data_analysis_task = Task(
          description="Analyze the given dataset and calculate the average age of participants. Ages: {ages}",
          agent=coding_agent,
          expected_output="5 bullet points, each with a paragraph and accompanying notes.",
        )

        # Create a crew and add the task
        analysis_crew = Crew(
          agents=[coding_agent],
          tasks=[data_analysis_task]
        )

        # Async function to kickoff the crew asynchronously
        async def async_crew_execution():
            result = await analysis_crew.kickoff_async(inputs={"ages": [25, 30, 35, 40, 45]})
            print("Crew Result:", result)

        # Run the async function
        asyncio.run(async_crew_execution())
        ```
      </Tab>
    </Tabs>

    Refer to OpenLIT [Python SDK repository](https://github.com/openlit/openlit/tree/main/sdk/python) for more advanced configurations and use cases.
  </Step>

  <Step title="Visualize and Analyze">
    With the Agent Observability data now being collected and sent to OpenLIT, the next step is to visualize and analyze this data to get insights into your Agent's performance, behavior, and identify areas of improvement.

    Just head over to OpenLIT at `127.0.0.1:3000` on your browser to start exploring. You can login using the default credentials

    * **Email**: `user@openlit.io`
    * **Password**: `openlituser`

    <Frame>
      <img alt="Overview Agent usage including cost and tokens" />

      <img alt="Overview of agent otel traces and metrics" />
    </Frame>
  </Step>
</Steps>


# Opik Integration
Source: https://docs.crewai.com/en/observability/opik

Learn how to use Comet Opik to debug, evaluate, and monitor your CrewAI applications with comprehensive tracing, automated evaluations, and production-ready dashboards.

# Opik Overview

With [Comet Opik](https://www.comet.com/docs/opik/), debug, evaluate, and monitor your LLM applications, RAG systems, and agentic workflows with comprehensive tracing, automated evaluations, and production-ready dashboards.

<Frame>
  <img alt="Opik agent monitoring example with CrewAI" />
</Frame>

Opik provides comprehensive support for every stage of your CrewAI application development:

* **Log Traces and Spans**: Automatically track LLM calls and application logic to debug and analyze development and production systems. Manually or programmatically annotate, view, and compare responses across projects.
* **Evaluate Your LLM Application's Performance**: Evaluate against a custom test set and run built-in evaluation metrics or define your own metrics in the SDK or UI.
* **Test Within Your CI/CD Pipeline**: Establish reliable performance baselines with Opik's LLM unit tests, built on PyTest. Run online evaluations for continuous monitoring in production.
* **Monitor & Analyze Production Data**: Understand your models' performance on unseen data in production and generate datasets for new dev iterations.

## Setup

Comet provides a hosted version of the Opik platform, or you can run the platform locally.

To use the hosted version, simply [create a free Comet account](https://www.comet.com/signup?utm_medium=github\&utm_source=crewai_docs) and grab you API Key.

To run the Opik platform locally, see our [installation guide](https://www.comet.com/docs/opik/self-host/overview/) for more information.

For this guide we will use CrewAI’s quickstart example.

<Steps>
  <Step title="Install required packages">
    ```shell theme={null}
    pip install crewai crewai-tools opik --upgrade
    ```
  </Step>

  <Step title="Configure Opik">
    ```python theme={null}
    import opik
    opik.configure(use_local=False)
    ```
  </Step>

  <Step title="Prepare environment">
    First, we set up our API keys for our LLM-provider as environment variables:

    ```python theme={null}
    import os
    import getpass

    if "OPENAI_API_KEY" not in os.environ:
    os.environ["OPENAI_API_KEY"] = getpass.getpass("Enter your OpenAI API key: ")
    ```
  </Step>

  <Step title="Using CrewAI">
    The first step is to create our project. We will use an example from CrewAI’s documentation:

    ```python theme={null}
    from crewai import Agent, Crew, Task, Process


    class YourCrewName:
        def agent_one(self) -> Agent:
            return Agent(
                role="Data Analyst",
                goal="Analyze data trends in the market",
                backstory="An experienced data analyst with a background in economics",
                verbose=True,
            )

        def agent_two(self) -> Agent:
            return Agent(
                role="Market Researcher",
                goal="Gather information on market dynamics",
                backstory="A diligent researcher with a keen eye for detail",
                verbose=True,
            )

        def task_one(self) -> Task:
            return Task(
                name="Collect Data Task",
                description="Collect recent market data and identify trends.",
                expected_output="A report summarizing key trends in the market.",
                agent=self.agent_one(),
            )

        def task_two(self) -> Task:
            return Task(
                name="Market Research Task",
                description="Research factors affecting market dynamics.",
                expected_output="An analysis of factors influencing the market.",
                agent=self.agent_two(),
            )

        def crew(self) -> Crew:
            return Crew(
                agents=[self.agent_one(), self.agent_two()],
                tasks=[self.task_one(), self.task_two()],
                process=Process.sequential,
                verbose=True,
            )

    ```

    Now we can import Opik’s tracker and run our crew:

    ```python theme={null}
    from opik.integrations.crewai import track_crewai

    track_crewai(project_name="crewai-integration-demo")

    my_crew = YourCrewName().crew()
    result = my_crew.kickoff()

    print(result)
    ```

    After running your CrewAI application, visit the Opik app to view:

    * LLM traces, spans, and their metadata
    * Agent interactions and task execution flow
    * Performance metrics like latency and token usage
    * Evaluation metrics (built-in or custom)
  </Step>
</Steps>

## Resources

* [🦉 Opik Documentation](https://www.comet.com/docs/opik/)
* [👉 Opik + CrewAI Colab](https://colab.research.google.com/github/comet-ml/opik/blob/main/apps/opik-documentation/documentation/docs/cookbook/crewai.ipynb)
* [🐦 X](https://x.com/cometml)
* [💬 Slack](https://slack.comet.com/)


# Overview
Source: https://docs.crewai.com/en/observability/overview

Monitor, evaluate, and optimize your CrewAI agents with comprehensive observability tools

## Observability for CrewAI

Observability is crucial for understanding how your CrewAI agents perform, identifying bottlenecks, and ensuring reliable operation in production environments. This section covers various tools and platforms that provide monitoring, evaluation, and optimization capabilities for your agent workflows.

## Why Observability Matters

* **Performance Monitoring**: Track agent execution times, token usage, and resource consumption
* **Quality Assurance**: Evaluate output quality and consistency across different scenarios
* **Debugging**: Identify and resolve issues in agent behavior and task execution
* **Cost Management**: Monitor LLM API usage and associated costs
* **Continuous Improvement**: Gather insights to optimize agent performance over time

## Available Observability Tools

### Monitoring & Tracing Platforms

<CardGroup>
  <Card title="LangDB" icon="database" href="/en/observability/langdb">
    End-to-end tracing for CrewAI workflows with automatic agent interaction capture.
  </Card>

  <Card title="OpenLIT" icon="magnifying-glass-chart" href="/en/observability/openlit">
    OpenTelemetry-native monitoring with cost tracking and performance analytics.
  </Card>

  <Card title="MLflow" icon="bars-staggered" href="/en/observability/mlflow">
    Machine learning lifecycle management with tracing and evaluation capabilities.
  </Card>

  <Card title="Langfuse" icon="link" href="/en/observability/langfuse">
    LLM engineering platform with detailed tracing and analytics.
  </Card>

  <Card title="Langtrace" icon="chart-line" href="/en/observability/langtrace">
    Open-source observability for LLMs and agent frameworks.
  </Card>

  <Card title="Arize Phoenix" icon="meteor" href="/en/observability/arize-phoenix">
    AI observability platform for monitoring and troubleshooting.
  </Card>

  <Card title="Portkey" icon="key" href="/en/observability/portkey">
    AI gateway with comprehensive monitoring and reliability features.
  </Card>

  <Card title="Opik" icon="meteor" href="/en/observability/opik">
    Debug, evaluate, and monitor LLM applications with comprehensive tracing.
  </Card>

  <Card title="Weave" icon="network-wired" href="/en/observability/weave">
    Weights & Biases platform for tracking and evaluating AI applications.
  </Card>
</CardGroup>

### Evaluation & Quality Assurance

<CardGroup>
  <Card title="Patronus AI" icon="shield-check" href="/en/observability/patronus-evaluation">
    Comprehensive evaluation platform for LLM outputs and agent behaviors.
  </Card>
</CardGroup>

## Key Observability Metrics

### Performance Metrics

* **Execution Time**: How long agents take to complete tasks
* **Token Usage**: Input/output tokens consumed by LLM calls
* **API Latency**: Response times from external services
* **Success Rate**: Percentage of successfully completed tasks

### Quality Metrics

* **Output Accuracy**: Correctness of agent responses
* **Consistency**: Reliability across similar inputs
* **Relevance**: How well outputs match expected results
* **Safety**: Compliance with content policies and guidelines

### Cost Metrics

* **API Costs**: Expenses from LLM provider usage
* **Resource Utilization**: Compute and memory consumption
* **Cost per Task**: Economic efficiency of agent operations
* **Budget Tracking**: Monitoring against spending limits

## Getting Started

1. **Choose Your Tools**: Select observability platforms that match your needs
2. **Instrument Your Code**: Add monitoring to your CrewAI applications
3. **Set Up Dashboards**: Configure visualizations for key metrics
4. **Define Alerts**: Create notifications for important events
5. **Establish Baselines**: Measure initial performance for comparison
6. **Iterate and Improve**: Use insights to optimize your agents

## Best Practices

### Development Phase

* Use detailed tracing to understand agent behavior
* Implement evaluation metrics early in development
* Monitor resource usage during testing
* Set up automated quality checks

### Production Phase

* Implement comprehensive monitoring and alerting
* Track performance trends over time
* Monitor for anomalies and degradation
* Maintain cost visibility and control

### Continuous Improvement

* Regular performance reviews and optimization
* A/B testing of different agent configurations
* Feedback loops for quality improvement
* Documentation of lessons learned

Choose the observability tools that best fit your use case, infrastructure, and monitoring requirements to ensure your CrewAI agents perform reliably and efficiently.


# Patronus AI Evaluation
Source: https://docs.crewai.com/en/observability/patronus-evaluation

Monitor and evaluate CrewAI agent performance using Patronus AI's comprehensive evaluation platform for LLM outputs and agent behaviors.

# Patronus AI Evaluation

## Overview

[Patronus AI](https://patronus.ai) provides comprehensive evaluation and monitoring capabilities for CrewAI agents, enabling you to assess model outputs, agent behaviors, and overall system performance. This integration allows you to implement continuous evaluation workflows that help maintain quality and reliability in production environments.

## Key Features

* **Automated Evaluation**: Real-time assessment of agent outputs and behaviors
* **Custom Criteria**: Define specific evaluation criteria tailored to your use cases
* **Performance Monitoring**: Track agent performance metrics over time
* **Quality Assurance**: Ensure consistent output quality across different scenarios
* **Safety & Compliance**: Monitor for potential issues and policy violations

## Evaluation Tools

Patronus provides three main evaluation tools for different use cases:

1. **PatronusEvalTool**: Allows agents to select the most appropriate evaluator and criteria for the evaluation task.
2. **PatronusPredefinedCriteriaEvalTool**: Uses predefined evaluator and criteria specified by the user.
3. **PatronusLocalEvaluatorTool**: Uses custom function evaluators defined by the user.

## Installation

To use these tools, you need to install the Patronus package:

```shell theme={null}
uv add patronus
```

You'll also need to set up your Patronus API key as an environment variable:

```shell theme={null}
export PATRONUS_API_KEY="your_patronus_api_key"
```

## Steps to Get Started

To effectively use the Patronus evaluation tools, follow these steps:

1. **Install Patronus**: Install the Patronus package using the command above.
2. **Set Up API Key**: Set your Patronus API key as an environment variable.
3. **Choose the Right Tool**: Select the appropriate Patronus evaluation tool based on your needs.
4. **Configure the Tool**: Configure the tool with the necessary parameters.

## Examples

### Using PatronusEvalTool

The following example demonstrates how to use the `PatronusEvalTool`, which allows agents to select the most appropriate evaluator and criteria:

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import PatronusEvalTool

# Initialize the tool
patronus_eval_tool = PatronusEvalTool()

# Define an agent that uses the tool
coding_agent = Agent(
    role="Coding Agent",
    goal="Generate high quality code and verify that the output is code",
    backstory="An experienced coder who can generate high quality python code.",
    tools=[patronus_eval_tool],
    verbose=True,
)

# Example task to generate and evaluate code
generate_code_task = Task(
    description="Create a simple program to generate the first N numbers in the Fibonacci sequence. Select the most appropriate evaluator and criteria for evaluating your output.",
    expected_output="Program that generates the first N numbers in the Fibonacci sequence.",
    agent=coding_agent,
)

# Create and run the crew
crew = Crew(agents=[coding_agent], tasks=[generate_code_task])
result = crew.kickoff()
```

### Using PatronusPredefinedCriteriaEvalTool

The following example demonstrates how to use the `PatronusPredefinedCriteriaEvalTool`, which uses predefined evaluator and criteria:

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import PatronusPredefinedCriteriaEvalTool

# Initialize the tool with predefined criteria
patronus_eval_tool = PatronusPredefinedCriteriaEvalTool(
    evaluators=[{"evaluator": "judge", "criteria": "contains-code"}]
)

# Define an agent that uses the tool
coding_agent = Agent(
    role="Coding Agent",
    goal="Generate high quality code",
    backstory="An experienced coder who can generate high quality python code.",
    tools=[patronus_eval_tool],
    verbose=True,
)

# Example task to generate code
generate_code_task = Task(
    description="Create a simple program to generate the first N numbers in the Fibonacci sequence.",
    expected_output="Program that generates the first N numbers in the Fibonacci sequence.",
    agent=coding_agent,
)

# Create and run the crew
crew = Crew(agents=[coding_agent], tasks=[generate_code_task])
result = crew.kickoff()
```

### Using PatronusLocalEvaluatorTool

The following example demonstrates how to use the `PatronusLocalEvaluatorTool`, which uses custom function evaluators:

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import PatronusLocalEvaluatorTool
from patronus import Client, EvaluationResult
import random

# Initialize the Patronus client
client = Client()

# Register a custom evaluator
@client.register_local_evaluator("random_evaluator")
def random_evaluator(**kwargs):
    score = random.random()
    return EvaluationResult(
        score_raw=score,
        pass_=score >= 0.5,
        explanation="example explanation",
    )

# Initialize the tool with the custom evaluator
patronus_eval_tool = PatronusLocalEvaluatorTool(
    patronus_client=client,
    evaluator="random_evaluator",
    evaluated_model_gold_answer="example label",
)

# Define an agent that uses the tool
coding_agent = Agent(
    role="Coding Agent",
    goal="Generate high quality code",
    backstory="An experienced coder who can generate high quality python code.",
    tools=[patronus_eval_tool],
    verbose=True,
)

# Example task to generate code
generate_code_task = Task(
    description="Create a simple program to generate the first N numbers in the Fibonacci sequence.",
    expected_output="Program that generates the first N numbers in the Fibonacci sequence.",
    agent=coding_agent,
)

# Create and run the crew
crew = Crew(agents=[coding_agent], tasks=[generate_code_task])
result = crew.kickoff()
```

## Parameters

### PatronusEvalTool

The `PatronusEvalTool` does not require any parameters during initialization. It automatically fetches available evaluators and criteria from the Patronus API.

### PatronusPredefinedCriteriaEvalTool

The `PatronusPredefinedCriteriaEvalTool` accepts the following parameters during initialization:

* **evaluators**: Required. A list of dictionaries containing the evaluator and criteria to use. For example: `[{"evaluator": "judge", "criteria": "contains-code"}]`.

### PatronusLocalEvaluatorTool

The `PatronusLocalEvaluatorTool` accepts the following parameters during initialization:

* **patronus\_client**: Required. The Patronus client instance.
* **evaluator**: Optional. The name of the registered local evaluator to use. Default is an empty string.
* **evaluated\_model\_gold\_answer**: Optional. The gold answer to use for evaluation. Default is an empty string.

## Usage

When using the Patronus evaluation tools, you provide the model input, output, and context, and the tool returns the evaluation results from the Patronus API.

For the `PatronusEvalTool` and `PatronusPredefinedCriteriaEvalTool`, the following parameters are required when calling the tool:

* **evaluated\_model\_input**: The agent's task description in simple text.
* **evaluated\_model\_output**: The agent's output of the task.
* **evaluated\_model\_retrieved\_context**: The agent's context.

For the `PatronusLocalEvaluatorTool`, the same parameters are required, but the evaluator and gold answer are specified during initialization.

## Conclusion

The Patronus evaluation tools provide a powerful way to evaluate and score model inputs and outputs using the Patronus AI platform. By enabling agents to evaluate their own outputs or the outputs of other agents, these tools can help improve the quality and reliability of CrewAI workflows.


# Portkey Integration
Source: https://docs.crewai.com/en/observability/portkey

How to use Portkey with CrewAI

<img alt="Portkey CrewAI Header Image" />

## Introduction

Portkey enhances CrewAI with production-readiness features, turning your experimental agent crews into robust systems by providing:

* **Complete observability** of every agent step, tool use, and interaction
* **Built-in reliability** with fallbacks, retries, and load balancing
* **Cost tracking and optimization** to manage your AI spend
* **Access to 200+ LLMs** through a single integration
* **Guardrails** to keep agent behavior safe and compliant
* **Version-controlled prompts** for consistent agent performance

### Installation & Setup

<Steps>
  <Step title="Install the required packages">
    ```bash theme={null}
    pip install -U crewai portkey-ai
    ```
  </Step>

  <Step title="Generate API Key" icon="lock">
    Create a Portkey API key with optional budget/rate limits from the [Portkey dashboard](https://app.portkey.ai/). You can also attach configurations for reliability, caching, and more to this key. More on this later.
  </Step>

  <Step title="Configure CrewAI with Portkey">
    The integration is simple - you just need to update the LLM configuration in your CrewAI setup:

    ```python theme={null}
    from crewai import LLM
    from portkey_ai import createHeaders, PORTKEY_GATEWAY_URL

    # Create an LLM instance with Portkey integration
    gpt_llm = LLM(
        model="gpt-4o",
        base_url=PORTKEY_GATEWAY_URL,
        api_key="dummy",  # We are using a Virtual key, so this is a placeholder
        extra_headers=createHeaders(
            api_key="YOUR_PORTKEY_API_KEY",
            virtual_key="YOUR_LLM_VIRTUAL_KEY",
            trace_id="unique-trace-id",               # Optional, for request tracing
        )
    )

    #Use them in your Crew Agents like this:

    	@agent
    	def lead_market_analyst(self) -> Agent:
    		return Agent(
    			config=self.agents_config['lead_market_analyst'],
    			verbose=True,
    			memory=False,
    			llm=gpt_llm
    		)

    ```

    <Info>
      **What are Virtual Keys?** Virtual keys in Portkey securely store your LLM provider API keys (OpenAI, Anthropic, etc.) in an encrypted vault. They allow for easier key rotation and budget management. [Learn more about virtual keys here](https://portkey.ai/docs/product/ai-gateway/virtual-keys).
    </Info>
  </Step>
</Steps>

## Production Features

### 1. Enhanced Observability

Portkey provides comprehensive observability for your CrewAI agents, helping you understand exactly what's happening during each execution.

<Tabs>
  <Tab title="Traces">
    <Frame>
      <img />
    </Frame>

    Traces provide a hierarchical view of your crew's execution, showing the sequence of LLM calls, tool invocations, and state transitions.

    ```python theme={null}
    # Add trace_id to enable hierarchical tracing in Portkey
    portkey_llm = LLM(
        model="gpt-4o",
        base_url=PORTKEY_GATEWAY_URL,
        api_key="dummy",
        extra_headers=createHeaders(
            api_key="YOUR_PORTKEY_API_KEY",
            virtual_key="YOUR_OPENAI_VIRTUAL_KEY",
            trace_id="unique-session-id"  # Add unique trace ID
        )
    )
    ```
  </Tab>

  <Tab title="Logs">
    <Frame>
      <img />
    </Frame>

    Portkey logs every interaction with LLMs, including:

    * Complete request and response payloads
    * Latency and token usage metrics
    * Cost calculations
    * Tool calls and function executions

    All logs can be filtered by metadata, trace IDs, models, and more, making it easy to debug specific crew runs.
  </Tab>

  <Tab title="Metrics & Dashboards">
    <Frame>
      <img />
    </Frame>

    Portkey provides built-in dashboards that help you:

    * Track cost and token usage across all crew runs
    * Analyze performance metrics like latency and success rates
    * Identify bottlenecks in your agent workflows
    * Compare different crew configurations and LLMs

    You can filter and segment all metrics by custom metadata to analyze specific crew types, user groups, or use cases.
  </Tab>

  <Tab title="Metadata Filtering">
    <Frame>
      <img alt="Analytics with metadata filters" />
    </Frame>

    Add custom metadata to your CrewAI LLM configuration to enable powerful filtering and segmentation:

    ```python theme={null}
    portkey_llm = LLM(
        model="gpt-4o",
        base_url=PORTKEY_GATEWAY_URL,
        api_key="dummy",
        extra_headers=createHeaders(
            api_key="YOUR_PORTKEY_API_KEY",
            virtual_key="YOUR_OPENAI_VIRTUAL_KEY",
            metadata={
                "crew_type": "research_crew",
                "environment": "production",
                "_user": "user_123",   # Special _user field for user analytics
                "request_source": "mobile_app"
            }
        )
    )
    ```

    This metadata can be used to filter logs, traces, and metrics on the Portkey dashboard, allowing you to analyze specific crew runs, users, or environments.
  </Tab>
</Tabs>

### 2. Reliability - Keep Your Crews Running Smoothly

When running crews in production, things can go wrong - API rate limits, network issues, or provider outages. Portkey's reliability features ensure your agents keep running smoothly even when problems occur.

It's simple to enable fallback in your CrewAI setup by using a Portkey Config:

```python theme={null}
from crewai import LLM
from portkey_ai import createHeaders, PORTKEY_GATEWAY_URL

# Create LLM with fallback configuration
portkey_llm = LLM(
    model="gpt-4o",
    max_tokens=1000,
    base_url=PORTKEY_GATEWAY_URL,
    api_key="dummy",
    extra_headers=createHeaders(
        api_key="YOUR_PORTKEY_API_KEY",
        config={
            "strategy": {
                "mode": "fallback"
            },
            "targets": [
                {
                    "provider": "openai",
                    "api_key": "YOUR_OPENAI_API_KEY",
                    "override_params": {"model": "gpt-4o"}
                },
                {
                    "provider": "anthropic",
                    "api_key": "YOUR_ANTHROPIC_API_KEY",
                    "override_params": {"model": "claude-3-opus-20240229"}
                }
            ]
        }
    )
)

# Use this LLM configuration with your agents
```

This configuration will automatically try Claude if the GPT-4o request fails, ensuring your crew can continue operating.

<CardGroup>
  <Card title="Automatic Retries" icon="rotate" href="https://portkey.ai/docs/product/ai-gateway/automatic-retries">
    Handles temporary failures automatically. If an LLM call fails, Portkey will retry the same request for the specified number of times - perfect for rate limits or network blips.
  </Card>

  <Card title="Request Timeouts" icon="clock" href="https://portkey.ai/docs/product/ai-gateway/request-timeouts">
    Prevent your agents from hanging. Set timeouts to ensure you get responses (or can fail gracefully) within your required timeframes.
  </Card>

  <Card title="Conditional Routing" icon="route" href="https://portkey.ai/docs/product/ai-gateway/conditional-routing">
    Send different requests to different providers. Route complex reasoning to GPT-4, creative tasks to Claude, and quick responses to Gemini based on your needs.
  </Card>

  <Card title="Fallbacks" icon="shield" href="https://portkey.ai/docs/product/ai-gateway/fallbacks">
    Keep running even if your primary provider fails. Automatically switch to backup providers to maintain availability.
  </Card>

  <Card title="Load Balancing" icon="scale-balanced" href="https://portkey.ai/docs/product/ai-gateway/load-balancing">
    Spread requests across multiple API keys or providers. Great for high-volume crew operations and staying within rate limits.
  </Card>
</CardGroup>

### 3. Prompting in CrewAI

Portkey's Prompt Engineering Studio helps you create, manage, and optimize the prompts used in your CrewAI agents. Instead of hardcoding prompts or instructions, use Portkey's prompt rendering API to dynamically fetch and apply your versioned prompts.

<Frame>
  ![Prompt Playground Interface](https://raw.githubusercontent.com/siddharthsambharia-portkey/Portkey-Product-Images/refs/heads/main/CrewAI%20Portkey%20Docs.webp)
</Frame>

<Tabs>
  <Tab title="Prompt Playground">
    Prompt Playground is a place to compare, test and deploy perfect prompts for your AI application. It's where you experiment with different models, test variables, compare outputs, and refine your prompt engineering strategy before deploying to production. It allows you to:

    1. Iteratively develop prompts before using them in your agents
    2. Test prompts with different variables and models
    3. Compare outputs between different prompt versions
    4. Collaborate with team members on prompt development

    This visual environment makes it easier to craft effective prompts for each step in your CrewAI agents' workflow.
  </Tab>

  <Tab title="Using Prompt Templates">
    The Prompt Render API retrieves your prompt templates with all parameters configured:

    ```python theme={null}
    from crewai import Agent, LLM
    from portkey_ai import createHeaders, PORTKEY_GATEWAY_URL, Portkey

    # Initialize Portkey admin client
    portkey_admin = Portkey(api_key="YOUR_PORTKEY_API_KEY")

    # Retrieve prompt using the render API
    prompt_data = portkey_client.prompts.render(
        prompt_id="YOUR_PROMPT_ID",
        variables={
            "agent_role": "Senior Research Scientist",
        }
    )

    backstory_agent_prompt=prompt_data.data.messages[0]["content"]


    # Set up LLM with Portkey integration
    portkey_llm = LLM(
        model="gpt-4o",
        base_url=PORTKEY_GATEWAY_URL,
        api_key="dummy",
        extra_headers=createHeaders(
            api_key="YOUR_PORTKEY_API_KEY",
            virtual_key="YOUR_OPENAI_VIRTUAL_KEY"
        )
    )

    # Create agent using the rendered prompt
    researcher = Agent(
        role="Senior Research Scientist",
        goal="Discover groundbreaking insights about the assigned topic",
        backstory=backstory_agent,  # Use the rendered prompt
        verbose=True,
        llm=portkey_llm
    )
    ```
  </Tab>

  <Tab title="Prompt Versioning">
    You can:

    * Create multiple versions of the same prompt
    * Compare performance between versions
    * Roll back to previous versions if needed
    * Specify which version to use in your code:

    ```python theme={null}
    # Use a specific prompt version
    prompt_data = portkey_admin.prompts.render(
        prompt_id="YOUR_PROMPT_ID@version_number",
        variables={
            "agent_role": "Senior Research Scientist",
            "agent_goal": "Discover groundbreaking insights"
        }
    )
    ```
  </Tab>

  <Tab title="Mustache Templating for variables">
    Portkey prompts use Mustache-style templating for easy variable substitution:

    ```
    You are a {{agent_role}} with expertise in {{domain}}.

    Your mission is to {{agent_goal}} by leveraging your knowledge
    and experience in the field.

    Always maintain a {{tone}} tone and focus on providing {{focus_area}}.
    ```

    When rendering, simply pass the variables:

    ```python theme={null}
    prompt_data = portkey_admin.prompts.render(
        prompt_id="YOUR_PROMPT_ID",
        variables={
            "agent_role": "Senior Research Scientist",
            "domain": "artificial intelligence",
            "agent_goal": "discover groundbreaking insights",
            "tone": "professional",
            "focus_area": "practical applications"
        }
    )
    ```
  </Tab>
</Tabs>

<Card title="Prompt Engineering Studio" icon="wand-magic-sparkles" href="https://portkey.ai/docs/product/prompt-library">
  Learn more about Portkey's prompt management features
</Card>

### 4. Guardrails for Safe Crews

Guardrails ensure your CrewAI agents operate safely and respond appropriately in all situations.

**Why Use Guardrails?**

CrewAI agents can experience various failure modes:

* Generating harmful or inappropriate content
* Leaking sensitive information like PII
* Hallucinating incorrect information
* Generating outputs in incorrect formats

Portkey's guardrails add protections for both inputs and outputs.

**Implementing Guardrails**

```python theme={null}
from crewai import Agent, LLM
from portkey_ai import createHeaders, PORTKEY_GATEWAY_URL

# Create LLM with guardrails
portkey_llm = LLM(
    model="gpt-4o",
    base_url=PORTKEY_GATEWAY_URL,
    api_key="dummy",
    extra_headers=createHeaders(
        api_key="YOUR_PORTKEY_API_KEY",
        virtual_key="YOUR_OPENAI_VIRTUAL_KEY",
        config={
            "input_guardrails": ["guardrails-id-xxx", "guardrails-id-yyy"],
            "output_guardrails": ["guardrails-id-zzz"]
        }
    )
)

# Create agent with guardrailed LLM
researcher = Agent(
    role="Senior Research Scientist",
    goal="Discover groundbreaking insights about the assigned topic",
    backstory="You are an expert researcher with deep domain knowledge.",
    verbose=True,
    llm=portkey_llm
)
```

Portkey's guardrails can:

* Detect and redact PII in both inputs and outputs
* Filter harmful or inappropriate content
* Validate response formats against schemas
* Check for hallucinations against ground truth
* Apply custom business logic and rules

<Card title="Learn More About Guardrails" icon="shield-check" href="https://portkey.ai/docs/product/guardrails">
  Explore Portkey's guardrail features to enhance agent safety
</Card>

### 5. User Tracking with Metadata

Track individual users through your CrewAI agents using Portkey's metadata system.

**What is Metadata in Portkey?**

Metadata allows you to associate custom data with each request, enabling filtering, segmentation, and analytics. The special `_user` field is specifically designed for user tracking.

```python theme={null}
from crewai import Agent, LLM
from portkey_ai import createHeaders, PORTKEY_GATEWAY_URL

# Configure LLM with user tracking
portkey_llm = LLM(
    model="gpt-4o",
    base_url=PORTKEY_GATEWAY_URL,
    api_key="dummy",
    extra_headers=createHeaders(
        api_key="YOUR_PORTKEY_API_KEY",
        virtual_key="YOUR_OPENAI_VIRTUAL_KEY",
        metadata={
            "_user": "user_123",  # Special _user field for user analytics
            "user_tier": "premium",
            "user_company": "Acme Corp",
            "session_id": "abc-123"
        }
    )
)

# Create agent with tracked LLM
researcher = Agent(
    role="Senior Research Scientist",
    goal="Discover groundbreaking insights about the assigned topic",
    backstory="You are an expert researcher with deep domain knowledge.",
    verbose=True,
    llm=portkey_llm
)
```

**Filter Analytics by User**

With metadata in place, you can filter analytics by user and analyze performance metrics on a per-user basis:

<Frame>
  <img />
</Frame>

This enables:

* Per-user cost tracking and budgeting
* Personalized user analytics
* Team or organization-level metrics
* Environment-specific monitoring (staging vs. production)

<Card title="Learn More About Metadata" icon="tags" href="https://portkey.ai/docs/product/observability/metadata">
  Explore how to use custom metadata to enhance your analytics
</Card>

### 6. Caching for Efficient Crews

Implement caching to make your CrewAI agents more efficient and cost-effective:

<Tabs>
  <Tab title="Simple Caching">
    ```python theme={null}
    from crewai import Agent, LLM
    from portkey_ai import createHeaders, PORTKEY_GATEWAY_URL

    # Configure LLM with simple caching
    portkey_llm = LLM(
        model="gpt-4o",
        base_url=PORTKEY_GATEWAY_URL,
        api_key="dummy",
        extra_headers=createHeaders(
            api_key="YOUR_PORTKEY_API_KEY",
            virtual_key="YOUR_OPENAI_VIRTUAL_KEY",
            config={
                "cache": {
                    "mode": "simple"
                }
            }
        )
    )

    # Create agent with cached LLM
    researcher = Agent(
        role="Senior Research Scientist",
        goal="Discover groundbreaking insights about the assigned topic",
        backstory="You are an expert researcher with deep domain knowledge.",
        verbose=True,
        llm=portkey_llm
    )
    ```

    Simple caching performs exact matches on input prompts, caching identical requests to avoid redundant model executions.
  </Tab>

  <Tab title="Semantic Caching">
    ```python theme={null}
    from crewai import Agent, LLM
    from portkey_ai import createHeaders, PORTKEY_GATEWAY_URL

    # Configure LLM with semantic caching
    portkey_llm = LLM(
        model="gpt-4o",
        base_url=PORTKEY_GATEWAY_URL,
        api_key="dummy",
        extra_headers=createHeaders(
            api_key="YOUR_PORTKEY_API_KEY",
            virtual_key="YOUR_OPENAI_VIRTUAL_KEY",
            config={
                "cache": {
                    "mode": "semantic"
                }
            }
        )
    )

    # Create agent with semantically cached LLM
    researcher = Agent(
        role="Senior Research Scientist",
        goal="Discover groundbreaking insights about the assigned topic",
        backstory="You are an expert researcher with deep domain knowledge.",
        verbose=True,
        llm=portkey_llm
    )
    ```

    Semantic caching considers the contextual similarity between input requests, caching responses for semantically similar inputs.
  </Tab>
</Tabs>

### 7. Model Interoperability

CrewAI supports multiple LLM providers, and Portkey extends this capability by providing access to over 200 LLMs through a unified interface. You can easily switch between different models without changing your core agent logic:

```python theme={null}
from crewai import Agent, LLM
from portkey_ai import createHeaders, PORTKEY_GATEWAY_URL

# Set up LLMs with different providers
openai_llm = LLM(
    model="gpt-4o",
    base_url=PORTKEY_GATEWAY_URL,
    api_key="dummy",
    extra_headers=createHeaders(
        api_key="YOUR_PORTKEY_API_KEY",
        virtual_key="YOUR_OPENAI_VIRTUAL_KEY"
    )
)

anthropic_llm = LLM(
    model="claude-3-5-sonnet-latest",
    max_tokens=1000,
    base_url=PORTKEY_GATEWAY_URL,
    api_key="dummy",
    extra_headers=createHeaders(
        api_key="YOUR_PORTKEY_API_KEY",
        virtual_key="YOUR_ANTHROPIC_VIRTUAL_KEY"
    )
)

# Choose which LLM to use for each agent based on your needs
researcher = Agent(
    role="Senior Research Scientist",
    goal="Discover groundbreaking insights about the assigned topic",
    backstory="You are an expert researcher with deep domain knowledge.",
    verbose=True,
    llm=openai_llm  # Use anthropic_llm for Anthropic
)
```

Portkey provides access to LLMs from providers including:

* OpenAI (GPT-4o, GPT-4 Turbo, etc.)
* Anthropic (Claude 3.5 Sonnet, Claude 3 Opus, etc.)
* Mistral AI (Mistral Large, Mistral Medium, etc.)
* Google Vertex AI (Gemini 1.5 Pro, etc.)
* Cohere (Command, Command-R, etc.)
* AWS Bedrock (Claude, Titan, etc.)
* Local/Private Models

<Card title="Supported Providers" icon="server" href="https://portkey.ai/docs/integrations/llms">
  See the full list of LLM providers supported by Portkey
</Card>

## Set Up Enterprise Governance for CrewAI

**Why Enterprise Governance?**
If you are using CrewAI inside your organization, you need to consider several governance aspects:

* **Cost Management**: Controlling and tracking AI spending across teams
* **Access Control**: Managing which teams can use specific models
* **Usage Analytics**: Understanding how AI is being used across the organization
* **Security & Compliance**: Maintaining enterprise security standards
* **Reliability**: Ensuring consistent service across all users

Portkey adds a comprehensive governance layer to address these enterprise needs. Let's implement these controls step by step.

<Steps>
  <Step title="Create Virtual Key">
    Virtual Keys are Portkey's secure way to manage your LLM provider API keys. They provide essential controls like:

    * Budget limits for API usage
    * Rate limiting capabilities
    * Secure API key storage

    To create a virtual key:
    Go to [Virtual Keys](https://app.portkey.ai/virtual-keys) in the Portkey App. Save and copy the virtual key ID

    <Frame>
      <img />
    </Frame>

    <Note>
      Save your virtual key ID - you'll need it for the next step.
    </Note>
  </Step>

  <Step title="Create Default Config">
    Configs in Portkey define how your requests are routed, with features like advanced routing, fallbacks, and retries.

    To create your config:

    1. Go to [Configs](https://app.portkey.ai/configs) in Portkey dashboard
    2. Create new config with:
       ```json theme={null}
       {
           "virtual_key": "YOUR_VIRTUAL_KEY_FROM_STEP1",
          	"override_params": {
             "model": "gpt-4o" // Your preferred model name
           }
       }
       ```
    3. Save and note the Config name for the next step

    <Frame>
      <img />
    </Frame>
  </Step>

  <Step title="Configure Portkey API Key">
    Now create a Portkey API key and attach the config you created in Step 2:

    1. Go to [API Keys](https://app.portkey.ai/api-keys) in Portkey and Create new API key
    2. Select your config from `Step 2`
    3. Generate and save your API key

    <Frame>
      <img />
    </Frame>
  </Step>

  <Step title="Connect to CrewAI">
    After setting up your Portkey API key with the attached config, connect it to your CrewAI agents:

    ```python theme={null}
    from crewai import Agent, LLM
    from portkey_ai import PORTKEY_GATEWAY_URL

    # Configure LLM with your API key
    portkey_llm = LLM(
        model="gpt-4o",
        base_url=PORTKEY_GATEWAY_URL,
        api_key="YOUR_PORTKEY_API_KEY"
    )

    # Create agent with Portkey-enabled LLM
    researcher = Agent(
        role="Senior Research Scientist",
        goal="Discover groundbreaking insights about the assigned topic",
        backstory="You are an expert researcher with deep domain knowledge.",
        verbose=True,
        llm=portkey_llm
    )
    ```
  </Step>
</Steps>

<AccordionGroup>
  <Accordion title="Step 1: Implement Budget Controls & Rate Limits">
    ### Step 1: Implement Budget Controls & Rate Limits

    Virtual Keys enable granular control over LLM access at the team/department level. This helps you:

    * Set up [budget limits](https://portkey.ai/docs/product/ai-gateway/virtual-keys/budget-limits)
    * Prevent unexpected usage spikes using Rate limits
    * Track departmental spending

    #### Setting Up Department-Specific Controls:

    1. Navigate to [Virtual Keys](https://app.portkey.ai/virtual-keys) in Portkey dashboard
    2. Create new Virtual Key for each department with budget limits and rate limits
    3. Configure department-specific limits

    <Frame>
      <img />
    </Frame>
  </Accordion>

  <Accordion title="Step 2: Define Model Access Rules">
    ### Step 2: Define Model Access Rules

    As your AI usage scales, controlling which teams can access specific models becomes crucial. Portkey Configs provide this control layer with features like:

    #### Access Control Features:

    * **Model Restrictions**: Limit access to specific models
    * **Data Protection**: Implement guardrails for sensitive data
    * **Reliability Controls**: Add fallbacks and retry logic

    #### Example Configuration:

    Here's a basic configuration to route requests to OpenAI, specifically using GPT-4o:

    ```json theme={null}
    {
    	"strategy": {
    		"mode": "single"
    	},
    	"targets": [
    		{
    			"virtual_key": "YOUR_OPENAI_VIRTUAL_KEY",
    			"override_params": {
    				"model": "gpt-4o"
    			}
    		}
    	]
    }
    ```

    Create your config on the [Configs page](https://app.portkey.ai/configs) in your Portkey dashboard.

    <Note>
      Configs can be updated anytime to adjust controls without affecting running applications.
    </Note>
  </Accordion>

  <Accordion title="Step 3: Implement Access Controls">
    ### Step 3: Implement Access Controls

    Create User-specific API keys that automatically:

    * Track usage per user/team with the help of virtual keys
    * Apply appropriate configs to route requests
    * Collect relevant metadata to filter logs
    * Enforce access permissions

    Create API keys through the [Portkey App](https://app.portkey.ai/)

    Example using Python SDK:

    ```python theme={null}
    from portkey_ai import Portkey

    portkey = Portkey(api_key="YOUR_ADMIN_API_KEY")

    api_key = portkey.api_keys.create(
        name="engineering-team",
        type="organisation",
        workspace_id="YOUR_WORKSPACE_ID",
        defaults={
            "config_id": "your-config-id",
            "metadata": {
                "environment": "production",
                "department": "engineering"
            }
        },
        scopes=["logs.view", "configs.read"]
    )
    ```

    For detailed key management instructions, see the [Portkey documentation](https://portkey.ai/docs).
  </Accordion>

  <Accordion title="Step 4: Deploy & Monitor">
    ### Step 4: Deploy & Monitor

    After distributing API keys to your team members, your enterprise-ready CrewAI setup is ready to go. Each team member can now use their designated API keys with appropriate access levels and budget controls.

    Monitor usage in Portkey dashboard:

    * Cost tracking by department
    * Model usage patterns
    * Request volumes
    * Error rates
  </Accordion>
</AccordionGroup>

<Note>
  ### Enterprise Features Now Available

  **Your CrewAI integration now has:**

  * Departmental budget controls
  * Model access governance
  * Usage tracking & attribution
  * Security guardrails
  * Reliability features
</Note>

## Frequently Asked Questions

<AccordionGroup>
  <Accordion title="How does Portkey enhance CrewAI?">
    Portkey adds production-readiness to CrewAI through comprehensive observability (traces, logs, metrics), reliability features (fallbacks, retries, caching), and access to 200+ LLMs through a unified interface. This makes it easier to debug, optimize, and scale your agent applications.
  </Accordion>

  <Accordion title="Can I use Portkey with existing CrewAI applications?">
    Yes! Portkey integrates seamlessly with existing CrewAI applications. You just need to update your LLM configuration code with the Portkey-enabled version. The rest of your agent and crew code remains unchanged.
  </Accordion>

  <Accordion title="Does Portkey work with all CrewAI features?">
    Portkey supports all CrewAI features, including agents, tools, human-in-the-loop workflows, and all task process types (sequential, hierarchical, etc.). It adds observability and reliability without limiting any of the framework's functionality.
  </Accordion>

  <Accordion title="Can I track usage across multiple agents in a crew?">
    Yes, Portkey allows you to use a consistent `trace_id` across multiple agents in a crew to track the entire workflow. This is especially useful for complex crews where you want to understand the full execution path across multiple agents.
  </Accordion>

  <Accordion title="How do I filter logs and traces for specific crew runs?">
    Portkey allows you to add custom metadata to your LLM configuration, which you can then use for filtering. Add fields like `crew_name`, `crew_type`, or `session_id` to easily find and analyze specific crew executions.
  </Accordion>

  <Accordion title="Can I use my own API keys with Portkey?">
    Yes! Portkey uses your own API keys for the various LLM providers. It securely stores them as virtual keys, allowing you to easily manage and rotate keys without changing your code.
  </Accordion>
</AccordionGroup>

## Resources

<CardGroup>
  <Card title="CrewAI Docs" icon="book" href="https://docs.crewai.com/">
    <p>Official CrewAI documentation</p>
  </Card>

  <Card title="Book a Demo" icon="calendar" href="https://calendly.com/portkey-ai">
    <p>Get personalized guidance on implementing this integration</p>
  </Card>
</CardGroup>


# CrewAI Tracing
Source: https://docs.crewai.com/en/observability/tracing

Built-in tracing for CrewAI Crews and Flows with the CrewAI AMP platform

# CrewAI Built-in Tracing

CrewAI provides built-in tracing capabilities that allow you to monitor and debug your Crews and Flows in real-time. This guide demonstrates how to enable tracing for both **Crews** and **Flows** using CrewAI's integrated observability platform.

> **What is CrewAI Tracing?** CrewAI's built-in tracing provides comprehensive observability for your AI agents, including agent decisions, task execution timelines, tool usage, and LLM calls - all accessible through the [CrewAI AMP platform](https://app.crewai.com).

<img alt="CrewAI Tracing Interface" />

## Prerequisites

Before you can use CrewAI tracing, you need:

1. **CrewAI AMP Account**: Sign up for a free account at [app.crewai.com](https://app.crewai.com)
2. **CLI Authentication**: Use the CrewAI CLI to authenticate your local environment

```bash theme={null}
crewai login
```

## Setup Instructions

### Step 1: Create Your CrewAI AMP Account

Visit [app.crewai.com](https://app.crewai.com) and create your free account. This will give you access to the CrewAI AMP platform where you can view traces, metrics, and manage your crews.

### Step 2: Install CrewAI CLI and Authenticate

If you haven't already, install CrewAI with the CLI tools:

```bash theme={null}
uv add 'crewai[tools]'
```

Then authenticate your CLI with your CrewAI AMP account:

```bash theme={null}
crewai login
```

This command will:

1. Open your browser to the authentication page
2. Prompt you to enter a device code
3. Authenticate your local environment with your CrewAI AMP account
4. Enable tracing capabilities for your local development

### Step 3: Enable Tracing in Your Crew

You can enable tracing for your Crew by setting the `tracing` parameter to `True`:

```python theme={null}
from crewai import Agent, Crew, Process, Task
from crewai_tools import SerperDevTool

# Define your agents
researcher = Agent(
    role="Senior Research Analyst",
    goal="Uncover cutting-edge developments in AI and data science",
    backstory="""You work at a leading tech think tank.
    Your expertise lies in identifying emerging trends.
    You have a knack for dissecting complex data and presenting actionable insights.""",
    verbose=True,
    tools=[SerperDevTool()],
)

writer = Agent(
    role="Tech Content Strategist",
    goal="Craft compelling content on tech advancements",
    backstory="""You are a renowned Content Strategist, known for your insightful and engaging articles.
    You transform complex concepts into compelling narratives.""",
    verbose=True,
)

# Create tasks for your agents
research_task = Task(
    description="""Conduct a comprehensive analysis of the latest advancements in AI in 2024.
    Identify key trends, breakthrough technologies, and potential industry impacts.""",
    expected_output="Full analysis report in bullet points",
    agent=researcher,
)

writing_task = Task(
    description="""Using the insights provided, develop an engaging blog
    post that highlights the most significant AI advancements.
    Your post should be informative yet accessible, catering to a tech-savvy audience.""",
    expected_output="Full blog post of at least 4 paragraphs",
    agent=writer,
)

# Enable tracing in your crew
crew = Crew(
    agents=[researcher, writer],
    tasks=[research_task, writing_task],
    process=Process.sequential,
    tracing=True,  # Enable built-in tracing
    verbose=True
)

# Execute your crew
result = crew.kickoff()
```

### Step 4: Enable Tracing in Your Flow

Similarly, you can enable tracing for CrewAI Flows:

```python theme={null}
from crewai.flow.flow import Flow, listen, start
from pydantic import BaseModel

class ExampleState(BaseModel):
    counter: int = 0
    message: str = ""

class ExampleFlow(Flow[ExampleState]):
    def __init__(self):
        super().__init__(tracing=True)  # Enable tracing for the flow

    @start()
    def first_method(self):
        print("Starting the flow")
        self.state.counter = 1
        self.state.message = "Flow started"
        return "continue"

    @listen("continue")
    def second_method(self):
        print("Continuing the flow")
        self.state.counter += 1
        self.state.message = "Flow continued"
        return "finish"

    @listen("finish")
    def final_method(self):
        print("Finishing the flow")
        self.state.counter += 1
        self.state.message = "Flow completed"

# Create and run the flow with tracing enabled
flow = ExampleFlow(tracing=True)
result = flow.kickoff()
```

### Step 5: View Traces in the CrewAI AMP Dashboard

After running the crew or flow, you can view the traces generated by your CrewAI application in the CrewAI AMP dashboard. You should see detailed steps of the agent interactions, tool usages, and LLM calls.
Just click on the link below to view the traces or head over to the traces tab in the dashboard [here](https://app.crewai.com/crewai_plus/trace_batches)

<img alt="CrewAI Tracing Interface" />

### Alternative: Environment Variable Configuration

You can also enable tracing globally by setting an environment variable:

```bash theme={null}
export CREWAI_TRACING_ENABLED=true
```

Or add it to your `.env` file:

```env theme={null}
CREWAI_TRACING_ENABLED=true
```

When this environment variable is set, all Crews and Flows will automatically have tracing enabled, even without explicitly setting `tracing=True`.

## Viewing Your Traces

### Access the CrewAI AMP Dashboard

1. Visit [app.crewai.com](https://app.crewai.com) and log in to your account
2. Navigate to your project dashboard
3. Click on the **Traces** tab to view execution details

### What You'll See in Traces

CrewAI tracing provides comprehensive visibility into:

* **Agent Decisions**: See how agents reason through tasks and make decisions
* **Task Execution Timeline**: Visual representation of task sequences and dependencies
* **Tool Usage**: Monitor which tools are called and their results
* **LLM Calls**: Track all language model interactions, including prompts and responses
* **Performance Metrics**: Execution times, token usage, and costs
* **Error Tracking**: Detailed error information and stack traces

### Trace Features

* **Execution Timeline**: Click through different stages of execution
* **Detailed Logs**: Access comprehensive logs for debugging
* **Performance Analytics**: Analyze execution patterns and optimize performance
* **Export Capabilities**: Download traces for further analysis

### Authentication Issues

If you encounter authentication problems:

1. Ensure you're logged in: `crewai login`
2. Check your internet connection
3. Verify your account at [app.crewai.com](https://app.crewai.com)

### Traces Not Appearing

If traces aren't showing up in the dashboard:

1. Confirm `tracing=True` is set in your Crew/Flow
2. Check that `CREWAI_TRACING_ENABLED=true` if using environment variables
3. Ensure you're authenticated with `crewai login`
4. Verify your crew/flow is actually executing


# TrueFoundry Integration
Source: https://docs.crewai.com/en/observability/truefoundry



TrueFoundry provides an enterprise-ready [AI Gateway](https://www.truefoundry.com/ai-gateway) which can integrate with agentic frameworks like CrewAI and provides governance and observability for your AI Applications. TrueFoundry AI Gateway serves as a unified interface for LLM access, providing:

* **Unified API Access**: Connect to 250+ LLMs (OpenAI, Claude, Gemini, Groq, Mistral) through one API
* **Low Latency**: Sub-3ms internal latency with intelligent routing and load balancing
* **Enterprise Security**: SOC 2, HIPAA, GDPR compliance with RBAC and audit logging
* **Quota and cost management**: Token-based quotas, rate limiting, and comprehensive usage tracking
* **Observability**: Full request/response logging, metrics, and traces with customizable retention

## How TrueFoundry Integrates with CrewAI

### Installation & Setup

<Steps>
  <Step title="Install CrewAI">
    ```bash theme={null}
    pip install crewai
    ```
  </Step>

  <Step title="Get TrueFoundry Access Token">
    1. Sign up for a [TrueFoundry account](https://www.truefoundry.com/register)
    2. Follow the steps here in [Quick start](https://docs.truefoundry.com/gateway/quick-start)
  </Step>

  <Step title="Configure CrewAI with TrueFoundry">
    <img alt="TrueFoundry Code Configuration" />

    ```python theme={null}
    from crewai import LLM

    # Create an LLM instance with TrueFoundry AI Gateway
    truefoundry_llm = LLM(
        model="openai-main/gpt-4o",  # Similarly, you can call any model from any provider
        base_url="your_truefoundry_gateway_base_url",
        api_key="your_truefoundry_api_key"
    )

    # Use in your CrewAI agents
    from crewai import Agent

    @agent
    def researcher(self) -> Agent:
        return Agent(
            config=self.agents_config['researcher'],
            llm=truefoundry_llm,
            verbose=True
        )
    ```
  </Step>
</Steps>

### Complete CrewAI Example

```python theme={null}
from crewai import Agent, Task, Crew, LLM

# Configure LLM with TrueFoundry
llm = LLM(
    model="openai-main/gpt-4o",
    base_url="your_truefoundry_gateway_base_url", 
    api_key="your_truefoundry_api_key"
)

# Create agents
researcher = Agent(
    role='Research Analyst',
    goal='Conduct detailed market research',
    backstory='Expert market analyst with attention to detail',
    llm=llm,
    verbose=True
)

writer = Agent(
    role='Content Writer', 
    goal='Create comprehensive reports',
    backstory='Experienced technical writer',
    llm=llm,
    verbose=True
)

# Create tasks
research_task = Task(
    description='Research AI market trends for 2024',
    agent=researcher,
    expected_output='Comprehensive research summary'
)

writing_task = Task(
    description='Create a market research report',
    agent=writer,
    expected_output='Well-structured report with insights',
    context=[research_task]
)

# Create and execute crew
crew = Crew(
    agents=[researcher, writer],
    tasks=[research_task, writing_task],
    verbose=True
)

result = crew.kickoff()
```

### Observability and Governance

Monitor your CrewAI agents through TrueFoundry's metrics tab:

<img alt="TrueFoundry metrics" />

With Truefoundry's AI gateway, you can monitor and analyze:

* **Performance Metrics**: Track key latency metrics like Request Latency, Time to First Token (TTFS), and Inter-Token Latency (ITL) with P99, P90, and P50 percentiles
* **Cost and Token Usage**: Gain visibility into your application's costs with detailed breakdowns of input/output tokens and the associated expenses for each model
* **Usage Patterns**: Understand how your application is being used with detailed analytics on user activity, model distribution, and team-based usage
* **Rate limit and Load balancing**: You can set up rate limiting, load balancing and fallback for your models

## Tracing

For a more detailed understanding on tracing, please see [getting-started-tracing](https://docs.truefoundry.com/docs/tracing/tracing-getting-started).For tracing, you can add the Traceloop SDK:
For tracing, you can add the Traceloop SDK:

```bash theme={null}
pip install traceloop-sdk
```

```python theme={null}
from traceloop.sdk import Traceloop

# Initialize enhanced tracing
Traceloop.init(
    api_endpoint="https://your-truefoundry-endpoint/api/tracing",
    headers={
        "Authorization": f"Bearer {your_truefoundry_pat_token}",
        "TFY-Tracing-Project": "your_project_name",
    },
)
```

This provides additional trace correlation across your entire CrewAI workflow.

<img alt="TrueFoundry CrewAI Tracing" />


# Weave Integration
Source: https://docs.crewai.com/en/observability/weave

Learn how to use Weights & Biases (W&B) Weave to track, experiment with, evaluate, and improve your CrewAI applications.

# Weave Overview

[Weights & Biases (W\&B) Weave](https://weave-docs.wandb.ai/) is a framework for tracking, experimenting with, evaluating, deploying, and improving LLM-based applications.

<img alt="Overview of W&B Weave CrewAI tracing usage" />

Weave provides comprehensive support for every stage of your CrewAI application development:

* **Tracing & Monitoring**: Automatically track LLM calls and application logic to debug and analyze production systems
* **Systematic Iteration**: Refine and iterate on prompts, datasets, and models
* **Evaluation**: Use custom or pre-built scorers to systematically assess and enhance agent performance
* **Guardrails**: Protect your agents with pre- and post-safeguards for content moderation and prompt safety

Weave automatically captures traces for your CrewAI applications, enabling you to monitor and analyze your agents' performance, interactions, and execution flow. This helps you build better evaluation datasets and optimize your agent workflows.

## Setup Instructions

<Steps>
  <Step title="Install required packages">
    ```shell theme={null}
    pip install crewai weave
    ```
  </Step>

  <Step title="Set up W&B Account">
    Sign up for a [Weights & Biases account](https://wandb.ai) if you haven't already. You'll need this to view your traces and metrics.
  </Step>

  <Step title="Initialize Weave in Your Application">
    Add the following code to your application:

    ```python theme={null}
    import weave

    # Initialize Weave with your project name
    weave.init(project_name="crewai_demo")
    ```

    After initialization, Weave will provide a URL where you can view your traces and metrics.
  </Step>

  <Step title="Create your Crews/Flows">
    ```python theme={null}
    from crewai import Agent, Task, Crew, LLM, Process

    # Create an LLM with a temperature of 0 to ensure deterministic outputs
    llm = LLM(model="gpt-4o", temperature=0)

    # Create agents
    researcher = Agent(
        role='Research Analyst',
        goal='Find and analyze the best investment opportunities',
        backstory='Expert in financial analysis and market research',
        llm=llm,
        verbose=True,
        allow_delegation=False,
    )

    writer = Agent(
        role='Report Writer',
        goal='Write clear and concise investment reports',
        backstory='Experienced in creating detailed financial reports',
        llm=llm,
        verbose=True,
        allow_delegation=False,
    )

    # Create tasks
    research_task = Task(
        description='Deep research on the {topic}',
        expected_output='Comprehensive market data including key players, market size, and growth trends.',
        agent=researcher
    )

    writing_task = Task(
        description='Write a detailed report based on the research',
        expected_output='The report should be easy to read and understand. Use bullet points where applicable.',
        agent=writer
    )

    # Create a crew
    crew = Crew(
        agents=[researcher, writer],
        tasks=[research_task, writing_task],
        verbose=True,
        process=Process.sequential,
    )

    # Run the crew
    result = crew.kickoff(inputs={"topic": "AI in material science"})
    print(result)
    ```
  </Step>

  <Step title="View Traces in Weave">
    After running your CrewAI application, visit the Weave URL provided during initialization to view:

    * LLM calls and their metadata
    * Agent interactions and task execution flow
    * Performance metrics like latency and token usage
    * Any errors or issues that occurred during execution

    <Frame>
      <img alt="Weave tracing example with CrewAI" />
    </Frame>
  </Step>
</Steps>

## Features

* Weave automatically captures all CrewAI operations: agent interactions and task executions; LLM calls with metadata and token usage; tool usage and results.
* The integration supports all CrewAI execution methods: `kickoff()`, `kickoff_for_each()`, `kickoff_async()`, and `kickoff_for_each_async()`.
* Automatic tracing of all [crewAI-tools](https://github.com/crewAIInc/crewAI-tools).
* Flow feature support with decorator patching (`@start`, `@listen`, `@router`, `@or_`, `@and_`).
* Track custom guardrails passed to CrewAI `Task` with `@weave.op()`.

For detailed information on what's supported, visit the [Weave CrewAI documentation](https://weave-docs.wandb.ai/guides/integrations/crewai/#getting-started-with-flow).

## Resources

* [📘 Weave Documentation](https://weave-docs.wandb.ai)
* [📊 Example Weave x CrewAI dashboard](https://wandb.ai/ayut/crewai_demo/weave/traces?cols=%7B%22wb_run_id%22%3Afalse%2C%22attributes.weave.client_version%22%3Afalse%2C%22attributes.weave.os_name%22%3Afalse%2C%22attributes.weave.os_release%22%3Afalse%2C%22attributes.weave.os_version%22%3Afalse%2C%22attributes.weave.source%22%3Afalse%2C%22attributes.weave.sys_version%22%3Afalse%7D\&peekPath=%2Fayut%2Fcrewai_demo%2Fcalls%2F0195c838-38cb-71a2-8a15-651ecddf9d89)
* [🐦 X](https://x.com/weave_wb)


# Telemetry
Source: https://docs.crewai.com/en/telemetry

Understanding the telemetry data collected by CrewAI and how it contributes to the enhancement of the library.

## Telemetry

<Note>
  By default, we collect no data that would be considered personal information under GDPR and other privacy regulations.
  We do collect Tool's names and Agent's roles, so be advised not to include any personal information in the tool's names or the Agent's roles.
  Because no personal information is collected, it's not necessary to worry about data residency.
  When `share_crew` is enabled, additional data is collected which may contain personal information if included by the user.
  Users should exercise caution when enabling this feature to ensure compliance with privacy regulations.
</Note>

CrewAI utilizes anonymous telemetry to gather usage statistics with the primary goal of enhancing the library.
Our focus is on improving and developing the features, integrations, and tools most utilized by our users.

It's pivotal to understand that by default, **NO personal data is collected** concerning prompts, task descriptions, agents' backstories or goals,
usage of tools, API calls, responses, any data processed by the agents, or secrets and environment variables.
When the `share_crew` feature is enabled, detailed data including task descriptions, agents' backstories or goals, and other specific attributes are collected
to provide deeper insights. This expanded data collection may include personal information if users have incorporated it into their crews or tasks.
Users should carefully consider the content of their crews and tasks before enabling `share_crew`.
Users can disable telemetry by setting the environment variable `CREWAI_DISABLE_TELEMETRY` to `true` or by setting `OTEL_SDK_DISABLED` to `true` (note that the latter disables all OpenTelemetry instrumentation globally).

### Examples:

```python theme={null}
# Disable CrewAI telemetry only
os.environ['CREWAI_DISABLE_TELEMETRY'] = 'true'

# Disable all OpenTelemetry (including CrewAI)
os.environ['OTEL_SDK_DISABLED'] = 'true'
```

### Data Explanation:

| Defaulted | Data                                     | Reason and Specifics                                                                                                                                                                                                                                                                                             |
| :-------- | :--------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Yes       | CrewAI and Python Version                | Tracks software versions. Example: CrewAI v1.2.3, Python 3.8.10. No personal data.                                                                                                                                                                                                                               |
| Yes       | Crew Metadata                            | Includes: randomly generated key and ID, process type (e.g., 'sequential', 'parallel'), boolean flag for memory usage (true/false), count of tasks, count of agents. All non-personal.                                                                                                                           |
| Yes       | Agent Data                               | Includes: randomly generated key and ID, role name (should not include personal info), boolean settings (verbose, delegation enabled, code execution allowed), max iterations, max RPM, max retry limit, LLM info (see LLM Attributes), list of tool names (should not include personal info). No personal data. |
| Yes       | Task Metadata                            | Includes: randomly generated key and ID, boolean execution settings (async\_execution, human\_input), associated agent's role and key, list of tool names. All non-personal.                                                                                                                                     |
| Yes       | Tool Usage Statistics                    | Includes: tool name (should not include personal info), number of usage attempts (integer), LLM attributes used. No personal data.                                                                                                                                                                               |
| Yes       | Test Execution Data                      | Includes: crew's randomly generated key and ID, number of iterations, model name used, quality score (float), execution time (in seconds). All non-personal.                                                                                                                                                     |
| Yes       | Task Lifecycle Data                      | Includes: creation and execution start/end times, crew and task identifiers. Stored as spans with timestamps. No personal data.                                                                                                                                                                                  |
| Yes       | LLM Attributes                           | Includes: name, model\_name, model, top\_k, temperature, and class name of the LLM. All technical, non-personal data.                                                                                                                                                                                            |
| Yes       | Crew Deployment attempt using crewAI CLI | Includes: The fact a deploy is being made and crew id, and if it's trying to pull logs, no other data.                                                                                                                                                                                                           |
| No        | Agent's Expanded Data                    | Includes: goal description, backstory text, i18n prompt file identifier. Users should ensure no personal info is included in text fields.                                                                                                                                                                        |
| No        | Detailed Task Information                | Includes: task description, expected output description, context references. Users should ensure no personal info is included in these fields.                                                                                                                                                                   |
| No        | Environment Information                  | Includes: platform, release, system, version, and CPU count. Example: 'Windows 10', 'x86\_64'. No personal data.                                                                                                                                                                                                 |
| No        | Crew and Task Inputs and Outputs         | Includes: input parameters and output results as non-identifiable data. Users should ensure no personal info is included.                                                                                                                                                                                        |
| No        | Comprehensive Crew Execution Data        | Includes: detailed logs of crew operations, all agents and tasks data, final output. All non-personal and technical in nature.                                                                                                                                                                                   |

<Note>
  "No" in the "Defaulted" column indicates that this data is only collected when `share_crew` is set to `true`.
</Note>

### Opt-In Further Telemetry Sharing

Users can choose to share their complete telemetry data by enabling the `share_crew` attribute to `True` in their crew configurations.
Enabling `share_crew` results in the collection of detailed crew and task execution data, including `goal`, `backstory`, `context`, and `output` of tasks.
This enables a deeper insight into usage patterns.

<Warning>
  If you enable `share_crew`, the collected data may include personal information if it has been incorporated into crew configurations, task descriptions, or outputs.
  Users should carefully review their data and ensure compliance with GDPR and other applicable privacy regulations before enabling this feature.
</Warning>


# Apify Actors
Source: https://docs.crewai.com/en/tools/automation/apifyactorstool

`ApifyActorsTool` lets you call Apify Actors to provide your CrewAI workflows with web scraping, crawling, data extraction, and web automation capabilities.

# `ApifyActorsTool`

Integrate [Apify Actors](https://apify.com/actors) into your CrewAI workflows.

## Description

The `ApifyActorsTool` connects [Apify Actors](https://apify.com/actors), cloud-based programs for web scraping and automation, to your CrewAI workflows.
Use any of the 4,000+ Actors on [Apify Store](https://apify.com/store) for use cases such as extracting data from social media, search engines, online maps, e-commerce sites, travel portals, or general websites.

For details, see the [Apify CrewAI integration](https://docs.apify.com/platform/integrations/crewai) in Apify documentation.

## Steps to get started

<Steps>
  <Step title="Install dependencies">
    Install `crewai[tools]` and `langchain-apify` using pip: `pip install 'crewai[tools]' langchain-apify`.
  </Step>

  <Step title="Obtain an Apify API token">
    Sign up to [Apify Console](https://console.apify.com/) and get your [Apify API token](https://console.apify.com/settings/integrations)..
  </Step>

  <Step title="Configure environment">
    Set your Apify API token as the `APIFY_API_TOKEN` environment variable to enable the tool's functionality.
  </Step>
</Steps>

## Usage example

Use the `ApifyActorsTool` manually to run the [RAG Web Browser Actor](https://apify.com/apify/rag-web-browser) to perform a web search:

```python theme={null}
from crewai_tools import ApifyActorsTool

# Initialize the tool with an Apify Actor
tool = ApifyActorsTool(actor_name="apify/rag-web-browser")

# Run the tool with input parameters
results = tool.run(run_input={"query": "What is CrewAI?", "maxResults": 5})

# Process the results
for result in results:
    print(f"URL: {result['metadata']['url']}")
    print(f"Content: {result.get('markdown', 'N/A')[:100]}...")
```

### Expected output

Here is the output from running the code above:

```text theme={null}
URL: https://www.example.com/crewai-intro
Content: CrewAI is a framework for building AI-powered workflows...
URL: https://docs.crewai.com/
Content: Official documentation for CrewAI...
```

The `ApifyActorsTool` automatically fetches the Actor definition and input schema from Apify using the provided `actor_name` and then constructs the tool description and argument schema. This means you need to specify only a valid `actor_name`, and the tool handles the rest when used with agents—no need to specify the `run_input`. Here's how it works:

```python theme={null}
from crewai import Agent
from crewai_tools import ApifyActorsTool

rag_browser = ApifyActorsTool(actor_name="apify/rag-web-browser")

agent = Agent(
    role="Research Analyst",
    goal="Find and summarize information about specific topics",
    backstory="You are an experienced researcher with attention to detail",
    tools=[rag_browser],
)
```

You can run other Actors from [Apify Store](https://apify.com/store) simply by changing the `actor_name` and, when using it manually, adjusting the `run_input` based on the Actor input schema.

For an example of usage with agents, see the [CrewAI Actor template](https://apify.com/templates/python-crewai).

## Configuration

The `ApifyActorsTool` requires these inputs to work:

* **`actor_name`**
  The ID of the Apify Actor to run, e.g., `"apify/rag-web-browser"`. Browse all Actors on [Apify Store](https://apify.com/store).
* **`run_input`**
  A dictionary of input parameters for the Actor when running the tool manually.
  * For example, for the `apify/rag-web-browser` Actor: `{"query": "search term", "maxResults": 5}`
  * See the Actor's [input schema](https://apify.com/apify/rag-web-browser/input-schema) for the list of input parameters.

## Resources

* **[Apify](https://apify.com/)**: Explore the Apify platform.
* **[How to build an AI agent on Apify](https://blog.apify.com/how-to-build-an-ai-agent/)** - A complete step-by-step guide to creating, publishing, and monetizing AI agents on the Apify platform.
* **[RAG Web Browser Actor](https://apify.com/apify/rag-web-browser)**: A popular Actor for web search for LLMs.
* **[CrewAI Integration Guide](https://docs.apify.com/platform/integrations/crewai)**: Follow the official guide for integrating Apify and CrewAI.


# Composio Tool
Source: https://docs.crewai.com/en/tools/automation/composiotool

Composio provides 250+ production-ready tools for AI agents with flexible authentication management.

# `ComposioToolSet`

## Description

Composio is an integration platform that allows you to connect your AI agents to 250+ tools. Key features include:

* **Enterprise-Grade Authentication**: Built-in support for OAuth, API Keys, JWT with automatic token refresh
* **Full Observability**: Detailed tool usage logs, execution timestamps, and more

## Installation

To incorporate Composio tools into your project, follow the instructions below:

```shell theme={null}
pip install composio composio-crewai
pip install crewai
```

After the installation is complete, set your Composio API key as `COMPOSIO_API_KEY`. Get your Composio API key from [here](https://platform.composio.dev)

## Example

The following example demonstrates how to initialize the tool and execute a github action:

1. Initialize Composio with CrewAI Provider

```python Code theme={null}
from composio_crewai import ComposioProvider
from composio import Composio
from crewai import Agent, Task, Crew

composio = Composio(provider=ComposioProvider())
```

2. Create a new Composio Session and retrieve the tools

<CodeGroup>
  ```python theme={null}
  session = composio.create(
      user_id="your-user-id",
      toolkits=["gmail", "github"] # optional, default is all toolkits
  )
  tools = session.tools()
  ```

  Read more about sessions and user management [here](https://docs.composio.dev/docs/configuring-sessions)
</CodeGroup>

3. Authenticating users manually

Composio automatically authenticates the users during the agent chat session. However, you can also authenticate the user manually by calling the `authorize` method.

```python Code theme={null}
connection_request = session.authorize("github")
print(f"Open this URL to authenticate: {connection_request.redirect_url}")
```

4. Define agent

```python Code theme={null}
crewai_agent = Agent(
    role="GitHub Agent",
    goal="You take action on GitHub using GitHub APIs",
    backstory="You are AI agent that is responsible for taking actions on GitHub on behalf of users using GitHub APIs",
    verbose=True,
    tools=tools,
    llm= # pass an llm
)
```

5. Execute task

```python Code theme={null}
task = Task(
    description="Star a repo composiohq/composio on GitHub",
    agent=crewai_agent,
    expected_output="Status of the operation",
)

crew = Crew(agents=[crewai_agent], tasks=[task])

crew.kickoff()
```

* More detailed list of tools can be found [here](https://docs.composio.dev/toolkits)


# MultiOn Tool
Source: https://docs.crewai.com/en/tools/automation/multiontool

The `MultiOnTool` empowers CrewAI agents with the capability to navigate and interact with the web through natural language instructions.

## Overview

The `MultiOnTool` is designed to wrap [MultiOn's](https://docs.multion.ai/welcome) web browsing capabilities, enabling CrewAI agents to control web browsers using natural language instructions. This tool facilitates seamless web browsing, making it an essential asset for projects requiring dynamic web data interaction and automation of web-based tasks.

## Installation

To use this tool, you need to install the MultiOn package:

```shell theme={null}
uv add multion
```

You'll also need to install the MultiOn browser extension and enable API usage.

## Steps to Get Started

To effectively use the `MultiOnTool`, follow these steps:

1. **Install CrewAI**: Ensure that the `crewai[tools]` package is installed in your Python environment.
2. **Install and use MultiOn**: Follow [MultiOn documentation](https://docs.multion.ai/learn/browser-extension) for installing the MultiOn Browser Extension.
3. **Enable API Usage**: Click on the MultiOn extension in the extensions folder of your browser (not the hovering MultiOn icon on the web page) to open the extension configurations. Click the API Enabled toggle to enable the API.

## Example

The following example demonstrates how to initialize the tool and execute a web browsing task:

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import MultiOnTool

# Initialize the tool
multion_tool = MultiOnTool(api_key="YOUR_MULTION_API_KEY", local=False)

# Define an agent that uses the tool
browser_agent = Agent(
    role="Browser Agent",
    goal="Control web browsers using natural language",
    backstory="An expert browsing agent.",
    tools=[multion_tool],
    verbose=True,
)

# Example task to search and summarize news
browse_task = Task(
    description="Summarize the top 3 trending AI News headlines",
    expected_output="A summary of the top 3 trending AI News headlines",
    agent=browser_agent,
)

# Create and run the crew
crew = Crew(agents=[browser_agent], tasks=[browse_task])
result = crew.kickoff()
```

## Parameters

The `MultiOnTool` accepts the following parameters during initialization:

* **api\_key**: Optional. Specifies the MultiOn API key. If not provided, it will look for the `MULTION_API_KEY` environment variable.
* **local**: Optional. Set to `True` to run the agent locally on your browser. Make sure the MultiOn browser extension is installed and API Enabled is checked. Default is `False`.
* **max\_steps**: Optional. Sets the maximum number of steps the MultiOn agent can take for a command. Default is `3`.

## Usage

When using the `MultiOnTool`, the agent will provide natural language instructions that the tool translates into web browsing actions. The tool returns the results of the browsing session along with a status.

```python Code theme={null}
# Example of using the tool with an agent
browser_agent = Agent(
    role="Web Browser Agent",
    goal="Search for and summarize information from the web",
    backstory="An expert at finding and extracting information from websites.",
    tools=[multion_tool],
    verbose=True,
)

# Create a task for the agent
search_task = Task(
    description="Search for the latest AI news on TechCrunch and summarize the top 3 headlines",
    expected_output="A summary of the top 3 AI news headlines from TechCrunch",
    agent=browser_agent,
)

# Run the task
crew = Crew(agents=[browser_agent], tasks=[search_task])
result = crew.kickoff()
```

If the status returned is `CONTINUE`, the agent should be instructed to reissue the same instruction to continue execution.

## Implementation Details

The `MultiOnTool` is implemented as a subclass of `BaseTool` from CrewAI. It wraps the MultiOn client to provide web browsing capabilities:

```python Code theme={null}
class MultiOnTool(BaseTool):
    """Tool to wrap MultiOn Browse Capabilities."""

    name: str = "Multion Browse Tool"
    description: str = """Multion gives the ability for LLMs to control web browsers using natural language instructions.
            If the status is 'CONTINUE', reissue the same instruction to continue execution
        """
    
    # Implementation details...
    
    def _run(self, cmd: str, *args: Any, **kwargs: Any) -> str:
        """
        Run the Multion client with the given command.
        
        Args:
            cmd (str): The detailed and specific natural language instruction for web browsing
            *args (Any): Additional arguments to pass to the Multion client
            **kwargs (Any): Additional keyword arguments to pass to the Multion client
        """
        # Implementation details...
```

## Conclusion

The `MultiOnTool` provides a powerful way to integrate web browsing capabilities into CrewAI agents. By enabling agents to interact with websites through natural language instructions, it opens up a wide range of possibilities for web-based tasks, from data collection and research to automated interactions with web services.


# Overview
Source: https://docs.crewai.com/en/tools/automation/overview

Automate workflows and integrate with external platforms and services

These tools enable your agents to automate workflows, integrate with external platforms, and connect with various third-party services for enhanced functionality.

## **Available Tools**

<CardGroup>
  <Card title="Apify Actor Tool" icon="spider" href="/en/tools/automation/apifyactorstool">
    Run Apify actors for web scraping and automation tasks.
  </Card>

  <Card title="Composio Tool" icon="puzzle-piece" href="/en/tools/automation/composiotool">
    Integrate with hundreds of apps and services through Composio.
  </Card>

  <Card title="Multion Tool" icon="window-restore" href="/en/tools/automation/multiontool">
    Automate browser interactions and web-based workflows.
  </Card>

  <Card title="Zapier Actions Adapter" icon="bolt" href="/en/tools/automation/zapieractionstool">
    Expose Zapier Actions as CrewAI tools for automation across thousands of apps.
  </Card>
</CardGroup>

## **Common Use Cases**

* **Workflow Automation**: Automate repetitive tasks and processes
* **API Integration**: Connect with external APIs and services
* **Data Synchronization**: Sync data between different platforms
* **Process Orchestration**: Coordinate complex multi-step workflows
* **Third-party Services**: Leverage external tools and platforms

```python theme={null}
from crewai_tools import ApifyActorTool, ComposioTool, MultiOnTool

# Create automation tools
apify_automation = ApifyActorTool()
platform_integration = ComposioTool()
browser_automation = MultiOnTool()

# Add to your agent
agent = Agent(
    role="Automation Specialist",
    tools=[apify_automation, platform_integration, browser_automation],
    goal="Automate workflows and integrate systems"
)
```

## **Integration Benefits**

* **Efficiency**: Reduce manual work through automation
* **Scalability**: Handle increased workloads automatically
* **Reliability**: Consistent execution of workflows
* **Connectivity**: Bridge different systems and platforms
* **Productivity**: Focus on high-value tasks while automation handles routine work


# Zapier Actions Tool
Source: https://docs.crewai.com/en/tools/automation/zapieractionstool

The `ZapierActionsAdapter` exposes Zapier actions as CrewAI tools for automation.

# `ZapierActionsAdapter`

## Description

Use the Zapier adapter to list and call Zapier actions as CrewAI tools. This enables agents to trigger automations across thousands of apps.

## Installation

This adapter is included with `crewai-tools`. No extra install required.

## Environment Variables

* `ZAPIER_API_KEY` (required): Zapier API key. Get one from the Zapier Actions dashboard at [https://actions.zapier.com/](https://actions.zapier.com/) (create an account, then generate an API key). You can also pass `zapier_api_key` directly when constructing the adapter.

## Example

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools.adapters.zapier_adapter import ZapierActionsAdapter

adapter = ZapierActionsAdapter(api_key="your_zapier_api_key")
tools = adapter.tools()

agent = Agent(
    role="Automator",
    goal="Execute Zapier actions",
    backstory="Automation specialist",
    tools=tools,
    verbose=True,
)

task = Task(
    description="Create a new Google Sheet and add a row using Zapier actions",
    expected_output="Confirmation with created resource IDs",
    agent=agent,
)

crew = Crew(agents=[agent], tasks=[task])
result = crew.kickoff()
```

## Notes & limits

* The adapter lists available actions for your key and creates `BaseTool` wrappers dynamically.
* Handle action‑specific required fields in your task instructions or tool call.
* Rate limits depend on your Zapier plan; see the Zapier Actions docs.

## Notes

* The adapter fetches available actions and generates `BaseTool` wrappers dynamically.


# Bedrock Knowledge Base Retriever
Source: https://docs.crewai.com/en/tools/cloud-storage/bedrockkbretriever

Retrieve information from Amazon Bedrock Knowledge Bases using natural language queries

# `BedrockKBRetrieverTool`

The `BedrockKBRetrieverTool` enables CrewAI agents to retrieve information from Amazon Bedrock Knowledge Bases using natural language queries.

## Installation

```bash theme={null}
uv pip install 'crewai[tools]'
```

## Requirements

* AWS credentials configured (either through environment variables or AWS CLI)
* `boto3` and `python-dotenv` packages
* Access to Amazon Bedrock Knowledge Base

## Usage

Here's how to use the tool with a CrewAI agent:

```python {2, 4-17} theme={null}
from crewai import Agent, Task, Crew
from crewai_tools.aws.bedrock.knowledge_base.retriever_tool import BedrockKBRetrieverTool

# Initialize the tool
kb_tool = BedrockKBRetrieverTool(
    knowledge_base_id="your-kb-id",
    number_of_results=5
)

# Create a CrewAI agent that uses the tool
researcher = Agent(
    role='Knowledge Base Researcher',
    goal='Find information about company policies',
    backstory='I am a researcher specialized in retrieving and analyzing company documentation.',
    tools=[kb_tool],
    verbose=True
)

# Create a task for the agent
research_task = Task(
    description="Find our company's remote work policy and summarize the key points.",
    agent=researcher
)

# Create a crew with the agent
crew = Crew(
    agents=[researcher],
    tasks=[research_task],
    verbose=2
)

# Run the crew
result = crew.kickoff()
print(result)   
```

## Tool Arguments

| Argument                     | Type   | Required | Default | Description                                                                |
| :--------------------------- | :----- | :------- | :------ | :------------------------------------------------------------------------- |
| **knowledge\_base\_id**      | `str`  | Yes      | None    | The unique identifier of the knowledge base (0-10 alphanumeric characters) |
| **number\_of\_results**      | `int`  | No       | 5       | Maximum number of results to return                                        |
| **retrieval\_configuration** | `dict` | No       | None    | Custom configurations for the knowledge base query                         |
| **guardrail\_configuration** | `dict` | No       | None    | Content filtering settings                                                 |
| **next\_token**              | `str`  | No       | None    | Token for pagination                                                       |

## Environment Variables

```bash theme={null}
BEDROCK_KB_ID=your-knowledge-base-id  # Alternative to passing knowledge_base_id
AWS_REGION=your-aws-region            # Defaults to us-east-1
AWS_ACCESS_KEY_ID=your-access-key     # Required for AWS authentication
AWS_SECRET_ACCESS_KEY=your-secret-key # Required for AWS authentication
```

## Response Format

The tool returns results in JSON format:

```json theme={null}
{
  "results": [
    {
      "content": "Retrieved text content",
      "content_type": "text",
      "source_type": "S3",
      "source_uri": "s3://bucket/document.pdf",
      "score": 0.95,
      "metadata": {
        "additional": "metadata"
      }
    }
  ],
  "nextToken": "pagination-token",
  "guardrailAction": "NONE"
}
```

## Advanced Usage

### Custom Retrieval Configuration

```python theme={null}
kb_tool = BedrockKBRetrieverTool(
    knowledge_base_id="your-kb-id",
    retrieval_configuration={
        "vectorSearchConfiguration": {
            "numberOfResults": 10,
            "overrideSearchType": "HYBRID"
        }
    }
)

policy_expert = Agent(
    role='Policy Expert',
    goal='Analyze company policies in detail',
    backstory='I am an expert in corporate policy analysis with deep knowledge of regulatory requirements.',
    tools=[kb_tool]
)
```

## Supported Data Sources

* Amazon S3
* Confluence
* Salesforce
* SharePoint
* Web pages
* Custom document locations
* Amazon Kendra
* SQL databases

## Use Cases

### Enterprise Knowledge Integration

* Enable CrewAI agents to access your organization's proprietary knowledge without exposing sensitive data
* Allow agents to make decisions based on your company's specific policies, procedures, and documentation
* Create agents that can answer questions based on your internal documentation while maintaining data security

### Specialized Domain Knowledge

* Connect CrewAI agents to domain-specific knowledge bases (legal, medical, technical) without retraining models
* Leverage existing knowledge repositories that are already maintained in your AWS environment
* Combine CrewAI's reasoning with domain-specific information from your knowledge bases

### Data-Driven Decision Making

* Ground CrewAI agent responses in your actual company data rather than general knowledge
* Ensure agents provide recommendations based on your specific business context and documentation
* Reduce hallucinations by retrieving factual information from your knowledge bases

### Scalable Information Access

* Access terabytes of organizational knowledge without embedding it all into your models
* Dynamically query only the relevant information needed for specific tasks
* Leverage AWS's scalable infrastructure to handle large knowledge bases efficiently

### Compliance and Governance

* Ensure CrewAI agents provide responses that align with your company's approved documentation
* Create auditable trails of information sources used by your agents
* Maintain control over what information sources your agents can access


# S3 Reader Tool
Source: https://docs.crewai.com/en/tools/cloud-storage/s3readertool

The `S3ReaderTool` enables CrewAI agents to read files from Amazon S3 buckets.

# `S3ReaderTool`

## Description

The `S3ReaderTool` is designed to read files from Amazon S3 buckets. This tool allows CrewAI agents to access and retrieve content stored in S3, making it ideal for workflows that require reading data, configuration files, or any other content stored in AWS S3 storage.

## Installation

To use this tool, you need to install the required dependencies:

```shell theme={null}
uv add boto3
```

## Steps to Get Started

To effectively use the `S3ReaderTool`, follow these steps:

1. **Install Dependencies**: Install the required packages using the command above.
2. **Configure AWS Credentials**: Set up your AWS credentials as environment variables.
3. **Initialize the Tool**: Create an instance of the tool.
4. **Specify S3 Path**: Provide the S3 path to the file you want to read.

## Example

The following example demonstrates how to use the `S3ReaderTool` to read a file from an S3 bucket:

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools.aws.s3 import S3ReaderTool

# Initialize the tool
s3_reader_tool = S3ReaderTool()

# Define an agent that uses the tool
file_reader_agent = Agent(
    role="File Reader",
    goal="Read files from S3 buckets",
    backstory="An expert in retrieving and processing files from cloud storage.",
    tools=[s3_reader_tool],
    verbose=True,
)

# Example task to read a configuration file
read_task = Task(
    description="Read the configuration file from {my_bucket} and summarize its contents.",
    expected_output="A summary of the configuration file contents.",
    agent=file_reader_agent,
)

# Create and run the crew
crew = Crew(agents=[file_reader_agent], tasks=[read_task])
result = crew.kickoff(inputs={"my_bucket": "s3://my-bucket/config/app-config.json"})
```

## Parameters

The `S3ReaderTool` accepts the following parameter when used by an agent:

* **file\_path**: Required. The S3 file path in the format `s3://bucket-name/file-name`.

## AWS Credentials

The tool requires AWS credentials to access S3 buckets. You can configure these credentials using environment variables:

* **CREW\_AWS\_REGION**: The AWS region where your S3 bucket is located. Default is `us-east-1`.
* **CREW\_AWS\_ACCESS\_KEY\_ID**: Your AWS access key ID.
* **CREW\_AWS\_SEC\_ACCESS\_KEY**: Your AWS secret access key.

## Usage

When using the `S3ReaderTool` with an agent, the agent will need to provide the S3 file path:

```python Code theme={null}
# Example of using the tool with an agent
file_reader_agent = Agent(
    role="File Reader",
    goal="Read files from S3 buckets",
    backstory="An expert in retrieving and processing files from cloud storage.",
    tools=[s3_reader_tool],
    verbose=True,
)

# Create a task for the agent to read a specific file
read_config_task = Task(
    description="Read the application configuration file from {my_bucket} and extract the database connection settings.",
    expected_output="The database connection settings from the configuration file.",
    agent=file_reader_agent,
)

# Run the task
crew = Crew(agents=[file_reader_agent], tasks=[read_config_task])
result = crew.kickoff(inputs={"my_bucket": "s3://my-bucket/config/app-config.json"})
```

## Error Handling

The `S3ReaderTool` includes error handling for common S3 issues:

* Invalid S3 path format
* Missing or inaccessible files
* Permission issues
* AWS credential problems

When an error occurs, the tool will return an error message that includes details about the issue.

## Implementation Details

The `S3ReaderTool` uses the AWS SDK for Python (boto3) to interact with S3:

```python Code theme={null}
class S3ReaderTool(BaseTool):
    name: str = "S3 Reader Tool"
    description: str = "Reads a file from Amazon S3 given an S3 file path"
    
    def _run(self, file_path: str) -> str:
        try:
            bucket_name, object_key = self._parse_s3_path(file_path)

            s3 = boto3.client(
                's3',
                region_name=os.getenv('CREW_AWS_REGION', 'us-east-1'),
                aws_access_key_id=os.getenv('CREW_AWS_ACCESS_KEY_ID'),
                aws_secret_access_key=os.getenv('CREW_AWS_SEC_ACCESS_KEY')
            )

            # Read file content from S3
            response = s3.get_object(Bucket=bucket_name, Key=object_key)
            file_content = response['Body'].read().decode('utf-8')

            return file_content
        except ClientError as e:
            return f"Error reading file from S3: {str(e)}"
```

## Conclusion

The `S3ReaderTool` provides a straightforward way to read files from Amazon S3 buckets. By enabling agents to access content stored in S3, it facilitates workflows that require cloud-based file access. This tool is particularly useful for data processing, configuration management, and any task that involves retrieving information from AWS S3 storage.


# S3 Writer Tool
Source: https://docs.crewai.com/en/tools/cloud-storage/s3writertool

The `S3WriterTool` enables CrewAI agents to write content to files in Amazon S3 buckets.

# `S3WriterTool`

## Description

The `S3WriterTool` is designed to write content to files in Amazon S3 buckets. This tool allows CrewAI agents to create or update files in S3, making it ideal for workflows that require storing data, saving configuration files, or persisting any other content to AWS S3 storage.

## Installation

To use this tool, you need to install the required dependencies:

```shell theme={null}
uv add boto3
```

## Steps to Get Started

To effectively use the `S3WriterTool`, follow these steps:

1. **Install Dependencies**: Install the required packages using the command above.
2. **Configure AWS Credentials**: Set up your AWS credentials as environment variables.
3. **Initialize the Tool**: Create an instance of the tool.
4. **Specify S3 Path and Content**: Provide the S3 path where you want to write the file and the content to be written.

## Example

The following example demonstrates how to use the `S3WriterTool` to write content to a file in an S3 bucket:

```python Code theme={null}
from crewai import Agent, Task, Crew
from crewai_tools.aws.s3 import S3WriterTool

# Initialize the tool
s3_writer_tool = S3WriterTool()

# Define an agent that uses the tool
file_writer_agent = Agent(
    role="File Writer",
    goal="Write content to files in S3 buckets",
    backstory="An expert in storing and managing files in cloud storage.",
    tools=[s3_writer_tool],
    verbose=True,
)

# Example task to write a report
write_task = Task(
    description="Generate a summary report of the quarterly sales data and save it to {my_bucket}.",
    expected_output="Confirmation that the report was successfully saved to S3.",
    agent=file_writer_agent,
)

# Create and run the crew
crew = Crew(agents=[file_writer_agent], tasks=[write_task])
result = crew.kickoff(inputs={"my_bucket": "s3://my-bucket/reports/quarterly-summary.txt"})
```

## Parameters

The `S3WriterTool` accepts the following parameters when used by an agent:

* **file\_path**: Required. The S3 file path in the format `s3://bucket-name/file-name`.
* **content**: Required. The content to write to the file.

## AWS Credentials

The tool requires AWS credentials to access S3 buckets. You can configure these credentials using environment variables:

* **CREW\_AWS\_REGION**: The AWS region where your S3 bucket is located. Default is `us-east-1`.
* **CREW\_AWS\_ACCESS\_KEY\_ID**: Your AWS access key ID.
* **CREW\_AWS\_SEC\_ACCESS\_KEY**: Your AWS secret access key.

## Usage

When using the `S3WriterTool` with an agent, the agent will need to provide both the S3 file path and the content to write:

```python Code theme={null}
# Example of using the tool with an agent
file_writer_agent = Agent(
    role="File Writer",
    goal="Write content to files in S3 buckets",
    backstory="An expert in storing and managing files in cloud storage.",
    tools=[s3_writer_tool],
    verbose=True,
)

# Create a task for the agent to write a specific file
write_config_task = Task(
    description="""
    Create a configuration file with the following database settings:
    - host: db.example.com
    - port: 5432
    - username: app_user
    - password: secure_password
    
    Save this configuration as JSON to {my_bucket}.
    """,
    expected_output="Confirmation that the configuration file was successfully saved to S3.",
    agent=file_writer_agent,
)

# Run the task
crew = Crew(agents=[file_writer_agent], tasks=[write_config_task])
result = crew.kickoff(inputs={"my_bucket": "s3://my-bucket/config/db-config.json"})
```

## Error Handling

The `S3WriterTool` includes error handling for common S3 issues:

* Invalid S3 path format
* Permission issues (e.g., no write access to the bucket)
* AWS credential problems
* Bucket does not exist

When an error occurs, the tool will return an error message that includes details about the issue.

## Implementation Details

The `S3WriterTool` uses the AWS SDK for Python (boto3) to interact with S3:

```python Code theme={null}
class S3WriterTool(BaseTool):
    name: str = "S3 Writer Tool"
    description: str = "Writes content to a file in Amazon S3 given an S3 file path"
    
    def _run(self, file_path: str, content: str) -> str:
        try:
            bucket_name, object_key = self._parse_s3_path(file_path)

            s3 = boto3.client(
                's3',
                region_name=os.getenv('CREW_AWS_REGION', 'us-east-1'),
                aws_access_key_id=os.getenv('CREW_AWS_ACCESS_KEY_ID'),
                aws_secret_access_key=os.getenv('CREW_AWS_SEC_ACCESS_KEY')
            )

            s3.put_object(Bucket=bucket_name, Key=object_key, Body=content.encode('utf-8'))
            return f"Successfully wrote content to {file_path}"
        except ClientError as e:
            return f"Error writing file to S3: {str(e)}"
```

## Conclusion

The `S3WriterTool` provides a straightforward way to write content to files in Amazon S3 buckets. By enabling agents to create and update files in S3, it facilitates workflows that require cloud-based file storage. This tool is particularly useful for data persistence, configuration management, report generation, and any task that involves storing information in AWS S3 storage.


# Bedrock Invoke Agent Tool
Source: https://docs.crewai.com/en/tools/integration/bedrockinvokeagenttool

Enables CrewAI agents to invoke Amazon Bedrock Agents and leverage their capabilities within your workflows

# `BedrockInvokeAgentTool`

The `BedrockInvokeAgentTool` enables CrewAI agents to invoke Amazon Bedrock Agents and leverage their capabilities within your workflows.

## Installation

```bash theme={null}
uv pip install 'crewai[tools]'
```

## Requirements

* AWS credentials configured (either through environment variables or AWS CLI)
* `boto3` and `python-dotenv` packages
* Access to Amazon Bedrock Agents

## Usage

Here's how to use the tool with a CrewAI agent:

```python {2, 4-8} theme={null}
from crewai import Agent, Task, Crew
from crewai_tools.aws.bedrock.agents.invoke_agent_tool import BedrockInvokeAgentTool

# Initialize the tool
agent_tool = BedrockInvokeAgentTool(
    agent_id="your-agent-id",
    agent_alias_id="your-agent-alias-id"
)

# Create a CrewAI agent that uses the tool
aws_expert = Agent(
    role='AWS Service Expert',
    goal='Help users understand AWS services and quotas',
    backstory='I am an expert in AWS services and can provide detailed information about them.',
    tools=[agent_tool],
    verbose=True
)

# Create a task for the agent
quota_task = Task(
    description="Find out the current service quotas for EC2 in us-west-2 and explain any recent changes.",
    agent=aws_expert
)

# Create a crew with the agent
crew = Crew(
    agents=[aws_expert],
    tasks=[quota_task],
    verbose=2
)

# Run the crew
result = crew.kickoff()
print(result)
```

## Tool Arguments

| Argument             | Type   | Required | Default   | Description                                 |
| :------------------- | :----- | :------- | :-------- | :------------------------------------------ |
| **agent\_id**        | `str`  | Yes      | None      | The unique identifier of the Bedrock agent  |
| **agent\_alias\_id** | `str`  | Yes      | None      | The unique identifier of the agent alias    |
| **session\_id**      | `str`  | No       | timestamp | The unique identifier of the session        |
| **enable\_trace**    | `bool` | No       | False     | Whether to enable trace for debugging       |
| **end\_session**     | `bool` | No       | False     | Whether to end the session after invocation |
| **description**      | `str`  | No       | None      | Custom description for the tool             |

## Environment Variables

```bash theme={null}
BEDROCK_AGENT_ID=your-agent-id           # Alternative to passing agent_id
BEDROCK_AGENT_ALIAS_ID=your-agent-alias-id # Alternative to passing agent_alias_id
AWS_REGION=your-aws-region               # Defaults to us-west-2
AWS_ACCESS_KEY_ID=your-access-key        # Required for AWS authentication
AWS_SECRET_ACCESS_KEY=your-secret-key    # Required for AWS authentication
```

## Advanced Usage

### Multi-Agent Workflow with Session Management

```python {2, 4-22} theme={null}
from crewai import Agent, Task, Crew, Process
from crewai_tools.aws.bedrock.agents.invoke_agent_tool import BedrockInvokeAgentTool

# Initialize tools with session management
initial_tool = BedrockInvokeAgentTool(
    agent_id="your-agent-id",
    agent_alias_id="your-agent-alias-id",
    session_id="custom-session-id"
)

followup_tool = BedrockInvokeAgentTool(
    agent_id="your-agent-id",
    agent_alias_id="your-agent-alias-id",
    session_id="custom-session-id"
)

final_tool = BedrockInvokeAgentTool(
    agent_id="your-agent-id",
    agent_alias_id="your-agent-alias-id",
    session_id="custom-session-id",
    end_session=True
)

# Create agents for different stages
researcher = Agent(
    role='AWS Service Researcher',
    goal='Gather information about AWS services',
    backstory='I am specialized in finding detailed AWS service information.',
    tools=[initial_tool]
)

analyst = Agent(
    role='Service Compatibility Analyst',
    goal='Analyze service compatibility and requirements',
    backstory='I analyze AWS services for compatibility and integration possibilities.',
    tools=[followup_tool]
)

summarizer = Agent(
    role='Technical Documentation Writer',
    goal='Create clear technical summaries',
    backstory='I specialize in creating clear, concise technical documentation.',
    tools=[final_tool]
)

# Create tasks
research_task = Task(
    description="Find all available AWS services in us-west-2 region.",
    agent=researcher
)

analysis_task = Task(
    description="Analyze which services support IPv6 and their implementation requirements.",
    agent=analyst
)

summary_task = Task(
    description="Create a summary of IPv6-compatible services and their key features.",
    agent=summarizer
)

# Create a crew with the agents and tasks
crew = Crew(
    agents=[researcher, analyst, summarizer],
    tasks=[research_task, analysis_task, summary_task],
    process=Process.sequential,
    verbose=2
)

# Run the crew
result = crew.kickoff()
```

## Use Cases

### Hybrid Multi-Agent Collaborations

* Create workflows where CrewAI agents collaborate with managed Bedrock agents running as services in AWS
* Enable scenarios where sensitive data processing happens within your AWS environment while other agents operate externally
* Bridge on-premises CrewAI agents with cloud-based Bedrock agents for distributed intelligence workflows

### Data Sovereignty and Compliance

* Keep data-sensitive agentic workflows within your AWS environment while allowing external CrewAI agents to orchestrate tasks
* Maintain compliance with data residency requirements by processing sensitive information only within your AWS account
* Enable secure multi-agent collaborations where some agents cannot access your organization's private data

### Seamless AWS Service Integration

* Access any AWS service through Amazon Bedrock Actions without writing complex integration code
* Enable CrewAI agents to interact with AWS services through natural language requests
* Leverage pre-built Bedrock agent capabilities to interact with AWS services like Bedrock Knowledge Bases, Lambda, and more

### Scalable Hybrid Agent Architectures

* Offload computationally intensive tasks to managed Bedrock agents while lightweight tasks run in CrewAI
* Scale agent processing by distributing workloads between local CrewAI agents and cloud-based Bedrock agents

### Cross-Organizational Agent Collaboration

* Enable secure collaboration between your organization's CrewAI agents and partner organizations' Bedrock agents
* Create workflows where external expertise from Bedrock agents can be incorporated without exposing sensitive data
* Build agent ecosystems that span organizational boundaries while maintaining security and data control


# CrewAI Run Automation Tool
Source: https://docs.crewai.com/en/tools/integration/crewaiautomationtool

Enables CrewAI agents to invoke CrewAI Platform automations and leverage external crew services within your workflows.

# `InvokeCrewAIAutomationTool`

The `InvokeCrewAIAutomationTool` provides CrewAI Platform API integration with external crew services. This tool allows you to invoke and interact with CrewAI Platform automations from within your CrewAI agents, enabling seamless integration between different crew workflows.

## Installation

```bash theme={null}
uv pip install 'crewai[tools]'
```

## Requirements

* CrewAI Platform API access
* Valid bearer token for authentication
* Network access to CrewAI Platform automation endpoints

## Usage

Here's how to use the tool with a CrewAI agent:

```python {2, 4-9} theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import InvokeCrewAIAutomationTool

# Initialize the tool
automation_tool = InvokeCrewAIAutomationTool(
    crew_api_url="https://data-analysis-crew-[...].crewai.com",
    crew_bearer_token="your_bearer_token_here",
    crew_name="Data Analysis Crew",
    crew_description="Analyzes data and generates insights"
)

# Create a CrewAI agent that uses the tool
automation_coordinator = Agent(
    role='Automation Coordinator',
    goal='Coordinate and execute automated crew tasks',
    backstory='I am an expert at leveraging automation tools to execute complex workflows.',
    tools=[automation_tool],
    verbose=True
)

# Create a task for the agent
analysis_task = Task(
    description="Execute data analysis automation and provide insights",
    agent=automation_coordinator,
    expected_output="Comprehensive data analysis report"
)

# Create a crew with the agent
crew = Crew(
    agents=[automation_coordinator],
    tasks=[analysis_task],
    verbose=2
)

# Run the crew
result = crew.kickoff()
print(result)
```

## Tool Arguments

| Argument                | Type   | Required | Default | Description                                         |
| :---------------------- | :----- | :------- | :------ | :-------------------------------------------------- |
| **crew\_api\_url**      | `str`  | Yes      | None    | Base URL of the CrewAI Platform automation API      |
| **crew\_bearer\_token** | `str`  | Yes      | None    | Bearer token for API authentication                 |
| **crew\_name**          | `str`  | Yes      | None    | Name of the crew automation                         |
| **crew\_description**   | `str`  | Yes      | None    | Description of what the crew automation does        |
| **max\_polling\_time**  | `int`  | No       | 600     | Maximum time in seconds to wait for task completion |
| **crew\_inputs**        | `dict` | No       | None    | Dictionary defining custom input schema fields      |

## Environment Variables

```bash theme={null}
CREWAI_API_URL=https://your-crew-automation.crewai.com  # Alternative to passing crew_api_url
CREWAI_BEARER_TOKEN=your_bearer_token_here              # Alternative to passing crew_bearer_token
```

## Advanced Usage

### Custom Input Schema with Dynamic Parameters

```python {2, 4-15} theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import InvokeCrewAIAutomationTool
from pydantic import Field

# Define custom input schema
custom_inputs = {
    "year": Field(..., description="Year to retrieve the report for (integer)"),
    "region": Field(default="global", description="Geographic region for analysis"),
    "format": Field(default="summary", description="Report format (summary, detailed, raw)")
}

# Create tool with custom inputs
market_research_tool = InvokeCrewAIAutomationTool(
    crew_api_url="https://state-of-ai-report-crew-[...].crewai.com",
    crew_bearer_token="your_bearer_token_here",
    crew_name="State of AI Report",
    crew_description="Retrieves a comprehensive report on state of AI for a given year and region",
    crew_inputs=custom_inputs,
    max_polling_time=15 * 60  # 15 minutes timeout
)

# Create an agent with the tool
research_agent = Agent(
    role="Research Coordinator",
    goal="Coordinate and execute market research tasks",
    backstory="You are an expert at coordinating research tasks and leveraging automation tools.",
    tools=[market_research_tool],
    verbose=True
)

# Create and execute a task with custom parameters
research_task = Task(
    description="Conduct market research on AI tools market for 2024 in North America with detailed format",
    agent=research_agent,
    expected_output="Comprehensive market research report"
)

crew = Crew(
    agents=[research_agent],
    tasks=[research_task]
)

result = crew.kickoff()
```

### Multi-Stage Automation Workflow

```python {2, 4-35} theme={null}
from crewai import Agent, Task, Crew, Process
from crewai_tools import InvokeCrewAIAutomationTool

# Initialize different automation tools
data_collection_tool = InvokeCrewAIAutomationTool(
    crew_api_url="https://data-collection-crew-[...].crewai.com",
    crew_bearer_token="your_bearer_token_here",
    crew_name="Data Collection Automation",
    crew_description="Collects and preprocesses raw data"
)

analysis_tool = InvokeCrewAIAutomationTool(
    crew_api_url="https://analysis-crew-[...].crewai.com",
    crew_bearer_token="your_bearer_token_here",
    crew_name="Analysis Automation",
    crew_description="Performs advanced data analysis and modeling"
)

reporting_tool = InvokeCrewAIAutomationTool(
    crew_api_url="https://reporting-crew-[...].crewai.com",
    crew_bearer_token="your_bearer_token_here",
    crew_name="Reporting Automation",
    crew_description="Generates comprehensive reports and visualizations"
)

# Create specialized agents
data_collector = Agent(
    role='Data Collection Specialist',
    goal='Gather and preprocess data from various sources',
    backstory='I specialize in collecting and cleaning data from multiple sources.',
    tools=[data_collection_tool]
)

data_analyst = Agent(
    role='Data Analysis Expert',
    goal='Perform advanced analysis on collected data',
    backstory='I am an expert in statistical analysis and machine learning.',
    tools=[analysis_tool]
)

report_generator = Agent(
    role='Report Generation Specialist',
    goal='Create comprehensive reports and visualizations',
    backstory='I excel at creating clear, actionable reports from complex data.',
    tools=[reporting_tool]
)

# Create sequential tasks
collection_task = Task(
    description="Collect market data for Q4 2024 analysis",
    agent=data_collector
)

analysis_task = Task(
    description="Analyze collected data to identify trends and patterns",
    agent=data_analyst
)

reporting_task = Task(
    description="Generate executive summary report with key insights and recommendations",
    agent=report_generator
)

# Create a crew with sequential processing
crew = Crew(
    agents=[data_collector, data_analyst, report_generator],
    tasks=[collection_task, analysis_task, reporting_task],
    process=Process.sequential,
    verbose=2
)

result = crew.kickoff()
```

## Use Cases

### Distributed Crew Orchestration

* Coordinate multiple specialized crew automations to handle complex, multi-stage workflows
* Enable seamless handoffs between different automation services for comprehensive task execution
* Scale processing by distributing workloads across multiple CrewAI Platform automations

### Cross-Platform Integration

* Bridge CrewAI agents with CrewAI Platform automations for hybrid local-cloud workflows
* Leverage specialized automations while maintaining local control and orchestration
* Enable secure collaboration between local agents and cloud-based automation services

### Enterprise Automation Pipelines

* Create enterprise-grade automation pipelines that combine local intelligence with cloud processing power
* Implement complex business workflows that span multiple automation services
* Enable scalable, repeatable processes for data analysis, reporting, and decision-making

### Dynamic Workflow Composition

* Dynamically compose workflows by chaining different automation services based on task requirements
* Enable adaptive processing where the choice of automation depends on data characteristics or business rules
* Create flexible, reusable automation components that can be combined in various ways

### Specialized Domain Processing

* Access domain-specific automations (financial analysis, legal research, technical documentation) from general-purpose agents
* Leverage pre-built, specialized crew automations without rebuilding complex domain logic
* Enable agents to access expert-level capabilities through targeted automation services

## Custom Input Schema

When defining `crew_inputs`, use Pydantic Field objects to specify the input parameters:

```python theme={null}
from pydantic import Field

crew_inputs = {
    "required_param": Field(..., description="This parameter is required"),
    "optional_param": Field(default="default_value", description="This parameter is optional"),
    "typed_param": Field(..., description="Integer parameter", ge=1, le=100)  # With validation
}
```

## Error Handling

The tool provides comprehensive error handling for common scenarios:

* **API Connection Errors**: Network connectivity issues with CrewAI Platform
* **Authentication Errors**: Invalid or expired bearer tokens
* **Timeout Errors**: Tasks that exceed the maximum polling time
* **Task Failures**: Crew automations that fail during execution
* **Input Validation Errors**: Invalid parameters passed to automation endpoints

## API Endpoints

The tool interacts with two main API endpoints:

* `POST {crew_api_url}/kickoff`: Starts a new crew automation task
* `GET {crew_api_url}/status/{crew_id}`: Checks the status of a running task

## Notes

* The tool automatically polls the status endpoint every second until completion or timeout
* Successful tasks return the result directly, while failed tasks return error information
* Bearer tokens should be kept secure and not hardcoded in production environments
* Consider using environment variables for sensitive configuration like bearer tokens
* Custom input schemas must be compatible with the target crew automation's expected parameters


# Merge Agent Handler Tool
Source: https://docs.crewai.com/en/tools/integration/mergeagenthandlertool

Enables CrewAI agents to securely access third-party integrations like Linear, GitHub, Slack, and more through Merge's Agent Handler platform

# `MergeAgentHandlerTool`

The `MergeAgentHandlerTool` enables CrewAI agents to securely access third-party integrations through [Merge's Agent Handler](https://www.merge.dev/products/merge-agent-handler) platform. Agent Handler provides pre-built, secure connectors to popular tools like Linear, GitHub, Slack, Notion, and hundreds more—all with built-in authentication, permissions, and monitoring.

## Installation

```bash theme={null}
uv pip install 'crewai[tools]'
```

## Requirements

* Merge Agent Handler account with a configured Tool Pack
* Agent Handler API key
* At least one registered user linked to your Tool Pack
* Third-party integrations configured in your Tool Pack

## Getting Started with Agent Handler

1. **Sign up** for a Merge Agent Handler account at [ah.merge.dev/signup](https://ah.merge.dev/signup)
2. **Create a Tool Pack** and configure the integrations you need
3. **Register users** who will authenticate with the third-party services
4. **Get your API key** from the Agent Handler dashboard
5. **Set environment variable**: `export AGENT_HANDLER_API_KEY='your-key-here'`
6. **Start building** with the MergeAgentHandlerTool in CrewAI

## Notes

* Tool Pack IDs and Registered User IDs can be found in your Agent Handler dashboard or created via API
* The tool uses the Model Context Protocol (MCP) for communication with Agent Handler
* Session IDs are automatically generated but can be customized for context persistence
* All tool calls are logged and auditable through the Agent Handler platform
* Tool parameters are dynamically discovered from the Agent Handler API and validated automatically

## Usage

### Single Tool Usage

Here's how to use a specific tool from your Tool Pack:

```python {2, 4-9} theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import MergeAgentHandlerTool

# Create a tool for Linear issue creation
linear_create_tool = MergeAgentHandlerTool.from_tool_name(
    tool_name="linear__create_issue",
    tool_pack_id="134e0111-0f67-44f6-98f0-597000290bb3",
    registered_user_id="91b2b905-e866-40c8-8be2-efe53827a0aa"
)

# Create a CrewAI agent that uses the tool
project_manager = Agent(
    role='Project Manager',
    goal='Manage project tasks and issues efficiently',
    backstory='I am an expert at tracking project work and creating actionable tasks.',
    tools=[linear_create_tool],
    verbose=True
)

# Create a task for the agent
create_issue_task = Task(
    description="Create a new high-priority issue in Linear titled 'Implement user authentication' with a detailed description of the requirements.",
    agent=project_manager,
    expected_output="Confirmation that the issue was created with its ID"
)

# Create a crew with the agent
crew = Crew(
    agents=[project_manager],
    tasks=[create_issue_task],
    verbose=True
)

# Run the crew
result = crew.kickoff()
print(result)
```

### Loading Multiple Tools from a Tool Pack

You can load all available tools from your Tool Pack at once:

```python {2, 4-8} theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import MergeAgentHandlerTool

# Load all tools from the Tool Pack
tools = MergeAgentHandlerTool.from_tool_pack(
    tool_pack_id="134e0111-0f67-44f6-98f0-597000290bb3",
    registered_user_id="91b2b905-e866-40c8-8be2-efe53827a0aa"
)

# Create an agent with access to all tools
automation_expert = Agent(
    role='Automation Expert',
    goal='Automate workflows across multiple platforms',
    backstory='I can work with any tool in the toolbox to get things done.',
    tools=tools,
    verbose=True
)

automation_task = Task(
    description="Check for any high-priority issues in Linear and post a summary to Slack.",
    agent=automation_expert
)

crew = Crew(
    agents=[automation_expert],
    tasks=[automation_task],
    verbose=True
)

result = crew.kickoff()
```

### Loading Specific Tools Only

Load only the tools you need:

```python {2, 4-10} theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import MergeAgentHandlerTool

# Load specific tools from the Tool Pack
selected_tools = MergeAgentHandlerTool.from_tool_pack(
    tool_pack_id="134e0111-0f67-44f6-98f0-597000290bb3",
    registered_user_id="91b2b905-e866-40c8-8be2-efe53827a0aa",
    tool_names=["linear__create_issue", "linear__get_issues", "slack__post_message"]
)

developer_assistant = Agent(
    role='Developer Assistant',
    goal='Help developers track and communicate about their work',
    backstory='I help developers stay organized and keep the team informed.',
    tools=selected_tools,
    verbose=True
)

daily_update_task = Task(
    description="Get all issues assigned to the current user in Linear and post a summary to the #dev-updates Slack channel.",
    agent=developer_assistant
)

crew = Crew(
    agents=[developer_assistant],
    tasks=[daily_update_task],
    verbose=True
)

result = crew.kickoff()
```

## Tool Arguments

### `from_tool_name()` Method

| Argument                 | Type  | Required | Default                                                | Description                                                        |
| :----------------------- | :---- | :------- | :----------------------------------------------------- | :----------------------------------------------------------------- |
| **tool\_name**           | `str` | Yes      | None                                                   | Name of the specific tool to use (e.g., "linear\_\_create\_issue") |
| **tool\_pack\_id**       | `str` | Yes      | None                                                   | UUID of your Agent Handler Tool Pack                               |
| **registered\_user\_id** | `str` | Yes      | None                                                   | UUID or origin\_id of the registered user                          |
| **base\_url**            | `str` | No       | "[https://ah-api.merge.dev](https://ah-api.merge.dev)" | Base URL for Agent Handler API                                     |
| **session\_id**          | `str` | No       | Auto-generated                                         | MCP session ID for maintaining context                             |

### `from_tool_pack()` Method

| Argument                 | Type        | Required | Default                                                | Description                                                     |
| :----------------------- | :---------- | :------- | :----------------------------------------------------- | :-------------------------------------------------------------- |
| **tool\_pack\_id**       | `str`       | Yes      | None                                                   | UUID of your Agent Handler Tool Pack                            |
| **registered\_user\_id** | `str`       | Yes      | None                                                   | UUID or origin\_id of the registered user                       |
| **tool\_names**          | `list[str]` | No       | None                                                   | Specific tool names to load. If None, loads all available tools |
| **base\_url**            | `str`       | No       | "[https://ah-api.merge.dev](https://ah-api.merge.dev)" | Base URL for Agent Handler API                                  |

## Environment Variables

```bash theme={null}
AGENT_HANDLER_API_KEY=your_api_key_here  # Required for authentication
```

## Advanced Usage

### Multi-Agent Workflow with Different Tool Access

```python {2, 4-20} theme={null}
from crewai import Agent, Task, Crew, Process
from crewai_tools import MergeAgentHandlerTool

# Create specialized tools for different agents
github_tools = MergeAgentHandlerTool.from_tool_pack(
    tool_pack_id="134e0111-0f67-44f6-98f0-597000290bb3",
    registered_user_id="91b2b905-e866-40c8-8be2-efe53827a0aa",
    tool_names=["github__create_pull_request", "github__get_pull_requests"]
)

linear_tools = MergeAgentHandlerTool.from_tool_pack(
    tool_pack_id="134e0111-0f67-44f6-98f0-597000290bb3",
    registered_user_id="91b2b905-e866-40c8-8be2-efe53827a0aa",
    tool_names=["linear__create_issue", "linear__update_issue"]
)

slack_tool = MergeAgentHandlerTool.from_tool_name(
    tool_name="slack__post_message",
    tool_pack_id="134e0111-0f67-44f6-98f0-597000290bb3",
    registered_user_id="91b2b905-e866-40c8-8be2-efe53827a0aa"
)

# Create specialized agents
code_reviewer = Agent(
    role='Code Reviewer',
    goal='Review pull requests and ensure code quality',
    backstory='I am an expert at reviewing code changes and providing constructive feedback.',
    tools=github_tools
)

task_manager = Agent(
    role='Task Manager',
    goal='Track and update project tasks based on code changes',
    backstory='I keep the project board up to date with the latest development progress.',
    tools=linear_tools
)

communicator = Agent(
    role='Team Communicator',
    goal='Keep the team informed about important updates',
    backstory='I make sure everyone knows what is happening in the project.',
    tools=[slack_tool]
)

# Create sequential tasks
review_task = Task(
    description="Review all open pull requests in the 'api-service' repository and identify any that need attention.",
    agent=code_reviewer,
    expected_output="List of pull requests that need review or have issues"
)

update_task = Task(
    description="Update Linear issues based on the pull request review findings. Mark completed PRs as done.",
    agent=task_manager,
    expected_output="Summary of updated Linear issues"
)

notify_task = Task(
    description="Post a summary of today's code review and task updates to the #engineering Slack channel.",
    agent=communicator,
    expected_output="Confirmation that the message was posted"
)

# Create a crew with sequential processing
crew = Crew(
    agents=[code_reviewer, task_manager, communicator],
    tasks=[review_task, update_task, notify_task],
    process=Process.sequential,
    verbose=True
)

result = crew.kickoff()
```

### Custom Session Management

Maintain context across multiple tool calls using session IDs:

```python {2, 4-17} theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import MergeAgentHandlerTool

# Create tools with the same session ID to maintain context
session_id = "project-sprint-planning-2024"

create_tool = MergeAgentHandlerTool(
    name="linear_create_issue",
    description="Creates a new issue in Linear",
    tool_name="linear__create_issue",
    tool_pack_id="134e0111-0f67-44f6-98f0-597000290bb3",
    registered_user_id="91b2b905-e866-40c8-8be2-efe53827a0aa",
    session_id=session_id
)

update_tool = MergeAgentHandlerTool(
    name="linear_update_issue",
    description="Updates an existing issue in Linear",
    tool_name="linear__update_issue",
    tool_pack_id="134e0111-0f67-44f6-98f0-597000290bb3",
    registered_user_id="91b2b905-e866-40c8-8be2-efe53827a0aa",
    session_id=session_id
)

sprint_planner = Agent(
    role='Sprint Planner',
    goal='Plan and organize sprint tasks',
    backstory='I help teams plan effective sprints with well-defined tasks.',
    tools=[create_tool, update_tool],
    verbose=True
)

planning_task = Task(
    description="Create 5 sprint tasks for the authentication feature and set their priorities based on dependencies.",
    agent=sprint_planner
)

crew = Crew(
    agents=[sprint_planner],
    tasks=[planning_task],
    verbose=True
)

result = crew.kickoff()
```

## Use Cases

### Unified Integration Access

* Access hundreds of third-party tools through a single unified API without managing multiple SDKs
* Enable agents to work with Linear, GitHub, Slack, Notion, Jira, Asana, and more from one integration point
* Reduce integration complexity by letting Agent Handler manage authentication and API versioning

### Secure Enterprise Workflows

* Leverage built-in authentication and permission management for all third-party integrations
* Maintain enterprise security standards with centralized access control and audit logging
* Enable agents to access company tools without exposing API keys or credentials in code

### Cross-Platform Automation

* Build workflows that span multiple platforms (e.g., create GitHub issues from Linear tasks, sync Notion pages to Slack)
* Enable seamless data flow between different tools in your tech stack
* Create intelligent automation that understands context across different platforms

### Dynamic Tool Discovery

* Load all available tools at runtime without hardcoding integration logic
* Enable agents to discover and use new tools as they're added to your Tool Pack
* Build flexible agents that can adapt to changing tool availability

### User-Specific Tool Access

* Different users can have different tool permissions and access levels
* Enable multi-tenant workflows where agents act on behalf of specific users
* Maintain proper attribution and permissions for all tool actions

## Available Integrations

Merge Agent Handler supports hundreds of integrations across multiple categories:

* **Project Management**: Linear, Jira, Asana, Monday.com, ClickUp
* **Code Management**: GitHub, GitLab, Bitbucket
* **Communication**: Slack, Microsoft Teams, Discord
* **Documentation**: Notion, Confluence, Google Docs
* **CRM**: Salesforce, HubSpot, Pipedrive
* **And many more...**

Visit the [Merge Agent Handler documentation](https://docs.ah.merge.dev/) for a complete list of available integrations.

## Error Handling

The tool provides comprehensive error handling:

* **Authentication Errors**: Invalid or missing API keys
* **Permission Errors**: User lacks permission for the requested action
* **API Errors**: Issues communicating with Agent Handler or third-party services
* **Validation Errors**: Invalid parameters passed to tool methods

All errors are wrapped in `MergeAgentHandlerToolError` for consistent error handling.


# Overview
Source: https://docs.crewai.com/en/tools/integration/overview

Connect CrewAI agents with external automations and managed AI services

Integration tools let your agents hand off work to other automation platforms and managed AI services. Use them when a workflow needs to invoke an existing CrewAI deployment or delegate specialised tasks to providers such as Amazon Bedrock.

## **Available Tools**

<CardGroup>
  <Card title="Merge Agent Handler Tool" icon="diagram-project" href="/en/tools/integration/mergeagenthandlertool">
    Securely access hundreds of third-party tools like Linear, GitHub, Slack, and more through Merge's unified API.
  </Card>

  <Card title="CrewAI Run Automation Tool" icon="robot" href="/en/tools/integration/crewaiautomationtool">
    Invoke live CrewAI Platform automations, pass custom inputs, and poll for results directly from your agent.
  </Card>

  <Card title="Bedrock Invoke Agent Tool" icon="aws" href="/en/tools/integration/bedrockinvokeagenttool">
    Call Amazon Bedrock Agents from your crews, reuse AWS guardrails, and stream responses back into the workflow.
  </Card>
</CardGroup>

## **Common Use Cases**

* **Chain automations**: Kick off an existing CrewAI deployment from within another crew or flow
* **Enterprise hand-off**: Route tasks to Bedrock Agents that already encapsulate company logic and guardrails
* **Hybrid workflows**: Combine CrewAI reasoning with downstream systems that expose their own agent APIs
* **Long-running jobs**: Poll external automations and merge the final results back into the current run

## **Quick Start Example**

```python theme={null}
from crewai import Agent, Task, Crew
from crewai_tools import InvokeCrewAIAutomationTool
from crewai_tools.aws.bedrock.agents.invoke_agent_tool import BedrockInvokeAgentTool

# External automation
analysis_automation = InvokeCrewAIAutomationTool(
    crew_api_url="https://analysis-crew.acme.crewai.com",
    crew_bearer_token="YOUR_BEARER_TOKEN",
    crew_name="Analysis Automation",
    crew_description="Runs the production-grade analysis pipeline",
)

# Managed agent on Bedrock
knowledge_router = BedrockInvokeAgentTool(
    agent_id="bedrock-agent-id",
    agent_alias_id="prod",
)

automation_strategist = Agent(
    role="Automation Strategist",
    goal="Orchestrate external automations and summarise their output",
    backstory="You coordinate enterprise workflows and know when to delegate tasks to specialised services.",
    tools=[analysis_automation, knowledge_router],
    verbose=True,
)

execute_playbook = Task(
    description="Run the analysis automation and ask the Bedrock agent for executive talking points.",
    agent=automation_strategist,
)

Crew(agents=[automation_strategist], tasks=[execute_playbook]).kickoff()
```

## **Best Practices**

* **Secure credentials**: Store API keys and bearer tokens in environment variables or a secrets manager
* **Plan for latency**: External automations may take longer—set appropriate polling intervals and timeouts
* **Reuse sessions**: Bedrock Agents support session IDs so you can maintain context across multiple tool calls
* **Validate responses**: Normalise remote output (JSON, text, status codes) before forwarding it to downstream tasks
* **Monitor usage**: Track audit logs in CrewAI Platform or AWS CloudWatch to stay ahead of quota limits and failures


# GET /inputs
Source: https://docs.crewai.com/en/api-reference/inputs

enterprise-api.en.yaml get /inputs
Get required inputs for your crew



# Introduction
Source: https://docs.crewai.com/en/api-reference/introduction

Complete reference for the CrewAI AMP REST API

# CrewAI AMP API

Welcome to the CrewAI AMP API reference. This API allows you to programmatically interact with your deployed crews, enabling integration with your applications, workflows, and services.

## Quick Start

<Steps>
  <Step title="Get Your API Credentials">
    Navigate to your crew's detail page in the CrewAI AMP dashboard and copy your Bearer Token from the Status tab.
  </Step>

  <Step title="Discover Required Inputs">
    Use the `GET /inputs` endpoint to see what parameters your crew expects.
  </Step>

  <Step title="Start a Crew Execution">
    Call `POST /kickoff` with your inputs to start the crew execution and receive
    a `kickoff_id`.
  </Step>

  <Step title="Monitor Progress">
    Use `GET /{kickoff_id}/status` to check execution status and retrieve results.
  </Step>
</Steps>

## Authentication

All API requests require authentication using a Bearer token. Include your token in the `Authorization` header:

```bash theme={null}
curl -H "Authorization: Bearer YOUR_CREW_TOKEN" \
  https://your-crew-url.crewai.com/inputs
```

### Token Types

| Token Type            | Scope                     | Use Case                                                     |
| :-------------------- | :------------------------ | :----------------------------------------------------------- |
| **Bearer Token**      | Organization-level access | Full crew operations, ideal for server-to-server integration |
| **User Bearer Token** | User-scoped access        | Limited permissions, suitable for user-specific operations   |

<Tip>
  You can find both token types in the Status tab of your crew's detail page in
  the CrewAI AMP dashboard.
</Tip>

## Base URL

Each deployed crew has its own unique API endpoint:

```
https://your-crew-name.crewai.com
```

Replace `your-crew-name` with your actual crew's URL from the dashboard.

## Typical Workflow

1. **Discovery**: Call `GET /inputs` to understand what your crew needs
2. **Execution**: Submit inputs via `POST /kickoff` to start processing
3. **Monitoring**: Poll `GET /{kickoff_id}/status` until completion
4. **Results**: Extract the final output from the completed response

## Error Handling

The API uses standard HTTP status codes:

| Code  | Meaning                                    |
| ----- | :----------------------------------------- |
| `200` | Success                                    |
| `400` | Bad Request - Invalid input format         |
| `401` | Unauthorized - Invalid bearer token        |
| `404` | Not Found - Resource doesn't exist         |
| `422` | Validation Error - Missing required inputs |
| `500` | Server Error - Contact support             |

## Interactive Testing

<Info>
  **Why no "Send" button?** Since each CrewAI AMP user has their own unique crew
  URL, we use **reference mode** instead of an interactive playground to avoid
  confusion. This shows you exactly what the requests should look like without
  non-functional send buttons.
</Info>

Each endpoint page shows you:

* ✅ **Exact request format** with all parameters
* ✅ **Response examples** for success and error cases
* ✅ **Code samples** in multiple languages (cURL, Python, JavaScript, etc.)
* ✅ **Authentication examples** with proper Bearer token format

### **To Test Your Actual API:**

<CardGroup>
  <Card title="Copy cURL Examples" icon="terminal">
    Copy the cURL examples and replace the URL + token with your real values
  </Card>

  <Card title="Use Postman/Insomnia" icon="play">
    Import the examples into your preferred API testing tool
  </Card>
</CardGroup>

**Example workflow:**

1. **Copy this cURL example** from any endpoint page
2. **Replace `your-actual-crew-name.crewai.com`** with your real crew URL
3. **Replace the Bearer token** with your real token from the dashboard
4. **Run the request** in your terminal or API client

## Need Help?

<CardGroup>
  <Card title="Enterprise Support" icon="headset" href="mailto:support@crewai.com">
    Get help with API integration and troubleshooting
  </Card>

  <Card title="Enterprise Dashboard" icon="chart-line" href="https://app.crewai.com">
    Manage your crews and view execution logs
  </Card>
</CardGroup>


# POST /kickoff
Source: https://docs.crewai.com/en/api-reference/kickoff

enterprise-api.en.yaml post /kickoff
Start a crew execution



# POST /resume
Source: https://docs.crewai.com/en/api-reference/resume

enterprise-api.en.yaml post /resume
Resume crew execution with human feedback



# GET /{kickoff_id}/status
Source: https://docs.crewai.com/en/api-reference/status

enterprise-api.en.yaml get /{kickoff_id}/status
Get execution status



# Changelog
Source: https://docs.crewai.com/en/changelog

Product updates, improvements, and bug fixes for CrewAI

<Update label="Feb 27, 2026">
  ## v1.10.1a1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.10.1a1)

  ## What's Changed

  ### Features

  * Implement asynchronous invocation support in step callback methods
  * Implement lazy loading for heavy dependencies in Memory module

  ### Documentation

  * Update changelog and version for v1.10.0

  ### Refactoring

  * Refactor step callback methods to support asynchronous invocation
  * Refactor to implement lazy loading for heavy dependencies in Memory module

  ### Bug Fixes

  * Fix branch for release notes

  ## Contributors

  @greysonlalonde, @joaomdmoura
</Update>

<Update label="Feb 27, 2026">
  ## v1.10.1a1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.10.1a1)

  ## What's Changed

  ### Refactoring

  * Refactor step callback methods to support asynchronous invocation
  * Implement lazy loading for heavy dependencies in Memory module

  ### Documentation

  * Update changelog and version for v1.10.0

  ### Bug Fixes

  * Make branch for release notes

  ## Contributors

  @greysonlalonde, @joaomdmoura
</Update>

<Update label="Feb 26, 2026">
  ## v1.10.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.10.0)

  ## What's Changed

  ### Features

  * Enhance MCP tool resolution and related events
  * Update lancedb version and add lance-namespace packages
  * Enhance JSON argument parsing and validation in CrewAgentExecutor and BaseTool
  * Migrate CLI HTTP client from requests to httpx
  * Add versioned documentation
  * Add yanked detection for version notes
  * Implement user input handling in Flows
  * Enhance HITL self-loop functionality in human feedback integration tests
  * Add started\_event\_id and set in eventbus
  * Auto update tools.specs

  ### Bug Fixes

  * Validate tool kwargs even when empty to prevent cryptic TypeError
  * Preserve null types in tool parameter schemas for LLM
  * Map output\_pydantic/output\_json to native structured output
  * Ensure callbacks are ran/awaited if promise
  * Capture method name in exception context
  * Preserve enum type in router result; improve types
  * Fix cyclic flows silently breaking when persistence ID is passed in inputs
  * Correct CLI flag format from --skip-provider to --skip\_provider
  * Ensure OpenAI tool call stream is finalized
  * Resolve complex schema \$ref pointers in MCP tools
  * Enforce additionalProperties=false in schemas
  * Reject reserved script names for crew folders
  * Resolve race condition in guardrail event emission test

  ### Documentation

  * Add litellm dependency note for non-native LLM providers
  * Clarify NL2SQL security model and hardening guidance
  * Add 96 missing actions across 9 integrations

  ### Refactoring

  * Refactor crew to provider
  * Extract HITL to provider pattern
  * Improve hook typing and registration

  ## Contributors

  @dependabot\[bot], @github-actions\[bot], @github-code-quality\[bot], @greysonlalonde, @heitorado, @hobostay, @joaomdmoura, @johnvan7, @jonathansampson, @lorenzejay, @lucasgomide, @mattatcha, @mplachta, @nicoferdi96, @theCyberTech, @thiagomoretto, @vinibrsl
</Update>

<Update label="Jan 26, 2026">
  ## v1.9.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.9.0)

  ## What's Changed

  ### Features

  * Add structured outputs and response\_format support across providers
  * Add response ID to streaming responses
  * Add event ordering with parent-child hierarchies
  * Add Keycloak SSO authentication support
  * Add multimodal file handling capabilities
  * Add native OpenAI responses API support
  * Add A2A task execution utilities
  * Add A2A server configuration and agent card generation
  * Enhance event system and expand transport options
  * Improve tool calling mechanisms

  ### Bug Fixes

  * Enhance file store with fallback memory cache when aiocache is not available
  * Ensure document list is not empty
  * Handle Bedrock stop sequences properly
  * Add Google Vertex API key support
  * Enhance Azure model stop word detection
  * Improve error handling for HumanFeedbackPending in flow execution
  * Fix execution span task unlinking

  ### Documentation

  * Add native file handling documentation
  * Add OpenAI responses API documentation
  * Add agent card implementation guidance
  * Refine A2A documentation
  * Update changelog for v1.8.0

  ### Contributors

  @Anaisdg, @GininDenis, @Vidit-Ostwal, @greysonlalonde, @heitorado, @joaomdmoura, @koushiv777, @lorenzejay, @nicoferdi96, @vinibrsl
</Update>

<Update label="Jan 15, 2026">
  ## v1.8.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.8.1)

  ## What's Changed

  ### Features

  * Add A2A task execution utilities
  * Add A2A server configuration and agent card generation
  * Add additional transport mechanisms
  * Add Galileo integration support

  ### Bug Fixes

  * Improve Azure model compatibility
  * Expand frame inspection depth to detect parent\_flow
  * Resolve task execution span management issues
  * Enhance error handling for human feedback scenarios during flow execution

  ### Documentation

  * Add A2A agent card documentation
  * Add PII redaction feature documentation

  ### Contributors

  @Anaisdg, @GininDenis, @greysonlalonde, @joaomdmoura, @koushiv777, @lorenzejay, @vinibrsl
</Update>

<Update label="Jan 08, 2026">
  ## v1.8.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.8.0)

  ## What's Changed

  ### Features

  * Add native async chain for a2a
  * Add a2a update mechanisms (poll/stream/push) with handlers and config
  * Introduce global flow configuration for human-in-the-loop feedback
  * Add streaming tool call events and fix provider ID tracking
  * Introduce production-ready Flows and Crews architecture
  * Add HITL for Flows
  * Improve EventListener and TraceCollectionListener for enhanced event handling

  ### Bug Fixes

  * Handle missing a2a dependency as optional
  * Correct error fetching for WorkOS login polling
  * Fix wrong trigger name in sample documentation

  ### Documentation

  * Update webhook-streaming documentation
  * Adjust AOP to AMP documentation language

  ### Contributors

  @Vidit-Ostwal, @greysonlalonde, @heitorado, @joaomdmoura, @lorenzejay, @lucasgomide, @mplachta
</Update>

<Update label="Dec 19, 2025">
  ## v1.7.2

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.7.2)

  ## What's Changed

  ### Bug Fixes

  * Resolve connection issues

  ### Documentation

  * Update api-reference/status docs page

  ### Contributors

  @greysonlalonde, @heitorado, @lorenzejay, @lucasgomide
</Update>

<Update label="Dec 16, 2025">
  ## v1.7.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.7.1)

  ## What's Changed

  ### Improvements

  * Add `--no-commit` flag to bump command
  * Use JSON schema for tool argument serialization

  ### Bug Fixes

  * Fix error message display from response when tool repository login fails
  * Fix graceful termination of future when executing a task asynchronously
  * Fix task ordering by adding index
  * Fix platform compatibility checks for Windows signals
  * Fix RPM controller timer to prevent process hang
  * Fix token usage recording and validate response model on stream

  ### Documentation

  * Add translated documentation for async
  * Add documentation for AOP Deploy API
  * Add documentation for the agent handler connector
  * Add documentation on native async

  ### Contributors

  @Llamrei, @dragosmc, @gilfeig, @greysonlalonde, @heitorado, @lorenzejay, @mattatcha, @vinibrsl
</Update>

<Update label="Dec 09, 2025">
  ## v1.7.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.7.0)

  ## What's Changed

  ### Features

  * Add async flow kickoff
  * Add async crew support
  * Add async task support
  * Add async knowledge support
  * Add async memory support
  * Add async support for tools and agent executor; improve typing and docs
  * Implement a2a extensions API and async agent card caching; fix task propagation & streaming
  * Add native async tool support
  * Add async llm support
  * Create sys event types and handler

  ### Bug Fixes

  * Fix issue to ensure nonetypes are not passed to otel
  * Fix deadlock in token store file operations
  * Fix to ensure otel span is closed
  * Use HuggingFaceEmbeddingFunction for embeddings, update keys and add tests
  * Fix to ensure supports\_tools is true for all supported anthropic models
  * Ensure hooks work with lite agents flows

  ### Contributors

  @greysonlalonde, @lorenzejay
</Update>

<Update label="Nov 29, 2025">
  ## v1.6.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.6.1)

  ## What's Changed

  ### Bug Fixes

  * Fix ChatCompletionsClient call to ensure proper functionality
  * Ensure async methods are executable for annotations
  * Fix parameters in RagTool.add, add typing, and tests
  * Remove invalid parameter from SSE client
  * Erase 'oauth2\_extra' setting on 'crewai config reset' command

  ### Refactoring

  * Enhance model validation and provider inference in LLM class

  ### Contributors

  @Vidit-Ostwal, @greysonlalonde, @heitorado, @lorenzejay
</Update>

<Update label="Nov 25, 2025">
  ## v1.6.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.6.0)

  ## What's Changed

  ### Features

  * Add streaming result support to flows and crews
  * Add gemini-3-pro-preview
  * Support CLI login with Entra ID
  * Add Merge Agent Handler tool
  * Enhance flow event state management

  ### Bug Fixes

  * Ensure custom rag store persist path is set if passed
  * Ensure fuzzy returns are more strict and show type warning
  * Re-add openai response\_format parameter and add test
  * Fix rag tool embeddings configuration
  * Ensure flow execution start panel is not shown on plot

  ### Documentation

  * Update references from AMP to AOP in documentation
  * Update AMP to AOP

  ### Contributors

  @Vidit-Ostwal, @gilfeig, @greysonlalonde, @heitorado, @joaomdmoura, @lorenzejay, @markmcd
</Update>

<Update label="Nov 22, 2025">
  ## v0.203.2

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.203.2)

  ## What's Changed

  * Hotfix version bump from 0.203.1 to 0.203.2
</Update>

<Update label="Nov 16, 2025">
  ## v1.5.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.5.0)

  ## What's Changed

  ### Features

  * Add a2a trust remote completion status flag
  * Fetch and store more data about Okta authorization server
  * Implement before and after LLM call hooks in CrewAgentExecutor
  * Expose messages to TaskOutput and LiteAgentOutputs
  * Enhance schema description of QdrantVectorSearchTool

  ### Bug Fixes

  * Ensure tracing instrumentation flags are correctly applied
  * Fix custom tool documentation links and add Mintlify broken links action

  ### Documentation

  * Enhance task guardrail documentation with LLM-based validation support

  ### Contributors

  @danielfsbarreto, @greysonlalonde, @heitorado, @lorenzejay, @theCyberTech
</Update>

<Update label="Nov 07, 2025">
  ## v1.4.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.4.1)

  ## What's Changed

  ### Bug Fixes

  * Fix handling of agent max iterations
  * Resolve routing issues for LLM model syntax to respected providers

  ### Contributors

  @greysonlalonde
</Update>

<Update label="Nov 07, 2025">
  ## v1.4.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.4.0)

  ## What's Changed

  ### Features

  * Add support for non-AST plot routes
  * Implement first-class support for MCP
  * Add Pydantic validation dunder to BaseInterceptor
  * Add support for LLM message interceptor hooks
  * Cache i18n prompts for efficient use
  * Enhance QdrantVectorSearchTool

  ### Bug Fixes

  * Fix issues with keeping stopwords updated
  * Resolve unpickleable values in flow state
  * Ensure lite agents course-correct on validation errors
  * Fix callback argument hashing to ensure caching works
  * Allow adding RAG source content from valid URLs
  * Make plot node selection smoother
  * Fix duplicating document IDs for knowledge

  ### Refactoring

  * Improve MCP tool execution handling with concurrent futures
  * Simplify flow handling, typing, and logging; update UI and tests
  * Refactor stop word management to a property

  ### Documentation

  * Migrate embedder to embedding\_model and require vectordb across tool docs; add provider examples (en/ko/pt-BR)

  ### Contributors

  @danielfsbarreto, @greysonlalonde, @lorenzejay, @lucasgomide, @tonykipkemboi
</Update>

<Update label="Nov 01, 2025">
  ## v1.3.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.3.0)

  ## What's Changed

  ### Features

  * Refactor flow handling, typing, and logging
  * Enhance QdrantVectorSearchTool

  ### Bug Fixes

  * Fix Firecrawl tools and add tests
  * Refactor use\_stop\_words to property and add check for stop words

  ### Documentation

  * Migrate embedder to embedding\_model and require vectordb across tool docs
  * Add provider examples in English, Korean, and Portuguese

  ### Refactoring

  * Improve flow handling and UI updates

  ### Contributors

  @danielfsbarreto, @greysonlalonde, @lorenzejay, @lucasgomide, @tonykipkemboi
</Update>

<Update label="Oct 27, 2025">
  ## v1.2.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.2.1)

  ## What's Changed

  ### Features

  * Add support for Datadog integration
  * Support apps and mcps in liteagent

  ### Documentation

  * Describe mandatory environment variable for calling Platform tools for each integration
  * Add Datadog integration documentation

  ### Contributors

  @barieom, @lorenzejay, @lucasgomide, @sabrenner
</Update>

<Update label="Oct 24, 2025">
  ## v1.2.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.2.0)

  ## What's Changed

  ### Bug Fixes

  * Update default LLM model and improve error logging in LLM utilities
  * Change flow visualization directory and method inspection

  ### Dropping Unused

  * Remove aisuite

  ### Contributors

  @greysonlalonde, @lorenzejay
</Update>

<Update label="Oct 21, 2025">
  ## v1.1.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.1.0)

  ## What's Changed

  ### Features

  * Enhance InternalInstructor to support multiple LLM providers
  * Implement mypy plugin base
  * Improve QdrantVectorSearchTool

  ### Bug Fixes

  * Correct broken integration documentation links
  * Fix double trace call and add types
  * Pin template versions to latest

  ### Documentation

  * Update LLM integration details and examples

  ### Refactoring

  * Improve CrewBase typing

  ### Contributors

  @cwarre33, @danielfsbarreto, @greysonlalonde, @lorenzejay
</Update>

<Update label="Oct 20, 2025">
  ## v1.0.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.0.0)

  ## What's Changed

  ### Features

  * Bump versions to 1.0.0
  * Enhance knowledge and guardrail event handling in Agent class
  * Inject tool repository credentials in crewai run command

  ### Bug Fixes

  * Preserve nested condition structure in Flow decorators
  * Add standard print parameters to Printer.print method
  * Fix errors when there is no input() available
  * Add a leeway of 10s when decoding JWT
  * Revert bad cron schedule
  * Correct cron schedule to run every 5 days at specific dates
  * Use system PATH for Docker binary instead of hardcoded path
  * Add CodeQL configuration to properly exclude template directories

  ### Documentation

  * Update security policy for vulnerability reporting
  * Add guide for capturing telemetry logs in CrewAI AMP
  * Add missing /resume files
  * Clarify webhook URL parameter in HITL workflows

  ### Contributors

  @Vidit-Ostwal, @greysonlalonde, @heitorado, @joaomdmoura, @lorenzejay, @lucasgomide, @mplachta, @theCyberTech
</Update>

<Update label="Oct 18, 2025">
  ## v1.0.0b3 (Pre-release)

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.0.0b3)

  ## What's Changed

  ### Features

  * Enhance task guardrail functionality and validation
  * Improve support for importing native SDK
  * Add Azure native tests
  * Enhance BedrockCompletion class with advanced features
  * Enhance GeminiCompletion class with client parameter support
  * Enhance AnthropicCompletion class with additional client parameters

  ### Bug Fixes

  * Preserve nested condition structure in Flow decorators
  * Add standard print parameters to Printer.print method
  * Remove stdout prints and improve test determinism

  ### Refactoring

  * Convert project module to metaclass with full typing

  ### Contributors

  @greysonlalonde, @lorenzejay
</Update>

<Update label="Oct 16, 2025">
  ## v1.0.0b2 (Pre-release)

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.0.0b2)

  ## What's Changed

  ### Features

  * Enhance OpenAICompletion class with additional client parameters
  * Improve event bus thread safety and async support
  * Inject tool repository credentials in crewai run command

  ### Bug Fixes

  * Fix issue where it errors out if there is no input() available
  * Add a leeway of 10s when decoding JWT
  * Fix copying and adding NOT\_SPECIFIED check in task.py

  ### Documentation

  * Ensure CREWAI\_PLATFORM\_INTEGRATION\_TOKEN is mentioned in documentation
  * Update triggers documentation

  ### Contributors

  @Vidit-Ostwal, @greysonlalonde, @heitorado, @joaomdmoura, @lorenzejay, @lucasgomide
</Update>

<Update label="Oct 14, 2025">
  ## v1.0.0b1 (Pre-release)

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.0.0b1)

  ## What's Changed

  ### Features

  * Enhance OpenAICompletion class with additional client parameters
  * Improve event bus thread safety and async support
  * Implement Bedrock LLM integration

  ### Bug Fixes

  * Fix issue with missing input() availability
  * Resolve JWT decoding error by adding a leeway of 10 seconds
  * Inject tool repository credentials in crewai run command
  * Fix copy and add NOT\_SPECIFIED check in task.py

  ### Documentation

  * Ensure CREWAI\_PLATFORM\_INTEGRATION\_TOKEN is mentioned in documentation
  * Update triggers documentation

  ### Contributors

  @Vidit-Ostwal, @greysonlalonde, @heitorado, @joaomdmoura, @lorenzejay, @lucasgomide
</Update>

<Update label="Oct 13, 2025">
  ## v0.203.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.203.1)

  ## What's Changed

  ### Core Improvements & Fixes

  * Fixed injection of tool repository credentials into the `crewai run` command
  * Added a 10-second leeway when decoding JWTs to reduce token validation errors
  * Corrected (then reverted) cron schedule fix intended to run jobs every 5 days at specific dates

  ### Documentation & Guides

  * Updated security policy to clarify the process for vulnerability reporting
</Update>

<Update label="Oct 09, 2025">
  ## v1.0.0a4 (Pre-release)

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.0.0a4)

  ## What's Changed

  ### Features

  * Enhance knowledge and guardrail event handling in Agent class
  * Introduce trigger listing and execution commands for local development
  * Update documentation with new approach to consume Platform Actions
  * Add guide for capturing telemetry logs in CrewAI AMP

  ### Bug Fixes

  * Revert bad cron schedule
  * Correct cron schedule to run every 5 days at specific dates
  * Remove duplicate line and add explicit environment variable
  * Resolve linting errors across the codebase
  * Replace print statements with logger in agent and memory handling
  * Use system PATH for Docker binary instead of hardcoded path
  * Allow failed PyPI publish
  * Match tag and release title, ignore devtools build for PyPI

  ### Documentation

  * Update security policy for vulnerability reporting
  * Add missing /resume files
  * Clarify webhook URL parameter in HITL workflows

  ### Contributors

  @Vidit-Ostwal, @greysonlalonde, @lorenzejay, @lucasgomide, @theCyberTech
</Update>

<Update label="Sep 30, 2025">
  ## v1.0.0a1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/1.0.0a1)

  ## What's Changed

  ### Core Improvements & Fixes

  * Fixed permission handling for `actions` in agent configuration
  * Updated CI workflows and release publishing to support the new monorepo structure
  * Bumped Python support to 3.13 and refreshed workspace metadata

  ### New Features & Enhancements

  * Added `apps` and `actions` attributes to `Agent` for richer runtime control
  * Merged the `crewai-tools` repository into the main workspace (monorepo)
  * Bumped all packages to 1.0.0a1 to mark the alpha milestone

  ### Cleanup & Infrastructure

  * Delivered a new CI pipeline with version pinning and publishing strategy
  * Unified internal code to manage multiple packages coherently
</Update>

<Update label="Sep 26, 2025">
  ## v0.201.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.201.1)

  ## What's Changed

  ### Core Improvements & Fixes

  * Renamed Watson embedding provider to `watsonx` and refreshed environment variable prefixes
  * Added ChromaDB compatibility for `watsonx` and `voyageai` embedding providers

  ### Cleanup & Deprecations

  * Standardized environment variable prefixes for all embedding providers
  * Bumped CrewAI to 0.201.1 and updated internal dependencies
</Update>

<Update label="Sep 24, 2025">
  ## v0.201.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.201.0)

  ## What's Changed

  ### Core Improvements & Fixes

  * Made the `ready` parameter optional in `_create_reasoning_plan`
  * Fixed nested config handling for embedder configuration
  * Added `batch_size` support to avoid token limit errors
  * Corrected Quickstart documentation directory naming
  * Resolved test duration cache issues and event exports
  * Added fallback logic to crew settings

  ### New Features & Enhancements

  * Introduced thread-safe platform context management
  * Added `crewai uv` wrapper command to run `uv` from the CLI
  * Enabled marking traces as failed for observability workflows
  * Added custom embedding types and provider migration support
  * Upgraded ChromaDB to v1.1.0 with compatibility fixes and type improvements
  * Added Pydantic-compatible import validation and reorganized dependency groups

  ### Documentation & Guides

  * Updated changelog coverage for recent releases (0.193.x series)
  * Documented metadata support for LLM Guardrail events
  * Added guidance for fallback behavior and configuration visibility

  ### Cleanup & Deprecations

  * Resolved Ruff and MyPy issues across modules
  * Improved type annotations and consolidated utilities
  * Deprecated legacy utilities in favor of Pydantic-compatible imports

  ### Contributors

  * @qizwiz (first contribution)
</Update>

<Update label="Sep 20, 2025">
  ## v0.193.2

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.193.2)

  ## What's Changed

  * Updated pyproject templates to use the right version
</Update>

<Update label="Sep 20, 2025">
  ## v0.193.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.193.1)

  ## What's Changed

  * Series of minor fixes and linter improvements
</Update>

<Update label="Sep 19, 2025">
  ## v0.193.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.193.0)

  ## Core Improvements & Fixes

  * Fixed handling of the `model` parameter during OpenAI adapter initialization
  * Resolved test duration cache issues in CI workflows
  * Fixed flaky test related to repeated tool usage by agents
  * Added missing event exports to `__init__.py` for consistent module behavior
  * Dropped message storage from metadata in Mem0 to reduce bloat
  * Fixed L2 distance metric support for backward compatibility in vector search

  ## New Features & Enhancements

  * Introduced thread-safe platform context management
  * Added test duration caching for optimized `pytest-split` runs
  * Added ephemeral trace improvements for better trace control
  * Made search parameters for RAG, knowledge, and memory fully configurable
  * Enabled ChromaDB to use OpenAI API for embedding functions
  * Added deeper observability tools for user-level insights
  * Unified RAG storage system with instance-specific client support

  ## Documentation & Guides

  * Updated `RagTool` references to reflect CrewAI native RAG implementation
  * Improved internal docs for `langgraph` and `openai` agent adapters with type annotations and docstrings
</Update>

<Update label="Sep 11, 2025">
  ## v0.186.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.186.1)

  ## What's Changed

  * Fixed version not being found and silently failing reversion
  * Bumped CrewAI version to 0.186.1 and updated dependencies in the CLI
</Update>

<Update label="Sep 10, 2025">
  ## v0.186.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.186.0)

  ## What's Changed

  * Refer to the GitHub release notes for detailed changes
</Update>

<Update label="Sep 04, 2025">
  ## v0.177.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.177.0)

  ## Core Improvements & Fixes

  * Achieved parity between `rag` package and current implementation
  * Enhanced LLM event handling with task and agent metadata
  * Fixed mutable default arguments by replacing them with `None`
  * Suppressed Pydantic deprecation warnings during initialization
  * Fixed broken example link in `README.md`
  * Removed Python 3.12+ only Ruff rules for compatibility
  * Migrated CI workflows to use `uv` and updated dev tooling

  ## New Features & Enhancements

  * Added tracing improvements and cleanup
  * Centralized event logic by moving `events` module to `crewai.events`

  ## Documentation & Guides

  * Updated Enterprise Action Auth Token section documentation
  * Published documentation updates for `v0.175.0` release

  ## Cleanup & Refactoring

  * Refactored parser into modular functions for better structure
</Update>

<Update label="Aug 28, 2025">
  ## v0.175.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.175.0)

  ## Core Improvements & Fixes

  * Fixed migration of the `tool` section during `crewai update`
  * Reverted OpenAI pin: now requires `openai >=1.13.3` due to fixed import issues
  * Fixed flaky tests and improved test stability
  * Improved `Flow` listener resumability for HITL and cyclic flows
  * Enhanced timeout handling in `PlusAPI` and `TraceBatchManager`
  * Batched entity memory items to reduce redundant operations

  ## New Features & Enhancements

  * Added support for additional parameters in `Flow.start()` methods
  * Displayed task names in verbose CLI output
  * Added centralized embedding types and introduced a base embedding client
  * Introduced generic clients for ChromaDB and Qdrant
  * Added support for `crewai config reset` to clear tokens
  * Enabled `crewai_trigger_payload` auto-injection
  * Simplified RAG client initialization and introduced RAG configuration system
  * Added Qdrant RAG provider support
  * Improved tracing with better event data
  * Added support to remove Auth0 and email entry on `crewai login`

  ## Documentation & Guides

  * Added documentation for automation triggers
  * Fixed API Reference OpenAPI sources and redirects
  * Added hybrid search alpha parameter to the docs

  ## Cleanup & Deprecations

  * Added deprecation notice for `Task.max_retries`
  * Removed Auth0 dependency from login flow
</Update>

<Update label="Aug 19, 2025">
  ## v0.165.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.165.1)

  ## Core Improvements & Fixes

  * Fixed compatibility in `XMLSearchTool` by converting config values to strings for `configparser`
  * Fixed flaky Pytest test involving `PytestUnraisableExceptionWarning`
  * Mocked telemetry in test suite for more stable CI runs
  * Moved Chroma lockfile handling to `db_storage_path`
  * Ignored deprecation warnings from `chromadb`
  * Pinned OpenAI version `<1.100.0` due to `ResponseTextConfigParam` import issue

  ## New Features & Enhancements

  * Included exchanged agent messages into `ExternalMemory` metadata
  * Automatically injected `crewai_trigger_payload`
  * Renamed internal flag `inject_trigger_input` to `allow_crewai_trigger_context`
  * Continued tracing improvements and ephemeral tracing logic
  * Consolidated tracing logic conditions
  * Added support for `agent_id`-linked memory entries in `Mem0`

  ## Documentation & Guides

  * Added example to Tool Repository docs
  * Updated Mem0 documentation for Short-Term and Entity Memory integration
  * Revised Korean translations and improved sentence structures

  ## Cleanup & Chores

  * Removed deprecated AgentOps integration
</Update>

<Update label="Aug 19, 2025">
  ## v0.165.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.165.0)

  ## Core Improvements & Fixes

  * Fixed compatibility in `XMLSearchTool` by converting config values to strings for `configparser`
  * Fixed flaky Pytest test involving `PytestUnraisableExceptionWarning`
  * Mocked telemetry in test suite for more stable CI runs
  * Moved Chroma lockfile handling to `db_storage_path`
  * Ignored deprecation warnings from `chromadb`
  * Pinned OpenAI version `<1.100.0` due to `ResponseTextConfigParam` import issue

  ## New Features & Enhancements

  * Included exchanged agent messages into `ExternalMemory` metadata
  * Automatically injected `crewai_trigger_payload`
  * Renamed internal flag `inject_trigger_input` to `allow_crewai_trigger_context`
  * Continued tracing improvements and ephemeral tracing logic
  * Consolidated tracing logic conditions
  * Added support for `agent_id`-linked memory entries in `Mem0`

  ## Documentation & Guides

  * Added example to Tool Repository docs
  * Updated Mem0 documentation for Short-Term and Entity Memory integration
  * Revised Korean translations and improved sentence structures

  ## Cleanup & Chores

  * Removed deprecated AgentOps integration
</Update>

<Update label="Aug 13, 2025">
  ## v0.159.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.159.0)

  ## Core Improvements & Fixes

  * Improved LLM message formatting performance for better runtime efficiency
  * Fixed use of incorrect endpoint in enterprise configuration auth/parameters
  * Commented out listener resumability check for stability during partial flow resumption

  ## New Features & Enhancements

  * Added `enterprise configure` command to CLI for streamlined enterprise setup
  * Introduced partial flow resumability support

  ## Documentation & Guides

  * Added documentation for new tools
  * Added Korean translations
  * Updated documentation with TrueFoundry integration details
  * Added RBAC documentation and general cleanup
  * Fixed API reference and revamped examples/cookbooks across EN, PT-BR, and KO
</Update>

<Update label="Aug 06, 2025">
  ## v0.157.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.157.0)

  ## v0.157.0 What's Changed

  ## Core Improvements & Fixes

  * Enabled word wrapping for long input tool
  * Allowed persisting Flow state with `BaseModel` entries
  * Optimized string operations using `partition()` for performance
  * Dropped support for deprecated User Memory system
  * Bumped LiteLLM version to `1.74.9`
  * Fixed CLI to show missing modules more clearly during import
  * Supported device authorization with Okta

  ## New Features & Enhancements

  * Added `crewai config` CLI command group with tests
  * Added default value support for `crew.name`
  * Introduced initial tracing capabilities
  * Added support for LangDB integration
  * Added support for CLI configuration documentation

  ## Documentation & Guides

  * Updated MCP documentation with `connect_timeout` attribute
  * Added LangDB integration documentation
  * Added CLI config documentation
  * General feature doc updates and cleanup
</Update>

<Update label="Jul 30, 2025">
  ## v0.152.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.152.0)

  ## Core Improvements & Fixes

  * Removed `crewai signup` references and replaced them with `crewai login`
  * Fixed support for adding memories to Mem0 using `agent_id`
  * Changed the default value in Mem0 configuration
  * Updated import error to show missing module files clearly
  * Added timezone support to event timestamps

  ## New Features & Enhancements

  * Enhanced `Flow` class to support custom flow names
  * Refactored RAG components into a dedicated top-level module

  ## Documentation & Guides

  * Fixed incorrect model naming in Google Vertex AI documentation
</Update>

<Update label="Jul 23, 2025">
  ## v0.150.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.150.0)

  ## Core Improvements & Fixes

  * Used file lock around Chroma client initialization
  * Removed workaround related to SQLite without FTS5
  * Dropped unsupported `stop` parameter for LLM models automatically
  * Fixed `save` method and updated related test cases
  * Fixed message handling for Ollama models when last message is from assistant
  * Removed duplicate print on LLM call error
  * Added deprecation notice to `UserMemory`
  * Upgraded LiteLLM to version 1.74.3

  ## New Features & Enhancements

  * Added support for ad-hoc tool calling via internal LLM class
  * Updated Mem0 Storage from v1.1 to v2

  ## Documentation & Guides

  * Fixed neatlogs documentation
  * Added Tavily Search & Extractor tools to the Search-Research suite
  * Added documentation for `SerperScrapeWebsiteTool` and reorganized Serper section
  * General documentation updates and improvements

  ## crewai-tools v0.58.0

  ### New Tools / Enhancements

  * **SerperScrapeWebsiteTool**: Added a tool for extracting clean content from URLs
  * **Bedrock AgentCore**: Integrated browser and code interpreter toolkits for Bedrock agents
  * **Stagehand Update**: Refactored and updated Stagehand integration

  ### Fixes & Cleanup

  * **FTS5 Support**: Enabled SQLite FTS5 for improved text search in test workflows
  * **Test Speedups**: Parallelized GitHub Actions test suite for faster CI runs
  * **Cleanup**: Removed SQLite workaround due to FTS5 support being available
    **MongoDBVectorSearchTool**: Fixed serialization and schema handling
</Update>

<Update label="Jul 16, 2025">
  ## v0.148.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.148.0)

  ## Core Improvements & Fixes

  * Used production WorkOS environment ID
  * Added SQLite FTS5 support to test workflow
  * Fixed agent knowledge handling
  * Compared using `BaseLLM` class instead of `LLM`
  * Fixed missing `create_directory` parameter in `Task` class

  ## New Features & Enhancements

  * Introduced Agent evaluation functionality
  * Added Evaluator experiment and regression testing methods
  * Implemented thread-safe `AgentEvaluator`
  * Enabled event emission for Agent evaluation
  * Supported evaluation of single `Agent` and `LiteAgent`
  * Added integration with `neatlogs`
  * Added crew context tracking for LLM guardrail events

  ## Documentation & Guides

  * Added documentation for `guardrail` attributes and usage examples
  * Added integration guide for `neatlogs`
  * Updated documentation for Agent repository and `Agent.kickoff` usage
</Update>

<Update label="Jul 09, 2025">
  ## v0.141.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.141.0)

  ## Core Improvements & Fixes

  * Sped up GitHub Actions tests through parallelization

  ## New Features & Enhancements

  * Added crew context tracking for LLM guardrail events

  ## Documentation & Guides

  * Added documentation for Agent repository usage
  * Added documentation for `Agent.kickoff` method
</Update>

<Update label="Jul 02, 2025">
  ## v0.140.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.140.0)

  ## Core Improvements & Fixes

  * Fixed typo in test prompts
  * Fixed project name normalization by stripping trailing slashes during crew creation
  * Ensured environment variables are written in uppercase
  * Updated LiteLLM dependency
  * Refactored collection handling in `RAGStorage`
  * Implemented PEP 621 dynamic versioning

  ## New Features & Enhancements

  * Added capability to track LLM calls by task and agent
  * Introduced `MemoryEvents` to monitor memory usage
  * Added console logging for memory system and LLM guardrail events
  * Improved data training support for models up to 7B parameters
  * Added Scarf and Reo.dev analytics tracking
  * CLI workos login

  ## Documentation & Guides

  * Updated CLI LLM documentation
  * Added Nebius integration to the docs
  * Corrected typos in installation and pt-BR documentation
  * Added docs about `MemoryEvents`
  * Implemented docs redirects and included development tools
</Update>

<Update label="Jun 25, 2025">
  ## v0.134.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.134.0)

  ## Core Improvements & Fixes

  * Fixed tools parameter syntax
  * Fixed type annotation in `Task`
  * Fixed SSL error when retrieving LLM data from GitHub
  * Ensured compatibility with Pydantic 2.7.x
  * Removed `mkdocs` from project dependencies
  * Upgraded Langfuse code examples to use Python SDK v3
  * Added sanitize role feature in `mem0` storage
  * Improved Crew search during memory reset
  * Improved console printer output

  ## New Features & Enhancements

  * Added support for initializing a tool from defined `Tool` attributes
  * Added official way to use MCP Tools within a `CrewBase`
  * Enhanced MCP tools support to allow selecting multiple tools per agent in `CrewBase`
  * Added Oxylabs Web Scraping tools

  ## Documentation & Guides

  * Updated `quickstart.mdx`
  * Added docs on `LLMGuardrail` events
  * Updated documentation with comprehensive service integration details
  * Updated recommendation filters for MCP and Enterprise tools
  * Updated docs for Maxim observability
  * Added pt-BR documentation translation
  * General documentation improvements
</Update>

<Update label="Jun 12, 2025">
  ## v0.130.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.130.0)

  ## Core Improvements & Fixes

  * Removed duplicated message related to Tool result output
  * Fixed missing `manager_agent` tokens in `usage_metrics` from kickoff
  * Fixed telemetry singleton to respect dynamic environment variables
  * Fixed issue where Flow status logs could hide human input
  * Increased default X-axis spacing for flow plotting

  ## New Features & Enhancements

  * Added support for multi-org actions in the CLI
  * Enabled async tool executions for more efficient workflows
  * Introduced `LiteAgent` with Guardrail integration
  * Upgraded `LiteLLM` to support latest OpenAI version

  ## Documentation & Guides

  * Documented minimum `UV` version for Tool repository
  * Improved examples for Hallucination Guardrail
  * Updated planning docs for LLM usage
  * Added documentation for Maxim support in Agent observability
  * Expanded integrations documentation with images for enterprise features
  * Fixed guide on persistence
  * Updated Python version support to support python 3.13.x
</Update>

<Update label="Jun 05, 2025">
  ## v0.126.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.126.0)

  ### What’s Changed

  #### Core Improvements & Fixes

  * Added support for Python 3.13
  * Fixed agent knowledge sources issue
  * Persisted available tools from a Tool repository
  * Enabled tools to be loaded from Agent repository via their own module
  * Logged usage of tools when called by an LLM

  #### New Features & Enhancements

  * Added streamable-http transport support in MCP integration
  * Added support for community analytics
  * Expanded OpenAI-compatible section with a Gemini example
  * Introduced transparency features for prompts and memory systems
  * Minor enhancements for Tool publishing

  #### Documentation & Guides

  * Major restructuring of docs for better navigation
  * Expanded MCP integration documentation
  * Updated memory docs and README visuals
  * Fixed missing await keywords in async kickoff examples
  * Updated Portkey and Azure embeddings documentation
  * Added enterprise testing image to the LLM guide
  * General updates to the README
</Update>

<Update label="May 27, 2025">
  ## v0.121.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.121.1)

  Bug fixes and better docs
</Update>

<Update label="May 22, 2025">
  ## v0.121.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.121.0)

  # What’s Changed

  ## Core Improvements & Fixes

  * Fixed encoding error when creating tools
  * Fixed failing llama test
  * Updated logging configuration for consistency
  * Enhanced telemetry initialization and event handling

  ## New Features & Enhancements

  * Added markdown attribute to the Task class
  * Added reasoning attribute to the Agent class
  * Added inject\_date flag to Agent for automatic date injection
  * Implemented HallucinationGuardrail (no-op with test coverage)

  ## Documentation & Guides

  * Added documentation for StagehandTool and improved MDX structure
  * Added documentation for MCP integration and updated enterprise docs
  * Documented knowledge events and updated reasoning docs
  * Added stop parameter documentation
  * Fixed import references in doc examples (before\_kickoff, after\_kickoff)
  * General docs updates and restructuring for clarity
</Update>

<Update label="May 15, 2025">
  ## v0.120.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.120.1)

  ## Whats New

  * Fixes Interpolation with hyphens
</Update>

<Update label="May 14, 2025">
  ## v0.120.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.120.0)

  ### Core Improvements & Fixes

  •	Enabled full Ruff rule set by default for stricter linting
  •	Addressed race condition in FilteredStream using context managers
  •	Fixed agent knowledge reset issue
  •	Refactored agent fetching logic into utility module

  ### New Features & Enhancements

  •	Added support for loading an Agent directly from a repository
  •	Enabled setting an empty context for Task
  •	Enhanced Agent repository feedback and fixed Tool auto-import behavior
  •	Introduced direct initialization of knowledge (bypassing knowledge\_sources)

  ### Documentation & Guides

  •	Updated security.md for current security practices
  •	Cleaned up Google setup section for clarity
  •	Added link to AI Studio when entering Gemini key
  •	Updated Arize Phoenix observability guide
  •	Refreshed flow documentation
</Update>

<Update label="May 08, 2025">
  ## v0.119.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.119.0)

  What’s Changed

  ## Core Improvements & Fixes

  * Improved test reliability by enhancing pytest handling for flaky tests
  * Fixed memory reset crash when embedding dimensions mismatch
  * Enabled parent flow identification for Crew and LiteAgent
  * Prevented telemetry-related crashes when unavailable
  * Upgraded LiteLLM version for better compatibility
  * Fixed llama converter tests by removing skip\_external\_api

  ## New Features & Enhancements

  * Introduced knowledge retrieval prompt re-writting in Agent for improved tracking and debugging
  * Made LLM setup and quickstart guides model-agnostic

  ## Documentation & Guides

  * Added advanced configuration docs for the RAG tool
  * Updated Windows troubleshooting guide
  * Refined documentation examples for better clarity
  * Fixed typos across docs and config files
</Update>

<Update label="Apr 30, 2025">
  ## v0.118.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.118.0)

  ### Core Improvements & Fixes

  * Fixed issues with missing prompt or system templates.
  * Removed global logging configuration to avoid unintended overrides.
  * Renamed TaskGuardrail to LLMGuardrail for improved clarity.
  * Downgraded litellm to version 1.167.1 for compatibility.
  * Added missing **init**.py files to ensure proper module initialization.

  ### New Features & Enhancements

  * Added support for no-code Guardrail creation to simplify AI behavior controls.

  ### Documentation & Guides

  * Removed CrewStructuredTool from public documentation to reflect internal usage.
  * Updated enterprise documentation and YouTube embed for improved onboarding experience.
</Update>

<Update label="Apr 28, 2025">
  ## v0.117.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.117.1)

  * build: upgrade crewai-tools
  * upgrade liteLLM to latest version
  * Fix Mem0 OSS
</Update>

<Update label="Apr 28, 2025">
  ## v0.117.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.117.0)

  # What's Changed

  ## New Features & Enhancements

  * Added `result_as_answer` parameter support in `@tool` decorator.
  * Introduced support for new language models: GPT-4.1, Gemini-2.0, and Gemini-2.5 Pro.
  * Enhanced knowledge management capabilities.
  * Added Huggingface provider option in CLI.
  * Improved compatibility and CI support for Python 3.10+.

  ## Core Improvements & Fixes

  * Fixed issues with incorrect template parameters and missing inputs.
  * Improved asynchronous flow handling with coroutine condition checks.
  * Enhanced memory management with isolated configuration and correct memory object copying.
  * Fixed initialization of lite agents with correct references.
  * Addressed Python type hint issues and removed redundant imports.
  * Updated event placement for improved tool usage tracking.
  * Raised explicit exceptions when flows fail.
  * Removed unused code and redundant comments from various modules.
  * Updated GitHub App token action to v2.

  ## Documentation & Guides

  * Enhanced documentation structure, including enterprise deployment instructions.
  * Automatically create output folders for documentation generation.
  * Fixed broken link in `WeaviateVectorSearchTool` documentation.
  * Fixed guardrail documentation usage and import paths for JSON search tools.
  * Updated documentation for `CodeInterpreterTool`.
  * Improved SEO, contextual navigation, and error handling for documentation pages.
</Update>

<Update label="Apr 10, 2025">
  ## v0.114.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.114.0)

  # What's Changed

  ## New Features & Enhancements

  * Agents as an atomic unit. (`Agent(...).kickoff()`)
  * Support to Custom LLM implementations.
  * Integrated External Memory and Opik observability.
  * Enhanced YAML extraction.
  * Multimodal agent validation.
  * Added Secure fingerprints for agents and crews.

  ## Core Improvements & Fixes

  * Improved serialization, agent copying, and Python compatibility.
  * Added wildcard support to emit()
  * Added support for additional router calls and context window adjustments.
  * Fixed typing issues, validation, and import statements.
  * Improved method performance.
  * Enhanced agent task handling, event emissions, and memory management.
  * Fixed CLI issues, conditional tasks, cloning behavior, and tool outputs.

  ## Documentation & Guides

  * Improved documentation structure, theme, and organization.
  * Added guides for Local NVIDIA NIM with WSL2, W\&B Weave, and Arize Phoenix.
  * Updated tool configuration examples, prompts, and observability docs.
  * Guide on using singular agents within Flows
</Update>

<Update label="Mar 17, 2025">
  ## v0.108.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.108.0)

  # Features

  * Converted tabs to spaces in crew\.py template in PR #2190
  * Enhanced LLM Streaming Response Handling and Event System in PR #2266
  * Included model\_name in PR #2310
  * Enhanced Event Listener with rich visualization and improved logging in PR #2321
  * Added fingerprints in PR #2332

  # Bug Fixes

  * Fixed Mistral issues in PR #2308
  * Fixed a bug in documentation in PR #2370
  * Fixed type check error in fingerprint property in PR #2369

  # Documentation Updates

  * Improved tool documentation in PR #2259
  * Updated installation guide for the uv tool package in PR #2196
  * Added instructions for upgrading crewAI with the uv tool in PR #2363
  * Added documentation for ApifyActorsTool in PR #2254
</Update>

<Update label="Mar 09, 2025">
  ## v0.105.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.105.0)

  **Core Improvements & Fixes**

  * Fixed issues with missing template variables and user memory configuration.
  * Improved async flow support and addressed agent response formatting.
  * Enhanced memory reset functionality and fixed CLI memory commands.
  * Fixed type issues, tool calling properties, and telemetry decoupling.

  **New Features & Enhancements**

  * Added Flow state export and improved state utilities.
  * Enhanced agent knowledge setup with optional crew embedder.
  * Introduced event emitter for better observability and LLM call tracking.
  * Added support for Python 3.10 and ChatOllama from langchain\_ollama.
  * Integrated context window size support for the o3-mini model.
  * Added support for multiple router calls.

  **Documentation & Guides**

  * Improved documentation layout and hierarchical structure.
  * Added QdrantVectorSearchTool guide and clarified event listener usage.
  * Fixed typos in prompts and updated Amazon Bedrock model listings.
</Update>

<Update label="Feb 13, 2025">
  ## v0.102.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.102.0)

  ### Core Improvements & Fixes

  * Enhanced LLM Support: Improved structured LLM output, parameter handling, and formatting for Anthropic models.
  * Crew & Agent Stability: Fixed issues with cloning agents/crews using knowledge sources, multiple task outputs in conditional tasks, and ignored Crew task callbacks.
  * Memory & Storage Fixes: Fixed short-term memory handling with Bedrock, ensured correct embedder initialization, and added a reset memories function in the crew class.
  * Training & Execution Reliability: Fixed broken training and interpolation issues with dict and list input types.

  ### New Features & Enhancements

  * Advanced Knowledge Management: Improved naming conventions and enhanced embedding configuration with custom embedder support.
  * Expanded Logging & Observability: Added JSON format support for logging and integrated MLflow tracing documentation.
  * Data Handling Improvements: Updated excel\_knowledge\_source.py to process multi-tab files.
  * General Performance & Codebase Clean-Up: Streamlined enterprise code alignment and resolved linting issues.
  * Adding new tool QdrantVectorSearchTool

  ### Documentation & Guides

  * Updated AI & Memory Docs: Improved Bedrock, Google AI, and long-term memory documentation.
  * Task & Workflow Clarity: Added "Human Input" row to Task Attributes, Langfuse guide, and FileWriterTool documentation.
  * Fixed Various Typos & Formatting Issues.

  ### Maintenance & Miscellaneous

  * Refined Google Docs integrations and task handling for the current year.
</Update>

<Update label="Jan 28, 2025">
  ## v0.100.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.100.0)

  * Feat: Add Composio docs
  * Feat: Add SageMaker as a LLM provider
  * Fix: Overall LLM connection issues
  * Fix: Using safe accessors on training
  * Fix: Add version check to crew\_chat.py
  * Docs: New docs for crewai chat
  * Docs: Improve formatting and clarity in CLI and Composio Tool docs
</Update>

<Update label="Jan 20, 2025">
  ## v0.98.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.98.0)

  * Feat: Conversation crew v1
  * Feat: Add unique ID to flow states
  * Feat: Add @persist decorator with FlowPersistence interface
  * Integration: Add SambaNova integration
  * Integration: Add NVIDIA NIM provider in cli
  * Integration: Introducing VoyageAI
  * Chore: Update date to current year in template
  * Fix: Fix API Key Behavior and Entity Handling in Mem0 Integration
  * Fix: Fixed core invoke loop logic and relevant tests
  * Fix: Make tool inputs actual objects and not strings
  * Fix: Add important missing parts to creating tools
  * Fix: Drop litellm version to prevent windows issue
  * Fix: Before kickoff if inputs are none
  * Fix: TYPOS
  * Fix: Nested pydantic model issue
  * Fix: Docling issues
  * Fix: union issue
  * Docs updates
</Update>

<Update label="Jan 04, 2025">
  ## v0.95.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.95.0)

  * Feat: Adding Multimodal Abilities to Crew
  * Feat: Programatic Guardrails
  * Feat: HITL multiple rounds
  * Feat: Gemini 2.0 Support
  * Feat: CrewAI Flows Improvements
  * Feat: Add Workflow Permissions
  * Feat: Add support for langfuse with litellm
  * Feat: Portkey Integration with CrewAI
  * Feat: Add interpolate\_only method and improve error handling
  * Feat: Docling Support
  * Feat: Weviate Support
  * Fix: output\_file not respecting system path
  * Fix disk I/O error when resetting short-term memory.
  * Fix: CrewJSONEncoder now accepts enums
  * Fix: Python max version
  * Fix: Interpolation for output\_file in Task
  * Fix: Handle coworker role name case/whitespace properly
  * Fix: Add tiktoken as explicit dependency and document Rust requirement
  * Fix: Include agent knowledge in planning process
  * Fix: Change storage initialization to None for KnowledgeStorage
  * Fix: Fix optional storage checks
  * Fix: include event emitter in flows
  * Fix: Docstring, Error Handling, and Type Hints Improvements
  * Fix: Suppressed userWarnings from litellm pydantic issues
</Update>

<Update label="Dec 05, 2024">
  ## v0.86.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.86.0)

  * remove all references to pipeline and pipeline router
  * docs: Add Nvidia NIM as provider in Custom LLM
  * add knowledge demo + improve knowledge docs
  * Brandon/cre 509 hitl multiple rounds of followup
  * New docs about yaml crew with decorators. Simplify template crew
</Update>

<Update label="Dec 04, 2024">
  ## v0.85.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.85.0)

  * Added knowledge to agent level
  * Feat/remove langchain
  * Improve typed task outputs
  * Log in to Tool Repository on `crewai login`
  * Fixes issues with result as answer not properly exiting LLM loop
  * fix: missing key name when running with ollama provider
  * fix spelling issue found
  * Update readme for running mypy
  * Add knowledge to mint.json
  * Update Github actions
  * Docs Update Agents docs to include two approaches for creating an agent
  * Documentation Improvements: LLM Configuration and Usage
</Update>

<Update label="Nov 25, 2024">
  ## v0.83.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.83.0)

  * New `before_kickoff` and `after_kickoff` crew callbacks
  * Support to pre-seed agents with Knowledge
  * Add support for retrieving user preferences and memories using Mem0
  * Fix Async Execution
  * Upgrade chroma and adjust embedder function generator
  * Update CLI Watson supported models + docs
  * Reduce level for Bandit
  * Fixing all tests
  * Update Docs
</Update>

<Update label="Nov 14, 2024">
  ## v0.80.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.80.0)

  * Fixing Tokens callback replacement bug
  * Fixing Step callback issue
  * Add cached prompt tokens info on usage metrics
  * Fix crew\_train\_success test
</Update>

<Update label="Nov 11, 2024">
  ## v0.79.4

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.79.4)

  Series of small bug fixes around llms support
</Update>

<Update label="Nov 10, 2024">
  ## v0.79.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.79.0)

  * Add inputs to flows
  * Enhance log storage to support more data types
  * Add support to IBM memory
  * Add Watson as an option in CLI
  * Add security.md file
  * Replace .netrc with uv environment variables
  * Move BaseTool to main package and centralize tool description generation
  * Raise an error if an LLM doesnt return a response
  * Fix flows to support cycles and added in test
  * Update how we name crews and fix missing config
  * Update docs
</Update>

<Update label="Oct 30, 2024">
  ## v0.76.9

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.76.9)

  * Update plot command for flow to crewai flow plot
  * Add tomli so we can support 3.10
  * Forward install command options to `uv sync`
  * Improve tool text description and args
  * Improve tooling and flow docs
  * Update flows cli to allow you to easily add additional crews to a flow with crewai flow add-crew
  * Fixed flows bug when using multiple start and listen(and\_(..., ..., ...))
</Update>

<Update label="Oct 23, 2024">
  ## v0.76.2

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.76.2)

  Updating crewai create commadn
</Update>

<Update label="Oct 23, 2024">
  ## v0.76.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.76.0)

  * fix/fixed missing API prompt + CLI docs update
  * chore(readme): fixing step for 'running tests' in the contribution
  * support unsafe code execution. add in docker install and running checks
  * Fix memory imports for embedding functions by
</Update>

<Update label="Oct 23, 2024">
  ## v0.75.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.75.1)

  new `--provider` option on crewai crewat
</Update>

<Update label="Oct 23, 2024">
  ## v0.75.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.75.0)

  * Fixing test post training
  * Simplify flows
  * Adapt `crewai tool install <tool>`
  * Ensure original embedding config works
  * Fix bugs
  * Update docs - Including adding Cerebras LLM example configuration to LLM docs
  * Drop unnecessary tests
</Update>

<Update label="Oct 18, 2024">
  ## v0.74.2

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.74.2)

  * feat: add poetry.lock to uv migration
  * fix tool calling issue
</Update>

<Update label="Oct 18, 2024">
  ## v0.74.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.74.0)

  * UV migration
  * Adapt Tools CLI to UV
  * Add warning from Poetry -> UV
  * CLI to allow for model selection & submitting API keys
  * New Memory Base
  * Fix Linting and Warnings
  * Update Docs
  * Bug fixesh
</Update>

<Update label="Oct 11, 2024">
  ## v0.70.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.70.1)

  * New Flow feature
  * Flow visualizer
  * Create `crewai create flow` command
  * Create `crewai tool create <tool>` command
  * Add Git validations for publishing tools
  * fix: JSON encoding date objects
  * New Docs
  * Update README
  * Bug fixes
</Update>

<Update label="Sep 27, 2024">
  ## v0.65.2

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.65.2)

  * Adding experimental Flows feature
  * Fixing order of tasks bug
  * Updating templates
</Update>

<Update label="Sep 27, 2024">
  ## v0.64.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.64.0)

  * Ordering tasks properly
  * Fixing summarization logic
  * Fixing stop words logic
  * Increases default max iterations to 20
  * Fix crew's key after input interpolation
  * Fixing Training Feature
  * Adding initial tools API
  * TYPOS
  * Updating Docs

  Fixes: #1359 #1355 #1353 #1356 and others
</Update>

<Update label="Sep 25, 2024">
  ## v0.63.6

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.63.6)

  * Updating projects templates
</Update>

<Update label="Sep 25, 2024">
  ## v0.63.5

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.63.5)

  * Bringing support to o1 family back, and any model that don't support stop words
  * Updating dependencies
  * Updating logs
  * Updating docs
</Update>

<Update label="Sep 24, 2024">
  ## v0.63.2

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.63.2)

  * Adding OPENAI\_BASE\_URL as fallback
  * Adding proper LLM import
  * Updating docs
</Update>

<Update label="Sep 24, 2024">
  ## v0.63.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.63.1)

  * Small bug fix for support future CrewAI deploy
</Update>

<Update label="Sep 24, 2024">
  ## v0.63.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.63.0)

  * New LLM class to interact with LLMs (leveraging LiteLLM)
  * Adding support to custom memory interfaces
  * Bringing GPT-4o-mini as the default model
  * Updates Docs
  * Updating dependencies
  * Bug fixes
    * Remove redundant task creation in `kickoff_for_each_async`
</Update>

<Update label="Sep 18, 2024">
  ## v0.61.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.61.0)

  * Updating dependencies
  * Printing max rpm message in different color
  * Updating all cassettes for tests
  * Always ending on a user message - to better support certain models like bedrock ones
  * Overall small bug fixes
</Update>

<Update label="Sep 16, 2024">
  ## v0.60.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.60.0)

  * Removing LangChain and Rebuilding Executor
  * Get all of out tests back to green
  * Adds the ability to not use system prompt use\_system\_prompt on the Agent
  * Adds the ability to not use stop words (to support o1 models) use\_stop\_words on the Agent
  * Sliding context window gets renamed to respect\_context\_window, and enable by default
  * Delegation is now disabled by default
  * Inner prompts were slightly changed as well
  * Overall reliability and quality of results
  * New support for:
    * Number of max requests per minute
    * A maximum number of iterations before giving a final answer
    * Proper take advantage of system prompts
    * Token calculation flow
    * New logging of the crew and agent execution
</Update>

<Update label="Sep 13, 2024">
  ## v0.55.2

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.55.2)

  * Adding ability for auto complete
  * Add name and expected\_output to TaskOutput
  * New `crewai install` CLI
  * New `crewai deploy` CLI
  * Cleaning up of Pipeline feature
  * Updated docs
  * Dev experience improvements like bandit CI pipeline
  * Fix bugs:
    * Ability to use `planning_llm`
    * Fix YAML based projects
    * Fix Azure support
    * Add support to Python 3.10
    * Moving away from Pydantic v1
</Update>

<Update label="Aug 11, 2024">
  ## v0.51.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.51.0)

  * crewAI Testing / Evaluation - [https://docs.crewai.com/core-concepts/Testing/](https://docs.crewai.com/core-concepts/Testing/)
  * Adding new sliding context window
  * Allowing all attributes on YAML - [https://docs.crewai.com/getting-started/Start-a-New-CrewAI-Project-Template-Method/#customizing-your-project](https://docs.crewai.com/getting-started/Start-a-New-CrewAI-Project-Template-Method/#customizing-your-project)
  * Adding initial Pipeline Structure - [https://docs.crewai.com/core-concepts/Pipeline/](https://docs.crewai.com/core-concepts/Pipeline/)
  * Ability to set LLM for planning step - [https://docs.crewai.com/core-concepts/Planning/](https://docs.crewai.com/core-concepts/Planning/)
  * New crew run command - [https://docs.crewai.com/getting-started/Start-a-New-CrewAI-Project-Template-Method/#running-your-project](https://docs.crewai.com/getting-started/Start-a-New-CrewAI-Project-Template-Method/#running-your-project)
  * Saving file now dumps dict into JSON - [https://docs.crewai.com/core-concepts/Tasks/#creating-directories-when-saving-files](https://docs.crewai.com/core-concepts/Tasks/#creating-directories-when-saving-files)
  * Using verbose settings for tool outputs
  * Added new Github Templates
  * New Vision tool - [https://docs.crewai.com/tools/VisionTool/](https://docs.crewai.com/tools/VisionTool/)
  * New DALL-E Tool - [https://docs.crewai.com/tools/DALL-ETool/](https://docs.crewai.com/tools/DALL-ETool/)
  * New MySQL tool - [https://docs.crewai.com/tools/MySQLTool/](https://docs.crewai.com/tools/MySQLTool/)
  * New NL2SQL Tool - [https://docs.crewai.com/tools/NL2SQLTool.md](https://docs.crewai.com/tools/NL2SQLTool.md)
  * Bug Fixes:
    * Bug with planning feature output
    * Async tasks for hierarchical process
    * Better pydantic output for non OAI models
    * JSON truncation issues
    * Fix logging types
    * Only import AgentOps if the Env Key is set
    * Sanitize agent roles to ensure valid directory names (Windows)
    * Tools name shouldn't contain space for OpenAI
    * A bunch of minor issues
</Update>

<Update label="Jul 20, 2024">
  ## v0.41.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.41.1)

  * Fix bug with planning feature
</Update>

<Update label="Jul 19, 2024">
  ## v0.41.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.41.0)

  * **\[Breaking Change]** Type Safe output
    * All crews and tasks now return a proper object TaskOuput and CrewOutput
  * **\[Feature]** New planning feature for crews (plan before act)
    * by adding planning=True to the Crew instance
  * **\[Feature]** Introduced Replay Feature
    * New CLI that allow you to list the tasks from last run and replay from a specific one
  * **\[Feature]** Ability to reset memory
    * You can clean your crew memory before running it again
  * **\[Feature]** Add retry feature for LLM calls
    * You can retry llm calls and not stop the crew execution
  * **\[Feature]** Added ability to customize converter
  * **\[Tool]** Enhanced tools with type hinting and new attributes
  * **\[Tool]** Added MultiON Tool
  * **\[Tool]** Fixed filecrawl tools
  * **\[Tool]** Fixed bug in Scraping tool
  * **\[Tools]** Bumped crewAI-tools dependency to version
  * **\[Bugs]** General bug fixes and improvements
  * **\[Bugs]** Telemetry fixes
  * **\[Bugs]** Spell check corrections
  * **\[Docs]** Updated documentation
</Update>

<Update label="Jul 06, 2024">
  ## v0.36.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.36.0)

  * Bug fix
  * Updating Docs
  * Updating native prompts
  * Fixing TYPOs on the prompts
  * Adding AgentOps native support
  * Adding Firecrawl Tools
  * Adding new ability to return a tool results as an agent result
  * Improving coding Interpreter tool
  * Adding new option to create your own corveter class (docs pending)
</Update>

<Update label="Jul 04, 2024">
  ## v0.35.8

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.35.8)

  * fixing embechain dependency issue
</Update>

<Update label="Jul 02, 2024">
  ## v0.35.7

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.35.7)

  * New @composiohq integration is out
  * Documentation update
  * Custom GPT Updated
  * Adjusting manager verbosity level
  * Bug fixes
</Update>

<Update label="Jul 01, 2024">
  ## v0.35.5

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.35.5)

  * Fix embedchain dependency
</Update>

<Update label="Jul 01, 2024">
  ## v0.35.4

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.35.4)

  * Updating crewai create CLI to use the new version
</Update>

<Update label="Jul 01, 2024">
  ## v0.35.3

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.35.3)

  * Code Execution Bug fixed
  * Updating overall docs
  * Bumping version of crewai-tools
  * Bumping versions of many dependencies
  * Overall bugfixes
</Update>

<Update label="Jun 29, 2024">
  ## v0.35.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.35.0)

  * Your agents can now execute code
  * Bring Any 3rd-party agent, LlamaIndex, LangChain and Autogen  agents can all be part of your crew now!
  * Train you crew before you execute it and get consistent results! New CLI `crewai train -n X`
  * Bug fixes and docs updates (still missing some new docs updates coming soon)
</Update>

<Update label="Jun 22, 2024">
  ## v0.32.2

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.32.2)

  * Updating `crewai create` CLI to use the new version
  * Fixing delegation agent matching
</Update>

<Update label="Jun 21, 2024">
  ## v0.32.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.32.0)

  * New `kickoff_for_each`, `kickoff_async` and `kickoff_for_each_async` methods for better control over the kickoff process
  * Adding support for all LlamaIndex hub integrations
  * Adding `usage_metrics` to full output or a crew
  * Adding support to multiple crews on the new YAML format
  * Updating dependencies
  * Fixed Bugs and TYPOs
  * Documentation updated
  * Added search in docs
  * Making gpt-4o the default model
  * Adding new docs for LangTrace, Browserbase and Exa Search
  * Adding timestamp to logging
</Update>

<Update label="May 23, 2024">
  ## v0.30.11

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.30.11)

  * Updating project generation template
</Update>

<Update label="May 14, 2024">
  ## v0.30.8

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.30.8)

  * Updating dependencies
  * Small bug fixes on crewAI project structure
  * Removing custom YAML parser for now
</Update>

<Update label="May 14, 2024">
  ## v0.30.5

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.30.5)

  * Making agent delegation more versatile for smaller models
</Update>

<Update label="May 13, 2024">
  ## v0.30.4

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.30.4)

  **Docs Update will follow** sorry about that and thank you for bearing with me, we are launching new docs soon!

  ➿  Fixing task callback
  🧙  Ability to set a specific agent as manager instead of having crew create your one
  📄  Ability to set system, prompt and response templates, so it works more reliable with opensource models (works better with smaller models)
  👨‍💻  Improving json and pydantic output (works better with smaller models)
  🔎 Improving tool name recognition (works better with smaller models)
  🧰  Improvements for tool usage (works better with smaller models)
  📃  Initial support to bring your own prompts
  2️⃣  Fixing duplicating token calculator metrics
  🪚  Adding couple new tools, Browserbase and Exa Search
  📁  Ability to create directory when saving as file
  🔁  Updating dependencies - double check tools
  📄  Overall small documentation improvements
  🐛  Smaller bug fixes (typos and such)
  👬  Fixing co-worker / coworker issues
  👀  Smaller Readme Updates
</Update>

<Update label="Apr 11, 2024">
  ## v0.28.8

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.28.8)

  * updating version used on crewai CLI
</Update>

<Update label="Apr 11, 2024">
  ## v0.28.7

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.28.7)

  * Bug fixes
  * Updating crewAI tool version with bug fixes
</Update>

<Update label="Apr 08, 2024">
  ## v0.28.5

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.28.5)

  * Major Long term memory interpolation issue
  * Updating tools package dependency with fixes
  * Removing unnecessary certificate
</Update>

<Update label="Apr 07, 2024">
  ## v0.28.2

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.28.2)

  * Major long term memory fix
</Update>

<Update label="Apr 06, 2024">
  ## v0.28.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.28.1)

  * Updating crewai-tools to 0.1.15
</Update>

<Update label="Apr 05, 2024">
  ## v0.28.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.28.0)

  * Not overriding LLM callbacks
  * Adding `max_execution_time` support
  * Adding specific memory docs
  * Moving tool usage logging color to purple from yellow
  * Updating Docs
</Update>

<Update label="Apr 04, 2024">
  ## v0.27.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.27.0)

  * 🧠 **Memory (shared crew memory)** - To enable it just add `memory=True` to your crew, it will work transparently and make outcomes better and more reliable, it's disable by default for now
  * 🤚🏼 **Native Human Input Support:** [docs](https://docs.crewai.com/how-to/Human-Input-on-Execution/)
  * 🌐 **Universal RAG Tools Support:** Any models, beyond just OpenAI. [Example](https://docs.crewai.com/tools/DirectorySearchTool/#custom-model-and-embeddings)
  * 🔍 **Enhanced Cache Control:** Meet the ingenious cache\_function attribute: [docs](https://docs.crewai.com/core-concepts/Tools/#custom-caching-mechanism)
  * 🔁 **Updated crewai-tools Dependency:** Always in sync with the latest and greatest.
  * ⛓️ **Cross Agent Delegation:** Smoother cooperation between agents.
  * 💠 **Inner Prompt Improvements:** A finer conversational flow.
  * 📝 **Improving tool usage with better parsing**
  * 🔒 **Security improvements and updating dependencies**
  * 📄 **Documentation improved**
  * 🐛 **Bug fixes**
</Update>

<Update label="Mar 12, 2024">
  ## v0.22.5

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.22.5)

  * Other minor import issues on the new templates
</Update>

<Update label="Mar 12, 2024">
  ## v0.22.4

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.22.4)

  Fixing template issues
</Update>

<Update label="Mar 11, 2024">
  ## v0.22.2

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.22.2)

  * Fixing bug on the new cli template
  * Guaranteeing tasks order on new cli template
</Update>

<Update label="Mar 11, 2024">
  ## v0.22.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.22.0)

  * Adding initial CLI `crewai create` command
  * Adding ability to agents and tasks to be defined using dictionaries
  * Adding more clear agent logging
  * Fixing bug Exceed maximum recursion depth bug
  * Fixing docs
  * Updating README
</Update>

<Update label="Mar 04, 2024">
  ## v0.19.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.19.0)

  * Efficiency in tool usage +1023.21%
  * Mean tools used +276%
  * Tool errors slashed by 67%, more reliable than ever.
  * Delegation capabilities enhanced
  * Ability to fallback to function calling by setting `function_calling_llm` to Agent or Crew
  * Ability to get crew execution metrics after `kickoff` with `crew.usage_metrics`
  * Adding ability for inputs being passed in kickoff now `crew.kickoff(inputs: {'key': 'value})`
  * Updating Docs
</Update>

<Update label="Feb 28, 2024">
  ## v0.16.3

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.16.3)

  * Fixing overall bugs
  * Making sure code is backwards compatible
</Update>

<Update label="Feb 28, 2024">
  ## v0.16.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.16.0)

  * Removing lingering `crewai_tools` dependency
  * Adding initial support for inputs interpolation (missing docs)
  * Adding ability to track tools usage, tools error, formatting errors, tokens usage
  * Updating README
</Update>

<Update label="Feb 26, 2024">
  ## v0.14.4

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.14.4)

  * Updating timeouts
  * Updating docs
  * Removing crewai\_tools as a mandatory
  * Making agents memory-less by default for token count reduction (breaking change for people counting on this previously)
</Update>

<Update label="Feb 24, 2024">
  ## v0.14.3

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.14.3)

  * Fixing broken docs link
  * Adding support for agents without tools
  * Avoid empty task outputs
</Update>

<Update label="Feb 22, 2024">
  ## v0.14.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.14.0)

  All improvements from the v0.14.0rc.

  * Support to export json and pydantic from opensource models
</Update>

<Update label="Feb 20, 2024">
  ## v0.14.0rc

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.14.0rc0)

  * Adding support to crewai-tools
  * Adding support to format tasks output as Pydantic Objects Or JSON
  * Adding support to save tasks ouput to a file
  * Improved reliability for inter agent delegation
  * Revamp tools usage logic to proper use function calling
  * Updating internal prompts
  * Supporting tools with no arguments
  * Bug fixes
</Update>

<Update label="Feb 16, 2024">
  ## v0.11.2

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.11.2)

  * Adding further error logging so users understand what is happening if a tool fails
</Update>

<Update label="Feb 16, 2024">
  ## v0.11.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.11.1)

  * It fixes a  bug on the tool usage logic that was early caching the result even if there was an error on the usage, preventing it from using the tool again.
  * It will also print any error message in red allowing the user to understand what was the problem with the tool.
</Update>

<Update label="Feb 13, 2024">
  ## v0.11.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.11.0)

  * Ability to set `function_calling_llm` on both the entire crew and individual agents
  * Some early attempts on cost reduction
  * Improving function calling for tools
  * Updates docs
</Update>

<Update label="Feb 10, 2024">
  ## v0.10.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.10.0)

  * Ability to get `full_ouput` from crew kickoff with all tasks outputs
  * Ability to set `step_callback` function for both Agents and Crews so you can get all intermediate steps
  * Remembering Agent of the expected format after certain number of tool usages.
  * New tool usage internals now using json, unlocking tools with multiple arguments
  * Refactoring overall delegation logic, now way more reliable
  * Fixed `max_inter` bug now properly forcing llm to answer as it gets to that
  * Rebuilt caching structure, making sure multiple agents can use the same cache
  * Refactoring Task repeated usage prevention logic
  * Removing now unnecessary `CrewAgentOutputParser`
  * Opt-in to share complete crew related data with the crewAI team
  * Overall Docs update
</Update>

<Update label="Feb 08, 2024">
  ## v0.5.5

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.5.5)

  * Overall doc + readme improvements
  * Fixing RPM controller being set unnecessarily
  * Adding early stage anonymous telemetry for lib improvement
</Update>

<Update label="Feb 07, 2024">
  ## v0.5.3

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.5.3)

  * quick Fix for hierarchical manager
</Update>

<Update label="Feb 06, 2024">
  ## v0.5.2

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.5.2)

  * Adding `manager_llm` for hierarchical process
  * Improving `max_inter` and `max_rpm` logic
  * Updating README and Docs
</Update>

<Update label="Feb 04, 2024">
  ## v0.5.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.5.0)

  This new version bring a lot of new features and improvements to the library.

  ## Features

  * Adding Task Callbacks.
  * Adding support for Hierarchical process.
  * Adding ability to references specific tasks in another task.
  * Adding ability to parallel task execution.

  ## Improvements

  * Revamping Max Iterations and Max Requests per Minute.
  * Developer experience improvements, docstrings and such.
  * Small improvements and TYPOs.
  * Fix static typing errors.
  * Updated README and Docs.
</Update>

<Update label="Jan 14, 2024">
  ## v0.1.32

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.1.32)

  * Moving to LangChain 0.1.0
  * Improving Prompts
  * Adding ability to limit maximum number of iterations for an agent
  * Adding ability to Request Per Minute throttling for both Agents and Crews
  * Adding initial support for translations
  * Adding Greek translation
  * Improve code readability
  * Starting new documentation with mkdocs
</Update>

<Update label="Jan 07, 2024">
  ## v0.1.23

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.1.23)

  * Many Reliability improvements
  * Prompt changes
  * Initial changes for supporting multiple languages
  * Fixing bug on task repeated execution
  * Better execution error handling
  * Updating READMe
</Update>

<Update label="Dec 30, 2023">
  ## v0.1.14

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.1.14)

  * Adding tool caching a loop execution prevention. (@joaomdmoura)
  * Adding more guidelines for Agent delegation. (@joaomdmoura)
  * Updating to use new openai lib version. (@joaomdmoura)
  * Adding verbose levels to the logger. (@joaomdmoura)
  * Removing WIP code. (@joaomdmoura)
  * A lot of developer quality of life improvements (Special thanks to @greysonlalonde).
  * Updating to pydantic v2 (Special thanks to @greysonlalonde as well).
</Update>

<Update label="Nov 24, 2023">
  ## v0.1.2

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.1.2)

  * Adding ability to use other LLMs, not OpenAI
</Update>

<Update label="Nov 19, 2023">
  ## v0.1.1

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.1.1)

  # CrewAI v0.1.1 Release Notes

  ## What's New

  * **Crew Verbose Mode**:  Now allowing you to inspect a the tasks are being executed.

  * **README and Docs Updates**: A series of minor updates on the docs
</Update>

<Update label="Nov 14, 2023">
  ## v0.1.0

  [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.1.0)

  # CrewAI v0.1.0 Release Notes

  We are thrilled to announce the initial release of CrewAI, version 0.1.0! CrewAI is a framework designed to facilitate the orchestration of autonomous AI agents capable of role-playing and collaboration to accomplish complex tasks more efficiently.

  ## What's New

  * **Initial Launch**: CrewAI is now officially in the wild! This foundational release lays the groundwork for AI agents to work in tandem, each with its own specialized role and objectives.

  * **Role-Based Agent Design**: Define and customize agents with specific roles, goals, and the tools they need to succeed.

  * **Inter-Agent Delegation**: Agents are now equipped to autonomously delegate tasks, enabling dynamic distribution of workload among the team.

  * **Task Management**: Create and assign tasks dynamically with the flexibility to specify the tools needed for each task.

  * **Sequential Processes**: Set up your agents to tackle tasks one after the other, ensuring organized and predictable workflows.

  * **Documentation**: Start exploring CrewAI with our initial documentation that guides you through the setup and use of the framework.

  ## Enhancements

  * Detailed API documentation for the `Agent`, `Task`, `Crew`, and `Process` classes.
  * Examples and tutorials to help you build your first CrewAI application.
  * Basic setup for collaborative and delegation mechanisms among agents.

  ## Known Issues

  * As this is the first release, there may be undiscovered bugs and areas for optimization. We encourage the community to report any issues found during use.

  ## Upcoming Features

  * **Advanced Process Management**: In future releases, we will introduce more complex processes for task management including consensual and hierarchical workflows.
</Update>


# Azure OpenAI Setup
Source: https://docs.crewai.com/en/enterprise/guides/azure-openai-setup

Configure Azure OpenAI with Crew Studio for enterprise LLM connections

This guide walks you through connecting Azure OpenAI with Crew Studio for seamless enterprise AI operations.

## Setup Process

<Steps>
  <Step title="Access Azure AI Foundry">
    1. In Azure, go to [Azure AI Foundry](https://ai.azure.com/) > select your Azure OpenAI deployment.
    2. On the left menu, click `Deployments`. If you don't have one, create a deployment with your desired model.
    3. Once created, select your deployment and locate the `Target URI` and `Key` on the right side of the page. Keep this page open, as you'll need this information.
       <Frame>
         <img alt="Azure AI Foundry" />
       </Frame>
  </Step>

  <Step title="Configure CrewAI AMP Connection">
    4. In another tab, open `CrewAI AMP > LLM Connections`. Name your LLM Connection, select Azure as the provider, and choose the same model you selected in Azure.
    5. On the same page, add environment variables from step 3:
       * One named `AZURE_DEPLOYMENT_TARGET_URL` (using the Target URI). The URL should look like this: [https://your-deployment.openai.azure.com/openai/deployments/gpt-4o/chat/completions?api-version=2024-08-01-preview](https://your-deployment.openai.azure.com/openai/deployments/gpt-4o/chat/completions?api-version=2024-08-01-preview)
       * Another named `AZURE_API_KEY` (using the Key).
    6. Click `Add Connection` to save your LLM Connection.
  </Step>

  <Step title="Set Default Configuration">
    7. In `CrewAI AMP > Settings > Defaults > Crew Studio LLM Settings`, set the new LLM Connection and model as defaults.
  </Step>

  <Step title="Configure Network Access">
    8. Ensure network access settings:
       * In Azure, go to `Azure OpenAI > select your deployment`.
       * Navigate to `Resource Management > Networking`.
       * Ensure that `Allow access from all networks` is enabled. If this setting is restricted, CrewAI may be blocked from accessing your Azure OpenAI endpoint.
  </Step>
</Steps>

## Verification

You're all set! Crew Studio will now use your Azure OpenAI connection. Test the connection by creating a simple crew or task to ensure everything is working properly.

## Troubleshooting

If you encounter issues:

* Verify the Target URI format matches the expected pattern
* Check that the API key is correct and has proper permissions
* Ensure network access is configured to allow CrewAI connections
* Confirm the deployment model matches what you've configured in CrewAI


# Build Crew
Source: https://docs.crewai.com/en/enterprise/guides/build-crew

A Crew is a group of agents that work together to complete a task.

## Overview

[CrewAI AMP](https://app.crewai.com) streamlines the process of **creating**, **deploying**, and **managing** your AI agents in production environments.

## Getting Started

<iframe title="Building crews with the CrewAI CLI" />

### Installation and Setup

<Card title="Follow Standard Installation" icon="wrench" href="/en/installation">
  Follow our standard installation guide to set up CrewAI CLI and create your
  first project.
</Card>

### Building Your Crew

<Card title="Quickstart Tutorial" icon="rocket" href="/en/quickstart">
  Follow our quickstart guide to create your first agent crew using YAML
  configuration.
</Card>

## Support and Resources

For Enterprise-specific support or questions, contact our dedicated support team at [support@crewai.com](mailto:support@crewai.com).

<Card title="Schedule a Demo" icon="calendar" href="mailto:support@crewai.com">
  Book time with our team to learn more about Enterprise features and how they
  can benefit your organization.
</Card>


# Open Telemetry Logs
Source: https://docs.crewai.com/en/enterprise/guides/capture_telemetry_logs

Understand how to capture telemetry logs from your CrewAI AMP deployments

CrewAI AMP provides a powerful way to capture telemetry logs from your deployments. This allows you to monitor the performance of your agents and workflows, and to debug issues that may arise.

## Prerequisites

<CardGroup>
  <Card title="ENTERPRISE OTEL SETUP enabled" icon="users">
    Your organization should have ENTERPRISE OTEL SETUP enabled
  </Card>

  <Card title="OTEL collector setup" icon="server">
    Your organization should have an OTEL collector setup or a provider like
    Datadog log intake setup
  </Card>
</CardGroup>

## How to capture telemetry logs

1. Go to settings/organization tab
2. Configure your OTEL collector setup
3. Save

Example to setup OTEL log collection capture to Datadog.

<Frame>
  <img alt="Capture Telemetry Logs" />
</Frame>


# Deploy to AMP
Source: https://docs.crewai.com/en/enterprise/guides/deploy-to-amp

Deploy your Crew or Flow to CrewAI AMP

<Note>
  After creating a Crew or Flow locally (or through Crew Studio), the next step is
  deploying it to the CrewAI AMP platform. This guide covers multiple deployment
  methods to help you choose the best approach for your workflow.
</Note>

## Prerequisites

<CardGroup>
  <Card title="Project Ready for Deployment" icon="check-circle">
    You should have a working Crew or Flow that runs successfully locally.
    Follow our [preparation guide](/en/enterprise/guides/prepare-for-deployment) to verify your project structure.
  </Card>

  <Card title="GitHub Repository" icon="github">
    Your code should be in a GitHub repository (for GitHub integration
    method)
  </Card>
</CardGroup>

<Info>
  **Crews vs Flows**: Both project types can be deployed as "automations" on CrewAI AMP.
  The deployment process is the same, but they have different project structures.
  See [Prepare for Deployment](/en/enterprise/guides/prepare-for-deployment) for details.
</Info>

## Option 1: Deploy Using CrewAI CLI

The CLI provides the fastest way to deploy locally developed Crews or Flows to the AMP platform.
The CLI automatically detects your project type from `pyproject.toml` and builds accordingly.

<Steps>
  <Step title="Install CrewAI CLI">
    If you haven't already, install the CrewAI CLI:

    ```bash theme={null}
    pip install crewai[tools]
    ```

    <Tip>
      The CLI comes with the main CrewAI package, but the `[tools]` extra ensures you have all deployment dependencies.
    </Tip>
  </Step>

  <Step title="Authenticate with the Enterprise Platform">
    First, you need to authenticate your CLI with the CrewAI AMP platform:

    ```bash theme={null}
    # If you already have a CrewAI AMP account, or want to create one:
    crewai login
    ```

    When you run either command, the CLI will:

    1. Display a URL and a unique device code
    2. Open your browser to the authentication page
    3. Prompt you to confirm the device
    4. Complete the authentication process

    Upon successful authentication, you'll see a confirmation message in your terminal!
  </Step>

  <Step title="Create a Deployment">
    From your project directory, run:

    ```bash theme={null}
    crewai deploy create
    ```

    This command will:

    1. Detect your GitHub repository information
    2. Identify environment variables in your local `.env` file
    3. Securely transfer these variables to the Enterprise platform
    4. Create a new deployment with a unique identifier

    On successful creation, you'll see a message like:

    ```shell theme={null}
    Deployment created successfully!
    Name: your_project_name
    Deployment ID: 01234567-89ab-cdef-0123-456789abcdef
    Current Status: Deploy Enqueued
    ```
  </Step>

  <Step title="Monitor Deployment Progress">
    Track the deployment status with:

    ```bash theme={null}
    crewai deploy status
    ```

    For detailed logs of the build process:

    ```bash theme={null}
    crewai deploy logs
    ```

    <Tip>
      The first deployment typically takes 10-15 minutes as it builds the container images. Subsequent deployments are much faster.
    </Tip>
  </Step>
</Steps>

## Additional CLI Commands

The CrewAI CLI offers several commands to manage your deployments:

```bash theme={null}
# List all your deployments
crewai deploy list

# Get the status of your deployment
crewai deploy status

# View the logs of your deployment
crewai deploy logs

# Push updates after code changes
crewai deploy push

# Remove a deployment
crewai deploy remove <deployment_id>
```

## Option 2: Deploy Directly via Web Interface

You can also deploy your Crews or Flows directly through the CrewAI AMP web interface by connecting your GitHub account. This approach doesn't require using the CLI on your local machine. The platform automatically detects your project type and handles the build appropriately.

<Steps>
  <Step title="Pushing to GitHub">
    You need to push your crew to a GitHub repository. If you haven't created a crew yet, you can [follow this tutorial](/en/quickstart).
  </Step>

  <Step title="Connecting GitHub to CrewAI AMP">
    1. Log in to [CrewAI AMP](https://app.crewai.com)
    2. Click on the button "Connect GitHub"

    <Frame>
      <img alt="Connect GitHub Button" />
    </Frame>
  </Step>

  <Step title="Select the Repository">
    After connecting your GitHub account, you'll be able to select which repository to deploy:

    <Frame>
      <img alt="Select Repository" />
    </Frame>
  </Step>

  <Step title="Set Environment Variables">
    Before deploying, you'll need to set up your environment variables to connect to your LLM provider or other services:

    1. You can add variables individually or in bulk
    2. Enter your environment variables in `KEY=VALUE` format (one per line)

    <Frame>
      <img alt="Set Environment Variables" />
    </Frame>

    <Info>
      Using private Python packages? You'll need to add your registry credentials here too.
      See [Private Package Registries](/en/enterprise/guides/private-package-registry) for the required variables.
    </Info>
  </Step>

  <Step title="Deploy Your Crew">
    1. Click the "Deploy" button to start the deployment process
    2. You can monitor the progress through the progress bar
    3. The first deployment typically takes around 10-15 minutes; subsequent deployments will be faster

    <Frame>
      <img alt="Deploy Progress" />
    </Frame>

    Once deployment is complete, you'll see:

    * Your crew's unique URL
    * A Bearer token to protect your crew API
    * A "Delete" button if you need to remove the deployment
  </Step>
</Steps>

## Option 3: Redeploy Using API (CI/CD Integration)

For automated deployments in CI/CD pipelines, you can use the CrewAI API to trigger redeployments of existing crews. This is particularly useful for GitHub Actions, Jenkins, or other automation workflows.

<Steps>
  <Step title="Get Your Personal Access Token">
    Navigate to your CrewAI AMP account settings to generate an API token:

    1. Go to [app.crewai.com](https://app.crewai.com)
    2. Click on **Settings** → **Account** → **Personal Access Token**
    3. Generate a new token and copy it securely
    4. Store this token as a secret in your CI/CD system
  </Step>

  <Step title="Find Your Automation UUID">
    Locate the unique identifier for your deployed crew:

    1. Go to **Automations** in your CrewAI AMP dashboard
    2. Select your existing automation/crew
    3. Click on **Additional Details**
    4. Copy the **UUID** - this identifies your specific crew deployment
  </Step>

  <Step title="Trigger Redeployment via API">
    Use the Deploy API endpoint to trigger a redeployment:

    ```bash theme={null}
    curl -i -X POST \
         -H "Authorization: Bearer YOUR_PERSONAL_ACCESS_TOKEN" \
         https://app.crewai.com/crewai_plus/api/v1/crews/YOUR-AUTOMATION-UUID/deploy

    # HTTP/2 200
    # content-type: application/json
    #
    # {
    #   "uuid": "your-automation-uuid",
    #   "status": "Deploy Enqueued",
    #   "public_url": "https://your-crew-deployment.crewai.com",
    #   "token": "your-bearer-token"
    # }
    ```

    <Info>
      If your automation was first created connected to Git, the API will automatically pull the latest changes from your repository before redeploying.
    </Info>
  </Step>

  <Step title="GitHub Actions Integration Example">
    Here's a GitHub Actions workflow with more complex deployment triggers:

    ```yaml theme={null}
    name: Deploy CrewAI Automation

    on:
      push:
        branches: [ main ]
      pull_request:
        types: [ labeled ]
      release:
        types: [ published ]

    jobs:
      deploy:
        runs-on: ubuntu-latest
        if: |
          (github.event_name == 'push' && github.ref == 'refs/heads/main') ||
          (github.event_name == 'pull_request' && contains(github.event.pull_request.labels.*.name, 'deploy')) ||
          (github.event_name == 'release')
        steps:
          - name: Trigger CrewAI Redeployment
            run: |
              curl -X POST \
                   -H "Authorization: Bearer ${{ secrets.CREWAI_PAT }}" \
                   https://app.crewai.com/crewai_plus/api/v1/crews/${{ secrets.CREWAI_AUTOMATION_UUID }}/deploy
    ```

    <Tip>
      Add `CREWAI_PAT` and `CREWAI_AUTOMATION_UUID` as repository secrets. For PR deployments, add a "deploy" label to trigger the workflow.
    </Tip>
  </Step>
</Steps>

## Interact with Your Deployed Automation

Once deployment is complete, you can access your crew through:

1. **REST API**: The platform generates a unique HTTPS endpoint with these key routes:

   * `/inputs`: Lists the required input parameters
   * `/kickoff`: Initiates an execution with provided inputs
   * `/status/{kickoff_id}`: Checks the execution status

2. **Web Interface**: Visit [app.crewai.com](https://app.crewai.com) to access:
   * **Status tab**: View deployment information, API endpoint details, and authentication token
   * **Run tab**: Visual representation of your crew's structure
   * **Executions tab**: History of all executions
   * **Metrics tab**: Performance analytics
   * **Traces tab**: Detailed execution insights

### Trigger an Execution

From the Enterprise dashboard, you can:

1. Click on your crew's name to open its details
2. Select "Trigger Crew" from the management interface
3. Enter the required inputs in the modal that appears
4. Monitor progress as the execution moves through the pipeline

### Monitoring and Analytics

The Enterprise platform provides comprehensive observability features:

* **Execution Management**: Track active and completed runs
* **Traces**: Detailed breakdowns of each execution
* **Metrics**: Token usage, execution times, and costs
* **Timeline View**: Visual representation of task sequences

### Advanced Features

The Enterprise platform also offers:

* **Environment Variables Management**: Securely store and manage API keys
* **LLM Connections**: Configure integrations with various LLM providers
* **Custom Tools Repository**: Create, share, and install tools
* **Crew Studio**: Build crews through a chat interface without writing code

## Troubleshooting Deployment Failures

If your deployment fails, check these common issues:

### Build Failures

#### Missing uv.lock File

**Symptom**: Build fails early with dependency resolution errors

**Solution**: Generate and commit the lock file:

```bash theme={null}
uv lock
git add uv.lock
git commit -m "Add uv.lock for deployment"
git push
```

<Warning>
  The `uv.lock` file is required for all deployments. Without it, the platform
  cannot reliably install your dependencies.
</Warning>

#### Wrong Project Structure

**Symptom**: "Could not find entry point" or "Module not found" errors

**Solution**: Verify your project matches the expected structure:

* **Both Crews and Flows**: Must have entry point at `src/project_name/main.py`
* **Crews**: Use a `run()` function as entry point
* **Flows**: Use a `kickoff()` function as entry point

See [Prepare for Deployment](/en/enterprise/guides/prepare-for-deployment) for detailed structure diagrams.

#### Missing CrewBase Decorator

**Symptom**: "Crew not found", "Config not found", or agent/task configuration errors

**Solution**: Ensure **all** crew classes use the `@CrewBase` decorator:

```python theme={null}
from crewai.project import CrewBase, agent, crew, task

@CrewBase  # This decorator is REQUIRED
class YourCrew():
    """Your crew description"""

    @agent
    def my_agent(self) -> Agent:
        return Agent(
            config=self.agents_config['my_agent'],  # type: ignore[index]
            verbose=True
        )

    # ... rest of crew definition
```

<Info>
  This applies to standalone Crews AND crews embedded inside Flow projects.
  Every crew class needs the decorator.
</Info>

#### Incorrect pyproject.toml Type

**Symptom**: Build succeeds but runtime fails, or unexpected behavior

**Solution**: Verify the `[tool.crewai]` section matches your project type:

```toml theme={null}
# For Crew projects:
[tool.crewai]
type = "crew"

# For Flow projects:
[tool.crewai]
type = "flow"
```

### Runtime Failures

#### LLM Connection Failures

**Symptom**: API key errors, "model not found", or authentication failures

**Solution**:

1. Verify your LLM provider's API key is correctly set in environment variables
2. Ensure the environment variable names match what your code expects
3. Test locally with the exact same environment variables before deploying

#### Crew Execution Errors

**Symptom**: Crew starts but fails during execution

**Solution**:

1. Check the execution logs in the AMP dashboard (Traces tab)
2. Verify all tools have required API keys configured
3. Ensure agent configurations in `agents.yaml` are valid
4. Check task configurations in `tasks.yaml` for syntax errors

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with deployment issues or questions
  about the AMP platform.
</Card>


# Enable Crew Studio
Source: https://docs.crewai.com/en/enterprise/guides/enable-crew-studio

Enabling Crew Studio on CrewAI AMP

<Tip>
  Crew Studio is a powerful **no-code/low-code** tool that allows you to quickly
  scaffold or build Crews through a conversational interface.
</Tip>

## What is Crew Studio?

Crew Studio is an innovative way to create AI agent crews without writing code.

<Frame>
  <img alt="Crew Studio Interface" />
</Frame>

With Crew Studio, you can:

* Chat with the Crew Assistant to describe your problem
* Automatically generate agents and tasks
* Select appropriate tools
* Configure necessary inputs
* Generate downloadable code for customization
* Deploy directly to the CrewAI AMP platform

## Configuration Steps

Before you can start using Crew Studio, you need to configure your LLM connections:

<Steps>
  <Step title="Set Up LLM Connection">
    Go to the **LLM Connections** tab in your CrewAI AMP dashboard and create a new LLM connection.

    <Note>
      Feel free to use any LLM provider you want that is supported by CrewAI.
    </Note>

    Configure your LLM connection:

    * Enter a `Connection Name` (e.g., `OpenAI`)
    * Select your model provider: `openai` or `azure`
    * Select models you'd like to use in your Studio-generated Crews
      * We recommend at least `gpt-4o`, `o1-mini`, and `gpt-4o-mini`
    * Add your API key as an environment variable:
      * For OpenAI: Add `OPENAI_API_KEY` with your API key
      * For Azure OpenAI: Refer to [this article](https://blog.crewai.com/configuring-azure-openai-with-crewai-a-comprehensive-guide/) for configuration details
    * Click `Add Connection` to save your configuration

    <Frame>
      <img alt="LLM Connection Configuration" />
    </Frame>
  </Step>

  <Step title="Verify Connection Added">
    Once you complete the setup, you'll see your new connection added to the list of available connections.

    <Frame>
      <img alt="Connection Added" />
    </Frame>
  </Step>

  <Step title="Configure LLM Defaults">
    In the main menu, go to **Settings → Defaults** and configure the LLM Defaults settings:

    * Select default models for agents and other components
    * Set default configurations for Crew Studio

    Click `Save Settings` to apply your changes.

    <Frame>
      <img alt="LLM Defaults Configuration" />
    </Frame>
  </Step>
</Steps>

## Using Crew Studio

Now that you've configured your LLM connection and default settings, you're ready to start using Crew Studio!

<Steps>
  <Step title="Access Studio">
    Navigate to the **Studio** section in your CrewAI AMP dashboard.
  </Step>

  <Step title="Start a Conversation">
    Start a conversation with the Crew Assistant by describing the problem you want to solve:

    ```md theme={null}
    I need a crew that can research the latest AI developments and create a summary report.
    ```

    The Crew Assistant will ask clarifying questions to better understand your requirements.
  </Step>

  <Step title="Review Generated Crew">
    Review the generated crew configuration, including:

    * Agents and their roles
    * Tasks to be performed
    * Required inputs
    * Tools to be used

    This is your opportunity to refine the configuration before proceeding.
  </Step>

  <Step title="Deploy or Download">
    Once you're satisfied with the configuration, you can:

    * Download the generated code for local customization
    * Deploy the crew directly to the CrewAI AMP platform
    * Modify the configuration and regenerate the crew
  </Step>

  <Step title="Test Your Crew">
    After deployment, test your crew with sample inputs to ensure it performs as expected.
  </Step>
</Steps>

<Tip>
  For best results, provide clear, detailed descriptions of what you want your
  crew to accomplish. Include specific inputs and expected outputs in your
  description.
</Tip>

## Example Workflow

Here's a typical workflow for creating a crew with Crew Studio:

<Steps>
  <Step title="Describe Your Problem">
    Start by describing your problem:

    ```md theme={null}
    I need a crew that can analyze financial news and provide investment recommendations
    ```
  </Step>

  <Step title="Answer Questions">
    Respond to clarifying questions from the Crew Assistant to refine your
    requirements.
  </Step>

  <Step title="Review the Plan">
    Review the generated crew plan, which might include:

    * A Research Agent to gather financial news
    * An Analysis Agent to interpret the data
    * A Recommendations Agent to provide investment advice
  </Step>

  <Step title="Approve or Modify">
    Approve the plan or request changes if necessary.
  </Step>

  <Step title="Download or Deploy">
    Download the code for customization or deploy directly to the platform.
  </Step>

  <Step title="Test and Refine">
    Test your crew with sample inputs and refine as needed.
  </Step>
</Steps>

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with Crew Studio or any other CrewAI
  AMP features.
</Card>


# HubSpot Trigger
Source: https://docs.crewai.com/en/enterprise/guides/hubspot-trigger

Trigger CrewAI crews directly from HubSpot Workflows

This guide provides a step-by-step process to set up HubSpot triggers for CrewAI AMP, enabling you to initiate crews directly from HubSpot Workflows.

## Prerequisites

* A CrewAI AMP account
* A HubSpot account with the [HubSpot Workflows](https://knowledge.hubspot.com/workflows/create-workflows) feature

## Setup Steps

<Steps>
  <Step title="Connect your HubSpot account with CrewAI AMP">
    * Log in to your `CrewAI AMP account > Triggers` - Select `HubSpot` from the
      list of available triggers - Choose the HubSpot account you want to connect
      with CrewAI AMP - Follow the on-screen prompts to authorize CrewAI AMP
      access to your HubSpot account - A confirmation message will appear once
      HubSpot is successfully connected with CrewAI AMP
  </Step>

  <Step title="Create a HubSpot Workflow">
    * Log in to your `HubSpot account > Automations > Workflows > New workflow`
    * Select the workflow type that fits your needs (e.g., Start from scratch) -
      In the workflow builder, click the Plus (+) icon to add a new action. -
      Choose `Integrated apps > CrewAI > Kickoff a Crew`. - Select the Crew you
      want to initiate. - Click `Save` to add the action to your workflow

    <Frame>
      <img alt="HubSpot Workflow 1" />
    </Frame>
  </Step>

  <Step title="Use Crew results with other actions">
    * After the Kickoff a Crew step, click the Plus (+) icon to add a new
      action. - For example, to send an internal email notification, choose
      `Communications > Send internal email notification` - In the Body field,
      click `Insert data`, select `View properties or action outputs from > Action
          outputs > Crew Result` to include Crew data in the email

    <Frame>
      <img alt="HubSpot Workflow 2" />
    </Frame>

    * Configure any additional actions as needed - Review your workflow
      steps to ensure everything is set up correctly - Activate the workflow
      <Frame>
        <img alt="HubSpot Workflow 3" />
      </Frame>
  </Step>
</Steps>

For more detailed information on available actions and customization options, refer to the [HubSpot Workflows Documentation](https://knowledge.hubspot.com/workflows/create-workflows).


# HITL Workflows
Source: https://docs.crewai.com/en/enterprise/guides/human-in-the-loop

Learn how to implement Human-In-The-Loop workflows in CrewAI for enhanced decision-making

Human-In-The-Loop (HITL) is a powerful approach that combines artificial intelligence with human expertise to enhance decision-making and improve task outcomes. This guide shows you how to implement HITL within CrewAI Enterprise.

## HITL Approaches in CrewAI

CrewAI offers two approaches for implementing human-in-the-loop workflows:

| Approach                                     | Best For                                                                     | Version      |
| -------------------------------------------- | ---------------------------------------------------------------------------- | ------------ |
| **Flow-based** (`@human_feedback` decorator) | Production with Enterprise UI, email-first workflows, full platform features | **1.8.0+**   |
| **Webhook-based**                            | Custom integrations, external systems (Slack, Teams, etc.), legacy setups    | All versions |

## Flow-Based HITL with Enterprise Platform

<Note>
  The `@human_feedback` decorator requires **CrewAI version 1.8.0 or higher**.
</Note>

When using the `@human_feedback` decorator in your Flows, CrewAI Enterprise provides an **email-first HITL system** that enables anyone with an email address to respond to review requests:

<CardGroup>
  <Card title="Email-First Design" icon="envelope">
    Responders receive email notifications and can reply directly—no login required.
  </Card>

  <Card title="Dashboard Review" icon="desktop">
    Review and respond to HITL requests in the Enterprise dashboard when preferred.
  </Card>

  <Card title="Flexible Routing" icon="route">
    Route requests to specific emails based on method patterns or pull from flow state.
  </Card>

  <Card title="Auto-Response" icon="clock">
    Configure automatic fallback responses when no human replies within the timeout.
  </Card>
</CardGroup>

### Key Benefits

* **External responders**: Anyone with an email can respond, even non-platform users
* **Dynamic assignment**: Pull assignee email from flow state (e.g., `account_owner_email`)
* **Simple configuration**: Email-based routing is easier to set up than user/role management
* **Deployment creator fallback**: If no routing rule matches, the deployment creator is notified

<Tip>
  For implementation details on the `@human_feedback` decorator, see the [Human Feedback in Flows](/en/learn/human-feedback-in-flows) guide.
</Tip>

## Setting Up Webhook-Based HITL Workflows

For custom integrations with external systems like Slack, Microsoft Teams, or your own applications, you can use the webhook-based approach:

<Steps>
  <Step title="Configure Your Task">
    Set up your task with human input enabled:

    <Frame>
      <img alt="Crew Human Input" />
    </Frame>
  </Step>

  <Step title="Provide Webhook URL">
    When kicking off your crew, include a webhook URL for human input:

    <Frame>
      <img alt="Crew Webhook URL" />
    </Frame>
  </Step>

  <Step title="Receive Webhook Notification">
    Once the crew completes the task requiring human input, you'll receive a webhook notification containing:

    * **Execution ID**
    * **Task ID**
    * **Task output**
  </Step>

  <Step title="Review Task Output">
    The system will pause in the `Pending Human Input` state. Review the task output carefully.
  </Step>

  <Step title="Submit Human Feedback">
    Call the resume endpoint of your crew with the following information:

    <Frame>
      <img alt="Crew Resume Endpoint" />
    </Frame>

    <Warning>
      **Critical: Webhook URLs Must Be Provided Again**:
      You **must** provide the same webhook URLs (`taskWebhookUrl`, `stepWebhookUrl`, `crewWebhookUrl`) in the resume call that you used in the kickoff call. Webhook configurations are **NOT** automatically carried over from kickoff - they must be explicitly included in the resume request to continue receiving notifications for task completion, agent steps, and crew completion.
    </Warning>

    Example resume call with webhooks:

    ```bash theme={null}
    curl -X POST {BASE_URL}/resume \
      -H "Authorization: Bearer YOUR_API_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "execution_id": "abcd1234-5678-90ef-ghij-klmnopqrstuv",
        "task_id": "research_task",
        "human_feedback": "Great work! Please add more details.",
        "is_approve": true,
        "taskWebhookUrl": "https://your-server.com/webhooks/task",
        "stepWebhookUrl": "https://your-server.com/webhooks/step",
        "crewWebhookUrl": "https://your-server.com/webhooks/crew"
      }'
    ```

    <Warning>
      **Feedback Impact on Task Execution**:
      It's crucial to exercise care when providing feedback, as the entire feedback content will be incorporated as additional context for further task executions.
    </Warning>

    This means:

    * All information in your feedback becomes part of the task's context.
    * Irrelevant details may negatively influence it.
    * Concise, relevant feedback helps maintain task focus and efficiency.
    * Always review your feedback carefully before submission to ensure it contains only pertinent information that will positively guide the task's execution.
  </Step>

  <Step title="Handle Negative Feedback">
    If you provide negative feedback:

    * The crew will retry the task with added context from your feedback.
    * You'll receive another webhook notification for further review.
    * Repeat steps 4-6 until satisfied.
  </Step>

  <Step title="Execution Continuation">
    When you submit positive feedback, the execution will proceed to the next steps.
  </Step>
</Steps>

## Best Practices

* **Be Specific**: Provide clear, actionable feedback that directly addresses the task at hand
* **Stay Relevant**: Only include information that will help improve the task execution
* **Be Timely**: Respond to HITL prompts promptly to avoid workflow delays
* **Review Carefully**: Double-check your feedback before submitting to ensure accuracy

## Common Use Cases

HITL workflows are particularly valuable for:

* Quality assurance and validation
* Complex decision-making scenarios
* Sensitive or high-stakes operations
* Creative tasks requiring human judgment
* Compliance and regulatory reviews

## Learn More

<CardGroup>
  <Card title="Flow HITL Management" icon="users-gear" href="/en/enterprise/features/flow-hitl-management">
    Explore the full Enterprise Flow HITL platform capabilities including email notifications, routing rules, auto-response, and analytics.
  </Card>

  <Card title="Human Feedback in Flows" icon="code" href="/en/learn/human-feedback-in-flows">
    Implementation guide for the `@human_feedback` decorator in your Flows.
  </Card>
</CardGroup>


# Kickoff Crew
Source: https://docs.crewai.com/en/enterprise/guides/kickoff-crew

Kickoff a Crew on CrewAI AMP

## Overview

Once you've deployed your crew to the CrewAI AMP platform, you can kickoff executions through the web interface or the API. This guide covers both approaches.

## Method 1: Using the Web Interface

### Step 1: Navigate to Your Deployed Crew

1. Log in to [CrewAI AMP](https://app.crewai.com)
2. Click on the crew name from your projects list
3. You'll be taken to the crew's detail page

<Frame>
  <img alt="Crew Dashboard" />
</Frame>

### Step 2: Initiate Execution

From your crew's detail page, you have two options to kickoff an execution:

#### Option A: Quick Kickoff

1. Click the `Kickoff` link in the Test Endpoints section
2. Enter the required input parameters for your crew in the JSON editor
3. Click the `Send Request` button

<Frame>
  <img alt="Kickoff Endpoint" />
</Frame>

#### Option B: Using the Visual Interface

1. Click the `Run` tab in the crew detail page
2. Enter the required inputs in the form fields
3. Click the `Run Crew` button

<Frame>
  <img alt="Run Crew" />
</Frame>

### Step 3: Monitor Execution Progress

After initiating the execution:

1. You'll receive a response containing a `kickoff_id` - **copy this ID**
2. This ID is essential for tracking your execution

<Frame>
  <img alt="Copy Task ID" />
</Frame>

### Step 4: Check Execution Status

To monitor the progress of your execution:

1. Click the "Status" endpoint in the Test Endpoints section
2. Paste the `kickoff_id` into the designated field
3. Click the "Get Status" button

<Frame>
  <img alt="Get Status" />
</Frame>

The status response will show:

* Current execution state (`running`, `completed`, etc.)
* Details about which tasks are in progress
* Any outputs produced so far

### Step 5: View Final Results

Once execution is complete:

1. The status will change to `completed`
2. You can view the full execution results and outputs
3. For a more detailed view, check the `Executions` tab in the crew detail page

## Method 2: Using the API

You can also kickoff crews programmatically using the CrewAI AMP REST API.

### Authentication

All API requests require a bearer token for authentication:

```bash theme={null}
curl -H "Authorization: Bearer YOUR_CREW_TOKEN" https://your-crew-url.crewai.com
```

Your bearer token is available on the Status tab of your crew's detail page.

### Checking Crew Health

Before executing operations, you can verify that your crew is running properly:

```bash theme={null}
curl -H "Authorization: Bearer YOUR_CREW_TOKEN" https://your-crew-url.crewai.com
```

A successful response will return a message indicating the crew is operational:

```
Healthy%
```

### Step 1: Retrieve Required Inputs

First, determine what inputs your crew requires:

```bash theme={null}
curl -X GET \
  -H "Authorization: Bearer YOUR_CREW_TOKEN" \
  https://your-crew-url.crewai.com/inputs
```

The response will be a JSON object containing an array of required input parameters, for example:

```json theme={null}
{ "inputs": ["topic", "current_year"] }
```

This example shows that this particular crew requires two inputs: `topic` and `current_year`.

### Step 2: Kickoff Execution

Initiate execution by providing the required inputs:

```bash theme={null}
curl -X POST \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_CREW_TOKEN" \
  -d '{"inputs": {"topic": "AI Agent Frameworks", "current_year": "2025"}}' \
  https://your-crew-url.crewai.com/kickoff
```

The response will include a `kickoff_id` that you'll need for tracking:

```json theme={null}
{ "kickoff_id": "abcd1234-5678-90ef-ghij-klmnopqrstuv" }
```

### Step 3: Check Execution Status

Monitor the execution progress using the kickoff\_id:

```bash theme={null}
curl -X GET \
  -H "Authorization: Bearer YOUR_CREW_TOKEN" \
  https://your-crew-url.crewai.com/status/abcd1234-5678-90ef-ghij-klmnopqrstuv
```

## Handling Executions

### Long-Running Executions

For executions that may take a long time:

1. Consider implementing a polling mechanism to check status periodically
2. Use webhooks (if available) for notification when execution completes
3. Implement error handling for potential timeouts

### Execution Context

The execution context includes:

* Inputs provided at kickoff
* Environment variables configured during deployment
* Any state maintained between tasks

### Debugging Failed Executions

If an execution fails:

1. Check the "Executions" tab for detailed logs
2. Review the "Traces" tab for step-by-step execution details
3. Look for LLM responses and tool usage in the trace details

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with execution issues or questions
  about the Enterprise platform.
</Card>


# Prepare for Deployment
Source: https://docs.crewai.com/en/enterprise/guides/prepare-for-deployment

Ensure your Crew or Flow is ready for deployment to CrewAI AMP

<Note>
  Before deploying to CrewAI AMP, it's crucial to verify your project is correctly structured.
  Both Crews and Flows can be deployed as "automations," but they have different project structures
  and requirements that must be met for successful deployment.
</Note>

## Understanding Automations

In CrewAI AMP, **automations** is the umbrella term for deployable Agentic AI projects. An automation can be either:

* **A Crew**: A standalone team of AI agents working together on tasks
* **A Flow**: An orchestrated workflow that can combine multiple crews, direct LLM calls, and procedural logic

Understanding which type you're deploying is essential because they have different project structures and entry points.

## Crews vs Flows: Key Differences

<CardGroup>
  <Card title="Crew Projects" icon="users">
    Standalone AI agent teams with `crew.py` defining agents and tasks. Best for focused, collaborative tasks.
  </Card>

  <Card title="Flow Projects" icon="diagram-project">
    Orchestrated workflows with embedded crews in a `crews/` folder. Best for complex, multi-stage processes.
  </Card>
</CardGroup>

| Aspect                      | Crew                               | Flow                                       |
| --------------------------- | ---------------------------------- | ------------------------------------------ |
| **Project structure**       | `src/project_name/` with `crew.py` | `src/project_name/` with `crews/` folder   |
| **Main logic location**     | `src/project_name/crew.py`         | `src/project_name/main.py` (Flow class)    |
| **Entry point function**    | `run()` in `main.py`               | `kickoff()` in `main.py`                   |
| **pyproject.toml type**     | `type = "crew"`                    | `type = "flow"`                            |
| **CLI create command**      | `crewai create crew name`          | `crewai create flow name`                  |
| **Config location**         | `src/project_name/config/`         | `src/project_name/crews/crew_name/config/` |
| **Can contain other crews** | No                                 | Yes (in `crews/` folder)                   |

## Project Structure Reference

### Crew Project Structure

When you run `crewai create crew my_crew`, you get this structure:

```
my_crew/
├── .gitignore
├── pyproject.toml          # Must have type = "crew"
├── README.md
├── .env
├── uv.lock                  # REQUIRED for deployment
└── src/
    └── my_crew/
        ├── __init__.py
        ├── main.py          # Entry point with run() function
        ├── crew.py          # Crew class with @CrewBase decorator
        ├── tools/
        │   ├── custom_tool.py
        │   └── __init__.py
        └── config/
            ├── agents.yaml  # Agent definitions
            └── tasks.yaml   # Task definitions
```

<Warning>
  The nested `src/project_name/` structure is critical for Crews.
  Placing files at the wrong level will cause deployment failures.
</Warning>

### Flow Project Structure

When you run `crewai create flow my_flow`, you get this structure:

```
my_flow/
├── .gitignore
├── pyproject.toml          # Must have type = "flow"
├── README.md
├── .env
├── uv.lock                  # REQUIRED for deployment
└── src/
    └── my_flow/
        ├── __init__.py
        ├── main.py          # Entry point with kickoff() function + Flow class
        ├── crews/           # Embedded crews folder
        │   └── poem_crew/
        │       ├── __init__.py
        │       ├── poem_crew.py  # Crew with @CrewBase decorator
        │       └── config/
        │           ├── agents.yaml
        │           └── tasks.yaml
        └── tools/
            ├── __init__.py
            └── custom_tool.py
```

<Info>
  Both Crews and Flows use the `src/project_name/` structure.
  The key difference is that Flows have a `crews/` folder for embedded crews,
  while Crews have `crew.py` directly in the project folder.
</Info>

## Pre-Deployment Checklist

Use this checklist to verify your project is ready for deployment.

### 1. Verify pyproject.toml Configuration

Your `pyproject.toml` must include the correct `[tool.crewai]` section:

<Tabs>
  <Tab title="For Crews">
    ```toml theme={null}
    [tool.crewai]
    type = "crew"
    ```
  </Tab>

  <Tab title="For Flows">
    ```toml theme={null}
    [tool.crewai]
    type = "flow"
    ```
  </Tab>
</Tabs>

<Warning>
  If the `type` doesn't match your project structure, the build will fail or
  the automation won't run correctly.
</Warning>

### 2. Ensure uv.lock File Exists

CrewAI uses `uv` for dependency management. The `uv.lock` file ensures reproducible builds and is **required** for deployment.

```bash theme={null}
# Generate or update the lock file
uv lock

# Verify it exists
ls -la uv.lock
```

If the file doesn't exist, run `uv lock` and commit it to your repository:

```bash theme={null}
uv lock
git add uv.lock
git commit -m "Add uv.lock for deployment"
git push
```

### 3. Validate CrewBase Decorator Usage

**Every crew class must use the `@CrewBase` decorator.** This applies to:

* Standalone crew projects
* Crews embedded inside Flow projects

```python theme={null}
from crewai import Agent, Crew, Process, Task
from crewai.project import CrewBase, agent, crew, task
from crewai.agents.agent_builder.base_agent import BaseAgent
from typing import List

@CrewBase  # This decorator is REQUIRED
class MyCrew():
    """My crew description"""

    agents: List[BaseAgent]
    tasks: List[Task]

    @agent
    def my_agent(self) -> Agent:
        return Agent(
            config=self.agents_config['my_agent'],  # type: ignore[index]
            verbose=True
        )

    @task
    def my_task(self) -> Task:
        return Task(
            config=self.tasks_config['my_task']  # type: ignore[index]
        )

    @crew
    def crew(self) -> Crew:
        return Crew(
            agents=self.agents,
            tasks=self.tasks,
            process=Process.sequential,
            verbose=True,
        )
```

<Warning>
  If you forget the `@CrewBase` decorator, your deployment will fail with
  errors about missing agents or tasks configurations.
</Warning>

### 4. Check Project Entry Points

Both Crews and Flows have their entry point in `src/project_name/main.py`:

<Tabs>
  <Tab title="For Crews">
    The entry point uses a `run()` function:

    ```python theme={null}
    # src/my_crew/main.py
    from my_crew.crew import MyCrew

    def run():
        """Run the crew."""
        inputs = {'topic': 'AI in Healthcare'}
        result = MyCrew().crew().kickoff(inputs=inputs)
        return result

    if __name__ == "__main__":
        run()
    ```
  </Tab>

  <Tab title="For Flows">
    The entry point uses a `kickoff()` function with a Flow class:

    ```python theme={null}
    # src/my_flow/main.py
    from crewai.flow import Flow, listen, start
    from my_flow.crews.poem_crew.poem_crew import PoemCrew

    class MyFlow(Flow):
        @start()
        def begin(self):
            # Flow logic here
            result = PoemCrew().crew().kickoff(inputs={...})
            return result

    def kickoff():
        """Run the flow."""
        MyFlow().kickoff()

    if __name__ == "__main__":
        kickoff()
    ```
  </Tab>
</Tabs>

### 5. Prepare Environment Variables

Before deployment, ensure you have:

1. **LLM API keys** ready (OpenAI, Anthropic, Google, etc.)
2. **Tool API keys** if using external tools (Serper, etc.)

<Info>
  If your project depends on packages from a **private PyPI registry**, you'll also need to configure
  registry authentication credentials as environment variables. See the
  [Private Package Registries](/en/enterprise/guides/private-package-registry) guide for details.
</Info>

<Tip>
  Test your project locally with the same environment variables before deploying
  to catch configuration issues early.
</Tip>

## Quick Validation Commands

Run these commands from your project root to quickly verify your setup:

```bash theme={null}
# 1. Check project type in pyproject.toml
grep -A2 "\[tool.crewai\]" pyproject.toml

# 2. Verify uv.lock exists
ls -la uv.lock || echo "ERROR: uv.lock missing! Run 'uv lock'"

# 3. Verify src/ structure exists
ls -la src/*/main.py 2>/dev/null || echo "No main.py found in src/"

# 4. For Crews - verify crew.py exists
ls -la src/*/crew.py 2>/dev/null || echo "No crew.py (expected for Crews)"

# 5. For Flows - verify crews/ folder exists
ls -la src/*/crews/ 2>/dev/null || echo "No crews/ folder (expected for Flows)"

# 6. Check for CrewBase usage
grep -r "@CrewBase" . --include="*.py"
```

## Common Setup Mistakes

| Mistake                         | Symptom                                  | Fix                               |
| ------------------------------- | ---------------------------------------- | --------------------------------- |
| Missing `uv.lock`               | Build fails during dependency resolution | Run `uv lock` and commit          |
| Wrong `type` in pyproject.toml  | Build succeeds but runtime fails         | Change to correct type            |
| Missing `@CrewBase` decorator   | "Config not found" errors                | Add decorator to all crew classes |
| Files at root instead of `src/` | Entry point not found                    | Move to `src/project_name/`       |
| Missing `run()` or `kickoff()`  | Cannot start automation                  | Add correct entry function        |

## Next Steps

Once your project passes all checklist items, you're ready to deploy:

<Card title="Deploy to AMP" icon="rocket" href="/en/enterprise/guides/deploy-to-amp">
  Follow the deployment guide to deploy your Crew or Flow to CrewAI AMP using
  the CLI, web interface, or CI/CD integration.
</Card>


# Private Package Registries
Source: https://docs.crewai.com/en/enterprise/guides/private-package-registry

Install private Python packages from authenticated PyPI registries in CrewAI AMP

<Note>
  This guide covers how to configure your CrewAI project to install Python packages
  from private PyPI registries (Azure DevOps Artifacts, GitHub Packages, GitLab, AWS CodeArtifact, etc.)
  when deploying to CrewAI AMP.
</Note>

## When You Need This

If your project depends on internal or proprietary Python packages hosted on a private registry
rather than the public PyPI, you'll need to:

1. Tell UV **where** to find the package (an index URL)
2. Tell UV **which** packages come from that index (a source mapping)
3. Provide **credentials** so UV can authenticate during install

CrewAI AMP uses [UV](https://docs.astral.sh/uv/) for dependency resolution and installation.
UV supports authenticated private registries through `pyproject.toml` configuration combined
with environment variables for credentials.

## Step 1: Configure pyproject.toml

Three pieces work together in your `pyproject.toml`:

### 1a. Declare the dependency

Add the private package to your `[project.dependencies]` like any other dependency:

```toml theme={null}
[project]
dependencies = [
    "crewai[tools]>=0.100.1,<1.0.0",
    "my-private-package>=1.2.0",
]
```

### 1b. Define the index

Register your private registry as a named index under `[[tool.uv.index]]`:

```toml theme={null}
[[tool.uv.index]]
name = "my-private-registry"
url = "https://pkgs.dev.azure.com/my-org/_packaging/my-feed/pypi/simple/"
explicit = true
```

<Info>
  The `name` field is important — UV uses it to construct the environment variable names
  for authentication (see [Step 2](#step-2-set-authentication-credentials) below).

  Setting `explicit = true` means UV won't search this index for every package — only the
  ones you explicitly map to it in `[tool.uv.sources]`. This avoids unnecessary queries
  against your private registry and protects against dependency confusion attacks.
</Info>

### 1c. Map the package to the index

Tell UV which packages should be resolved from your private index using `[tool.uv.sources]`:

```toml theme={null}
[tool.uv.sources]
my-private-package = { index = "my-private-registry" }
```

### Complete example

```toml theme={null}
[project]
name = "my-crew-project"
version = "0.1.0"
requires-python = ">=3.10,<=3.13"
dependencies = [
    "crewai[tools]>=0.100.1,<1.0.0",
    "my-private-package>=1.2.0",
]

[tool.crewai]
type = "crew"

[[tool.uv.index]]
name = "my-private-registry"
url = "https://pkgs.dev.azure.com/my-org/_packaging/my-feed/pypi/simple/"
explicit = true

[tool.uv.sources]
my-private-package = { index = "my-private-registry" }
```

After updating `pyproject.toml`, regenerate your lock file:

```bash theme={null}
uv lock
```

<Warning>
  Always commit the updated `uv.lock` along with your `pyproject.toml` changes.
  The lock file is required for deployment — see [Prepare for Deployment](/en/enterprise/guides/prepare-for-deployment).
</Warning>

## Step 2: Set Authentication Credentials

UV authenticates against private indexes using environment variables that follow a naming convention
based on the index name you defined in `pyproject.toml`:

```
UV_INDEX_{UPPER_NAME}_USERNAME
UV_INDEX_{UPPER_NAME}_PASSWORD
```

Where `{UPPER_NAME}` is your index name converted to **uppercase** with **hyphens replaced by underscores**.

For example, an index named `my-private-registry` uses:

| Variable                                | Value                                |
| --------------------------------------- | ------------------------------------ |
| `UV_INDEX_MY_PRIVATE_REGISTRY_USERNAME` | Your registry username or token name |
| `UV_INDEX_MY_PRIVATE_REGISTRY_PASSWORD` | Your registry password or token/PAT  |

<Warning>
  These environment variables **must** be added via the CrewAI AMP **Environment Variables** settings —
  either globally or at the deployment level. They cannot be set in `.env` files or hardcoded in your project.

  See [Setting Environment Variables in AMP](#setting-environment-variables-in-amp) below.
</Warning>

## Registry Provider Reference

The table below shows the index URL format and credential values for common registry providers.
Replace placeholder values with your actual organization and feed details.

| Provider                             | Index URL                                                               | Username                            | Password                                                   |
| ------------------------------------ | ----------------------------------------------------------------------- | ----------------------------------- | ---------------------------------------------------------- |
| **Azure DevOps Artifacts**           | `https://pkgs.dev.azure.com/{org}/_packaging/{feed}/pypi/simple/`       | Any non-empty string (e.g. `token`) | Personal Access Token (PAT) with Packaging Read scope      |
| **GitHub Packages**                  | `https://pypi.pkg.github.com/{owner}/simple/`                           | GitHub username                     | Personal Access Token (classic) with `read:packages` scope |
| **GitLab Package Registry**          | `https://gitlab.com/api/v4/projects/{project_id}/packages/pypi/simple/` | `__token__`                         | Project or Personal Access Token with `read_api` scope     |
| **AWS CodeArtifact**                 | Use the URL from `aws codeartifact get-repository-endpoint`             | `aws`                               | Token from `aws codeartifact get-authorization-token`      |
| **Google Artifact Registry**         | `https://{region}-python.pkg.dev/{project}/{repo}/simple/`              | `_json_key_base64`                  | Base64-encoded service account key                         |
| **JFrog Artifactory**                | `https://{instance}.jfrog.io/artifactory/api/pypi/{repo}/simple/`       | Username or email                   | API key or identity token                                  |
| **Self-hosted (devpi, Nexus, etc.)** | Your registry's simple API URL                                          | Registry username                   | Registry password                                          |

<Tip>
  For **AWS CodeArtifact**, the authorization token expires periodically.
  You'll need to refresh the `UV_INDEX_*_PASSWORD` value when it expires.
  Consider automating this in your CI/CD pipeline.
</Tip>

## Setting Environment Variables in AMP

Private registry credentials must be configured as environment variables in CrewAI AMP.
You have two options:

<Tabs>
  <Tab title="Web Interface">
    1. Log in to [CrewAI AMP](https://app.crewai.com)
    2. Navigate to your automation
    3. Open the **Environment Variables** tab
    4. Add each variable (`UV_INDEX_*_USERNAME` and `UV_INDEX_*_PASSWORD`) with its value

    See the [Deploy to AMP — Set Environment Variables](/en/enterprise/guides/deploy-to-amp#set-environment-variables) step for details.
  </Tab>

  <Tab title="CLI Deployment">
    Add the variables to your local `.env` file before running `crewai deploy create`.
    The CLI will securely transfer them to the platform:

    ```bash theme={null}
    # .env
    OPENAI_API_KEY=sk-...
    UV_INDEX_MY_PRIVATE_REGISTRY_USERNAME=token
    UV_INDEX_MY_PRIVATE_REGISTRY_PASSWORD=your-pat-here
    ```

    ```bash theme={null}
    crewai deploy create
    ```
  </Tab>
</Tabs>

<Warning>
  **Never** commit credentials to your repository. Use AMP environment variables for all secrets.
  The `.env` file should be listed in `.gitignore`.
</Warning>

To update credentials on an existing deployment, see [Update Your Crew — Environment Variables](/en/enterprise/guides/update-crew).

## How It All Fits Together

When CrewAI AMP builds your automation, the resolution flow works like this:

<Steps>
  <Step title="Build starts">
    AMP pulls your repository and reads `pyproject.toml` and `uv.lock`.
  </Step>

  <Step title="UV resolves dependencies">
    UV reads `[tool.uv.sources]` to determine which index each package should come from.
  </Step>

  <Step title="UV authenticates">
    For each private index, UV looks up `UV_INDEX_{NAME}_USERNAME` and `UV_INDEX_{NAME}_PASSWORD`
    from the environment variables you configured in AMP.
  </Step>

  <Step title="Packages install">
    UV downloads and installs all packages — both public (from PyPI) and private (from your registry).
  </Step>

  <Step title="Automation runs">
    Your crew or flow starts with all dependencies available.
  </Step>
</Steps>

## Troubleshooting

### Authentication Errors During Build

**Symptom**: Build fails with `401 Unauthorized` or `403 Forbidden` when resolving a private package.

**Check**:

* The `UV_INDEX_*` environment variable names match your index name exactly (uppercased, hyphens → underscores)
* Credentials are set in AMP environment variables, not just in a local `.env`
* Your token/PAT has the required read permissions for the package feed
* The token hasn't expired (especially relevant for AWS CodeArtifact)

### Package Not Found

**Symptom**: `No matching distribution found for my-private-package`.

**Check**:

* The index URL in `pyproject.toml` ends with `/simple/`
* The `[tool.uv.sources]` entry maps the correct package name to the correct index name
* The package is actually published to your private registry
* Run `uv lock` locally with the same credentials to verify resolution works

### Lock File Conflicts

**Symptom**: `uv lock` fails or produces unexpected results after adding a private index.

**Solution**: Set the credentials locally and regenerate:

```bash theme={null}
export UV_INDEX_MY_PRIVATE_REGISTRY_USERNAME=token
export UV_INDEX_MY_PRIVATE_REGISTRY_PASSWORD=your-pat
uv lock
```

Then commit the updated `uv.lock`.

## Related Guides

<CardGroup>
  <Card title="Prepare for Deployment" icon="clipboard-check" href="/en/enterprise/guides/prepare-for-deployment">
    Verify project structure and dependencies before deploying.
  </Card>

  <Card title="Deploy to AMP" icon="rocket" href="/en/enterprise/guides/deploy-to-amp">
    Deploy your crew or flow and configure environment variables.
  </Card>

  <Card title="Update Your Crew" icon="arrows-rotate" href="/en/enterprise/guides/update-crew">
    Update environment variables and push changes to a running deployment.
  </Card>
</CardGroup>


# React Component Export
Source: https://docs.crewai.com/en/enterprise/guides/react-component-export

Learn how to export and integrate CrewAI AMP React components into your applications

This guide explains how to export CrewAI AMP crews as React components and integrate them into your own applications.

## Exporting a React Component

<Steps>
  <Step title="Export the Component">
    Click on the ellipsis (three dots on the right of your deployed crew) and select the export option and save the file locally. We will be using `CrewLead.jsx` for our example.

    <Frame>
      <img alt="Export React Component" />
    </Frame>
  </Step>
</Steps>

## Setting Up Your React Environment

To run this React component locally, you'll need to set up a React development environment and integrate this component into a React project.

<Steps>
  <Step title="Install Node.js">
    * Download and install Node.js from the official website: [https://nodejs.org/](https://nodejs.org/)
    * Choose the LTS (Long Term Support) version for stability.
  </Step>

  <Step title="Create a new React project">
    * Open Command Prompt or PowerShell
    * Navigate to the directory where you want to create your project
    * Run the following command to create a new React project:

      ```bash theme={null}
      npx create-react-app my-crew-app
      ```
    * Change into the project directory:

      ```bash theme={null}
      cd my-crew-app
      ```
  </Step>

  <Step title="Install necessary dependencies">
    ```bash theme={null}
    npm install react-dom
    ```
  </Step>

  <Step title="Create the CrewLead component">
    * Move the downloaded file `CrewLead.jsx` into the `src` folder of your project,
  </Step>

  <Step title="Modify your App.js to use the CrewLead component">
    * Open `src/App.js`
    * Replace its contents with something like this:

    ```jsx theme={null}
    import React from 'react';
    import CrewLead from './CrewLead';

    function App() {
        return (
            <div className="App">
                <CrewLead baseUrl="YOUR_API_BASE_URL" bearerToken="YOUR_BEARER_TOKEN" />
            </div>
        );
    }

    export default App;
    ```

    * Replace `YOUR_API_BASE_URL` and `YOUR_BEARER_TOKEN` with the actual values for your API.
  </Step>

  <Step title="Start the development server">
    * In your project directory, run:

      ```bash theme={null}
      npm start
      ```
    * This will start the development server, and your default web browser should open automatically to [http://localhost:3000](http://localhost:3000), where you'll see your React app running.
  </Step>
</Steps>

## Customization

You can then customise the `CrewLead.jsx` to add color, title etc

<Frame>
  <img alt="Customise React Component" />
</Frame>

<Frame>
  <img alt="Customise React Component" />
</Frame>

## Next Steps

* Customize the component styling to match your application's design
* Add additional props for configuration
* Integrate with your application's state management
* Add error handling and loading states


# Salesforce Trigger
Source: https://docs.crewai.com/en/enterprise/guides/salesforce-trigger

Trigger CrewAI crews from Salesforce workflows for CRM automation

CrewAI AMP can be triggered from Salesforce to automate customer relationship management workflows and enhance your sales operations.

## Overview

Salesforce is a leading customer relationship management (CRM) platform that helps businesses streamline their sales, service, and marketing operations. By setting up CrewAI triggers from Salesforce, you can:

* Automate lead scoring and qualification
* Generate personalized sales materials
* Enhance customer service with AI-powered responses
* Streamline data analysis and reporting

## Demo

<iframe title="CrewAI + Salesforce trigger demo" />

## Getting Started

To set up Salesforce triggers:

1. **Contact Support**: Reach out to CrewAI AMP support for assistance with Salesforce trigger setup
2. **Review Requirements**: Ensure you have the necessary Salesforce permissions and API access
3. **Configure Connection**: Work with the support team to establish the connection between CrewAI and your Salesforce instance
4. **Test Triggers**: Verify the triggers work correctly with your specific use cases

## Use Cases

Common Salesforce + CrewAI trigger scenarios include:

* **Lead Processing**: Automatically analyze and score incoming leads
* **Proposal Generation**: Create customized proposals based on opportunity data
* **Customer Insights**: Generate analysis reports from customer interaction history
* **Follow-up Automation**: Create personalized follow-up messages and recommendations

## Next Steps

For detailed setup instructions and advanced configuration options, please contact CrewAI AMP support who can provide tailored guidance for your specific Salesforce environment and business needs.


# Slack Trigger
Source: https://docs.crewai.com/en/enterprise/guides/slack-trigger

Trigger CrewAI crews directly from Slack using slash commands

This guide explains how to start a crew directly from Slack using CrewAI triggers.

## Prerequisites

* CrewAI Slack trigger installed and connected to your Slack workspace
* At least one crew configured in CrewAI

## Setup Steps

<Steps>
  <Step title="Ensure the CrewAI Slack trigger is set up">
    In the CrewAI dashboard, navigate to the **Triggers** section.

    <Frame>
      <img alt="CrewAI Slack Integration" />
    </Frame>

    Verify that Slack is listed and is connected.
  </Step>

  <Step title="Open your Slack channel">
    * Navigate to the channel where you want to kickoff the crew.
    * Type the slash command "**/kickoff**" to initiate the crew kickoff process.
    * You should see a  "**Kickoff crew**" appear as you type:
      <Frame>
        <img alt="Kickoff crew" />
      </Frame>
    * Press Enter or select the "**Kickoff crew**" option. A dialog box titled "**Kickoff an AI Crew**" will appear.
  </Step>

  <Step title="Select the crew you want to start">
    * In the dropdown menu labeled "**Select of the crews online:**", choose the crew you want to start.
    * In the example below, "**prep-for-meeting**" is selected:
      <Frame>
        <img alt="Kickoff crew dropdown" />
      </Frame>
    * If your crew requires any inputs, click the "**Add Inputs**" button to provide them.
      <Note>
        The "**Add Inputs**" button is shown in the example above but is not yet clicked.
      </Note>
  </Step>

  <Step title="Click Kickoff and wait for the crew to complete">
    * Once you've selected the crew and added any necessary inputs, click "**Kickoff**" to start the crew.
      <Frame>
        <img alt="Kickoff crew" />
      </Frame>
    * The crew will start executing and you will see the results in the Slack channel.
      <Frame>
        <img alt="Kickoff crew results" />
      </Frame>
  </Step>
</Steps>

## Tips

* Make sure you have the necessary permissions to use the `/kickoff` command in your Slack workspace.
* If you don't see your desired crew in the dropdown, ensure it's properly configured and online in CrewAI.


# Team Management
Source: https://docs.crewai.com/en/enterprise/guides/team-management

Learn how to invite and manage team members in your CrewAI AMP organization

As an administrator of a CrewAI AMP account, you can easily invite new team members to join your organization. This guide will walk you through the process step-by-step.

## Inviting Team Members

<Steps>
  <Step title="Access the Settings Page">
    * Log in to your CrewAI AMP account - Look for the gear icon (⚙️) in the top
      right corner of the dashboard - Click on the gear icon to access the
      **Settings** page:

    <Frame>
      <img alt="Settings Page" />
    </Frame>
  </Step>

  <Step title="Navigate to the Members Section">
    * On the Settings page, you'll see a `Members` tab - Click on the `Members`
      tab to access the **Members** page:

    <Frame>
      <img alt="Members Tab" />
    </Frame>
  </Step>

  <Step title="Invite New Members">
    * In the Members section, you'll see a list of current members (including
      yourself) - Locate the `Email` input field - Enter the email address of the
      person you want to invite - Click the `Invite` button to send the invitation
  </Step>

  <Step title="Repeat as Needed">
    * You can repeat this process to invite multiple team members - Each invited
      member will receive an email invitation to join your organization
  </Step>
</Steps>

## Adding Roles

You can add roles to your team members to control their access to different parts of the platform.

<Steps>
  <Step title="Access the Settings Page">
    * Log in to your CrewAI AMP account - Look for the gear icon (⚙️) in the top
      right corner of the dashboard - Click on the gear icon to access the
      **Settings** page:

    <Frame>
      <img alt="Settings Page" />
    </Frame>
  </Step>

  <Step title="Navigate to the Members Section">
    * On the Settings page, you'll see a `Roles` tab - Click on the `Roles` tab
      to access the **Roles** page.

    <Frame>
      <img alt="Roles Tab" />
    </Frame>

    * Click on the `Add Role` button to add a new role. - Enter the
      details and permissions of the role and click the `Create Role` button to
      create the role.

    <Frame>
      <img alt="Add Role Modal" />
    </Frame>
  </Step>

  <Step title="Add Roles to Members">
    * In the Members section, you'll see a list of current members (including
      yourself)

    <Frame>
      <img alt="Member Accepted Invitation" />
    </Frame>

    * Once the member has accepted the invitation, you can add a role to
      them. - Navigate back to `Roles` tab - Go to the member you want to add a
      role to and under the `Role` column, click on the dropdown - Select the role
      you want to add to the member - Click the `Update` button to save the role

    <Frame>
      <img alt="Add Role to Member" />
    </Frame>
  </Step>
</Steps>

## Important Notes

* **Admin Privileges**: Only users with administrative privileges can invite new members
* **Email Accuracy**: Ensure you have the correct email addresses for your team members
* **Invitation Acceptance**: Invited members will need to accept the invitation to join your organization
* **Email Notifications**: You may want to inform your team members to check their email (including spam folders) for the invitation

By following these steps, you can easily expand your team and collaborate more effectively within your CrewAI AMP organization.


# Tool Repository
Source: https://docs.crewai.com/en/enterprise/guides/tool-repository

Using the Tool Repository to manage your tools

## Overview

The Tool Repository is a package manager for CrewAI tools. It allows users to publish, install, and manage tools that integrate with CrewAI crews and flows.

Tools can be:

* **Private**: accessible only within your organization (default)
* **Public**: accessible to all CrewAI users if published with the `--public` flag

The repository is not a version control system. Use Git to track code changes and enable collaboration.

## Prerequisites

Before using the Tool Repository, ensure you have:

* A [CrewAI AMP](https://app.crewai.com) account
* [CrewAI CLI](/en/concepts/cli#cli) installed
* uv>=0.5.0 installed. Check out [how to upgrade](https://docs.astral.sh/uv/getting-started/installation/#upgrading-uv)
* [Git](https://git-scm.com) installed and configured
* Access permissions to publish or install tools in your CrewAI AMP organization

## Installing Tools

To install a tool:

```bash theme={null}
crewai tool install <tool-name>
```

This installs the tool and adds it to `pyproject.toml`.

You can use the tool by importing it and adding it to your agents:

```python theme={null}
from your_tool.tool import YourTool

custom_tool = YourTool()

researcher = Agent(
    role='Market Research Analyst',
    goal='Provide up-to-date market analysis of the AI industry',
    backstory='An expert analyst with a keen eye for market trends.',
    tools=[custom_tool],
    verbose=True
)
```

## Adding other packages after installing a tool

After installing a tool from the CrewAI AMP Tool Repository, you need to use the `crewai uv` command to add other packages to your project.
Using pure `uv` commands will fail due to authentication to tool repository being handled by the CLI. By using the `crewai uv` command, you can add other packages to your project without having to worry about authentication.
Any `uv` command can be used with the `crewai uv` command, making it a powerful tool for managing your project's dependencies without the hassle of managing authentication through environment variables or other methods.

Say that you have installed a custom tool from the CrewAI AMP Tool Repository called "my-tool":

```bash theme={null}
crewai tool install my-tool
```

And now you want to add another package to your project, you can use the following command:

```bash theme={null}
crewai uv add requests
```

Other commands like `uv sync` or `uv remove` can also be used with the `crewai uv` command:

```bash theme={null}
crewai uv sync
```

```bash theme={null}
crewai uv remove requests
```

This will add the package to your project and update `pyproject.toml` accordingly.

## Creating and Publishing Tools

To create a new tool project:

```bash theme={null}
crewai tool create <tool-name>
```

This generates a scaffolded tool project locally.

After making changes, initialize a Git repository and commit the code:

```bash theme={null}
git init
git add .
git commit -m "Initial version"
```

To publish the tool:

```bash theme={null}
crewai tool publish
```

By default, tools are published as private. To make a tool public:

```bash theme={null}
crewai tool publish --public
```

For more details on how to build tools, see [Creating your own tools](/en/concepts/tools#creating-your-own-tools).

## Updating Tools

To update a published tool:

1. Modify the tool locally
2. Update the version in `pyproject.toml` (e.g., from `0.1.0` to `0.1.1`)
3. Commit the changes and publish

```bash theme={null}
git commit -m "Update version to 0.1.1"
crewai tool publish
```

## Deleting Tools

To delete a tool:

1. Go to [CrewAI AMP](https://app.crewai.com)
2. Navigate to **Tools**
3. Select the tool
4. Click **Delete**

<Warning>
  Deletion is permanent. Deleted tools cannot be restored or re-installed.
</Warning>

## Security Checks

Every published version undergoes automated security checks, and are only available to install after they pass.

You can check the security check status of a tool at:

`CrewAI AMP > Tools > Your Tool > Versions`

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with API integration or
  troubleshooting.
</Card>


# Update Crew
Source: https://docs.crewai.com/en/enterprise/guides/update-crew

Updating a Crew on CrewAI AMP

<Note>
  After deploying your crew to CrewAI AMP, you may need to make updates to the
  code, security settings, or configuration. This guide explains how to perform
  these common update operations.
</Note>

## Why Update Your Crew?

CrewAI won't automatically pick up GitHub updates by default, so you'll need to manually trigger updates, unless you checked the `Auto-update` option when deploying your crew.

There are several reasons you might want to update your crew deployment:

* You want to update the code with a latest commit you pushed to GitHub
* You want to reset the bearer token for security reasons
* You want to update environment variables

## 1. Updating Your Crew Code for a Latest Commit

When you've pushed new commits to your GitHub repository and want to update your deployment:

1. Navigate to your crew in the CrewAI AMP platform
2. Click on the `Re-deploy` button on your crew details page

<Frame>
  <img alt="Re-deploy Button" />
</Frame>

This will trigger an update that you can track using the progress bar. The system will pull the latest code from your repository and rebuild your deployment.

## 2. Resetting Bearer Token

If you need to generate a new bearer token (for example, if you suspect the current token might have been compromised):

1. Navigate to your crew in the CrewAI AMP platform
2. Find the `Bearer Token` section
3. Click the `Reset` button next to your current token

<Frame>
  <img alt="Reset Token" />
</Frame>

<Warning>
  Resetting your bearer token will invalidate the previous token immediately.
  Make sure to update any applications or scripts that are using the old token.
</Warning>

## 3. Updating Environment Variables

To update the environment variables for your crew:

1. First access the deployment page by clicking on your crew's name

<Frame>
  <img alt="Environment Variables Button" />
</Frame>

2. Locate the `Environment Variables` section (you will need to click the `Settings` icon to access it)
3. Edit the existing variables or add new ones in the fields provided
4. Click the `Update` button next to each variable you modify

<Frame>
  <img alt="Update Environment Variables" />
</Frame>

5. Finally, click the `Update Deployment` button at the bottom of the page to apply the changes

<Note>
  Updating environment variables will trigger a new deployment, but this will
  only update the environment configuration and not the code itself.
</Note>

## After Updating

After performing any update:

1. The system will rebuild and redeploy your crew
2. You can monitor the deployment progress in real-time
3. Once complete, test your crew to ensure the changes are working as expected

<Tip>
  If you encounter any issues after updating, you can view deployment logs in
  the platform or contact support for assistance.
</Tip>

<Card title="Need Help?" icon="headset" href="mailto:support@crewai.com">
  Contact our support team for assistance with updating your crew or
  troubleshooting deployment issues.
</Card>


# Webhook Automation
Source: https://docs.crewai.com/en/enterprise/guides/webhook-automation

Automate CrewAI AMP workflows using webhooks with platforms like ActivePieces, Zapier, and Make.com

CrewAI AMP allows you to automate your workflow using webhooks. This article will guide you through the process of setting up and using webhooks to kickoff your crew execution, with a focus on integration with ActivePieces, a workflow automation platform similar to Zapier and Make.com.

## Setting Up Webhooks

<Steps>
  <Step title="Accessing the Kickoff Interface">
    * Navigate to the CrewAI AMP dashboard
    * Look for the `/kickoff` section, which is used to start the crew execution
      <Frame>
        <img alt="Kickoff Interface" />
      </Frame>
  </Step>

  <Step title="Configuring the JSON Content">
    In the JSON Content section, you'll need to provide the following information:

    * **inputs**: A JSON object containing:
      * `company`: The name of the company (e.g., "tesla")
      * `product_name`: The name of the product (e.g., "crewai")
      * `form_response`: The type of response (e.g., "financial")
      * `icp_description`: A brief description of the Ideal Customer Profile
      * `product_description`: A short description of the product
      * `taskWebhookUrl`, `stepWebhookUrl`, `crewWebhookUrl`: URLs for various webhook endpoints (ActivePieces, Zapier, Make.com or another compatible platform)
  </Step>

  <Step title="Integrating with ActivePieces">
    In this example we will be using ActivePieces. You can use other platforms such as Zapier and Make.com

    To integrate with ActivePieces:

    1. Set up a new flow in ActivePieces

    2. Add a trigger (e.g., `Every Day` schedule)
       <Frame>
         <img alt="ActivePieces Trigger" />
       </Frame>

    3. Add an HTTP action step
       * Set the action to `Send HTTP request`

       * Use `POST` as the method

       * Set the URL to your CrewAI AMP kickoff endpoint

       * Add necessary headers (e.g., `Bearer Token`)
         <Frame>
           <img alt="ActivePieces Headers" />
         </Frame>

       * In the body, include the JSON content as configured in step 2
         <Frame>
           <img alt="ActivePieces Body" />
         </Frame>

       * The crew will then kickoff at the pre-defined time.
  </Step>

  <Step title="Setting Up the Webhook">
    1. Create a new flow in ActivePieces and name it
       <Frame>
         <img alt="ActivePieces Flow" />
       </Frame>

    2. Add a webhook step as the trigger:
       * Select `Catch Webhook` as the trigger type

       * This will generate a unique URL that will receive HTTP requests and trigger your flow
         <Frame>
           <img alt="ActivePieces Webhook" />
         </Frame>

       * Configure the email to use crew webhook body text
         <Frame>
           <img alt="ActivePieces Email" />
         </Frame>
  </Step>
</Steps>

## Webhook Output Examples

**Note:** Any `meta` object provided in your kickoff request will be included in all webhook payloads, allowing you to track requests and maintain context across the entire crew execution lifecycle.

<Tabs>
  <Tab title="Step Webhook">
    `stepWebhookUrl` - Callback that will be executed upon each agent inner thought

    ```json theme={null}
    {
        "prompt": "Research the financial industry for potential AI solutions",
        "thought": "I need to conduct preliminary research on the financial industry",
        "tool": "research_tool",
        "tool_input": "financial industry AI solutions",
        "result": "**Preliminary Research Report on the Financial Industry for crewai Enterprise Solution**\n1. Industry Overview and Trends\nThe financial industry in ....\nConclusion:\nThe financial industry presents a fertile ground for implementing AI solutions like crewai, particularly in areas such as digital customer engagement, risk management, and regulatory compliance. Further engagement with the lead is recommended to better tailor the crewai solution to their specific needs and scale.",
        "kickoff_id": "97eba64f-958c-40a0-b61c-625fe635a3c0",
        "meta": {
            "requestId": "travel-req-123",
            "source": "web-app"
        }
    }
    ```
  </Tab>

  <Tab title="Task Webhook">
    `taskWebhookUrl` - Callback that will be executed upon the end of each task

    ```json theme={null}
    {
        "description": "Using the information gathered from the lead's data, conduct preliminary research on the lead's industry, company background, and potential use cases for crewai. Focus on finding relevant data that can aid in scoring the lead and planning a strategy to pitch them crewai.",
        "name": "Industry Research Task",
        "expected_output": "Detailed research report on the financial industry",
        "summary": "The financial industry presents a fertile ground for implementing AI solutions like crewai, particularly in areas such as digital customer engagement, risk management, and regulatory compliance. Further engagement with the lead is recommended to better tailor the crewai solution to their specific needs and scale.",
        "agent": "Research Agent",
        "output": "**Preliminary Research Report on the Financial Industry for crewai Enterprise Solution**\n1. Industry Overview and Trends\nThe financial industry in ....\nConclusion:\nThe financial industry presents a fertile ground for implementing AI solutions like crewai, particularly in areas such as digital customer engagement, risk management, and regulatory compliance.",
        "output_json": {
            "industry": "financial",
            "key_opportunities": ["digital customer engagement", "risk management", "regulatory compliance"]
        },
        "kickoff_id": "97eba64f-958c-40a0-b61c-625fe635a3c0",
        "meta": {
            "requestId": "travel-req-123",
            "source": "web-app"
        }
    }
    ```
  </Tab>

  <Tab title="Crew Webhook">
    `crewWebhookUrl` - Callback that will be executed upon the end of the crew execution

    ```json theme={null}
    {
        "kickoff_id": "97eba64f-958c-40a0-b61c-625fe635a3c0",
        "result": "**Final Analysis Report**\n\nLead Score: Customer service enhancement and compliance are particularly relevant.\n\nTalking Points:\n- Highlight how crewai's AI solutions can transform customer service\n- Discuss crewai's potential for sustainability goals\n- Emphasize compliance capabilities\n- Stress adaptability for various operation scales",
        "result_json": {
            "lead_score": "Customer service enhancement, and compliance are particularly relevant.",
            "talking_points": [
                "Highlight how crewai's AI solutions can transform customer service with automated, personalized experiences and 24/7 support, improving both customer satisfaction and operational efficiency.",
                "Discuss crewai's potential to help the institution achieve its sustainability goals through better data analysis and decision-making, contributing to responsible investing and green initiatives.",
                "Emphasize crewai's ability to enhance compliance with evolving regulations through efficient data processing and reporting, reducing the risk of non-compliance penalties.",
                "Stress the adaptability of crewai to support both extensive multinational operations and smaller, targeted projects, ensuring the solution grows with the institution's needs."
            ]
        },
        "token_usage": {
            "total_tokens": 1250,
            "prompt_tokens": 800,
            "completion_tokens": 450
        },
        "meta": {
            "requestId": "travel-req-123",
            "source": "web-app"
        }
    }
    ```
  </Tab>
</Tabs>


# Zapier Trigger
Source: https://docs.crewai.com/en/enterprise/guides/zapier-trigger

Trigger CrewAI crews from Zapier workflows to automate cross-app workflows

This guide will walk you through the process of setting up Zapier triggers for CrewAI AMP, allowing you to automate workflows between CrewAI AMP and other applications.

## Prerequisites

* A CrewAI AMP account
* A Zapier account
* A Slack account (for this specific example)

## Step-by-Step Setup

<Steps>
  <Step title="Set Up the Slack Trigger">
    * In Zapier, create a new Zap.

    <Frame>
      <img alt="Zapier 1" />
    </Frame>
  </Step>

  <Step title="Choose Slack as your trigger app">
    <Frame>
      <img alt="Zapier 2" />
    </Frame>

    * Select `New Pushed Message` as the Trigger Event.
    * Connect your Slack account if you haven't already.
  </Step>

  <Step title="Configure the CrewAI AMP Action">
    * Add a new action step to your Zap.
    * Choose CrewAI+ as your action app and Kickoff as the Action Event

    <Frame>
      <img alt="Zapier 5" />
    </Frame>
  </Step>

  <Step title="Connect your CrewAI AMP account">
    * Connect your CrewAI AMP account.
    * Select the appropriate Crew for your workflow.

    <Frame>
      <img alt="Zapier 6" />
    </Frame>

    * Configure the inputs for the Crew using the data from the Slack message.
  </Step>

  <Step title="Format the CrewAI AMP Output">
    * Add another action step to format the text output from CrewAI AMP.
    * Use Zapier's formatting tools to convert the Markdown output to HTML.

    <Frame>
      <img alt="Zapier 8" />
    </Frame>

    <Frame>
      <img alt="Zapier 9" />
    </Frame>
  </Step>

  <Step title="Send the Output via Email">
    * Add a final action step to send the formatted output via email.
    * Choose your preferred email service (e.g., Gmail, Outlook).
    * Configure the email details, including recipient, subject, and body.
    * Insert the formatted CrewAI AMP output into the email body.

    <Frame>
      <img alt="Zapier 7" />
    </Frame>
  </Step>

  <Step title="Kick Off the crew from Slack">
    * Enter the text in your Slack channel

    <Frame>
      <img alt="Zapier 10" />
    </Frame>

    * Select the 3 ellipsis button and then chose Push to Zapier

    <Frame>
      <img alt="Zapier 11" />
    </Frame>
  </Step>

  <Step title="Select the crew and then Push to Kick Off">
    <Frame>
      <img alt="Zapier 12" />
    </Frame>
  </Step>
</Steps>

## Tips for Success

* Ensure that your CrewAI AMP inputs are correctly mapped from the Slack message.
* Test your Zap thoroughly before turning it on to catch any potential issues.
* Consider adding error handling steps to manage potential failures in the workflow.

By following these steps, you'll have successfully set up Zapier triggers for CrewAI AMP, allowing for automated workflows triggered by Slack messages and resulting in email notifications with CrewAI AMP output.


# FAQs
Source: https://docs.crewai.com/en/enterprise/resources/frequently-asked-questions

Frequently asked questions about CrewAI AMP

<AccordionGroup>
  <Accordion title="How is task execution handled in the hierarchical process?">
    In the hierarchical process, a manager agent is automatically created and coordinates the workflow, delegating tasks and validating outcomes for streamlined and effective execution. The manager agent utilizes tools to facilitate task delegation and execution by agents under the manager's guidance. The manager LLM is crucial for the hierarchical process and must be set up correctly for proper function.
  </Accordion>

  <Accordion title="Where can I get the latest CrewAI documentation?">
    The most up-to-date documentation for CrewAI is available on our official documentation website: [https://docs.crewai.com/](https://docs.crewai.com/)
    <Card href="https://docs.crewai.com/" icon="books">CrewAI Docs</Card>
  </Accordion>

  <Accordion title="What are the key differences between Hierarchical and Sequential Processes in CrewAI?">
    #### Hierarchical Process:

    * Tasks are delegated and executed based on a structured chain of command
    * A manager language model (`manager_llm`) must be specified for the manager agent
    * Manager agent oversees task execution, planning, delegation, and validation
    * Tasks are not pre-assigned; the manager allocates tasks to agents based on their capabilities

    #### Sequential Process:

    * Tasks are executed one after another, ensuring tasks are completed in an orderly progression
    * Output of one task serves as context for the next
    * Task execution follows the predefined order in the task list

    #### Which Process is Better for Complex Projects?

    The hierarchical process is better suited for complex projects because it allows for:

    * **Dynamic task allocation and delegation**: Manager agent can assign tasks based on agent capabilities
    * **Structured validation and oversight**: Manager agent reviews task outputs and ensures completion
    * **Complex task management**: Precise control over tool availability at the agent level
  </Accordion>

  <Accordion title="What are the benefits of using memory in the CrewAI framework?">
    * **Adaptive Learning**: Crews become more efficient over time, adapting to new information and refining their approach to tasks
    * **Enhanced Personalization**: Memory enables agents to remember user preferences and historical interactions, leading to personalized experiences
    * **Improved Problem Solving**: Access to a rich memory store aids agents in making more informed decisions, drawing on past learnings and contextual insights
  </Accordion>

  <Accordion title="What is the purpose of setting a maximum RPM limit for an agent?">
    Setting a maximum RPM limit for an agent prevents the agent from making too many requests to external services, which can help to avoid rate limits and improve performance.
  </Accordion>

  <Accordion title="What role does human input play in the execution of tasks within a CrewAI crew?">
    Human input allows agents to request additional information or clarification when necessary. This feature is crucial in complex decision-making processes or when agents require more details to complete a task effectively.

    To integrate human input into agent execution, set the `human_input` flag in the task definition. When enabled, the agent prompts the user for input before delivering its final answer. This input can provide extra context, clarify ambiguities, or validate the agent's output.

    For detailed implementation guidance, see our [Human-in-the-Loop guide](/en/enterprise/guides/human-in-the-loop).
  </Accordion>

  <Accordion title="What advanced customization options are available for tailoring and enhancing agent behavior and capabilities in CrewAI?">
    CrewAI provides a range of advanced customization options:

    * **Language Model Customization**: Agents can be customized with specific language models (`llm`) and function-calling language models (`function_calling_llm`)
    * **Performance and Debugging Settings**: Adjust an agent's performance and monitor its operations
    * **Verbose Mode**: Enables detailed logging of an agent's actions, useful for debugging and optimization
    * **RPM Limit**: Sets the maximum number of requests per minute (`max_rpm`)
    * **Maximum Iterations**: The `max_iter` attribute allows users to define the maximum number of iterations an agent can perform for a single task
    * **Delegation and Autonomy**: Control an agent's ability to delegate or ask questions with the `allow_delegation` attribute (default: True)
    * **Human Input Integration**: Agents can request additional information or clarification when necessary
  </Accordion>

  <Accordion title="In what scenarios is human input particularly useful in agent execution?">
    Human input is particularly useful when:

    * **Agents require additional information or clarification**: When agents encounter ambiguity or incomplete data
    * **Agents need to make complex or sensitive decisions**: Human input can assist in ethical or nuanced decision-making
    * **Oversight and validation of agent output**: Human input can help validate results and prevent errors
    * **Customizing agent behavior**: Human input can provide feedback to refine agent responses over time
    * **Identifying and resolving errors or limitations**: Human input helps address agent capability gaps
  </Accordion>

  <Accordion title="What are the different types of memory that are available in crewAI?">
    The different types of memory available in CrewAI are:

    * **Short-term memory**: Temporary storage for immediate context
    * **Long-term memory**: Persistent storage for learned patterns and information
    * **Entity memory**: Focused storage for specific entities and their attributes
    * **Contextual memory**: Memory that maintains context across interactions

    Learn more about the different types of memory:
    <Card href="https://docs.crewai.com/concepts/memory" icon="brain">CrewAI Memory</Card>
  </Accordion>

  <Accordion title="How do I use Output Pydantic in a Task?">
    To use Output Pydantic in a task, you need to define the expected output of the task as a Pydantic model. Here's a quick example:

    <Steps>
      <Step title="Define a Pydantic model">
        ```python theme={null}
        from pydantic import BaseModel

        class User(BaseModel):
            name: str
            age: int
        ```
      </Step>

      <Step title="Create a task with Output Pydantic">
        ```python theme={null}
        from crewai import Task, Crew, Agent
        from my_models import User

        task = Task(
            description="Create a user with the provided name and age",
            expected_output=User,  # This is the Pydantic model
            agent=agent,
            tools=[tool1, tool2]
        )
        ```
      </Step>

      <Step title="Set the output_pydantic attribute in your agent">
        ```python theme={null}
        from crewai import Agent
        from my_models import User

        agent = Agent(
            role='User Creator',
            goal='Create users',
            backstory='I am skilled in creating user accounts',
            tools=[tool1, tool2],
            output_pydantic=User
        )
        ```
      </Step>
    </Steps>

    Here's a tutorial on how to consistently get structured outputs from your agents:

    <iframe title="Structured outputs in CrewAI" />
  </Accordion>

  <Accordion title="How can I create custom tools for my CrewAI agents?">
    You can create custom tools by subclassing the `BaseTool` class provided by CrewAI or by using the tool decorator. Subclassing involves defining a new class that inherits from `BaseTool`, specifying the name, description, and the `_run` method for operational logic. The tool decorator allows you to create a `Tool` object directly with the required attributes and a functional logic.

    <Card href="/en/learn/create-custom-tools" icon="code">CrewAI Tools Guide</Card>
  </Accordion>

  <Accordion title="How can you control the maximum number of requests per minute that the entire crew can perform?">
    The `max_rpm` attribute sets the maximum number of requests per minute the crew can perform to avoid rate limits and will override individual agents' `max_rpm` settings if you set it.
  </Accordion>
</AccordionGroup>


# CrewAI Cookbooks
Source: https://docs.crewai.com/en/examples/cookbooks

Feature-focused quickstarts and notebooks for learning patterns fast.

## Quickstarts & Demos

<CardGroup>
  <Card title="Collaboration" icon="people-arrows" href="https://github.com/crewAIInc/crewAI-quickstarts/blob/main/Collaboration/crewai_collaboration.ipynb">
    Coordinate multiple agents on shared tasks. Includes notebook with end-to-end collaboration pattern.
  </Card>

  <Card title="Planning" icon="timeline" href="https://github.com/crewAIInc/crewAI-quickstarts/blob/main/Planning/crewai_planning.ipynb">
    Teach agents to reason about multi-step plans before execution using the planning toolkit.
  </Card>

  <Card title="Reasoning" icon="lightbulb" href="https://github.com/crewAIInc/crewAI-quickstarts/blob/main/Reasoning/crewai_reasoning.ipynb">
    Explore self-reflection loops, critique prompts, and structured thinking patterns.
  </Card>
</CardGroup>

<CardGroup>
  <Card title="Structured Guardrails" icon="shield-check" href="https://github.com/crewAIInc/crewAI-quickstarts/blob/main/Guardrails/task_guardrails.ipynb">
    Apply task-level guardrails with retries, validation functions, and safe fallbacks.
  </Card>

  <Card title="Gemini Search & Grounding" icon="magnifying-glass" href="https://github.com/crewAIInc/crewAI-quickstarts/blob/main/Custom%20LLM/gemini_search_grounding_crewai.ipynb">
    Connect CrewAI to Gemini with search grounding for factual, citation-rich outputs.
  </Card>

  <Card title="Gemini Video Summaries" icon="video" href="https://github.com/crewAIInc/crewAI-quickstarts/blob/main/Custom%20LLM/summarize_video_gemini_crewai.ipynb">
    Generate video recaps using Gemini multimodal LLM and CrewAI orchestration.
  </Card>
</CardGroup>

<CardGroup>
  <Card title="Browse Quickstarts" icon="bolt" href="https://github.com/crewAIInc/crewAI-quickstarts">
    View all notebooks and feature demos showcasing specific CrewAI capabilities.
  </Card>

  <Card title="Request a cookbook" icon="message-plus" href="https://community.crewai.com">
    Missing a pattern? Drop a request in the community forum and we’ll expand the library.
  </Card>
</CardGroup>

<Tip>
  Use Cookbooks to learn a pattern quickly, then jump to Full Examples for production‑grade implementations.
</Tip>


# CrewAI Examples
Source: https://docs.crewai.com/en/examples/example

Explore curated examples organized by Crews, Flows, Integrations, and Notebooks.

## Crews

<CardGroup>
  <Card title="Marketing Strategy" icon="bullhorn" href="https://github.com/crewAIInc/crewAI-examples/tree/main/crews/marketing_strategy">
    Multi‑agent marketing campaign planning.
  </Card>

  <Card title="Surprise Trip" icon="plane" href="https://github.com/crewAIInc/crewAI-examples/tree/main/crews/surprise_trip">
    Personalized surprise travel planning.
  </Card>

  <Card title="Match Profile to Positions" icon="id-card" href="https://github.com/crewAIInc/crewAI-examples/tree/main/crews/match_profile_to_positions">
    CV‑to‑job matching with vector search.
  </Card>

  <Card title="Job Posting" icon="newspaper" href="https://github.com/crewAIInc/crewAI-examples/tree/main/crews/job-posting">
    Automated job description creation.
  </Card>

  <Card title="Game Builder Crew" icon="gamepad" href="https://github.com/crewAIInc/crewAI-examples/tree/main/crews/game-builder-crew">
    Multi‑agent team that designs and builds Python games.
  </Card>

  <Card title="Recruitment" icon="user-group" href="https://github.com/crewAIInc/crewAI-examples/tree/main/crews/recruitment">
    Candidate sourcing and evaluation.
  </Card>

  <Card title="Browse all Crews" icon="users" href="https://github.com/crewAIInc/crewAI-examples/tree/main/crews">
    See the full list of crew examples.
  </Card>
</CardGroup>

## Flows

<CardGroup>
  <Card title="Content Creator Flow" icon="pen" href="https://github.com/crewAIInc/crewAI-examples/tree/main/flows/content_creator_flow">
    Multi‑crew content generation with routing.
  </Card>

  <Card title="Email Auto Responder" icon="envelope" href="https://github.com/crewAIInc/crewAI-examples/tree/main/flows/email_auto_responder_flow">
    Automated email monitoring and replies.
  </Card>

  <Card title="Lead Score Flow" icon="chart-line" href="https://github.com/crewAIInc/crewAI-examples/tree/main/flows/lead_score_flow">
    Lead qualification with human‑in‑the‑loop.
  </Card>

  <Card title="Meeting Assistant Flow" icon="calendar" href="https://github.com/crewAIInc/crewAI-examples/tree/main/flows/meeting_assistant_flow">
    Notes processing with integrations.
  </Card>

  <Card title="Self Evaluation Loop" icon="rotate" href="https://github.com/crewAIInc/crewAI-examples/tree/main/flows/self_evaluation_loop_flow">
    Iterative self‑improvement workflows.
  </Card>

  <Card title="Write a Book (Flows)" icon="book" href="https://github.com/crewAIInc/crewAI-examples/tree/main/flows/write_a_book_with_flows">
    Parallel chapter generation.
  </Card>

  <Card title="Browse all Flows" icon="diagram-project" href="https://github.com/crewAIInc/crewAI-examples/tree/main/flows">
    See the full list of flow examples.
  </Card>
</CardGroup>

## Integrations

<CardGroup>
  <Card title="CrewAI ↔ LangGraph" icon="link" href="https://github.com/crewAIInc/crewAI-examples/tree/main/integrations/crewai-langgraph">
    Integration with LangGraph framework.
  </Card>

  <Card title="Azure OpenAI" icon="cloud" href="https://github.com/crewAIInc/crewAI-examples/tree/main/integrations/azure_model">
    Using CrewAI with Azure OpenAI.
  </Card>

  <Card title="NVIDIA Models" icon="microchip" href="https://github.com/crewAIInc/crewAI-examples/tree/main/integrations/nvidia_models">
    NVIDIA ecosystem integrations.
  </Card>

  <Card title="Browse Integrations" icon="puzzle-piece" href="https://github.com/crewAIInc/crewAI-examples/tree/main/integrations">
    See all integration examples.
  </Card>
</CardGroup>

## Notebooks

<CardGroup>
  <Card title="Simple QA Crew + Flow" icon="book" href="https://github.com/crewAIInc/crewAI-examples/tree/main/Notebooks/Simple%20QA%20Crew%20%2B%20Flow">
    Simple QA Crew + Flow.
  </Card>

  <Card title="All Notebooks" icon="book" href="https://github.com/crewAIInc/crewAI-examples/tree/main/Notebooks">
    Interactive examples for learning and experimentation.
  </Card>
</CardGroup>


