-
-You can connect your application to agents directly via **AG-UI**, **MCP**, and **A2A**.
-
-* **MCP** (Model Context Protocol) Connects agents to tools and to context — but those tools are themselves becoming agentic.
-* **A2A** (Agent to Agent) Connects agents to other agents.
-* **AG-UI (Agent–User Interaction)** Connects agents to users (through user-facing applications).
-
- You can think of AG-UI as the **"kitchen sink" protocol** — informed by bottom-up, real-world needs for building best-in-class agentic applications.
-
-These three agentic protocols are complementary and have distinct technical goals; a single agent can and often does use all 3 simultaneously.
-
-## AG-UI Handshakes with MCP and A2A
-
-AG-UI contributors have recently added handshakes, allowing AG-UI to "front for" agents through MCP and A2A protocols, which allows AG-UI client apps and libraries to seamlessly use MCP and A2A supporting agents.
-
-AG-UI's mandate is to support the full set of building blocks required by modern agentic applications.
-
-## Generative UI Specs
-
-Recently several [generative ui specs](./concepts/generative-ui-specs) (including MCP-UI, Open JSON UI, and A2UI) have been released which allow agents to deliver UI widgets through the interaction protocols. AG-UI works with all of these. Visit our [generative ui specs page](./concepts/generative-ui-specs) to lern more.
-
-
-# Agents
-Source: https://docs.ag-ui.com/concepts/agents
-
-Learn about agents in the Agent User Interaction Protocol
-
-# Agents
-
-Agents are the core components in the AG-UI protocol that process requests and
-generate responses. They establish a standardized way for front-end applications
-to communicate with AI services through a consistent interface, regardless of
-the underlying implementation.
-
-## What is an Agent?
-
-In AG-UI, an agent is a class that:
-
-1. Manages conversation state and message history
-2. Processes incoming messages and context
-3. Generates responses through an event-driven streaming interface
-4. Follows a standardized protocol for communication
-
-Agents can be implemented to connect with any AI service, including:
-
-* Large language models (LLMs) like GPT-4 or Claude
-* Custom AI systems
-* Retrieval augmented generation (RAG) systems
-* Multi-agent systems
-
-## Agent Architecture
-
-All agents in AG-UI extend the `AbstractAgent` class, which provides the
-foundation for:
-
-* State management
-* Message history tracking
-* Event stream processing
-* Tool usage
-
-```typescript theme={null}
-import { AbstractAgent } from "@ag-ui/client"
-
-class MyAgent extends AbstractAgent {
- run(input: RunAgentInput): RunAgent {
- // Implementation details
- }
-}
-```
-
-### Core Components
-
-AG-UI agents have several key components:
-
-1. **Configuration**: Agent ID, thread ID, and initial state
-2. **Messages**: Conversation history with user and assistant messages
-3. **State**: Structured data that persists across interactions
-4. **Events**: Standardized messages for communication with clients
-5. **Tools**: Functions that agents can use to interact with external systems
-
-## Agent Types
-
-AG-UI provides different agent implementations to suit various needs:
-
-### AbstractAgent
-
-The base class that all agents extend. It handles core event processing, state
-management, and message history.
-
-### HttpAgent
-
-A concrete implementation that connects to remote AI services via HTTP:
-
-```typescript theme={null}
-import { HttpAgent } from "@ag-ui/client"
-
-const agent = new HttpAgent({
- url: "https://your-agent-endpoint.com/agent",
- headers: {
- Authorization: "Bearer your-api-key",
- },
-})
-```
-
-### Custom Agents
-
-You can create custom agents to integrate with any AI service by extending
-`AbstractAgent`:
-
-```typescript theme={null}
-class CustomAgent extends AbstractAgent {
- // Custom properties and methods
-
- run(input: RunAgentInput): RunAgent {
- // Implement the agent's logic
- }
-}
-```
-
-## Implementing Agents
-
-### Basic Implementation
-
-To create a custom agent, extend the `AbstractAgent` class and implement the
-required `run` method:
-
-```typescript theme={null}
-import {
- AbstractAgent,
- RunAgent,
- RunAgentInput,
- EventType,
- BaseEvent,
-} from "@ag-ui/client"
-import { Observable } from "rxjs"
-
-class SimpleAgent extends AbstractAgent {
- run(input: RunAgentInput): RunAgent {
- const { threadId, runId } = input
-
- return () =>
- new Observable((observer) => {
- // Emit RUN_STARTED event
- observer.next({
- type: EventType.RUN_STARTED,
- threadId,
- runId,
- })
-
- // Send a message
- const messageId = Date.now().toString()
-
- // Message start
- observer.next({
- type: EventType.TEXT_MESSAGE_START,
- messageId,
- role: "assistant",
- })
-
- // Message content
- observer.next({
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId,
- delta: "Hello, world!",
- })
-
- // Message end
- observer.next({
- type: EventType.TEXT_MESSAGE_END,
- messageId,
- })
-
- // Emit RUN_FINISHED event
- observer.next({
- type: EventType.RUN_FINISHED,
- threadId,
- runId,
- })
-
- // Complete the observable
- observer.complete()
- })
- }
-}
-```
-
-## Agent Capabilities
-
-Agents in the AG-UI protocol provide a rich set of capabilities that enable
-sophisticated AI interactions:
-
-### Interactive Communication
-
-Agents establish bi-directional communication channels with front-end
-applications through event streams. This enables:
-
-* Real-time streaming responses character-by-character
-* Immediate feedback loops between user and AI
-* Progress indicators for long-running operations
-* Structured data exchange in both directions
-
-### Tool Usage
-
-Agents can use tools to perform actions and access external resources.
-Importantly, tools are defined and passed in from the front-end application to
-the agent, allowing for a flexible and extensible system:
-
-```typescript theme={null}
-// Tool definition
-const confirmAction = {
- name: "confirmAction",
- description: "Ask the user to confirm a specific action before proceeding",
- parameters: {
- type: "object",
- properties: {
- action: {
- type: "string",
- description: "The action that needs user confirmation",
- },
- importance: {
- type: "string",
- enum: ["low", "medium", "high", "critical"],
- description: "The importance level of the action",
- },
- details: {
- type: "string",
- description: "Additional details about the action",
- },
- },
- required: ["action"],
- },
-}
-
-// Running an agent with tools from the frontend
-agent.runAgent({
- tools: [confirmAction], // Frontend-defined tools passed to the agent
- // other parameters
-})
-```
-
-Tools are invoked through a sequence of events:
-
-1. `TOOL_CALL_START`: Indicates the beginning of a tool call
-2. `TOOL_CALL_ARGS`: Streams the arguments for the tool call
-3. `TOOL_CALL_END`: Marks the completion of the tool call
-
-Front-end applications can then execute the tool and provide results back to the
-agent. This bidirectional flow enables sophisticated human-in-the-loop workflows
-where:
-
-* The agent can request specific actions be performed
-* Humans can execute those actions with appropriate judgment
-* Results are fed back to the agent for continued reasoning
-* The agent maintains awareness of all decisions made in the process
-
-This mechanism is particularly powerful for implementing interfaces where AI and
-humans collaborate. For example, [CopilotKit](https://docs.copilotkit.ai/)
-leverages this exact pattern with their
-[`useCopilotAction`](https://docs.copilotkit.ai/guides/frontend-actions) hook,
-which provides a simplified way to define and handle tools in React
-applications.
-
-By keeping the AI informed about human decisions through the tool mechanism,
-applications can maintain context and create more natural collaborative
-experiences between users and AI assistants.
-
-### State Management
-
-Agents maintain a structured state that persists across interactions. This state
-can be:
-
-* Updated incrementally through `STATE_DELTA` events
-* Completely refreshed with `STATE_SNAPSHOT` events
-* Accessed by both the agent and front-end
-* Used to store user preferences, conversation context, or application state
-
-```typescript theme={null}
-// Accessing agent state
-console.log(agent.state.preferences)
-
-// State is automatically updated during agent runs
-agent.runAgent().subscribe((event) => {
- if (event.type === EventType.STATE_DELTA) {
- // State has been updated
- console.log("New state:", agent.state)
- }
-})
-```
-
-### Multi-Agent Collaboration
-
-AG-UI supports agent-to-agent handoff and collaboration:
-
-* Agents can delegate tasks to other specialized agents
-* Multiple agents can work together in a coordinated workflow
-* State and context can be transferred between agents
-* The front-end maintains a consistent experience across agent transitions
-
-For example, a general assistant agent might hand off to a specialized coding
-agent when programming help is needed, passing along the conversation context
-and specific requirements.
-
-### Human-in-the-Loop Workflows
-
-Agents support human intervention and assistance:
-
-* Agents can request human input on specific decisions
-* Front-ends can pause agent execution and resume it after human feedback
-* Human experts can review and modify agent outputs before they're finalized
-* Hybrid workflows combine AI efficiency with human judgment
-
-This enables applications where the agent acts as a collaborative partner rather
-than an autonomous system.
-
-### Conversational Memory
-
-Agents maintain a complete history of conversation messages:
-
-* Past interactions inform future responses
-* Message history is synchronized between client and server
-* Messages can include rich content (text, structured data, references)
-* The context window can be managed to focus on relevant information
-
-```typescript theme={null}
-// Accessing message history
-console.log(agent.messages)
-
-// Adding a new user message
-agent.messages.push({
- id: "msg_123",
- role: "user",
- content: "Can you explain that in more detail?",
-})
-```
-
-### Metadata and Instrumentation
-
-Agents can emit metadata about their internal processes:
-
-* Reasoning steps through custom events
-* Performance metrics and timing information
-* Source citations and reference tracking
-* Confidence scores for different response options
-
-This allows front-ends to provide transparency into the agent's decision-making
-process and help users understand how conclusions were reached.
-
-## Using Agents
-
-Once you've implemented or instantiated an agent, you can use it like this:
-
-```typescript theme={null}
-// Create an agent instance
-const agent = new HttpAgent({
- url: "https://your-agent-endpoint.com/agent",
-})
-
-// Add initial messages if needed
-agent.messages = [
- {
- id: "1",
- role: "user",
- content: "Hello, how can you help me today?",
- },
-]
-
-// Run the agent
-agent
- .runAgent({
- runId: "run_123",
- tools: [], // Optional tools
- context: [], // Optional context
- })
- .subscribe({
- next: (event) => {
- // Handle different event types
- switch (event.type) {
- case EventType.TEXT_MESSAGE_CONTENT:
- console.log("Content:", event.delta)
- break
- // Handle other events
- }
- },
- error: (error) => console.error("Error:", error),
- complete: () => console.log("Run complete"),
- })
-```
-
-## Agent Configuration
-
-Agents accept configuration through the constructor:
-
-```typescript theme={null}
-interface AgentConfig {
- agentId?: string // Unique identifier for the agent
- description?: string // Human-readable description
- threadId?: string // Conversation thread identifier
- initialMessages?: Message[] // Initial messages
- initialState?: State // Initial state object
-}
-
-// Using the configuration
-const agent = new HttpAgent({
- agentId: "my-agent-123",
- description: "A helpful assistant",
- threadId: "thread-456",
- initialMessages: [
- { id: "1", role: "system", content: "You are a helpful assistant." },
- ],
- initialState: { preferredLanguage: "English" },
-})
-```
-
-## Agent State Management
-
-AG-UI agents maintain state across interactions:
-
-```typescript theme={null}
-// Access current state
-console.log(agent.state)
-
-// Access messages
-console.log(agent.messages)
-
-// Clone an agent with its state
-const clonedAgent = agent.clone()
-```
-
-## Conclusion
-
-Agents are the foundation of the AG-UI protocol, providing a standardized way to
-connect front-end applications with AI services. By implementing the
-`AbstractAgent` class, you can create custom integrations with any AI service
-while maintaining a consistent interface for your applications.
-
-The event-driven architecture enables real-time, streaming interactions that are
-essential for modern AI applications, and the standardized protocol ensures
-compatibility across different implementations.
-
-
-# Core architecture
-Source: https://docs.ag-ui.com/concepts/architecture
-
-Understand how AG-UI connects front-end applications to AI agents
-
-Agent User Interaction Protocol (AG-UI) is built on a flexible, event-driven
-architecture that enables seamless, efficient communication between front-end
-applications and AI agents. This document covers the core architectural
-components and concepts.
-
-## Design Principles
-
-AG-UI is designed to be lightweight and minimally opinionated, making it easy to
-integrate with a wide range of agent implementations. The protocol's flexibility
-comes from its simple requirements:
-
-1. **Event-Driven Communication**: Agents need to emit any of the 16
- standardized event types during execution, creating a stream of updates that
- clients can process.
-
-2. **Bidirectional Interaction**: Agents accept input from users, enabling
- collaborative workflows where humans and AI work together seamlessly.
-
-The protocol includes a built-in middleware layer that maximizes compatibility
-in two key ways:
-
-* **Flexible Event Structure**: Events don't need to match AG-UI's format
- exactly—they just need to be AG-UI-compatible. This allows existing agent
- frameworks to adapt their native event formats with minimal effort.
-
-* **Transport Agnostic**: AG-UI doesn't mandate how events are delivered,
- supporting various transport mechanisms including Server-Sent Events (SSE),
- webhooks, WebSockets, and more. This flexibility lets developers choose the
- transport that best fits their architecture.
-
-This pragmatic approach makes AG-UI easy to adopt without requiring major
-changes to existing agent implementations or frontend applications.
-
-## Architectural Overview
-
-AG-UI follows a client-server architecture that standardizes communication
-between agents and applications:
-
-```mermaid theme={null}
-flowchart LR
- subgraph "Frontend"
- App["Application"]
- Client["AG-UI Client"]
- end
-
- subgraph "Backend"
- A1["AI Agent A"]
- P["Secure Proxy"]
- A2["AI Agent B"]
- A3["AI Agent C"]
- end
-
- App <--> Client
- Client <-->|"AG-UI Protocol"| A1
- Client <-->|"AG-UI Protocol"| P
- P <-->|"AG-UI Protocol"| A2
- P <-->|"AG-UI Protocol"| A3
-
- class P mintStyle;
- classDef mintStyle fill:#E0F7E9,stroke:#66BB6A,stroke-width:2px,color:#000000;
-
- style App rx:5, ry:5;
- style Client rx:5, ry:5;
- style A1 rx:5, ry:5;
- style P rx:5, ry:5;
- style A2 rx:5, ry:5;
- style A3 rx:5, ry:5;
-```
-
-* **Application**: User-facing apps (i.e. chat or any AI-enabled application).
-* **AG-UI Client**: Generic communication clients like `HttpAgent` or
- specialized clients for connecting to existing protocols.
-* **Agents**: Backend AI agents that process requests and generate streaming
- responses.
-* **Secure Proxy**: Backend services that provide additional capabilities and
- act as a secure proxy.
-
-## Core components
-
-### Protocol layer
-
-AG-UI's protocol layer provides a flexible foundation for agent communication.
-
-* **Universal compatibility**: Connect to any protocol by implementing
- `run(input: RunAgentInput) -> Observable`
-
-The protocol's primary abstraction enables applications to run agents and
-receive a stream of events:
-
-```typescript theme={null}
-// Core agent execution interface
-type RunAgent = () => Observable
-
-class MyAgent extends AbstractAgent {
- run(input: RunAgentInput): RunAgent {
- const { threadId, runId } = input
- return () =>
- from([
- { type: EventType.RUN_STARTED, threadId, runId },
- {
- type: EventType.MESSAGES_SNAPSHOT,
- messages: [
- { id: "msg_1", role: "assistant", content: "Hello, world!" }
- ],
- },
- { type: EventType.RUN_FINISHED, threadId, runId },
- ])
- }
-}
-```
-
-### Standard HTTP client
-
-AG-UI offers a standard HTTP client `HttpAgent` that can be used to connect to
-any endpoint that accepts POST requests with a body of type `RunAgentInput` and
-sends a stream of `BaseEvent` objects.
-
-`HttpAgent` supports the following transports:
-
-* **HTTP SSE (Server-Sent Events)**
-
- * Text-based streaming for wide compatibility
- * Easy to read and debug
-
-* **HTTP binary protocol**
- * Highly performant and space-efficient custom transport
- * Robust binary serialization for production environments
-
-### Message types
-
-AG-UI defines several event categories for different aspects of agent
-communication:
-
-* **Lifecycle events**
-
- * `RUN_STARTED`, `RUN_FINISHED`, `RUN_ERROR`
- * `STEP_STARTED`, `STEP_FINISHED`
-
-* **Text message events**
-
- * `TEXT_MESSAGE_START`, `TEXT_MESSAGE_CONTENT`, `TEXT_MESSAGE_END`
-
-* **Tool call events**
-
- * `TOOL_CALL_START`, `TOOL_CALL_ARGS`, `TOOL_CALL_END`
-
-* **State management events**
-
- * `STATE_SNAPSHOT`, `STATE_DELTA`, `MESSAGES_SNAPSHOT`
-
-* **Special events**
- * `RAW`, `CUSTOM`
-
-## Running Agents
-
-To run an agent, you create a client instance and execute it:
-
-```typescript theme={null}
-// Create an HTTP agent client
-const agent = new HttpAgent({
- url: "https://your-agent-endpoint.com/agent",
- agentId: "unique-agent-id",
- threadId: "conversation-thread"
-});
-
-// Start the agent and handle events
-agent.runAgent({
- tools: [...],
- context: [...]
-}).subscribe({
- next: (event) => {
- // Handle different event types
- switch(event.type) {
- case EventType.TEXT_MESSAGE_CONTENT:
- // Update UI with new content
- break;
- // Handle other event types
- }
- },
- error: (error) => console.error("Agent error:", error),
- complete: () => console.log("Agent run complete")
-});
-```
-
-## State Management
-
-AG-UI provides efficient state management through specialized events:
-
-* `STATE_SNAPSHOT`: Complete state representation at a point in time
-* `STATE_DELTA`: Incremental state changes using JSON Patch format (RFC 6902)
-* `MESSAGES_SNAPSHOT`: Complete conversation history
-
-These events enable efficient client-side state management with minimal data
-transfer.
-
-## Tools and Handoff
-
-AG-UI supports agent-to-agent handoff and tool usage through standardized
-events:
-
-* Tool definitions are passed in the `runAgent` parameters
-* Tool calls are streamed as sequences of `TOOL_CALL_START` → `TOOL_CALL_ARGS` →
- `TOOL_CALL_END` events
-* Agents can hand off to other agents, maintaining context continuity
-
-## Events
-
-All communication in AG-UI is based on typed events. Every event inherits from
-`BaseEvent`:
-
-```typescript theme={null}
-interface BaseEvent {
- type: EventType
- timestamp?: number
- rawEvent?: any
-}
-```
-
-Events are strictly typed and validated, ensuring reliable communication between
-components.
-
-
-# Events
-Source: https://docs.ag-ui.com/concepts/events
-
-Understanding events in the Agent User Interaction Protocol
-
-# Events
-
-The Agent User Interaction Protocol uses a streaming event-based architecture.
-Events are the fundamental units of communication between agents and frontends,
-enabling real-time, structured interaction.
-
-## Event Types Overview
-
-Events in the protocol are categorized by their purpose:
-
-| Category | Description |
-| ----------------------- | --------------------------------------- |
-| Lifecycle Events | Monitor the progression of agent runs |
-| Text Message Events | Handle streaming textual content |
-| Tool Call Events | Manage tool executions by agents |
-| State Management Events | Synchronize state between agents and UI |
-| Activity Events | Represent ongoing activity progress |
-| Special Events | Support custom functionality |
-| Draft Events | Proposed events under development |
-
-## Base Event Properties
-
-All events share a common set of base properties:
-
-| Property | Description |
-| ----------- | ---------------------------------------------------------------- |
-| `type` | The specific event type identifier |
-| `timestamp` | Optional timestamp indicating when the event was created |
-| `rawEvent` | Optional field containing the original event data if transformed |
-
-## Lifecycle Events
-
-These events represent the lifecycle of an agent run. A typical agent run
-follows a predictable pattern: it begins with a `RunStarted` event, may contain
-multiple optional `StepStarted`/`StepFinished` pairs, and concludes with either
-a `RunFinished` event (success) or a `RunError` event (failure).
-
-Lifecycle events provide crucial structure to agent runs, enabling frontends to
-track progress, manage UI states appropriately, and handle errors gracefully.
-They create a consistent framework for understanding when operations begin and
-end, making it possible to implement features like loading indicators, progress
-tracking, and error recovery mechanisms.
-
-```mermaid theme={null}
-sequenceDiagram
- participant Agent
- participant Client
-
- Note over Agent,Client: Run begins
- Agent->>Client: RunStarted
-
- opt Sending steps is optional
- Note over Agent,Client: Step execution
- Agent->>Client: StepStarted
- Agent->>Client: StepFinished
- end
-
- Note over Agent,Client: Run completes
- alt
- Agent->>Client: RunFinished
- else
- Agent->>Client: RunError
- end
-```
-
-The `RunStarted` and either `RunFinished` or `RunError` events are mandatory,
-forming the boundaries of an agent run. Step events are optional and may occur
-multiple times within a run, allowing for structured, observable progress
-tracking.
-
-### RunStarted
-
-Signals the start of an agent run.
-
-The `RunStarted` event is the first event emitted when an agent begins
-processing a request. It establishes a new execution context identified by a
-unique `runId`. This event serves as a marker for frontends to initialize UI
-elements such as progress indicators or loading states. It also provides crucial
-identifiers that can be used to associate subsequent events with this specific
-run.
-
-| Property | Description |
-| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| `threadId` | ID of the conversation thread |
-| `runId` | ID of the agent run |
-| `parentRunId` | (Optional) Lineage pointer for branching/time travel. If present, refers to a prior run within the same thread, creating a git-like append-only log |
-| `input` | (Optional) The exact agent input payload that was sent to the agent for this run. May omit messages already present in history; compactEvents() will normalize |
-
-### RunFinished
-
-Signals the successful completion of an agent run.
-
-The `RunFinished` event indicates that an agent has successfully completed all
-its work for the current run. Upon receiving this event, frontends should
-finalize any UI states that were waiting on the agent's completion. This event
-marks a clean termination point and indicates that no further processing will
-occur in this run unless explicitly requested. The optional `result` field can
-contain any output data produced by the agent run.
-
-| Property | Description |
-| ---------- | ----------------------------- |
-| `threadId` | ID of the conversation thread |
-| `runId` | ID of the agent run |
-| `result` | Optional result data from run |
-
-### RunError
-
-Signals an error during an agent run.
-
-The `RunError` event indicates that the agent encountered an error it could not
-recover from, causing the run to terminate prematurely. This event provides
-information about what went wrong, allowing frontends to display appropriate
-error messages and potentially offer recovery options. After a `RunError` event,
-no further processing will occur in this run.
-
-| Property | Description |
-| --------- | ------------------- |
-| `message` | Error message |
-| `code` | Optional error code |
-
-### StepStarted
-
-Signals the start of a step within an agent run.
-
-The `StepStarted` event indicates that the agent is beginning a specific subtask
-or phase of its processing. Steps provide granular visibility into the agent's
-progress, enabling more precise tracking and feedback in the UI. Steps are
-optional but highly recommended for complex operations that benefit from being
-broken down into observable stages. The `stepName` could be the name of a node
-or function that is currently executing.
-
-| Property | Description |
-| ---------- | ---------------- |
-| `stepName` | Name of the step |
-
-### StepFinished
-
-Signals the completion of a step within an agent run.
-
-The `StepFinished` event indicates that the agent has completed a specific
-subtask or phase. When paired with a corresponding `StepStarted` event, it
-creates a bounded context for a discrete unit of work. Frontends can use these
-events to update progress indicators, show completion animations, or reveal
-results specific to that step. The `stepName` must match the corresponding
-`StepStarted` event to properly pair the beginning and end of the step.
-
-| Property | Description |
-| ---------- | ---------------- |
-| `stepName` | Name of the step |
-
-## Text Message Events
-
-These events represent the lifecycle of text messages in a conversation. Text
-message events follow a streaming pattern, where content is delivered
-incrementally. A message begins with a `TextMessageStart` event, followed by one
-or more `TextMessageContent` events that deliver chunks of text as they become
-available, and concludes with a `TextMessageEnd` event.
-
-This streaming approach enables real-time display of message content as it's
-generated, creating a more responsive user experience compared to waiting for
-the entire message to be complete before showing anything.
-
-```mermaid theme={null}
-sequenceDiagram
- participant Agent
- participant Client
-
- Note over Agent,Client: Message begins
- Agent->>Client: TextMessageStart
-
- loop Content streaming
- Agent->>Client: TextMessageContent
- end
-
- Note over Agent,Client: Message completes
- Agent->>Client: TextMessageEnd
-```
-
-The `TextMessageContent` events each contain a `delta` field with a chunk of
-text. Frontends should concatenate these deltas in the order received to
-construct the complete message. The `messageId` property links all related
-events, allowing the frontend to associate content chunks with the correct
-message.
-
-### TextMessageStart
-
-Signals the start of a text message.
-
-The `TextMessageStart` event initializes a new text message in the conversation.
-It establishes a unique `messageId` that will be referenced by subsequent
-content chunks and the end event. This event allows frontends to prepare the UI
-for an incoming message, such as creating a new message bubble with a loading
-indicator. The `role` property identifies whether the message is coming from the
-assistant or potentially another participant in the conversation.
-
-| Property | Description |
-| ----------- | ------------------------------------------------------------------------------- |
-| `messageId` | Unique identifier for the message |
-| `role` | Role of the message sender ("developer", "system", "assistant", "user", "tool") |
-
-### TextMessageContent
-
-Represents a chunk of content in a streaming text message.
-
-The `TextMessageContent` event delivers incremental parts of the message text as
-they become available. Each event contains a small chunk of text in the `delta`
-property that should be appended to previously received chunks. The streaming
-nature of these events enables real-time display of content, creating a more
-responsive and engaging user experience. Implementations should handle these
-events efficiently to ensure smooth text rendering without visible delays or
-flickering.
-
-| Property | Description |
-| ----------- | -------------------------------------- |
-| `messageId` | Matches the ID from `TextMessageStart` |
-| `delta` | Text content chunk (non-empty) |
-
-### TextMessageEnd
-
-Signals the end of a text message.
-
-The `TextMessageEnd` event marks the completion of a streaming text message.
-After receiving this event, the frontend knows that the message is complete and
-no further content will be added. This allows the UI to finalize rendering,
-remove any loading indicators, and potentially trigger actions that should occur
-after message completion, such as enabling reply controls or performing
-automatic scrolling to ensure the full message is visible.
-
-| Property | Description |
-| ----------- | -------------------------------------- |
-| `messageId` | Matches the ID from `TextMessageStart` |
-
-### TextMessageChunk
-
-Convenience event that expands to Start → Content → End automatically.
-
-The `TextMessageChunk` event lets you omit explicit `TextMessageStart` and
-`TextMessageEnd` events. The client stream transformer expands chunks into the
-standard triad:
-
-* First chunk for a message must include `messageId` and will emit
- `TextMessageStart` (role defaults to `assistant` when not provided).
-* Each chunk with a `delta` emits a `TextMessageContent` for the current
- `messageId`.
-* `TextMessageEnd` is emitted automatically when the stream switches to a new
- message ID or when the stream completes.
-
-| Property | Description |
-| ----------- | ------------------------------------------------------------------------------------ |
-| `messageId` | Optional unique identifier for the message; required on the first chunk of a message |
-| `role` | Optional role of the sender ("developer", "system", "assistant", "user") |
-| `delta` | Optional text content of the message |
-
-## Tool Call Events
-
-These events represent the lifecycle of tool calls made by agents. Tool calls
-follow a streaming pattern similar to text messages. When an agent needs to use
-a tool, it emits a `ToolCallStart` event, followed by one or more `ToolCallArgs`
-events that stream the arguments being passed to the tool, and concludes with a
-`ToolCallEnd` event.
-
-This streaming approach allows frontends to show tool executions in real-time,
-making the agent's actions transparent and providing immediate feedback about
-what tools are being invoked and with what parameters.
-
-```mermaid theme={null}
-sequenceDiagram
- participant Agent
- participant Client
-
- Note over Agent,Client: Tool call begins
- Agent->>Client: ToolCallStart
-
- loop Arguments streaming
- Agent->>Client: ToolCallArgs
- end
-
- Note over Agent,Client: Tool call completes
- Agent->>Client: ToolCallEnd
-
- Note over Agent,Client: Tool execution result
- Agent->>Client: ToolCallResult
-```
-
-The `ToolCallArgs` events each contain a `delta` field with a chunk of the
-arguments. Frontends should concatenate these deltas in the order received to
-construct the complete arguments object. The `toolCallId` property links all
-related events, allowing the frontend to associate argument chunks with the
-correct tool call.
-
-### ToolCallStart
-
-Signals the start of a tool call.
-
-The `ToolCallStart` event indicates that the agent is invoking a tool to perform
-a specific function. This event provides the name of the tool being called and
-establishes a unique `toolCallId` that will be referenced by subsequent events
-in this tool call. Frontends can use this event to display tool usage to users,
-such as showing a notification that a specific operation is in progress. The
-optional `parentMessageId` allows linking the tool call to a specific message in
-the conversation, providing context for why the tool is being used.
-
-| Property | Description |
-| ----------------- | ----------------------------------- |
-| `toolCallId` | Unique identifier for the tool call |
-| `toolCallName` | Name of the tool being called |
-| `parentMessageId` | Optional ID of the parent message |
-
-### ToolCallArgs
-
-Represents a chunk of argument data for a tool call.
-
-The `ToolCallArgs` event delivers incremental parts of the tool's arguments as
-they become available. Each event contains a segment of the argument data in the
-`delta` property. These deltas are often JSON fragments that, when combined,
-form the complete arguments object for the tool. Streaming the arguments is
-particularly valuable for complex tool calls where constructing the full
-arguments may take time. Frontends can progressively reveal these arguments to
-users, providing insight into exactly what parameters are being passed to tools.
-
-| Property | Description |
-| ------------ | ----------------------------------- |
-| `toolCallId` | Matches the ID from `ToolCallStart` |
-| `delta` | Argument data chunk |
-
-### ToolCallEnd
-
-Signals the end of a tool call.
-
-The `ToolCallEnd` event marks the completion of a tool call. After receiving
-this event, the frontend knows that all arguments have been transmitted and the
-tool execution is underway or completed. This allows the UI to finalize the tool
-call display and prepare for potential results. In systems where tool execution
-results are returned separately, this event indicates that the agent has
-finished specifying the tool and its arguments, and is now waiting for or has
-received the results.
-
-| Property | Description |
-| ------------ | ----------------------------------- |
-| `toolCallId` | Matches the ID from `ToolCallStart` |
-
-### ToolCallResult
-
-Provides the result of a tool call execution.
-
-The `ToolCallResult` event delivers the output or result from a tool that was
-previously invoked by the agent. This event is sent after the tool has been
-executed by the system and contains the actual output generated by the tool.
-Unlike the streaming pattern of tool call specification (start, args, end), the
-result is delivered as a complete unit since tool execution typically produces a
-complete output. Frontends can use this event to display tool results to users,
-append them to the conversation history, or trigger follow-up actions based on
-the tool's output.
-
-| Property | Description |
-| ------------ | ----------------------------------------------------------- |
-| `messageId` | ID of the conversation message this result belongs to |
-| `toolCallId` | Matches the ID from the corresponding `ToolCallStart` event |
-| `content` | The actual result/output content from the tool execution |
-| `role` | Optional role identifier, typically "tool" for tool results |
-
-### ToolCallChunk
-
-Convenience event that expands to Start → Args → End automatically.
-
-The `ToolCallChunk` event lets you omit explicit `ToolCallStart` and
-`ToolCallEnd` events. The client stream transformer expands chunks into the
-standard tool-call triad:
-
-* First chunk for a tool call must include `toolCallId` and `toolCallName` and
- will emit `ToolCallStart` (propagating any `parentMessageId`).
-* Each chunk with a `delta` emits a `ToolCallArgs` for the current `toolCallId`.
-* `ToolCallEnd` is emitted automatically when the stream switches to a new
- `toolCallId` or when the stream completes.
-
-| Property | Description |
-| ----------------- | -------------------------------------------------------------------- |
-| `toolCallId` | Optional on later chunks; required on the first chunk of a tool call |
-| `toolCallName` | Optional on later chunks; required on the first chunk of a tool call |
-| `parentMessageId` | Optional ID of the parent message |
-| `delta` | Optional argument data chunk (often a JSON fragment) |
-
-## State Management Events
-
-These events are used to manage and synchronize the agent's state with the
-frontend. State management in the protocol follows an efficient snapshot-delta
-pattern where complete state snapshots are sent initially or infrequently, while
-incremental updates (deltas) are used for ongoing changes.
-
-This approach optimizes for both completeness and efficiency: snapshots ensure
-the frontend has the full state context, while deltas minimize data transfer for
-frequent updates. Together, they enable frontends to maintain an accurate
-representation of agent state without unnecessary data transmission.
-
-```mermaid theme={null}
-sequenceDiagram
- participant Agent
- participant Client
-
- Note over Agent,Client: Initial state transfer
- Agent->>Client: StateSnapshot
-
- Note over Agent,Client: Incremental updates
- loop State changes over time
- Agent->>Client: StateDelta
- Agent->>Client: StateDelta
- end
-
- Note over Agent,Client: Occasional full refresh
- Agent->>Client: StateSnapshot
-
- loop More incremental updates
- Agent->>Client: StateDelta
- end
-
- Note over Agent,Client: Message history update
- Agent->>Client: MessagesSnapshot
-```
-
-The combination of snapshots and deltas allows frontends to efficiently track
-changes to agent state while ensuring consistency. Snapshots serve as
-synchronization points that reset the state to a known baseline, while deltas
-provide lightweight updates between snapshots.
-
-### StateSnapshot
-
-Provides a complete snapshot of an agent's state.
-
-The `StateSnapshot` event delivers a comprehensive representation of the agent's
-current state. This event is typically sent at the beginning of an interaction
-or when synchronization is needed. It contains all state variables relevant to
-the frontend, allowing it to completely rebuild its internal representation.
-Frontends should replace their existing state model with the contents of this
-snapshot rather than trying to merge it with previous state.
-
-| Property | Description |
-| ---------- | ----------------------- |
-| `snapshot` | Complete state snapshot |
-
-### StateDelta
-
-Provides a partial update to an agent's state using JSON Patch.
-
-The `StateDelta` event contains incremental updates to the agent's state in the
-form of JSON Patch operations (as defined in RFC 6902). Each delta represents
-specific changes to apply to the current state model. This approach is
-bandwidth-efficient, sending only what has changed rather than the entire state.
-Frontends should apply these patches in sequence to maintain an accurate state
-representation. If a frontend detects inconsistencies after applying patches, it
-may request a fresh `StateSnapshot`.
-
-| Property | Description |
-| -------- | ----------------------------------------- |
-| `delta` | Array of JSON Patch operations (RFC 6902) |
-
-### MessagesSnapshot
-
-Provides a snapshot of all messages in a conversation.
-
-The `MessagesSnapshot` event delivers a complete history of messages in the
-current conversation. Unlike the general state snapshot, this focuses
-specifically on the conversation transcript. This event is useful for
-initializing the chat history, synchronizing after connection interruptions, or
-providing a comprehensive view when a user joins an ongoing conversation.
-Frontends should use this to establish or refresh the conversational context
-displayed to users.
-
-| Property | Description |
-| ---------- | ------------------------ |
-| `messages` | Array of message objects |
-
-## Activity Events
-
-Activity Events expose structured, in-progress activity updates that occur
-between chat messages. They follow the same snapshot/delta pattern as the state
-system so that UIs can render a complete activity view immediately and then
-incrementally update it as new information arrives.
-
-### ActivitySnapshot
-
-Delivers a complete snapshot of an activity message.
-
-| Property | Description |
-| -------------- | --------------------------------------------------------------------------------------------- |
-| `messageId` | Identifier for the `ActivityMessage` this event updates |
-| `activityType` | Activity discriminator (for example `"PLAN"`, `"SEARCH"`) |
-| `content` | Structured JSON payload representing the full activity state |
-| `replace` | Optional. Defaults to `true`. When `false`, ignore the snapshot if the message already exists |
-
-Frontends should either create a new `ActivityMessage` or replace the existing
-one with the payload supplied by the snapshot.
-
-### ActivityDelta
-
-Applies incremental updates to an existing activity using JSON Patch operations.
-
-| Property | Description |
-| -------------- | ------------------------------------------------------------------------ |
-| `messageId` | Identifier for the target activity message |
-| `activityType` | Activity discriminator (mirrors the value from the most recent snapshot) |
-| `patch` | Array of RFC 6902 JSON Patch operations to apply to the activity data |
-
-Activity deltas should be applied in order to the previously synchronized
-activity content. If an application detects divergence, it can request or emit a
-fresh `ActivitySnapshot` to resynchronize.
-
-## Special Events
-
-Special events provide flexibility in the protocol by allowing for
-system-specific functionality and integration with external systems. These
-events don't follow the standard lifecycle or streaming patterns of other event
-types but instead serve specialized purposes.
-
-### Raw
-
-Used to pass through events from external systems.
-
-The `Raw` event acts as a container for events originating from external systems
-or sources that don't natively follow the Agent UI Protocol. This event type
-enables interoperability with other event-based systems by wrapping their events
-in a standardized format. The enclosed event data is preserved in its original
-form inside the `event` property, while the optional `source` property
-identifies the system it came from. Frontends can use this information to handle
-external events appropriately, either by processing them directly or by
-delegating them to system-specific handlers.
-
-| Property | Description |
-| -------- | -------------------------- |
-| `event` | Original event data |
-| `source` | Optional source identifier |
-
-### Custom
-
-Used for application-specific custom events.
-
-The `Custom` event provides an extension mechanism for implementing features not
-covered by the standard event types. Unlike `Raw` events which act as
-passthrough containers, `Custom` events are explicitly part of the protocol but
-with application-defined semantics. The `name` property identifies the specific
-custom event type, while the `value` property contains the associated data. This
-mechanism allows for protocol extensions without requiring formal specification
-changes. Teams should document their custom events to ensure consistent
-implementation across frontends and agents.
-
-| Property | Description |
-| -------- | ------------------------------- |
-| `name` | Name of the custom event |
-| `value` | Value associated with the event |
-
-## Reasoning Events
-
-Reasoning events support LLM reasoning visibility and continuity, enabling
-chain-of-thought reasoning while maintaining privacy. These events allow agents
-to surface reasoning signals (e.g., summaries) and support encrypted reasoning
-items for state carry-over across turns—especially under `store:false` or zero
-data retention policies—without exposing raw chain-of-thought.
-
-See
-[OpenAI ZTR documentation](https://developers.openai.com/cookbook/examples/responses_api/reasoning_items/#encrypted-reasoning-items),
-[OpenAI store parameter documentation](https://platform.openai.com/docs/api-reference/responses/create#responses_create-store),
-and
-[Gemini Thought Signatures](https://ai.google.dev/gemini-api/docs/thought-signatures)
-for the underlying concept of encrypted reasoning items, which inspired this
-design.
-
-See [Reasoning](/concepts/reasoning) for comprehensive documentation including
-privacy considerations, compliance guidance, and implementation examples.
-
-```mermaid theme={null}
-sequenceDiagram
- participant Agent
- participant Client
-
- Note over Agent,Client: Reasoning begins
- Agent->>Client: ReasoningStart
-
- Note over Agent,Client: Stream reasoning content
- Agent->>Client: ReasoningMessageStart
- Agent->>Client: ReasoningMessageContent
- Agent->>Client: ReasoningMessageEnd
-
- Note over Agent,Client: Reasoning completes
- Agent->>Client: ReasoningEnd
-```
-
-### ReasoningStart
-
-Marks the start of reasoning.
-
-The `ReasoningStart` event signals that the agent is beginning a reasoning
-process. It establishes a reasoning context identified by a unique `messageId`.
-
-| Property | Description |
-| ----------- | ----------------------------------- |
-| `messageId` | Unique identifier of this reasoning |
-
-### ReasoningMessageStart
-
-Signals the start of a reasoning message.
-
-The `ReasoningMessageStart` event begins a streaming reasoning message. This
-message will contain the visible portion of the agent's reasoning that should be
-displayed to users (e.g., a summary or partial chain-of-thought).
-
-| Property | Description |
-| ----------- | --------------------------------------------- |
-| `messageId` | Unique identifier of the message |
-| `role` | Role of the reasoning message (`"assistant"`) |
-
-### ReasoningMessageContent
-
-Represents a chunk of content in a streaming reasoning message.
-
-The `ReasoningMessageContent` event delivers incremental reasoning content to
-the client. Multiple content events with the same `messageId` should be
-concatenated to form the complete visible reasoning.
-
-| Property | Description |
-| ----------- | ------------------------------------------ |
-| `messageId` | Matches ID from ReasoningMessageStart |
-| `delta` | Reasoning content chunk (non-empty string) |
-
-### ReasoningMessageEnd
-
-Signals the end of a reasoning message.
-
-The `ReasoningMessageEnd` event indicates that all content for the specified
-reasoning message has been sent. Clients should finalize any UI representing
-this reasoning message.
-
-| Property | Description |
-| ----------- | ------------------------------------- |
-| `messageId` | Matches ID from ReasoningMessageStart |
-
-### ReasoningMessageChunk
-
-A convenience event to auto start/close reasoning messages.
-
-The `ReasoningMessageChunk` event simplifies implementation by automatically
-managing message lifecycle. The first chunk with a `messageId` implicitly starts
-the message. An empty `delta` or the next non-reasoning event implicitly closes
-the message.
-
-| Property | Description |
-| ----------- | --------------------------------------------------------- |
-| `messageId` | Message ID (first event must be non-empty) |
-| `delta` | Reasoning content chunk (empty string closes the message) |
-
-### ReasoningEnd
-
-Marks the end of reasoning.
-
-The `ReasoningEnd` event signals that the agent has completed its reasoning
-process for the given context. No further reasoning events with the same
-`messageId` should be expected after this event.
-
-| Property | Description |
-| ----------- | ----------------------------------- |
-| `messageId` | Unique identifier of this reasoning |
-
-### ReasoningEncryptedValue
-
-Attaches encrypted chain-of-thought reasoning to a message or tool call.
-
-The `ReasoningEncryptedValue` event carries encrypted reasoning content that
-represents the LLM's internal chain-of-thought related to a specific entity.
-This allows the agent to preserve reasoning state across conversation turns
-without exposing the raw content to the client. The client stores and forwards
-these encrypted values opaquely—only the agent (or authorized backend) can
-decrypt them.
-
-| Property | Description |
-| ---------------- | -------------------------------------------------------- |
-| `subtype` | Entity type: `"message"` or `"tool-call"` |
-| `entityId` | ID of the message or tool call this reasoning belongs to |
-| `encryptedValue` | Encrypted chain-of-thought content blob |
-
-Use cases:
-
-* **Message reasoning**: Attach encrypted reasoning to an `AssistantMessage` or
- `ReasoningMessage` to preserve context for follow-up turns
-* **Tool call reasoning**: Attach encrypted reasoning to a tool call to capture
- why the agent chose specific arguments or how it interpreted results
-
-## Deprecated Events
-
-
- The following events are deprecated and will be removed in version 1.0.0. Use
- the corresponding Reasoning events instead.
-
-
-### Thinking Events (Deprecated)
-
-The `THINKING_*` events have been replaced by `REASONING_*` events:
-
-| Deprecated Event | Replacement |
-| ------------------------------- | --------------------------- |
-| `THINKING_START` | `REASONING_START` |
-| `THINKING_END` | `REASONING_END` |
-| `THINKING_TEXT_MESSAGE_START` | `REASONING_MESSAGE_START` |
-| `THINKING_TEXT_MESSAGE_CONTENT` | `REASONING_MESSAGE_CONTENT` |
-| `THINKING_TEXT_MESSAGE_END` | `REASONING_MESSAGE_END` |
-
-See [Reasoning Migration](/concepts/reasoning#migration-from-thinking-events)
-for detailed migration guidance.
-
-## Draft Events
-
-These events are currently in draft status and may change before finalization.
-They represent proposed extensions to the protocol that are under active
-development and discussion.
-
-### Meta Events
-
-
- DRAFT
-
-
-[View Proposal](/drafts/meta-events)
-
-Meta events provide annotations and signals independent of agent runs, such as
-user feedback or external system events.
-
-#### MetaEvent
-
-A side-band annotation event that can occur anywhere in the stream.
-
-| Property | Description |
-| ---------- | ---------------------------------------------------- |
-| `metaType` | Application-defined type (e.g., "thumbs\_up", "tag") |
-| `payload` | Application-defined payload |
-
-### Modified Lifecycle Events
-
-
- DRAFT
-
-
-[View Proposal](/drafts/interrupts)
-
-Extensions to existing lifecycle events to support interrupts and branching.
-
-#### RunFinished (Extended)
-
-The `RunFinished` event gains new fields to support interrupt-aware workflows.
-
-| Property | Description |
-| ----------- | ------------------------------------------------ |
-| `outcome` | Optional: "success" or "interrupt" |
-| `interrupt` | Optional: Contains interrupt details when paused |
-
-See [Serialization](/concepts/serialization) for lineage and input capture.
-
-#### RunStarted (Extended)
-
-The `RunStarted` event gains new fields to support branching and input tracking.
-
-| Property | Description |
-| ------------- | ------------------------------------------------- |
-| `parentRunId` | Optional: Parent run ID for branching/time travel |
-| `input` | Optional: The exact agent input for this run |
-
-## Event Flow Patterns
-
-Events in the protocol typically follow specific patterns:
-
-1. **Start-Content-End Pattern**: Used for streaming content (text messages,
- tool calls)
- * `Start` event initiates the stream
- * `Content` events deliver data chunks
- * `End` event signals completion
-
-2. **Snapshot-Delta Pattern**: Used for state synchronization
- * `Snapshot` provides complete state
- * `Delta` events provide incremental updates
-
-3. **Lifecycle Pattern**: Used for monitoring agent runs
- * `Started` events signal beginnings
- * `Finished`/`Error` events signal endings
-
-## Implementation Considerations
-
-When implementing event handlers:
-
-* Events should be processed in the order they are received
-* Events with the same ID (e.g., `messageId`, `toolCallId`) belong to the same
- logical stream
-* Implementations should be resilient to out-of-order delivery
-* Custom events should follow the established patterns for consistency
-
-
-# Generative UI
-Source: https://docs.ag-ui.com/concepts/generative-ui-specs
-
-Understanding AG-UI's relationship with generative UI specifications
-
-## **AG-UI and Generative UI Specs**
-
-Several recently released specs have enabled agents to return generative UI, increasing the power and flexibility of the Agent\<->User conversation.
-
-A2UI, MCP-UI, and Open-JSON-UI are all **generative UI specifications.** Generative UIs allow agents to respond to users not only with text but also with dynamic UI components.
-
-| **Specification** | **Origin / Maintainer** | **Purpose** |
-| ----------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------- |
-| **A2UI** | Google | A declarative, LLM-friendly Generative UI spec. JSONL-based and streaming, designed for platform-agnostic rendering. |
-| **Open-JSON-UI** | OpenAI | An open standardization of OpenAI's internal declarative Generative UI schema. |
-| **MCP-UI** | Microsoft + Shopify | A fully open, iframe-based Generative UI standard extending MCP for user-facing experiences. |
-
-Despite the naming similarities, **AG-UI is not a generative UI specification** — it's a **User Interaction protocol** that provides the **bi-directional runtime connection** between the agent and the application.
-
-AG-UI natively supports all of the above generative UI specs and allows developers to define **their own custom generative UI standards** as well.
-
-
-# Messages
-Source: https://docs.ag-ui.com/concepts/messages
-
-Understanding message structure and communication in AG-UI
-
-# Messages
-
-Messages form the backbone of communication in the AG-UI protocol. They
-represent the conversation history between users and AI agents, and provide a
-standardized way to exchange information regardless of the underlying AI service
-being used.
-
-## Message Structure
-
-AG-UI messages follow a vendor-neutral format, ensuring compatibility across
-different AI providers while maintaining a consistent structure. This allows
-applications to switch between AI services (like OpenAI, Anthropic, or custom
-models) without changing the client-side implementation.
-
-The basic message structure includes:
-
-```typescript theme={null}
-interface BaseMessage {
- id: string // Unique identifier for the message
- role: string // The role of the sender (user, assistant, system, tool, reasoning)
- content?: string // Optional text content of the message
- name?: string // Optional name of the sender
- encryptedContent?: string // Optional encrypted content for privacy-preserving state continuity
-}
-```
-
-The `role` discriminator can be `"user"`, `"assistant"`, `"system"`, `"tool"`,
-`"developer"`, `"activity"`, or `"reasoning"`. Concrete message types extend
-this shape with the fields they need.
-
-> The `encryptedContent` field enables privacy-preserving workflows where
-> sensitive content (such as reasoning chains) can be passed across turns
-> without exposing the raw content. This is particularly useful for zero data
-> retention (ZDR) compliance and `store:false` scenarios.
-
-## Message Types
-
-AG-UI supports several message types to accommodate different participants in a
-conversation:
-
-### User Messages
-
-Messages from the end user to the agent:
-
-```typescript theme={null}
-interface UserMessage {
- id: string
- role: "user"
- content: string | InputContent[] // Text or multimodal input from the user
- name?: string // Optional user identifier
-}
-
-type InputContent = TextInputContent | BinaryInputContent
-
-interface TextInputContent {
- type: "text"
- text: string
-}
-
-interface BinaryInputContent {
- type: "binary"
- mimeType: string
- id?: string
- url?: string
- data?: string
- filename?: string
-}
-```
-
-> For `BinaryInputContent`, provide at least one of `id`, `url`, or `data` to
-> reference the payload.
-
-This structure keeps traditional plain-text inputs working while enabling richer
-payloads such as images, audio clips, or uploaded files in the same message.
-
-### Assistant Messages
-
-Messages from the AI assistant to the user:
-
-```typescript theme={null}
-interface AssistantMessage {
- id: string
- role: "assistant"
- content?: string // Text response from the assistant (optional if using tool calls)
- name?: string // Optional assistant identifier
- toolCalls?: ToolCall[] // Optional tool calls made by the assistant
- encryptedContent?: string // Optional encrypted content for state continuity
-}
-```
-
-### System Messages
-
-Instructions or context provided to the agent:
-
-```typescript theme={null}
-interface SystemMessage {
- id: string
- role: "system"
- content: string // Instructions or context for the agent
- name?: string // Optional identifier
-}
-```
-
-### Tool Messages
-
-Results from tool executions:
-
-```typescript theme={null}
-interface ToolMessage {
- id: string
- role: "tool"
- content: string // Result from the tool execution
- toolCallId: string // ID of the tool call this message responds to
- error?: string // Optional error message if the tool execution failed
- encryptedValue?: string // Optional encrypted reasoning for state continuity
-}
-```
-
-Key points:
-
-* The `toolCallId` links the result back to the original tool call
-* Use `error` to indicate tool execution failures
-* Use `encryptedValue` to attach encrypted chain-of-thought related to how the
- agent interpreted or processed the tool result
-
-### Activity Messages
-
-Structured UI messages that exist only on the frontend. Used for progress,
-status, or any custom visual element that shouldn’t be sent to the model:
-
-```typescript theme={null}
-interface ActivityMessage {
- id: string
- role: "activity"
- activityType: string // e.g. "PLAN", "SEARCH", "SCRAPE"
- content: Record // Structured payload rendered by the frontend
-}
-```
-
-Key points
-
-* Emitted via `ACTIVITY_SNAPSHOT` and `ACTIVITY_DELTA` to support live,
- updateable UI (checklists, steps, search-in-progress, etc.).
-* **Frontend-only:** never forwarded to the agent, so no filtering and no LLM
- confusion.
-* **Customizable:** define your own `activityType` and `content` and render a
- matching UI component.
-* **Streamable:** can be updated over time for long-running operations.
-* Helps persist/restore custom events by turning them into durable message
- objects.
-
-### Developer Messages
-
-Internal messages used for development or debugging:
-
-```typescript theme={null}
-interface DeveloperMessage {
- id: string
- role: "developer"
- content: string
- name?: string
-}
-```
-
-### Reasoning Messages
-
-Messages representing the agent's internal reasoning or chain-of-thought
-process:
-
-```typescript theme={null}
-interface ReasoningMessage {
- id: string
- role: "reasoning"
- content: string // Reasoning content (visible to client)
- encryptedValue?: string // Optional encrypted reasoning for state continuity
-}
-```
-
-
- Unlike Activity messages, Reasoning messages are intended to represent the
- agent's internal thought process and may be encrypted for privacy and are
- meant to be sent back to the agent for further processing on subsequent turns.
-
-
-Key points:
-
-* Emitted via `REASONING_MESSAGE_START`, `REASONING_MESSAGE_CONTENT`, and
- `REASONING_MESSAGE_END` events.
-* **Visibility control:** Content may be visible to users (as a summary) or
- fully encrypted.
-* **Encrypted values:** Use `REASONING_ENCRYPTED_VALUE` events to attach
- encrypted chain-of-thought to messages or tool calls without exposing content.
-* **State continuity:** Encrypted reasoning items can be passed across
- conversation turns without exposing raw chain-of-thought.
-* **Privacy-first:** Supports `store:false` and zero data retention (ZDR)
- policies while preserving reasoning capabilities.
-* **Separate from assistant messages:** Reasoning is kept distinct from final
- responses to avoid polluting the conversation history.
-
-See [Reasoning Events](/concepts/events#reasoning-events) for the streaming
-event lifecycle.
-
-## Vendor Neutrality
-
-AG-UI messages are designed to be vendor-neutral, meaning they can be easily
-mapped to and from proprietary formats used by various AI providers:
-
-```typescript theme={null}
-// Example: Converting AG-UI messages to OpenAI format
-const openaiMessages = agUiMessages
- .filter((msg) => ["user", "system", "assistant"].includes(msg.role))
- .map((msg) => ({
- role: msg.role as "user" | "system" | "assistant",
- content: msg.content || "",
- // Map tool calls if present
- ...(msg.role === "assistant" && msg.toolCalls
- ? {
- tool_calls: msg.toolCalls.map((tc) => ({
- id: tc.id,
- type: tc.type,
- function: {
- name: tc.function.name,
- arguments: tc.function.arguments,
- },
- })),
- }
- : {}),
- }))
-```
-
-This abstraction allows AG-UI to serve as a common interface regardless of the
-underlying AI service.
-
-## Message Synchronization
-
-Messages can be synchronized between client and server through two primary
-mechanisms:
-
-### Complete Snapshots
-
-The `MESSAGES_SNAPSHOT` event provides a complete view of all messages in a
-conversation:
-
-```typescript theme={null}
-interface MessagesSnapshotEvent {
- type: EventType.MESSAGES_SNAPSHOT
- messages: Message[] // Complete array of all messages
-}
-```
-
-This is typically used:
-
-* When initializing a conversation
-* After connection interruptions
-* When major state changes occur
-* To ensure client-server synchronization
-
-### Streaming Messages
-
-For real-time interactions, new messages can be streamed as they're generated:
-
-1. **Start a message**: Indicate a new message is being created
-
- ```typescript theme={null}
- interface TextMessageStartEvent {
- type: EventType.TEXT_MESSAGE_START
- messageId: string
- role: string
- }
- ```
-
-2. **Stream content**: Send content chunks as they become available
-
- ```typescript theme={null}
- interface TextMessageContentEvent {
- type: EventType.TEXT_MESSAGE_CONTENT
- messageId: string
- delta: string // Text chunk to append
- }
- ```
-
-3. **End a message**: Signal the message is complete
- ```typescript theme={null}
- interface TextMessageEndEvent {
- type: EventType.TEXT_MESSAGE_END
- messageId: string
- }
- ```
-
-This streaming approach provides a responsive user experience with immediate
-feedback.
-
-## Tool Integration in Messages
-
-AG-UI messages elegantly integrate tool usage, allowing agents to perform
-actions and process their results:
-
-### Tool Calls
-
-Tool calls are embedded within assistant messages:
-
-```typescript theme={null}
-interface ToolCall {
- id: string // Unique ID for this tool call
- type: "function" // Type of tool call
- function: {
- name: string // Name of the function to call
- arguments: string // JSON-encoded string of arguments
- }
-}
-```
-
-Example assistant message with tool calls:
-
-```typescript theme={null}
-{
- id: "msg_123",
- role: "assistant",
- content: "I'll help you with that calculation.",
- toolCalls: [
- {
- id: "call_456",
- type: "function",
- function: {
- name: "calculate",
- arguments: '{"expression": "24 * 7"}'
- }
- }
- ]
-}
-```
-
-### Tool Results
-
-Results from tool executions are represented as tool messages:
-
-```typescript theme={null}
-{
- id: "result_789",
- role: "tool",
- content: "168",
- toolCallId: "call_456" // References the original tool call
-}
-```
-
-This creates a clear chain of tool usage:
-
-1. Assistant requests a tool call
-2. Tool executes and returns a result
-3. Assistant can reference and respond to the result
-
-## Streaming Tool Calls
-
-Similar to text messages, tool calls can be streamed to provide real-time
-visibility into the agent's actions:
-
-1. **Start a tool call**:
-
- ```typescript theme={null}
- interface ToolCallStartEvent {
- type: EventType.TOOL_CALL_START
- toolCallId: string
- toolCallName: string
- parentMessageId?: string // Optional link to parent message
- }
- ```
-
-2. **Stream arguments**:
-
- ```typescript theme={null}
- interface ToolCallArgsEvent {
- type: EventType.TOOL_CALL_ARGS
- toolCallId: string
- delta: string // JSON fragment to append to arguments
- }
- ```
-
-3. **End a tool call**:
- ```typescript theme={null}
- interface ToolCallEndEvent {
- type: EventType.TOOL_CALL_END
- toolCallId: string
- }
- ```
-
-This allows frontends to show tools being invoked progressively as the agent
-constructs its reasoning.
-
-## Practical Example
-
-Here's a complete example of a conversation with tool usage:
-
-```typescript theme={null}
-// Conversation history
-;[
- // User query
- {
- id: "msg_1",
- role: "user",
- content: "What's the weather in New York?",
- },
-
- // Assistant response with tool call
- {
- id: "msg_2",
- role: "assistant",
- content: "Let me check the weather for you.",
- toolCalls: [
- {
- id: "call_1",
- type: "function",
- function: {
- name: "get_weather",
- arguments: '{"location": "New York", "unit": "celsius"}',
- },
- },
- ],
- },
-
- // Tool result
- {
- id: "result_1",
- role: "tool",
- content:
- '{"temperature": 22, "condition": "Partly Cloudy", "humidity": 65}',
- toolCallId: "call_1",
- },
-
- // Assistant's final response using tool results
- {
- id: "msg_3",
- role: "assistant",
- content:
- "The weather in New York is partly cloudy with a temperature of 22°C and 65% humidity.",
- },
-]
-```
-
-## Conclusion
-
-The message structure in AG-UI enables sophisticated conversational AI
-experiences while maintaining vendor neutrality. By standardizing how messages
-are represented, synchronized, and streamed, AG-UI provides a consistent way to
-implement interactive human-agent communication regardless of the underlying AI
-service.
-
-This system supports everything from simple text exchanges to complex tool-based
-workflows, all while optimizing for both real-time responsiveness and efficient
-data transfer.
-
-
-# Middleware
-Source: https://docs.ag-ui.com/concepts/middleware
-
-Transform and intercept events in AG-UI agents
-
-# Middleware
-
-Middleware in AG-UI provides a powerful way to transform, filter, and augment the event streams that flow through agents. It enables you to add cross-cutting concerns like logging, authentication, rate limiting, and event filtering without modifying the core agent logic.
-
-Examples below assume the relevant RxJS operators/utilities (`map`, `tap`, `catchError`, `switchMap`, `timer`, etc.) are imported.
-
-## What is Middleware?
-
-Middleware sits between the agent execution and the event consumer, allowing you to:
-
-1. **Transform events** – Modify or enhance events as they flow through the pipeline
-2. **Filter events** – Selectively allow or block certain events
-3. **Add metadata** – Inject additional context or tracking information
-4. **Handle errors** – Implement custom error recovery strategies
-5. **Monitor execution** – Add logging, metrics, or debugging capabilities
-
-## How Middleware Works
-
-Middleware forms a chain where each middleware wraps the next, creating layers of functionality. When an agent runs, the event stream flows through each middleware in sequence.
-
-```typescript theme={null}
-import { AbstractAgent } from "@ag-ui/client"
-
-const agent = new MyAgent()
-
-// Middleware chain: logging -> auth -> filter -> agent
-agent.use(loggingMiddleware, authMiddleware, filterMiddleware)
-
-// When agent runs, events flow through all middleware
-await agent.runAgent()
-```
-
-Middleware added with `agent.use(...)` is applied in `runAgent()`. `connectAgent()` currently calls `connect()` directly and does not run middleware.
-
-## Function-Based Middleware
-
-For simple transformations, you can use function-based middleware. This is the most concise way to add middleware:
-
-```typescript theme={null}
-import { MiddlewareFunction } from "@ag-ui/client"
-import { EventType } from "@ag-ui/core"
-
-const prefixMiddleware: MiddlewareFunction = (input, next) => {
- return next.run(input).pipe(
- map(event => {
- if (
- event.type === EventType.TEXT_MESSAGE_CHUNK ||
- event.type === EventType.TEXT_MESSAGE_CONTENT
- ) {
- return {
- ...event,
- delta: `[AI]: ${event.delta}`
- }
- }
- return event
- })
- )
-}
-
-agent.use(prefixMiddleware)
-```
-
-## Class-Based Middleware
-
-For more complex scenarios requiring state or configuration, use class-based middleware:
-
-```typescript theme={null}
-import { Middleware } from "@ag-ui/client"
-import { Observable } from "rxjs"
-import { tap } from "rxjs/operators"
-
-class MetricsMiddleware extends Middleware {
- private eventCount = 0
-
- constructor(private metricsService: MetricsService) {
- super()
- }
-
- run(input: RunAgentInput, next: AbstractAgent): Observable {
- const startTime = Date.now()
-
- return this.runNext(input, next).pipe(
- tap(event => {
- this.eventCount++
- this.metricsService.recordEvent(event.type)
- }),
- finalize(() => {
- const duration = Date.now() - startTime
- this.metricsService.recordDuration(duration)
- this.metricsService.recordEventCount(this.eventCount)
- })
- )
- }
-}
-
-agent.use(new MetricsMiddleware(metricsService))
-```
-
-If you are writing class middleware, prefer the helper methods:
-
-* `runNext(input, next)` normalizes chunk events into full `TEXT_MESSAGE_*`/`TOOL_CALL_*` sequences.
-* `runNextWithState(input, next)` also provides accumulated `messages` and `state` after each event.
-
-## Built-in Middleware
-
-AG-UI provides several built-in middleware components for common use cases:
-
-### FilterToolCallsMiddleware
-
-Filter tool calls based on allowed or disallowed lists:
-
-```typescript theme={null}
-import { FilterToolCallsMiddleware } from "@ag-ui/client"
-
-// Only allow specific tools
-const allowedFilter = new FilterToolCallsMiddleware({
- allowedToolCalls: ["search", "calculate"]
-})
-
-// Or block specific tools
-const blockedFilter = new FilterToolCallsMiddleware({
- disallowedToolCalls: ["delete", "modify"]
-})
-
-agent.use(allowedFilter)
-```
-
-`FilterToolCallsMiddleware` filters emitted `TOOL_CALL_*` events. It does not block tool execution in the upstream model/runtime.
-
-## Middleware Patterns
-
-Common patterns include logging, auth via `forwardedProps`, and rate limiting. See the [JS middleware reference](/sdk/js/client/middleware) for concrete implementations.
-
-## Combining Middleware
-
-You can combine multiple middleware to create sophisticated processing pipelines:
-
-```typescript theme={null}
-const logMiddleware: MiddlewareFunction = (input, next) => next.run(input)
-const metricsMiddleware = new MetricsMiddleware(metricsService)
-const filterMiddleware = new FilterToolCallsMiddleware({ allowedToolCalls: ["search"] })
-
-agent.use(logMiddleware, metricsMiddleware, filterMiddleware)
-```
-
-## Execution Order
-
-Middleware executes in the order it's added, with each middleware wrapping the next:
-
-1. First middleware receives the original input
-2. It can modify the input before passing to the next middleware
-3. Each middleware processes events from the next in the chain
-4. The final middleware calls the actual agent
-
-```typescript theme={null}
-agent.use(middleware1, middleware2, middleware3)
-
-// Execution flow:
-// → middleware1
-// → middleware2
-// → middleware3
-// → agent.run()
-// ← events flow back through middleware3
-// ← events flow back through middleware2
-// ← events flow back through middleware1
-```
-
-## Best Practices
-
-1. **Keep middleware focused** – Each middleware should have a single responsibility
-2. **Handle errors gracefully** – Use RxJS error handling operators
-3. **Avoid blocking operations** – Use async patterns for I/O operations
-4. **Document side effects** – Clearly indicate if middleware modifies state
-5. **Test middleware independently** – Write unit tests for each middleware
-6. **Consider performance** – Be mindful of processing overhead in the event stream
-
-## Advanced Use Cases
-
-### Conditional Middleware
-
-Apply middleware based on runtime conditions:
-
-```typescript theme={null}
-const conditionalMiddleware: MiddlewareFunction = (input, next) => {
- if (input.forwardedProps?.debug === true) {
- // Apply debug logging
- return next.run(input).pipe(
- tap(event => console.debug(event))
- )
- }
- return next.run(input)
-}
-```
-
-For event transformation and stream-control variants, see the [JS middleware reference](/sdk/js/client/middleware).
-
-## Conclusion
-
-Middleware provides a flexible and powerful way to extend AG-UI agents without modifying their core logic. Whether you need simple event transformation or complex stateful processing, the middleware system offers the tools to build robust, maintainable agent applications.
-
-
-# Reasoning
-Source: https://docs.ag-ui.com/concepts/reasoning
-
-Support for LLM reasoning visibility and continuity in AG-UI
-
-# Reasoning
-
-AG-UI provides first-class support for LLM reasoning, enabling chain-of-thought
-visibility while maintaining privacy and state continuity across conversation
-turns.
-
-## Overview
-
-Modern LLMs increasingly use chain-of-thought reasoning to improve response
-quality. AG-UI's reasoning support addresses three key challenges:
-
-* **Reasoning visibility**: Surface reasoning signals (e.g., summaries) to users
- without exposing raw chain-of-thought
-* **State continuity**: Maintain reasoning context across turns using encrypted
- reasoning items, even under `store:false` or zero data retention (ZDR)
- policies
-* **Privacy compliance**: Support enterprise privacy requirements while
- preserving reasoning capabilities
-
-
- Unlike Activity messages, Reasoning messages are intended to represent the
- agent's internal thought process and may be encrypted for privacy and are
- meant to be sent back to the agent for further processing on subsequent turns.
-
-
-## ReasoningMessage
-
-The `ReasoningMessage` type represents reasoning content in the message history:
-
-```typescript theme={null}
-interface ReasoningMessage {
- id: string
- role: "reasoning"
- content: string // Reasoning content (visible to client)
- encryptedValue?: string // Optional encrypted reasoning for state continuity
-}
-```
-
-| Property | Type | Description |
-| ---------------- | ------------- | ---------------------------------------------------- |
-| `id` | `string` | Unique identifier for the reasoning message |
-| `role` | `"reasoning"` | Message role discriminator |
-| `content` | `string` | Reasoning content visible to the client |
-| `encryptedValue` | `string?` | Encrypted chain-of-thought blob for state continuity |
-
-Key characteristics:
-
-* **Separate from assistant messages**: Reasoning is kept distinct from final
- responses to avoid polluting conversation history
-* **Streamable**: Content arrives via streaming events
-* **Optional encryption**: When `encryptedValue` is present, it represents
- encrypted chain-of-thought that the client stores and forwards opaquely
-
-## Reasoning Events
-
-Reasoning events manage the lifecycle of reasoning messages. See
-[Events](/concepts/events#reasoning-events) for the complete event reference.
-
-### Event Flow
-
-A typical reasoning flow follows this pattern:
-
-```mermaid theme={null}
-sequenceDiagram
- participant Agent
- participant Client
-
- Note over Agent,Client: Reasoning begins
- Agent->>Client: ReasoningStart
-
- Note over Agent,Client: Stream visible reasoning
- Agent->>Client: ReasoningMessageStart
- Agent->>Client: ReasoningMessageContent (delta)
- Agent->>Client: ReasoningMessageContent (delta)
- Agent->>Client: ReasoningMessageEnd
-
- Note over Agent,Client: Attach encrypted chain-of-thought
- Agent->>Client: ReasoningEncryptedValue
-
- Note over Agent,Client: Reasoning completes
- Agent->>Client: ReasoningEnd
-```
-
-### Event Types
-
-| Event | Purpose |
-| ------------------------- | ------------------------------------------------------------- |
-| `ReasoningStart` | Marks beginning of reasoning phase |
-| `ReasoningMessageStart` | Begins a streaming reasoning message |
-| `ReasoningMessageContent` | Delivers reasoning content chunks |
-| `ReasoningMessageEnd` | Completes a reasoning message |
-| `ReasoningMessageChunk` | Convenience event that auto-manages message lifecycle |
-| `ReasoningEnd` | Marks completion of reasoning |
-| `ReasoningEncryptedValue` | Attaches encrypted chain-of-thought to a message or tool call |
-
-## Privacy and Compliance
-
-AG-UI reasoning is designed with privacy-first principles:
-
-### Zero Data Retention (ZDR)
-
-For deployments requiring zero data retention:
-
-1. **Encrypted reasoning values** can carry state across turns without storing
- decryptable content on the client
-2. The client receives and forwards `encryptedValue` blobs opaquely via
- `ReasoningEncryptedValue` events
-3. Only the agent (or authorized backend) can decrypt the reasoning content
-
-### Visibility Control
-
-Agents control what reasoning is visible to users:
-
-* **Full visibility**: Stream the complete chain-of-thought via
- `ReasoningMessageContent` events
-* **Summary only**: Emit a condensed summary while attaching detailed reasoning
- as encrypted values
-* **Hidden**: Use only `ReasoningEncryptedValue` events with no visible
- streaming
-
-### Compliance Considerations
-
-| Requirement | Solution |
-| ----------------------- | ----------------------------------------------------------------------------------- |
-| GDPR right to erasure | Encrypted content can be discarded without losing reasoning capability |
-| SOC 2 data handling | Reasoning content never stored in plaintext on client |
-| HIPAA minimum necessary | Only summaries exposed; detailed reasoning stays encrypted |
-| Audit logging | `ReasoningStart`/`ReasoningEnd` events provide audit trail without content exposure |
-
-## Example Implementations
-
-### Basic Reasoning Flow
-
-A simple implementation showing visible reasoning:
-
-```typescript theme={null}
-// Agent emits reasoning start
-yield {
- type: "REASONING_START",
- messageId: "reasoning-001",
-}
-
-// Stream visible reasoning content
-yield {
- type: "REASONING_MESSAGE_START",
- messageId: "msg-123",
- role: "assistant",
-}
-
-yield {
- type: "REASONING_MESSAGE_CONTENT",
- messageId: "msg-123",
- delta: "Let me ",
-}
-
-yield {
- type: "REASONING_MESSAGE_CONTENT",
- messageId: "msg-123",
- delta: "think through ",
-}
-
-yield {
- type: "REASONING_MESSAGE_CONTENT",
- messageId: "msg-123",
- delta: "this step ",
-}
-
-yield {
- type: "REASONING_MESSAGE_CONTENT",
- messageId: "msg-123",
- delta: "by step...",
-}
-
-yield {
- type: "REASONING_MESSAGE_END",
- messageId: "msg-123",
-}
-
-// End reasoning
-yield {
- type: "REASONING_END",
- messageId: "reasoning-001",
-}
-```
-
-### Encrypted Content for State Continuity
-
-When maintaining reasoning state across turns without exposing content, use the
-`ReasoningEncryptedValue` event to attach encrypted chain-of-thought to messages
-or tool calls:
-
-```typescript theme={null}
-// Agent emits reasoning start
-yield {
- type: "REASONING_START",
- messageId: "reasoning-002",
-}
-
-// Stream a visible summary for the user
-yield {
- type: "REASONING_MESSAGE_START",
- messageId: "msg-456",
- role: "assistant",
-}
-
-yield {
- type: "REASONING_MESSAGE_CONTENT",
- messageId: "msg-456",
- delta: "Analyzing your request...",
-}
-
-yield {
- type: "REASONING_MESSAGE_END",
- messageId: "msg-456",
-}
-
-// Attach encrypted chain-of-thought to the reasoning message
-yield {
- type: "REASONING_ENCRYPTED_VALUE",
- subtype: "message",
- entityId: "msg-456",
- encryptedValue: "eyJhbGciOiJBMjU2R0NNIiwiZW5jIjoiQTI1NkdDTSJ9...",
-}
-
-yield {
- type: "REASONING_END",
- messageId: "reasoning-002",
-}
-
-// On subsequent turns, client sends back the message with encryptedValue
-// which the agent can decrypt to restore reasoning context
-```
-
-### Attaching Encrypted Reasoning to Tool Calls
-
-You can also attach encrypted reasoning to tool calls to capture why the agent
-chose specific arguments or how it interpreted results:
-
-```typescript theme={null}
-// Tool call with encrypted reasoning
-yield {
- type: "TOOL_CALL_START",
- toolCallId: "tool-123",
- toolCallName: "search_database",
- parentMessageId: "msg-789",
-}
-
-yield {
- type: "TOOL_CALL_ARGS",
- toolCallId: "tool-123",
- delta: '{"query": "user preferences"}',
-}
-
-yield {
- type: "TOOL_CALL_END",
- toolCallId: "tool-123",
-}
-
-// Attach encrypted reasoning explaining why this tool was called
-yield {
- type: "REASONING_ENCRYPTED_VALUE",
- subtype: "tool-call",
- entityId: "tool-123",
- encryptedValue: "encrypted-reasoning-about-tool-selection...",
-}
-```
-
-### ZDR-Compliant Implementation
-
-For zero data retention scenarios:
-
-```typescript theme={null}
-// Server-side: encrypt reasoning before sending
-const encryptedReasoning = await encrypt(detailedChainOfThought, secretKey)
-
-yield {
- type: "REASONING_START",
- messageId: "reasoning-003",
-}
-
-// Only emit a high-level summary to the client
-yield {
- type: "REASONING_MESSAGE_CHUNK",
- messageId: "summary-001",
- delta: "Processing your request securely...",
-}
-
-yield {
- type: "REASONING_MESSAGE_CHUNK",
- messageId: "summary-001",
- delta: "", // Empty delta closes the message
-}
-
-// Attach the encrypted chain-of-thought
-yield {
- type: "REASONING_ENCRYPTED_VALUE",
- subtype: "message",
- entityId: "summary-001",
- encryptedValue: encryptedReasoning,
-}
-
-yield {
- type: "REASONING_END",
- messageId: "reasoning-003",
-}
-
-// Client stores only:
-// - The encrypted blob (cannot decrypt)
-// - The summary text (no sensitive details)
-// Full reasoning is never persisted in plaintext
-```
-
-### Using the Convenience Chunk Event
-
-The `ReasoningMessageChunk` event simplifies implementation by auto-managing
-message lifecycle:
-
-```typescript theme={null}
-// First chunk with messageId starts the message automatically
-yield {
- type: "REASONING_MESSAGE_CHUNK",
- messageId: "msg-789",
- delta: "Analyzing the problem space...",
-}
-
-// Subsequent chunks continue the stream
-yield {
- type: "REASONING_MESSAGE_CHUNK",
- messageId: "msg-789",
- delta: " Considering multiple approaches...",
-}
-
-// Empty delta (or next non-reasoning event) closes automatically
-yield {
- type: "REASONING_MESSAGE_CHUNK",
- messageId: "msg-789",
- delta: "",
-}
-```
-
-## Client Integration
-
-### Handling Reasoning Events
-
-```typescript theme={null}
-import { EventType, type BaseEvent } from "@ag-ui/core"
-
-function handleEvent(event: BaseEvent) {
- switch (event.type) {
- case EventType.REASONING_START:
- // Initialize reasoning UI (e.g., "thinking" indicator)
- console.log("Agent is reasoning...")
- break
-
- case EventType.REASONING_MESSAGE_CONTENT:
- // Append visible reasoning to UI
- appendReasoningText(event.messageId, event.delta)
- break
-
- case EventType.REASONING_ENCRYPTED_VALUE:
- // Store encrypted value for the referenced entity
- if (event.subtype === "message") {
- storeMessageEncryptedValue(event.entityId, event.encryptedValue)
- } else if (event.subtype === "tool-call") {
- storeToolCallEncryptedValue(event.entityId, event.encryptedValue)
- }
- break
-
- case EventType.REASONING_END:
- // Finalize reasoning UI
- console.log("Reasoning complete")
- break
- }
-}
-```
-
-### Passing Encrypted Reasoning Back
-
-When making subsequent requests, include stored encrypted values:
-
-```typescript theme={null}
-const response = await agent.run({
- threadId: "thread-123",
- messages: [
- ...previousMessages,
- {
- id: "reasoning-002",
- role: "reasoning",
- content: "Analyzing your request...", // Visible summary
- encryptedValue: storedEncryptedBlob, // Opaque to client
- },
- {
- id: "user-msg-001",
- role: "user",
- content: "Follow up question...",
- },
- ],
-})
-```
-
-## Migration from Thinking Events
-
-
- The `THINKING_*` events are deprecated and will be removed in version 1.0.0.
- New implementations should use `REASONING_*` events.
-
-
-### Deprecated Events
-
-The following events are deprecated:
-
-| Deprecated Event | Replacement |
-| ------------------------------- | --------------------------- |
-| `THINKING_START` | `REASONING_START` |
-| `THINKING_END` | `REASONING_END` |
-| `THINKING_TEXT_MESSAGE_START` | `REASONING_MESSAGE_START` |
-| `THINKING_TEXT_MESSAGE_CONTENT` | `REASONING_MESSAGE_CONTENT` |
-| `THINKING_TEXT_MESSAGE_END` | `REASONING_MESSAGE_END` |
-
-### Migration Steps
-
-1. **Update event types**: Replace all `THINKING_*` event types with their
- `REASONING_*` equivalents
-2. **Update message types**: Use `ReasoningMessage` with `role: "reasoning"`
- instead of any thinking-specific message types
-3. **Add encrypted value support**: Consider using `ReasoningEncryptedValue`
- events for improved privacy compliance
-4. **Test thoroughly**: Ensure existing functionality works with the new event
- types
-
-### Example Migration
-
-Before (deprecated):
-
-```typescript theme={null}
-// ❌ Deprecated - do not use
-yield { type: "THINKING_START", messageId: "think-001" }
-yield { type: "THINKING_TEXT_MESSAGE_START", messageId: "msg-001" }
-yield { type: "THINKING_TEXT_MESSAGE_CONTENT", messageId: "msg-001", delta: "..." }
-yield { type: "THINKING_TEXT_MESSAGE_END", messageId: "msg-001" }
-yield { type: "THINKING_END", messageId: "think-001" }
-```
-
-After (current):
-
-```typescript theme={null}
-// ✅ Current implementation
-yield { type: "REASONING_START", messageId: "reasoning-001" }
-yield { type: "REASONING_MESSAGE_START", messageId: "msg-001", role: "assistant" }
-yield { type: "REASONING_MESSAGE_CONTENT", messageId: "msg-001", delta: "..." }
-yield { type: "REASONING_MESSAGE_END", messageId: "msg-001" }
-yield { type: "REASONING_END", messageId: "reasoning-001" }
-```
-
-## Best Practices
-
-1. **Always pair start/end events**: Every `ReasoningStart` should have a
- corresponding `ReasoningEnd`
-2. **Use encrypted values for sensitive reasoning**: When chain-of-thought
- contains sensitive information, use `ReasoningEncryptedValue` to attach
- encrypted content to messages or tool calls
-3. **Provide user feedback**: Even with encrypted reasoning, emit visible
- summaries so users know the agent is working
-4. **Handle missing events gracefully**: Clients should be resilient to
- incomplete event streams
-5. **Consider bandwidth**: For very long reasoning chains, consider emitting
- only summaries to reduce data transfer
-
-## Related Documentation
-
-* [Events](/concepts/events#reasoning-events) - Complete event type reference
-* [Messages](/concepts/messages#reasoning-messages) - Message type documentation
-* [Serialization](/concepts/serialization) - State continuity and lineage
-
-
-# Serialization
-Source: https://docs.ag-ui.com/concepts/serialization
-
-Serialize event streams for history restore, branching, and compaction in AG-UI
-
-# Serialization
-
-Serialization in AG-UI provides a standard way to persist and restore the event
-stream that drives an agent–UI session. With a serialized stream you can:
-
-* Restore chat history and UI state after reloads or reconnects
-* Attach to running agents and continue receiving events
-* Create branches (time travel) from any prior run
-* Compact stored history to reduce size without losing meaning
-
-This page explains the model, the updated event fields, and practical usage
-patterns with examples.
-
-## Core Concepts
-
-* Stream serialization – Convert the full event history to and from a portable
- representation (e.g., JSON) for storage in databases, files, or logs.
-* Event compaction – Reduce verbose streams to snapshots while preserving
- semantics (e.g., merge content chunks, collapse deltas into snapshots).
-* Run lineage – Track branches of conversation using a `parentRunId`, forming
- a git‑like append‑only log that enables time travel and alternative paths.
-
-## Updated Event Fields
-
-The `RunStarted` event includes additional optional fields:
-
-```ts theme={null}
-type RunStartedEvent = BaseEvent & {
- type: EventType.RUN_STARTED
- threadId: string
- runId: string
- /** Parent for branching/time travel within the same thread */
- parentRunId?: string
- /** Exact agent input for this run (may omit messages already in history) */
- input?: AgentInput
-}
-```
-
-These fields enable lineage tracking and let implementations record precisely
-what was passed to the agent, independent of previously recorded messages.
-
-## Event Compaction
-
-Compaction reduces noise in an event stream while keeping the same observable
-outcome. A typical implementation provides a utility:
-
-```ts theme={null}
-declare function compactEvents(events: BaseEvent[]): BaseEvent[]
-```
-
-Common compaction rules include:
-
-* Message streams – Combine `TEXT_MESSAGE_*` sequences into a single message
- snapshot; concatenate adjacent `TEXT_MESSAGE_CONTENT` for the same message.
-* Tool calls – Collapse tool call start/content/end into a compact record.
-* State – Merge consecutive `STATE_DELTA` events into a single final
- `STATE_SNAPSHOT` and discard superseded updates.
-* Run input normalization – Remove from `RunStarted.input.messages` any
- messages already present earlier in the stream.
-
-## Branching and Time Travel
-
-Setting `parentRunId` on a `RunStarted` event creates a git‑like lineage. The
-stream becomes an immutable append‑only log where each run can branch from any
-previous run.
-
-```mermaid theme={null}
-gitGraph
- commit id: "run1"
- commit id: "run2"
- branch alternative
- checkout alternative
- commit id: "run3 (parent run2)"
- commit id: "run4"
- checkout main
- commit id: "run5 (parent run2)"
- commit id: "run6"
-```
-
-Benefits:
-
-* Multiple branches in the same serialized log
-* Immutable history (append‑only)
-* Deterministic time travel to any point
-
-## Examples
-
-### Basic Serialization
-
-```ts theme={null}
-// Serialize event stream
-const events: BaseEvent[] = [...];
-const serialized = JSON.stringify(events);
-
-await storage.save(threadId, serialized);
-
-// Restore and compact later
-const restored = JSON.parse(await storage.load(threadId));
-const compacted = compactEvents(restored);
-```
-
-### Event Compaction
-
-Before:
-
-```ts theme={null}
-[
- { type: "TEXT_MESSAGE_START", messageId: "msg1", role: "user" },
- { type: "TEXT_MESSAGE_CONTENT", messageId: "msg1", delta: "Hello " },
- { type: "TEXT_MESSAGE_CONTENT", messageId: "msg1", delta: "world" },
- { type: "TEXT_MESSAGE_END", messageId: "msg1" },
- { type: "STATE_DELTA", patch: { op: "add", path: "/foo", value: 1 } },
- { type: "STATE_DELTA", patch: { op: "replace", path: "/foo", value: 2 } },
-]
-```
-
-After:
-
-```ts theme={null}
-[
- {
- type: "MESSAGES_SNAPSHOT",
- messages: [{ id: "msg1", role: "user", content: "Hello world" }],
- },
- {
- type: "STATE_SNAPSHOT",
- state: { foo: 2 },
- },
-]
-```
-
-### Branching With `parentRunId`
-
-```ts theme={null}
-// Original run
-{
- type: "RUN_STARTED",
- threadId: "thread1",
- runId: "run1",
- input: { messages: ["Tell me about Paris"] },
-}
-
-// Branch from run1
-{
- type: "RUN_STARTED",
- threadId: "thread1",
- runId: "run2",
- parentRunId: "run1",
- input: { messages: ["Actually, tell me about London instead"] },
-}
-```
-
-### Normalized Input
-
-```ts theme={null}
-// First run includes full message
-{
- type: "RUN_STARTED",
- runId: "run1",
- input: { messages: [{ id: "msg1", role: "user", content: "Hello" }] },
-}
-
-// Second run omits already‑present message
-{
- type: "RUN_STARTED",
- runId: "run2",
- input: { messages: [{ id: "msg2", role: "user", content: "How are you?" }] },
- // msg1 omitted; it already exists in history
-}
-```
-
-## Implementation Notes
-
-* Provide SDK helpers for compaction and (de)serialization.
-* Store streams append‑only; prefer incremental writes when possible.
-* Consider compression when persisting long histories.
-* Add indexes by `threadId`, `runId`, and timestamps for fast retrieval.
-
-## See Also
-
-* Concepts: [Events](/concepts/events), [State Management](/concepts/state)
-* SDKs: TypeScript encoder and core event types
-
-
-# State Management
-Source: https://docs.ag-ui.com/concepts/state
-
-Understanding state synchronization between agents and frontends in AG-UI
-
-# State Management
-
-State management is a core feature of the AG-UI protocol that enables real-time
-synchronization between agents and frontend applications. By providing efficient
-mechanisms for sharing and updating state, AG-UI creates a foundation for
-collaborative experiences where both AI agents and human users can work together
-seamlessly.
-
-## Shared State Architecture
-
-In AG-UI, state is a structured data object that:
-
-1. Persists across interactions with an agent
-2. Can be accessed by both the agent and the frontend
-3. Updates in real-time as the interaction progresses
-4. Provides context for decision-making on both sides
-
-This shared state architecture creates a bidirectional communication channel
-where:
-
-* Agents can access the application's current state to make informed decisions
-* Frontends can observe and react to changes in the agent's internal state
-* Both sides can modify the state, creating a collaborative workflow
-
-## State Synchronization Methods
-
-AG-UI provides two complementary methods for state synchronization:
-
-### State Snapshots
-
-The `STATE_SNAPSHOT` event delivers a complete representation of an agent's
-current state:
-
-```typescript theme={null}
-interface StateSnapshotEvent {
- type: EventType.STATE_SNAPSHOT
- snapshot: any // Complete state object
-}
-```
-
-Snapshots are typically used:
-
-* At the beginning of an interaction to establish the initial state
-* After connection interruptions to ensure synchronization
-* When major state changes occur that require a complete refresh
-* To establish a new baseline for future delta updates
-
-When a frontend receives a `STATE_SNAPSHOT` event, it should replace its
-existing state model entirely with the contents of the snapshot.
-
-### State Deltas
-
-The `STATE_DELTA` event delivers incremental updates to the state using JSON
-Patch format (RFC 6902):
-
-```typescript theme={null}
-interface StateDeltaEvent {
- type: EventType.STATE_DELTA
- delta: JsonPatchOperation[] // Array of JSON Patch operations
-}
-```
-
-Deltas are bandwidth-efficient, sending only what has changed rather than the
-entire state. This approach is particularly valuable for:
-
-* Frequent small updates during streaming interactions
-* Large state objects where most properties remain unchanged
-* High-frequency updates that would be inefficient to send as full snapshots
-
-## JSON Patch Format
-
-AG-UI uses the JSON Patch format (RFC 6902) for state deltas, which defines a
-standardized way to express changes to a JSON document:
-
-```typescript theme={null}
-interface JsonPatchOperation {
- op: "add" | "remove" | "replace" | "move" | "copy" | "test"
- path: string // JSON Pointer (RFC 6901) to the target location
- value?: any // The value to apply (for add, replace)
- from?: string // Source path (for move, copy)
-}
-```
-
-Common operations include:
-
-1. **add**: Adds a value to an object or array
-
- ```json theme={null}
- { "op": "add", "path": "/user/preferences", "value": { "theme": "dark" } }
- ```
-
-2. **replace**: Replaces a value
-
- ```json theme={null}
- { "op": "replace", "path": "/conversation_state", "value": "paused" }
- ```
-
-3. **remove**: Removes a value
-
- ```json theme={null}
- { "op": "remove", "path": "/temporary_data" }
- ```
-
-4. **move**: Moves a value from one location to another
- ```json theme={null}
- { "op": "move", "path": "/completed_items", "from": "/pending_items/0" }
- ```
-
-Frontends should apply these patches in sequence to maintain an accurate state
-representation. If inconsistencies are detected after applying patches, the
-frontend can request a fresh `STATE_SNAPSHOT`.
-
-## State Processing in AG-UI
-
-In the AG-UI implementation, state deltas are applied using the
-`fast-json-patch` library:
-
-```typescript theme={null}
-case EventType.STATE_DELTA: {
- const { delta } = event as StateDeltaEvent;
-
- try {
- // Apply the JSON Patch operations to the current state without mutating the original
- const result = applyPatch(state, delta, true, false);
- state = result.newDocument;
- return emitUpdate({ state });
- } catch (error: unknown) {
- console.warn(
- `Failed to apply state patch:\n` +
- `Current state: ${JSON.stringify(state, null, 2)}\n` +
- `Patch operations: ${JSON.stringify(delta, null, 2)}\n` +
- `Error: ${errorMessage}`
- );
- return emitNoUpdate();
- }
-}
-```
-
-This implementation ensures that:
-
-* Patches are applied atomically (all or none)
-* The original state is not mutated during the application process
-* Errors are caught and handled gracefully
-
-## Human-in-the-Loop Collaboration
-
-The shared state system is fundamental to human-in-the-loop workflows in AG-UI.
-It enables:
-
-1. **Real-time visibility**: Users can observe the agent's thought process and
- current status
-2. **Contextual awareness**: The agent can access user actions, preferences, and
- application state
-3. **Collaborative decision-making**: Both human and AI can contribute to the
- evolving state
-4. **Feedback loops**: Humans can correct or guide the agent by modifying state
- properties
-
-For example, an agent might update its state with a proposed action:
-
-```json theme={null}
-{
- "proposal": {
- "action": "send_email",
- "recipient": "client@example.com",
- "content": "Draft email content..."
- }
-}
-```
-
-The frontend can display this proposal to the user, who can then approve,
-reject, or modify it before execution.
-
-## CopilotKit Implementation
-
-[CopilotKit](https://docs.copilotkit.ai), a popular framework for building AI
-assistants, leverages AG-UI's state management system through its "shared state"
-feature. This implementation enables bidirectional state synchronization between
-agents (particularly LangGraph agents) and frontend applications.
-
-CopilotKit's shared state system is implemented through:
-
-```jsx theme={null}
-// In the frontend React application
-const { state: agentState, setState: setAgentState } = useCoAgent({
- name: "agent",
- initialState: { someProperty: "initialValue" },
-})
-```
-
-This hook creates a real-time connection to the agent's state, allowing:
-
-1. Reading the agent's current state in the frontend
-2. Updating the agent's state from the frontend
-3. Rendering UI components based on the agent's state
-
-On the backend, LangGraph agents can emit state updates using:
-
-```python theme={null}
-# In the LangGraph agent
-async def tool_node(self, state: ResearchState, config: RunnableConfig):
- # Update state with new information
- tool_state = {
- "title": new_state.get("title", ""),
- "outline": new_state.get("outline", {}),
- "sections": new_state.get("sections", []),
- # Other state properties...
- }
-
- # Emit updated state to frontend
- await copilotkit_emit_state(config, tool_state)
-
- return tool_state
-```
-
-These state updates are transmitted using AG-UI's state snapshot and delta
-mechanisms, creating a seamless shared context between agent and frontend.
-
-## Best Practices
-
-When implementing state management in AG-UI:
-
-1. **Use snapshots judiciously**: Full snapshots should be sent only when
- necessary to establish a baseline.
-2. **Prefer deltas for incremental changes**: Small state updates should use
- deltas to minimize data transfer.
-3. **Structure state thoughtfully**: Design state objects to support partial
- updates and minimize patch complexity.
-4. **Handle state conflicts**: Implement strategies for resolving conflicting
- updates from agent and frontend.
-5. **Include error recovery**: Provide mechanisms to resynchronize state if
- inconsistencies are detected.
-6. **Consider security implications**: Avoid storing sensitive information in
- shared state.
-
-## Conclusion
-
-AG-UI's state management system provides a powerful foundation for building
-collaborative applications where humans and AI agents work together. By
-efficiently synchronizing state between frontend and backend through snapshots
-and JSON Patch deltas, AG-UI enables sophisticated human-in-the-loop workflows
-that combine the strengths of both human intuition and AI capabilities.
-
-The implementation in frameworks like CopilotKit demonstrates how this shared
-state approach can create collaborative experiences that are more effective than
-either fully autonomous systems or traditional user interfaces.
-
-
-# Tools
-Source: https://docs.ag-ui.com/concepts/tools
-
-Understanding tools and how they enable human-in-the-loop AI workflows
-
-# Tools
-
-Tools are a fundamental concept in the AG-UI protocol that enable AI agents to
-interact with external systems and incorporate human judgment into their
-workflows. By defining tools in the frontend and passing them to agents,
-developers can create sophisticated human-in-the-loop experiences that combine
-AI capabilities with human expertise.
-
-## What Are Tools?
-
-In AG-UI, tools are functions that agents can call to:
-
-1. Request specific information
-2. Perform actions in external systems
-3. Ask for human input or confirmation
-4. Access specialized capabilities
-
-Tools bridge the gap between AI reasoning and real-world actions, allowing
-agents to accomplish tasks that would be impossible through conversation alone.
-
-## Tool Structure
-
-Tools follow a consistent structure that defines their name, purpose, and
-expected parameters:
-
-```typescript theme={null}
-interface Tool {
- name: string // Unique identifier for the tool
- description: string // Human-readable explanation of what the tool does
- parameters: {
- // JSON Schema defining the tool's parameters
- type: "object"
- properties: {
- // Tool-specific parameters
- }
- required: string[] // Array of required parameter names
- }
-}
-```
-
-The `parameters` field uses [JSON Schema](https://json-schema.org/) to define
-the structure of arguments that the tool accepts. This schema is used by both
-the agent (to generate valid tool calls) and the frontend (to validate and parse
-tool arguments).
-
-## Frontend-Defined Tools
-
-A key aspect of AG-UI's tool system is that tools are defined in the frontend
-and passed to the agent during execution:
-
-```typescript theme={null}
-// Define tools in the frontend
-const userConfirmationTool = {
- name: "confirmAction",
- description: "Ask the user to confirm a specific action before proceeding",
- parameters: {
- type: "object",
- properties: {
- action: {
- type: "string",
- description: "The action that needs user confirmation",
- },
- importance: {
- type: "string",
- enum: ["low", "medium", "high", "critical"],
- description: "The importance level of the action",
- },
- },
- required: ["action"],
- },
-}
-
-// Pass tools to the agent during execution
-agent.runAgent({
- tools: [userConfirmationTool],
- // Other parameters...
-})
-```
-
-This approach has several advantages:
-
-1. **Frontend control**: The frontend determines what capabilities are available
- to the agent
-2. **Dynamic capabilities**: Tools can be added or removed based on user
- permissions, context, or application state
-3. **Separation of concerns**: Agents focus on reasoning while frontends handle
- tool implementation
-4. **Security**: Sensitive operations are controlled by the application, not the
- agent
-
-## Tool Call Lifecycle
-
-When an agent needs to use a tool, it follows a standardized sequence of events:
-
-1. **ToolCallStart**: Indicates the beginning of a tool call with a unique ID
- and tool name
-
- ```typescript theme={null}
- {
- type: EventType.TOOL_CALL_START,
- toolCallId: "tool-123",
- toolCallName: "confirmAction",
- parentMessageId: "msg-456" // Optional reference to a message
- }
- ```
-
-2. **ToolCallArgs**: Streams the tool arguments as they're generated
-
- ```typescript theme={null}
- {
- type: EventType.TOOL_CALL_ARGS,
- toolCallId: "tool-123",
- delta: '{"act' // Partial JSON being streamed
- }
- ```
-
- ```typescript theme={null}
- {
- type: EventType.TOOL_CALL_ARGS,
- toolCallId: "tool-123",
- delta: 'ion":"Depl' // More JSON being streamed
- }
- ```
-
- ```typescript theme={null}
- {
- type: EventType.TOOL_CALL_ARGS,
- toolCallId: "tool-123",
- delta: 'oy the application to production"}' // Final JSON fragment
- }
- ```
-
-3. **ToolCallEnd**: Marks the completion of the tool call
- ```typescript theme={null}
- {
- type: EventType.TOOL_CALL_END,
- toolCallId: "tool-123"
- }
- ```
-
-The frontend accumulates these deltas to construct the complete tool call
-arguments. Once the tool call is complete, the frontend can execute the tool and
-provide results back to the agent.
-
-## Tool Results
-
-After a tool has been executed, the result is sent back to the agent as a "tool
-message":
-
-```typescript theme={null}
-{
- id: "result-789",
- role: "tool",
- content: "true", // Tool result as a string
- toolCallId: "tool-123" // References the original tool call
-}
-```
-
-This message becomes part of the conversation history, allowing the agent to
-reference and incorporate the tool's result in subsequent responses.
-
-## Human-in-the-Loop Workflows
-
-The AG-UI tool system is especially powerful for implementing human-in-the-loop
-workflows. By defining tools that request human input or confirmation,
-developers can create AI experiences that seamlessly blend autonomous operation
-with human judgment.
-
-For example:
-
-1. Agent needs to make an important decision
-2. Agent calls the `confirmAction` tool with details about the decision
-3. Frontend displays a confirmation dialog to the user
-4. User provides their input
-5. Frontend sends the user's decision back to the agent
-6. Agent continues processing with awareness of the user's choice
-
-This pattern enables use cases like:
-
-* **Approval workflows**: AI suggests actions that require human approval
-* **Data verification**: Humans verify or correct AI-generated data
-* **Collaborative decision-making**: AI and humans jointly solve complex
- problems
-* **Supervised learning**: Human feedback improves future AI decisions
-
-## CopilotKit Integration
-
-[CopilotKit](https://docs.copilotkit.ai/) provides a simplified way to work with
-AG-UI tools in React applications through its
-[`useCopilotAction`](https://docs.copilotkit.ai/guides/frontend-actions) hook:
-
-```tsx theme={null}
-import { useCopilotAction } from "@copilotkit/react-core"
-
-// Define a tool for user confirmation
-useCopilotAction({
- name: "confirmAction",
- description: "Ask the user to confirm an action",
- parameters: {
- type: "object",
- properties: {
- action: {
- type: "string",
- description: "The action to confirm",
- },
- },
- required: ["action"],
- },
- handler: async ({ action }) => {
- // Show a confirmation dialog
- const confirmed = await showConfirmDialog(action)
- return confirmed ? "approved" : "rejected"
- },
-})
-```
-
-This approach makes it easy to define tools that integrate with your React
-components and handle the tool execution logic in a clean, declarative way.
-
-## Tool Examples
-
-Here are some common types of tools used in AG-UI applications:
-
-### User Confirmation
-
-```typescript theme={null}
-{
- name: "confirmAction",
- description: "Ask the user to confirm an action",
- parameters: {
- type: "object",
- properties: {
- action: {
- type: "string",
- description: "The action to confirm"
- },
- importance: {
- type: "string",
- enum: ["low", "medium", "high", "critical"],
- description: "The importance level"
- }
- },
- required: ["action"]
- }
-}
-```
-
-### Data Retrieval
-
-```typescript theme={null}
-{
- name: "fetchUserData",
- description: "Retrieve data about a specific user",
- parameters: {
- type: "object",
- properties: {
- userId: {
- type: "string",
- description: "ID of the user"
- },
- fields: {
- type: "array",
- items: {
- type: "string"
- },
- description: "Fields to retrieve"
- }
- },
- required: ["userId"]
- }
-}
-```
-
-### User Interface Control
-
-```typescript theme={null}
-{
- name: "navigateTo",
- description: "Navigate to a different page or view",
- parameters: {
- type: "object",
- properties: {
- destination: {
- type: "string",
- description: "Destination page or view"
- },
- params: {
- type: "object",
- description: "Optional parameters for the navigation"
- }
- },
- required: ["destination"]
- }
-}
-```
-
-### Content Generation
-
-```typescript theme={null}
-{
- name: "generateImage",
- description: "Generate an image based on a description",
- parameters: {
- type: "object",
- properties: {
- prompt: {
- type: "string",
- description: "Description of the image to generate"
- },
- style: {
- type: "string",
- description: "Visual style for the image"
- },
- dimensions: {
- type: "object",
- properties: {
- width: { type: "number" },
- height: { type: "number" }
- },
- description: "Dimensions of the image"
- }
- },
- required: ["prompt"]
- }
-}
-```
-
-## Best Practices
-
-When designing tools for AG-UI:
-
-1. **Clear naming**: Use descriptive, action-oriented names
-2. **Detailed descriptions**: Include thorough descriptions to help the agent
- understand when and how to use the tool
-3. **Structured parameters**: Define precise parameter schemas with descriptive
- field names and constraints
-4. **Required fields**: Only mark parameters as required if they're truly
- necessary
-5. **Error handling**: Implement robust error handling in tool execution code
-6. **User experience**: Design tool UIs that provide appropriate context for
- human decision-making
-
-## Conclusion
-
-Tools in AG-UI bridge the gap between AI reasoning and real-world actions,
-enabling sophisticated workflows that combine the strengths of AI and human
-intelligence. By defining tools in the frontend and passing them to agents,
-developers can create interactive experiences where AI and humans collaborate
-efficiently.
-
-The tool system is particularly powerful for implementing human-in-the-loop
-workflows, where AI can suggest actions but defer critical decisions to humans.
-This balances automation with human judgment, creating AI experiences that are
-both powerful and trustworthy.
-
-
-# Contributing
-Source: https://docs.ag-ui.com/development/contributing
-
-How to participate in Agent User Interaction Protocol development
-
-# Naming conventions
-
-Add your package under `integrations/` with docs and tests.
-
-If your integration is work in progress, you can still add it to main branch.
-You can prefix it with `wip-`, i.e.
-(`integrations/wip-your-integration`) or if you're a third party
-contributor use the `community` prefix, i.e.
-(`integrations/community/your-integration`).
-
-For questions and discussions, please use
-[GitHub Discussions](https://github.com/ag-ui-protocol/ag-ui/discussions).
-
-
-# Roadmap
-Source: https://docs.ag-ui.com/development/roadmap
-
-Our plans for evolving Agent User Interaction Protocol
-
-You can follow the progress of the AG-UI Protocol on our
-[public roadmap](https://github.com/orgs/ag-ui-protocol/projects/1).
-
-## Get Involved
-
-If you’d like to contribute ideas, feature requests, or bug reports to
-the roadmap, please see the [Contributing Guide](https://github.com/ag-ui-protocol/ag-ui/blob/main/CONTRIBUTING.md)
-for details on how to get involved.
-
-
-# What's New
-Source: https://docs.ag-ui.com/development/updates
-
-The latest updates and improvements to AG-UI
-
-
- * Initial release of the Agent User Interaction Protocol
-
-
-
-# Generative User Interfaces
-Source: https://docs.ag-ui.com/drafts/generative-ui
-
-AI-generated interfaces without custom tool renderers
-
-# Generative User Interfaces
-
-## Summary
-
-### Problem Statement
-
-Currently, creating custom user interfaces for agent interactions requires
-programmers to define specific tool renderers. This limits the flexibility and
-adaptability of agent-driven applications.
-
-### Motivation
-
-This draft describes an AG-UI extension that addresses **generative user
-interfaces**—interfaces produced directly by artificial intelligence without
-requiring a programmer to define custom tool renderers. The key idea is to
-leverage our ability to send client-side tools to the agent, thereby enabling
-this capability across all agent frameworks supported by AG-UI.
-
-## Status
-
-* **Status**: Draft
-* **Author(s)**: Markus Ecker ([mail@mme.xyz](mailto:mail@mme.xyz))
-
-## Challenges and Limitations
-
-### Tool Description Length
-
-OpenAI enforces a limit of 1024 characters for tool descriptions. Gemini and
-Anthropic impose no such limit.
-
-### Arguments JSON Schema Constraints
-
-Classes, nesting, `$ref`, and `oneOf` are not reliably supported across LLM
-providers.
-
-### Context Window Considerations
-
-Injecting a large UI description language into an agent may reduce its
-performance. Agents dedicated solely to UI generation perform better than agents
-combining UI generation with other tasks.
-
-## Detailed Specification
-
-### Two-Step Generation Process
-
-```mermaid theme={null}
-flowchart TD
- A[Agent needs UI] --> B["Step 1: What? Agent calls generateUserInterface (description, data, output)"]
- B --> C["Step 2: How? Secondary generator builds actual UI (JSON Schema, React, etc.)"]
- C --> D[Rendered UI shown to user]
- D --> E[Validated user input returned to Agent]
-```
-
-### Step 1: What to Generate?
-
-Inject a lightweight tool into the agent:
-
-**Tool Definition:**
-
-* **Name:** `generateUserInterface`
-* **Arguments:**
- * **description**: A high-level description of the UI (e.g., *"A form for
- entering the user's address"*)
- * **data**: Arbitrary pre-populated data for the generated UI
- * **output**: A description or schema of the data the agent expects the user
- to submit back (fields, required/optional, types, constraints)
-
-**Example Tool Call:**
-
-```json theme={null}
-{
- "tool": "generateUserInterface",
- "arguments": {
- "description": "A form that collects a user's shipping address.",
- "data": {
- "firstName": "Ada",
- "lastName": "Lovelace",
- "city": "London"
- },
- "output": {
- "type": "object",
- "required": [
- "firstName",
- "lastName",
- "street",
- "city",
- "postalCode",
- "country"
- ],
- "properties": {
- "firstName": { "type": "string", "title": "First Name" },
- "lastName": { "type": "string", "title": "Last Name" },
- "street": { "type": "string", "title": "Street Address" },
- "city": { "type": "string", "title": "City" },
- "postalCode": { "type": "string", "title": "Postal Code" },
- "country": {
- "type": "string",
- "title": "Country",
- "enum": ["GB", "US", "DE", "AT"]
- }
- }
- }
- }
-}
-```
-
-### Step 2: How to Generate?
-
-Delegate UI generation to a secondary LLM or agent:
-
-* The CopilotKit user stays in control: Can make their own generators, add
- custom libraries, include additional prompts etc.
-* On tool invocation, the secondary model consumes `description`, `data`, and
- `output` to generate the user interface
-* This model is focused solely on UI generation, ensuring maximum fidelity and
- consistency
-* The generation method can be swapped as needed (e.g., JSON, HTML, or other
- renderable formats)
-* The UI format description is not subject to structural or length constraints,
- allowing arbitrarily complex specifications
-
-## Implementation Examples
-
-### Example Output: UISchemaGenerator
-
-```json theme={null}
-{
- "jsonSchema": {
- "title": "Shipping Address",
- "type": "object",
- "required": [
- "firstName",
- "lastName",
- "street",
- "city",
- "postalCode",
- "country"
- ],
- "properties": {
- "firstName": { "type": "string", "title": "First name" },
- "lastName": { "type": "string", "title": "Last name" },
- "street": { "type": "string", "title": "Street address" },
- "city": { "type": "string", "title": "City" },
- "postalCode": { "type": "string", "title": "Postal code" },
- "country": {
- "type": "string",
- "title": "Country",
- "enum": ["GB", "US", "DE", "AT"]
- }
- }
- },
- "uiSchema": {
- "type": "VerticalLayout",
- "elements": [
- {
- "type": "Group",
- "label": "Personal Information",
- "elements": [
- { "type": "Control", "scope": "#/properties/firstName" },
- { "type": "Control", "scope": "#/properties/lastName" }
- ]
- },
- {
- "type": "Group",
- "label": "Address",
- "elements": [
- { "type": "Control", "scope": "#/properties/street" },
- { "type": "Control", "scope": "#/properties/city" },
- { "type": "Control", "scope": "#/properties/postalCode" },
- { "type": "Control", "scope": "#/properties/country" }
- ]
- }
- ]
- },
- "initialData": {
- "firstName": "Ada",
- "lastName": "Lovelace",
- "city": "London",
- "country": "GB"
- }
-}
-```
-
-### Example Output: ReactFormHookGenerator
-
-```tsx theme={null}
-import React from "react"
-import { useForm } from "react-hook-form"
-import { z } from "zod"
-import { zodResolver } from "@hookform/resolvers/zod"
-
-// ----- Schema (contract) -----
-const AddressSchema = z.object({
- firstName: z.string().min(1, "Required"),
- lastName: z.string().min(1, "Required"),
- street: z.string().min(1, "Required"),
- city: z.string().min(1, "Required"),
- postalCode: z.string().regex(/^[A-Za-z0-9\\-\\s]{3,10}$/, "3–10 chars"),
- country: z.enum(["GB", "US", "DE", "AT", "FR", "IT", "ES"]),
-})
-export type Address = z.infer
-
-type Props = {
- initialData?: Partial
- meta?: { title?: string; submitLabel?: string }
- respond: (data: Address) => void // <-- called on successful submit
-}
-
-const COUNTRIES: Address["country"][] = [
- "GB",
- "US",
- "DE",
- "AT",
- "FR",
- "IT",
- "ES",
-]
-
-export default function AddressForm({ initialData, meta, respond }: Props) {
- const {
- register,
- handleSubmit,
- formState: { errors },
- } = useForm({
- resolver: zodResolver(AddressSchema),
- defaultValues: {
- firstName: "",
- lastName: "",
- street: "",
- city: "",
- postalCode: "",
- country: "GB",
- ...initialData,
- },
- })
-
- const onSubmit = (data: Address) => {
- // Guaranteed to match AddressSchema
- respond(data)
- }
-
- return (
-
- )
-}
-```
-
-## Implementation Considerations
-
-### Client SDK Changes
-
-TypeScript SDK additions:
-
-* New `generateUserInterface` tool type
-* UI generator registry for pluggable generators
-* Validation layer for generated UI schemas
-* Response handler for user-submitted data
-
-Python SDK additions:
-
-* Support for UI generation tool invocation
-* Schema validation utilities
-* Serialization for UI definitions
-
-### Integration Impact
-
-* All AG-UI integrations can leverage this capability without modification
-* Frameworks emit standard tool calls; client handles UI generation
-* Backward compatible with existing tool-based UI approaches
-
-## Use Cases
-
-### Dynamic Forms
-
-Agents can generate forms on-the-fly based on conversation context without
-pre-defined schemas.
-
-### Data Visualization
-
-Generate charts, graphs, or tables appropriate to the data being discussed.
-
-### Interactive Workflows
-
-Create multi-step wizards or guided processes tailored to user needs.
-
-### Adaptive Interfaces
-
-Generate different UI layouts based on user preferences or device capabilities.
-
-## Testing Strategy
-
-* Unit tests for tool injection and invocation
-* Integration tests with multiple UI generators
-* E2E tests demonstrating various UI types
-* Performance benchmarks comparing single vs. two-step generation
-* Cross-provider compatibility testing
-
-## References
-
-* [AG-UI Tools Documentation](/concepts/tools)
-* [JSON Schema](https://json-schema.org/)
-* [React Hook Form](https://react-hook-form.com/)
-* [JSON Forms](https://jsonforms.io/)
-
-
-# Interrupt-Aware Run Lifecycle
-Source: https://docs.ag-ui.com/drafts/interrupts
-
-Native support for human-in-the-loop pauses and interrupts
-
-# Interrupt-Aware Run Lifecycle Proposal
-
-## Summary
-
-### Problem Statement
-
-Agents often need to pause execution to request human approval, gather
-additional input, or confirm potentially risky actions. Currently, there's no
-standardized way to handle these interruptions across different agent
-frameworks.
-
-### Motivation
-
-Support **human-in-the-loop pauses** (and related mechanisms) natively in AG-UI
-and CopilotKit. This enables compatibility with various framework interrupts,
-workflow suspend/resume, and other framework-specific pause mechanisms.
-
-## Status
-
-* **Status**: Draft
-* **Author(s)**: Markus Ecker ([mail@mme.xyz](mailto:mail@mme.xyz))
-
-## Overview
-
-This proposal introduces a standardized interrupt/resume pattern:
-
-```mermaid theme={null}
-sequenceDiagram
- participant Agent
- participant Client as Client App
-
- Agent-->>Client: RUN_FINISHED { outcome: "interrupt", interrupt:{ id, reason, payload }}
- Client-->>Agent: RunAgentInput.resume { threadId, interruptId, payload }
- Agent-->>Client: RUN_FINISHED { outcome: "success", result }
-```
-
-## Detailed Specification
-
-### Updates to RUN\_FINISHED Event
-
-```typescript theme={null}
-type RunFinishedOutcome = "success" | "interrupt"
-
-type RunFinished = {
- type: "RUN_FINISHED"
-
- // ... existing fields
-
- outcome?: RunFinishedOutcome // optional for back-compat (see rules below)
-
- // Present when outcome === "success" (or when outcome omitted and interrupt is absent)
- result?: any
-
- // Present when outcome === "interrupt" (or when outcome omitted and interrupt is present)
- interrupt?: {
- id?: string // id can be set when needed
- reason?: string // e.g. "human_approval" | "upload_required" | "policy_hold"
- payload?: any // arbitrary JSON for UI (forms, proposals, diffs, etc.)
- }
-}
-```
-
-When a run finishes with `outcome == "interrupt"`, the agent indicates that on
-the next run, a value needs to be provided to continue.
-
-### Updates to RunAgentInput
-
-```typescript theme={null}
-type RunAgentInput = {
- // ... existing fields
-
- // NEW: resume channel for continuing a suspension
- resume?: {
- interruptId?: string // echo back if one was provided
- payload?: any // arbitrary JSON: approvals, edits, files-as-refs, etc.
- }
-}
-```
-
-### Contract Rules
-
-* Resume requests **must** use the same `threadId`
-* When given in the `interrupt`, the `interruptId` must be provided via
- `RunAgentInput`
-* Agents should handle missing or invalid resume payloads gracefully
-
-## Implementation Examples
-
-### Minimal Interrupt/Resume
-
-**Agent sends interrupt:**
-
-```json theme={null}
-{
- "type": "RUN_FINISHED",
- "threadId": "t1",
- "runId": "r1",
- "outcome": "interrupt",
- "interrupt": {
- "id": "int-abc123",
- "reason": "human_approval",
- "payload": {
- "proposal": {
- "tool": "sendEmail",
- "args": { "to": "a@b.com", "subject": "Hi", "body": "…" }
- }
- }
- }
-}
-```
-
-**User responds:**
-
-```json theme={null}
-{
- "threadId": "t1",
- "runId": "r2",
- "resume": {
- "interruptId": "int-abc123",
- "payload": { "approved": true }
- }
-}
-```
-
-### Complex Approval Flow
-
-**Agent requests approval with context:**
-
-```json theme={null}
-{
- "type": "RUN_FINISHED",
- "threadId": "thread-456",
- "runId": "run-789",
- "outcome": "interrupt",
- "interrupt": {
- "id": "approval-001",
- "reason": "database_modification",
- "payload": {
- "action": "DELETE",
- "table": "users",
- "affectedRows": 42,
- "query": "DELETE FROM users WHERE last_login < '2023-01-01'",
- "rollbackPlan": "Restore from backup snapshot-2025-01-23",
- "riskLevel": "high"
- }
- }
-}
-```
-
-**User approves with modifications:**
-
-```json theme={null}
-{
- "threadId": "thread-456",
- "runId": "run-790",
- "resume": {
- "interruptId": "approval-001",
- "payload": {
- "approved": true,
- "modifications": {
- "batchSize": 10,
- "dryRun": true
- }
- }
- }
-}
-```
-
-## Use Cases
-
-### Human Approval
-
-Agents pause before executing sensitive operations (sending emails, making
-purchases, deleting data).
-
-### Information Gathering
-
-Agent requests additional context or files from the user mid-execution.
-
-### Policy Enforcement
-
-Automatic pauses triggered by organizational policies or compliance
-requirements.
-
-### Multi-Step Wizards
-
-Complex workflows where each step requires user confirmation or input.
-
-### Error Recovery
-
-Agent pauses when encountering an error, allowing user to provide guidance.
-
-## Implementation Considerations
-
-### Client SDK Changes
-
-TypeScript SDK:
-
-* Extended `RunFinishedEvent` type with outcome and interrupt fields
-* Updated `RunAgentInput` with resume field
-* Helper methods for interrupt handling
-
-Python SDK:
-
-* Extended `RunFinishedEvent` class
-* Updated `RunAgentInput` with resume support
-* Interrupt state management utilities
-
-### Framework Integration
-
-**Planning Frameworks:**
-
-* Map framework interrupts to AG-UI interrupt events
-* Handle resume payloads in execution continuation
-
-**Workflow Systems:**
-
-* Convert workflow suspensions to AG-UI interrupts
-* Resume workflow execution with provided payload
-
-**Custom Frameworks:**
-
-* Provide interrupt/resume adapter interface
-* Documentation for integration patterns
-
-### UI Considerations
-
-* Standard components for common interrupt reasons
-* Customizable interrupt UI based on payload
-* Clear indication of pending interrupts
-* History of interrupt/resume actions
-
-## Testing Strategy
-
-* Unit tests for interrupt/resume serialization
-* Integration tests with multiple frameworks
-* E2E tests demonstrating various interrupt scenarios
-* State consistency tests across interrupt boundaries
-* Performance tests for rapid interrupt/resume cycles
-
-## References
-
-* [AG-UI Events Documentation](/concepts/events)
-* [AG-UI State Management](/concepts/state)
-
-
-# Meta Events
-Source: https://docs.ag-ui.com/drafts/meta-events
-
-Annotations and signals independent of agent runs
-
-# Meta Events Proposal
-
-## Summary
-
-### Problem Statement
-
-Currently, AG-UI events are tightly coupled to agent runs. There's no
-standardized way to attach user feedback, annotations, or external signals to
-the event stream that are independent of the agent's execution lifecycle.
-
-### Motivation
-
-AG-UI is extended with **MetaEvents**, a new class of events that can occur at
-any point in the event stream, independent of agent runs. MetaEvents provide a
-way to attach annotations, signals, or feedback to a serialized stream. They may
-originate from users, clients, or external systems rather than from agents.
-Examples include reactions such as thumbs up/down on a message.
-
-## Status
-
-* **Status**: Draft
-* **Author(s)**: Markus Ecker ([mail@mme.xyz](mailto:mail@mme.xyz))
-
-## Detailed Specification
-
-### Overview
-
-This proposal introduces:
-
-* A new **MetaEvent** type for side-band annotations
-* Events that can appear anywhere in the stream
-* Support for user feedback, tags, and external annotations
-* Extensible payload structure for application-specific data
-
-## New Type: MetaEvent
-
-```typescript theme={null}
-type MetaEvent = BaseEvent & {
- type: EventType.META
- /**
- * Application-defined type of the meta event.
- * Examples: "thumbs_up", "thumbs_down", "tag", "note"
- */
- metaType: string
-
- /**
- * Application-defined payload.
- * May reference other entities (e.g., messageId) or contain freeform data.
- */
- payload: Record
-}
-```
-
-### Key Characteristics
-
-* **Run-independent**: MetaEvents are not tied to any specific run lifecycle
-* **Position-flexible**: Can appear before, between, or after runs
-* **Origin-diverse**: May come from users, clients, or external systems
-* **Extensible**: Applications define their own metaType values and payload
- schemas
-
-## Implementation Examples
-
-### User Feedback
-
-**Thumbs Up:**
-
-```json theme={null}
-{
- "id": "evt_123",
- "ts": 1714063982000,
- "type": "META",
- "metaType": "thumbs_up",
- "payload": {
- "messageId": "msg_456",
- "userId": "user_789"
- }
-}
-```
-
-**Thumbs Down with Reason:**
-
-```json theme={null}
-{
- "id": "evt_124",
- "ts": 1714063985000,
- "type": "META",
- "metaType": "thumbs_down",
- "payload": {
- "messageId": "msg_456",
- "userId": "user_789",
- "reason": "inaccurate",
- "comment": "The calculation seems incorrect"
- }
-}
-```
-
-### Annotations
-
-**User Note:**
-
-```json theme={null}
-{
- "id": "evt_789",
- "ts": 1714064001000,
- "type": "META",
- "metaType": "note",
- "payload": {
- "text": "Important question to revisit",
- "relatedRunId": "run_001",
- "author": "user_123"
- }
-}
-```
-
-**Tag Assignment:**
-
-```json theme={null}
-{
- "id": "evt_890",
- "ts": 1714064100000,
- "type": "META",
- "metaType": "tag",
- "payload": {
- "tags": ["important", "follow-up"],
- "threadId": "thread_001"
- }
-}
-```
-
-### External System Events
-
-**Analytics Event:**
-
-```json theme={null}
-{
- "id": "evt_901",
- "ts": 1714064200000,
- "type": "META",
- "metaType": "analytics",
- "payload": {
- "event": "conversation_shared",
- "properties": {
- "shareMethod": "link",
- "recipientCount": 3
- }
- }
-}
-```
-
-**Moderation Flag:**
-
-```json theme={null}
-{
- "id": "evt_902",
- "ts": 1714064300000,
- "type": "META",
- "metaType": "moderation",
- "payload": {
- "action": "flag",
- "messageId": "msg_999",
- "category": "inappropriate_content",
- "confidence": 0.95
- }
-}
-```
-
-## Common Meta Event Types
-
-While applications can define their own types, these are commonly used:
-
-| MetaType | Description | Typical Payload |
-| ------------- | ----------------- | ---------------------------------- |
-| `thumbs_up` | Positive feedback | `{ messageId, userId }` |
-| `thumbs_down` | Negative feedback | `{ messageId, userId, reason? }` |
-| `note` | User annotation | `{ text, relatedId?, author }` |
-| `tag` | Categorization | `{ tags[], targetId }` |
-| `bookmark` | Save for later | `{ messageId, userId }` |
-| `copy` | Content copied | `{ messageId, content }` |
-| `share` | Content shared | `{ messageId, method }` |
-| `rating` | Numeric rating | `{ messageId, rating, maxRating }` |
-
-## Use Cases
-
-### User Feedback Collection
-
-Capture user reactions to agent responses for quality improvement.
-
-### Conversation Annotation
-
-Allow users to add notes, tags, or bookmarks to important parts of
-conversations.
-
-### Analytics and Tracking
-
-Record user interactions and behaviors without affecting agent execution.
-
-### Content Moderation
-
-Flag or mark content for review by external moderation systems.
-
-### Collaborative Features
-
-Enable multiple users to annotate or comment on shared conversations.
-
-### Audit Trail
-
-Create a complete record of all interactions, not just agent responses.
-
-## Implementation Considerations
-
-### Client SDK Changes
-
-TypeScript SDK:
-
-* New `MetaEvent` type in `@ag-ui/core`
-* Helper functions for common meta event types
-* MetaEvent filtering and querying utilities
-
-Python SDK:
-
-* `MetaEvent` class implementation
-* Meta event builders for common types
-* Event stream filtering capabilities
-
-## Testing Strategy
-
-* Unit tests for MetaEvent creation and validation
-* Integration tests with mixed event streams
-* Performance tests with high-volume meta events
-* Security tests for payload validation
-
-## References
-
-* [AG-UI Events Documentation](/concepts/events)
-* [Event Sourcing](https://martinfowler.com/eaaDev/EventSourcing.html)
-* [CQRS Pattern](https://martinfowler.com/bliki/CQRS.html)
-
-
-# Multi-modal Messages
-Source: https://docs.ag-ui.com/drafts/multimodal-messages
-
-Support for multimodal input messages including text, images, audio, video, and documents
-
-# Multi-modal Messages Proposal
-
-## Summary
-
-### Problem Statement
-
-Current AG-UI protocol only supports text-based user messages. As LLMs
-increasingly support multimodal inputs (images, audio, files), the protocol
-needs to evolve to handle these richer input types.
-
-### Motivation
-
-Evolve AG-UI to support **multimodal input messages** without breaking existing
-apps. Inputs may include text, images, audio, video, and documents. Each
-modality is represented as a distinct, typed content part with a clear source
-discriminator (`data` for inline base64, `url` for references), making it
-straightforward to map to any LLM provider's API.
-
-## Status
-
-* **Status**: Implemented — October 16, 2025
-* **Author(s)**: Markus Ecker ([mail@mme.xyz](mailto:mail@mme.xyz)), Alem Tuzlak ([t.zlak97@gmail.com](mailto:t.zlak97@gmail.com))
-
-## Detailed Specification
-
-### Overview
-
-Extend the `UserMessage` `content` property to be either a string or an array of
-`InputContentPart` objects. Each modality (image, audio, video, document) has
-its own dedicated part type with a typed `source` that is either inline `data`
-or a `url` reference. This makes it trivial to map content parts to any LLM
-provider's API.
-
-```typescript theme={null}
-/**
- * Supported input modality types for multimodal content.
- */
-type Modality = "text" | "image" | "audio" | "video" | "document"
-
-// ── Source types ──────────────────────────────────────────────
-
-interface InputContentDataSource {
- /** Indicates this is inline data content. */
- type: "data"
- /** The base64-encoded content value. */
- value: string
- /** MIME type of the content (e.g., "image/png", "audio/wav"). Required. */
- mimeType: string
-}
-
-interface InputContentUrlSource {
- /** Indicates this is URL-referenced content. */
- type: "url"
- /** HTTP(S) URL or data URI pointing to the content. */
- value: string
- /** Optional MIME type hint for when it can't be inferred from the URL. */
- mimeType?: string
-}
-
-type InputContentSource = InputContentDataSource | InputContentUrlSource
-
-// ── Content part types ────────────────────────────────────────
-
-interface TextInputPart {
- type: "text"
- /** The text content. */
- text: string
-}
-
-interface ImageInputPart {
- type: "image"
- /** Source of the image content. */
- source: InputContentSource
- /** Provider-specific metadata (e.g., OpenAI detail: "auto" | "low" | "high"). */
- metadata?: TMetadata
-}
-
-interface AudioInputPart {
- type: "audio"
- /** Source of the audio content. */
- source: InputContentSource
- /** Provider-specific metadata (e.g., format, sample rate). */
- metadata?: TMetadata
-}
-
-interface VideoInputPart {
- type: "video"
- /** Source of the video content. */
- source: InputContentSource
- /** Provider-specific metadata (e.g., duration, resolution). */
- metadata?: TMetadata
-}
-
-interface DocumentInputPart {
- type: "document"
- /** Source of the document content. */
- source: InputContentSource
- /** Provider-specific metadata (e.g., Anthropic media_type for PDFs). */
- metadata?: TMetadata
-}
-
-type InputContentPart =
- | TextInputPart
- | ImageInputPart
- | AudioInputPart
- | VideoInputPart
- | DocumentInputPart
-
-// ── Updated UserMessage ───────────────────────────────────────
-
-type UserMessage = {
- id: string
- role: "user"
- content: string | InputContentPart[]
- name?: string
-}
-```
-
-### Modality Type
-
-The `Modality` type enumerates the supported content modalities:
-
-| Value | Description |
-| ------------ | ------------------------------------------ |
-| `"text"` | Plain text content |
-| `"image"` | Image content (JPEG, PNG, GIF, WebP, etc.) |
-| `"audio"` | Audio content (WAV, MP3, OGG, etc.) |
-| `"video"` | Video content (MP4, WebM, etc.) |
-| `"document"` | Document content (PDF, DOCX, XLSX, etc.) |
-
-### Source Types
-
-Every non-text content part carries a `source` property that describes how the
-content is delivered. The source is a discriminated union with two variants:
-
-#### InputContentDataSource
-
-Inline base64-encoded content.
-
-| Property | Type | Required | Description |
-| ---------- | -------- | -------- | ----------------------------------------------- |
-| `type` | `"data"` | ✓ | Discriminator for inline data |
-| `value` | `string` | ✓ | Base64-encoded content |
-| `mimeType` | `string` | ✓ | MIME type (required to ensure correct handling) |
-
-#### InputContentUrlSource
-
-URL-referenced content.
-
-| Property | Type | Required | Description |
-| ---------- | --------- | -------- | ------------------------------- |
-| `type` | `"url"` | ✓ | Discriminator for URL reference |
-| `value` | `string` | ✓ | HTTP(S) URL or data URI |
-| `mimeType` | `string?` | | Optional MIME type hint |
-
-### Content Part Types
-
-#### TextInputPart
-
-Represents plain text content within a multimodal message.
-
-| Property | Type | Description |
-| -------- | -------- | ------------------------------- |
-| `type` | `"text"` | Identifies this as text content |
-| `text` | `string` | The text content |
-
-#### ImageInputPart
-
-Represents image content. Maps directly to provider image inputs (e.g., OpenAI
-vision, Anthropic image blocks).
-
-| Property | Type | Description |
-| ---------- | -------------------- | -------------------------------------------------------- |
-| `type` | `"image"` | Identifies this as image content |
-| `source` | `InputContentSource` | Either inline data or URL reference |
-| `metadata` | `TMetadata?` | Provider-specific metadata (e.g., OpenAI `detail` level) |
-
-#### AudioInputPart
-
-Represents audio content.
-
-| Property | Type | Description |
-| ---------- | -------------------- | ------------------------------------------------------ |
-| `type` | `"audio"` | Identifies this as audio content |
-| `source` | `InputContentSource` | Either inline data or URL reference |
-| `metadata` | `TMetadata?` | Provider-specific metadata (e.g., format, sample rate) |
-
-#### VideoInputPart
-
-Represents video content.
-
-| Property | Type | Description |
-| ---------- | -------------------- | ------------------------------------------------------- |
-| `type` | `"video"` | Identifies this as video content |
-| `source` | `InputContentSource` | Either inline data or URL reference |
-| `metadata` | `TMetadata?` | Provider-specific metadata (e.g., duration, resolution) |
-
-#### DocumentInputPart
-
-Represents document content such as PDFs, Word documents, or spreadsheets.
-
-| Property | Type | Description |
-| ---------- | -------------------- | --------------------------------------------------------- |
-| `type` | `"document"` | Identifies this as document content |
-| `source` | `InputContentSource` | Either inline data or URL reference |
-| `metadata` | `TMetadata?` | Provider-specific metadata (e.g., Anthropic `media_type`) |
-
-### Provider Metadata
-
-The generic `metadata` field on each content part allows provider-specific
-information to flow through the protocol without polluting the core schema.
-Examples:
-
-* **OpenAI**: `ImageInputPart<{ detail: 'auto' | 'low' | 'high' }>`
-* **Anthropic**: `DocumentInputPart<{ media_type: 'application/pdf' }>`
-* **Custom**: Any provider can define its own metadata shape
-
-## Implementation Examples
-
-### Simple Text Message (Backward Compatible)
-
-```json theme={null}
-{
- "id": "msg-001",
- "role": "user",
- "content": "What's in this image?"
-}
-```
-
-### Image with Inline Data
-
-```json theme={null}
-{
- "id": "msg-002",
- "role": "user",
- "content": [
- {
- "type": "text",
- "text": "What's in this image?"
- },
- {
- "type": "image",
- "source": {
- "type": "data",
- "value": "/9j/4AAQSkZJRg...",
- "mimeType": "image/jpeg"
- }
- }
- ]
-}
-```
-
-### Image with URL Reference
-
-```json theme={null}
-{
- "id": "msg-003",
- "role": "user",
- "content": [
- {
- "type": "text",
- "text": "What's in this image?"
- },
- {
- "type": "image",
- "source": {
- "type": "url",
- "value": "https://example.com/photo.png"
- },
- "metadata": {
- "detail": "high"
- }
- }
- ]
-}
-```
-
-### Multiple Images with Question
-
-```json theme={null}
-{
- "id": "msg-004",
- "role": "user",
- "content": [
- {
- "type": "text",
- "text": "What are the differences between these images?"
- },
- {
- "type": "image",
- "source": {
- "type": "url",
- "value": "https://example.com/image1.png",
- "mimeType": "image/png"
- }
- },
- {
- "type": "image",
- "source": {
- "type": "url",
- "value": "https://example.com/image2.png",
- "mimeType": "image/png"
- }
- }
- ]
-}
-```
-
-### Audio Transcription Request
-
-```json theme={null}
-{
- "id": "msg-005",
- "role": "user",
- "content": [
- {
- "type": "text",
- "text": "Please transcribe this audio recording"
- },
- {
- "type": "audio",
- "source": {
- "type": "url",
- "value": "https://example.com/meeting-recording.wav",
- "mimeType": "audio/wav"
- }
- }
- ]
-}
-```
-
-### Document Analysis
-
-```json theme={null}
-{
- "id": "msg-006",
- "role": "user",
- "content": [
- {
- "type": "text",
- "text": "Summarize the key points from this PDF"
- },
- {
- "type": "document",
- "source": {
- "type": "url",
- "value": "https://example.com/reports/q4-2024.pdf",
- "mimeType": "application/pdf"
- }
- }
- ]
-}
-```
-
-### Video Analysis
-
-```json theme={null}
-{
- "id": "msg-007",
- "role": "user",
- "content": [
- {
- "type": "text",
- "text": "Describe what happens in this video"
- },
- {
- "type": "video",
- "source": {
- "type": "url",
- "value": "https://example.com/demo.mp4",
- "mimeType": "video/mp4"
- },
- "metadata": {
- "duration": 120
- }
- }
- ]
-}
-```
-
-### Mixed Modalities
-
-```json theme={null}
-{
- "id": "msg-008",
- "role": "user",
- "content": [
- {
- "type": "text",
- "text": "Compare the screenshot with the design spec"
- },
- {
- "type": "image",
- "source": {
- "type": "data",
- "value": "iVBORw0KGgo...",
- "mimeType": "image/png"
- }
- },
- {
- "type": "document",
- "source": {
- "type": "url",
- "value": "https://example.com/design-spec.pdf",
- "mimeType": "application/pdf"
- }
- }
- ]
-}
-```
-
-## Implementation Considerations
-
-### Client SDK Changes
-
-TypeScript SDK:
-
-* New `Modality` type and all `InputContentPart` types in `@ag-ui/core`
-* `InputContentSource`, `InputContentDataSource`, `InputContentUrlSource` types
-* Updated `UserMessage` with `content: string | InputContentPart[]`
-* Helper methods for constructing typed content parts
-* Provider-specific metadata generics on each content part type
-
-Python SDK:
-
-* Pydantic models for each content part type (`TextInputPart`, `ImageInputPart`,
- etc.)
-* `InputContentSource` discriminated union
-* Updated `UserMessage` model
-* Provider-specific metadata support via generics
-
-### Framework Integration
-
-Frameworks need to:
-
-* Parse typed `InputContentPart` parts and dispatch on `part.type`
-* Map content parts to provider-specific formats (the typed structure makes this
- straightforward)
-* Use `source.type` to determine whether to send inline data or a URL to the
- provider
-* Forward `metadata` to providers that support it
-* Handle fallbacks for models that don't support certain modalities
-* Validate that `mimeType` is appropriate for the declared content part type
-
-## Use Cases
-
-### Visual Question Answering
-
-Users can upload images (`ImageInputPart`) and ask questions about them.
-
-### Document Processing
-
-Upload PDFs, Word documents, or spreadsheets (`DocumentInputPart`) for analysis.
-
-### Audio Transcription and Analysis
-
-Process voice recordings, podcasts, or meeting audio (`AudioInputPart`).
-
-### Video Understanding
-
-Analyze video content (`VideoInputPart`) for summaries, descriptions, or content
-moderation.
-
-### Multi-modal Comparison
-
-Compare multiple images, documents, or mixed media using different content part
-types in a single message.
-
-### Screenshot Analysis
-
-Share screenshots (`ImageInputPart`) for UI/UX feedback or debugging assistance.
-
-## Testing Strategy
-
-* Unit tests for each `InputContentPart` type and `InputContentSource` variant
-* Validate `source.type` discriminator correctly narrows the union
-* Integration tests with multimodal LLMs (OpenAI, Anthropic, Google)
-* Backward compatibility tests with plain `string` content
-* Verify `metadata` passthrough for provider-specific fields
-* Performance tests for large base64 payloads in `InputContentDataSource`
-* Security tests for URL validation and content sanitization
-* Type-safety tests ensuring generic `TMetadata` works across SDKs
-
-## References
-
-* [OpenAI Vision API](https://platform.openai.com/docs/guides/vision)
-* [Anthropic Vision](https://docs.anthropic.com/en/docs/vision)
-* [Vercel AI SDK — Multi-modal Content](https://sdk.vercel.ai/docs/ai-sdk-core/generating-text#multi-modal-content)
-* [MIME Types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types)
-* [Data URLs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URLs)
-
-
-# Overview
-Source: https://docs.ag-ui.com/drafts/overview
-
-Draft changes being considered for the AG-UI protocol
-
-# Overview
-
-This section contains draft changes being considered for the AG-UI protocol. These proposals are under internal review and may be modified or withdrawn before implementation.
-
-## Current Drafts
-
-
-
- Support for LLM reasoning visibility and continuity with encrypted content
-
-
-
- Support for multimodal input messages including images, audio, and files
-
-
-
- Native support for agent pauses requiring human approval or input
-
-
-
- AI-generated interfaces without requiring custom tool renderers
-
-
-
- Annotations and signals independent of agent runs
-
-
-
-## Status Definitions
-
-* **Draft** - Initial proposal under consideration
-* **Under Review** - Active development and testing
-* **Accepted** - Approved for implementation
-* **Implemented** - Merged into the main protocol specification
-* **Withdrawn** - Proposal has been withdrawn or superseded
-
-
-# AG-UI Overview
-Source: https://docs.ag-ui.com/introduction
-
-
-
-# The Agent–User Interaction (AG-UI) Protocol
-
-AG-UI is an open, lightweight, event-based protocol that standardizes how AI agents connect to user-facing applications.
-
-AG-UI is designed to be the general-purpose, bi-directional connection between a user-facing application and any agentic backend.
-
-Built for simplicity and flexibility, it standardizes how agent state, UI intents, and user interactions flow between your model/agent runtime and user-facing frontend applications—to allow application developers to ship reliable, debuggable, user‑friendly agentic features fast while focusing on application needs and avoiding complex ad-hoc wiring.
-
-
-
-
-
-
-
-***
-
-## Agentic Protocols
-
-
- Confused about "A2UI" and "AG-UI"? That's understandable! Despite the naming similarities, they are quite different and work well together. A2UI is a [generative UI specification](./concepts/generative-ui-specs) - allowing agents to deliver UI widgets, where AG-UI is the Agent↔User Interaction protocol - which connects an agentic frontend to any agentic backend. [Learn more](https://copilotkit.ai/ag-ui-and-a2ui)
-
-
-AG-UI is one of three prominent open [agentic protocols](./agentic-protocols).
-
-| **Layer** | **Protocol / Example** | **Purpose** |
-| ---------------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
-| **Agent ↔ User Interaction** | **AG-UI (Agent–User Interaction Protocol)** | The open, event-based standard that connects agents to user-facing applications — enabling real-time, multimodal, interactive experiences. |
-| **Agent ↔ Tools & Data** | **MCP (Model Context Protocol)** | Open standard (originated by Anthropic) that lets agents securely connect to external systems — tools, workflows, and data sources. |
-| **Agent ↔ Agent** | **A2A (Agent to Agent)** | Open standard (originated by Google) which defines how agents coordinate and share work across distributed agentic systems. |
-
-***
-
-## Building blocks (today & upcoming)
-
-
-
-
- Streaming chat
-
-
-
-
- Live token and event streaming for responsive multi turn sessions, with cancel and resume.
-
-
-
-
-
-
- Multimodality
-
-
-
-
- Typed attachments and real time media (files, images, audio, transcripts); supports voice, previews, annotations, provenance.
-
-
-
-
-
-
- Generative UI, static
-
-
-
-
- Render model output as stable, typed components under app control.
-
-
-
-
-
-
- Generative UI, declarative
-
-
-
-
- Small declarative language for constrained yet open-ended agent UIs; agents propose trees and constraints, the app validates and mounts.
-
-
-
-
-
-
- Shared state
-
-
-
-
- (Read-only & read-write). Typed store shared between agent and app, with streamed event-sourced diffs and conflict resolution for snappy collaboration.
-
-
-
-
-
-
- Thinking steps
-
-
-
-
- Visualize intermediate reasoning from traces and tool events; no raw chain of thought.
-
-
-
-
-
-
- Frontend tool calls
-
-
-
-
- Typed handoffs from agent to frontend-executed actions, and back.
-
-
-
-
-
-
- Backend tool rendering
-
-
-
-
- Visualize backend tool outputs in app and chat, emit side effects as first-class events.
-
-
-
-
-
-
- Interrupts (human in the loop)
-
-
-
-
- Pause, approve, edit, retry, or escalate mid flow without losing state.
-
-
-
-
-
-
- Sub-agents and composition
-
-
-
-
- Nested delegation with scoped state, tracing, and cancellation.
-
-
-
-
-
-
- Agent steering
-
-
-
-
- Dynamically redirect agent execution with real-time user input to guide behavior and outcomes.
-
-
-
-
-
-
- Tool output streaming
-
-
-
-
- Stream tool results and logs so UIs can render long-running effects in real time.
-
-
-
-
-
-
- Custom events
-
-
-
-
- Open-ended data exchange for needs not covered by the protocol.
-
-
-
-
-
-***
-
-## Why Agentic Apps need AG-UI
-
-Agentic applications break the simple request/response model that dominated frontend-backend development in the pre-agentic era: a client makes a request, the server returns data, the client renders it, and the interaction ends.
-
-#### The requirements of user‑facing agents
-
-While agents are just software, they exhibit characteristics that make them challenging to serve behind traditional REST/GraphQL APIs:
-
-* Agents are **long‑running** and **stream** intermediate work—often across multi‑turn sessions.
-* Agents are **nondeterministic** and can **control application UI nondeterministically**.
-* Agents simultanously mix **structured + unstructured IO** (e.g. text & voice, alongside tool calls and state updates).
-* Agents need user-interactive **composition**: e.g. they may call sub‑agents, often recursively.
-* And more...
-
-AG-UI is an event-based protocol that enables dynamic communication between agentic frontends and backends. It builds on top of the foundational protocols of the web (HTTP, WebSockets) as an abstraction layer designed for the agentic age—bridging the gap between traditional client-server architectures and the dynamic, stateful nature of AI agents.
-
-***
-
-## AG-UI in Action
-
-
-
-
-
-
- You can see demo apps of the AG-UI features with the framework of your choice, with preview, code, and walkthrough docs in the [AG-UI Dojo](https://dojo.ag-ui.com/)
-
-
-***
-
-## Supported Integrations
-
-AG-UI was born from CopilotKit's initial **partnership** with LangGraph and CrewAI - and brings the incredibly popular agent-user-interactivity infrastructure to the wider agentic ecosystem.
-
-**1st party** = the platforms that have AG‑UI built in and provide documentation for guidance.
-
-### Direct to LLM
-
-| Framework | Status | AG-UI Resources |
-| :------------ | --------- | ------------------------------------------------ |
-| Direct to LLM | Supported | [Docs](https://docs.copilotkit.ai/direct-to-llm) |
-
-### Agent Framework - Partnerships
-
-| Framework | Status | AG-UI Resources |
-| :----------------------------------------------- | --------- | --------------------------------------------------------------------------------------------------------------------- |
-| [LangGraph](https://www.langchain.com/langgraph) | Supported | [Docs](https://docs.copilotkit.ai/langgraph/), [Demos](https://dojo.ag-ui.com/langgraph-fastapi/feature/shared_state) |
-| [CrewAI](https://crewai.com/) | Supported | [Docs](https://docs.copilotkit.ai/crewai-flows), [Demos](https://dojo.ag-ui.com/crewai/feature/shared_state) |
-
-### Agent Framework - 1st Party
-
-| Framework | Status | AG-UI Resources |
-| :--------------------------------------------------------------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
-| [Microsoft Agent Framework](https://azure.microsoft.com/en-us/blog/introducing-microsoft-agent-framework/) | Supported | [Docs](https://docs.copilotkit.ai/microsoft-agent-framework), [Demos](https://dojo.ag-ui.com/microsoft-agent-framework-dotnet/feature/shared_state) |
-| [Google ADK](https://google.github.io/adk-docs/get-started/) | Supported | [Docs](https://docs.copilotkit.ai/adk), [Demos](https://dojo.ag-ui.com/adk-middleware/feature/shared_state?openCopilot=true) |
-| [AWS Strands Agents](https://github.com/strands-agents/sdk-python) | Supported | [Docs](https://docs.copilotkit.ai/aws-strands), [Demos](https://dojo.ag-ui.com/aws-strands/feature/shared_state) |
-| [Mastra](https://mastra.ai/) | Supported | [Docs](https://docs.copilotkit.ai/mastra/), [Demos](https://dojo.ag-ui.com/mastra/feature/tool_based_generative_ui) |
-| [Pydantic AI](https://github.com/pydantic/pydantic-ai) | Supported | [Docs](https://docs.copilotkit.ai/pydantic-ai/), [Demos](https://dojo.ag-ui.com/pydantic-ai/feature/shared_state) |
-| [Agno](https://github.com/agno-agi/agno) | Supported | [Docs](https://docs.copilotkit.ai/agno/), [Demos](https://dojo.ag-ui.com/agno/feature/tool_based_generative_ui) |
-| [LlamaIndex](https://github.com/run-llama/llama_index) | Supported | [Docs](https://docs.copilotkit.ai/llamaindex/), [Demos](https://dojo.ag-ui.com/llamaindex/feature/shared_state) |
-| [AG2](https://ag2.ai/) | Supported | [Docs](https://docs.copilotkit.ai/ag2/) [Demos](https://dojo.ag-ui.com/ag2/feature/shared_state) |
-| [AWS Bedrock Agents](https://aws.amazon.com/bedrock/agents/) | In Progress | – |
-
-### Agent Framework - Community
-
-| Framework | Status | AG-UI Resources |
-| :----------------------------------------------------------------- | ----------- | --------------- |
-| [OpenAI Agent SDK](https://openai.github.io/openai-agents-python/) | In Progress | – |
-| [Cloudflare Agents](https://developers.cloudflare.com/agents/) | In Progress | – |
-
-### Agent Interaction Protocols
-
-| Protocol | Status | AG-UI Resources | Integrations |
-| :------------------------------------------ | --------- | ----------------------------------------------- | ------------ |
-| [A2A Middleware](https://a2a-protocol.org/) | Supported | [Docs](https://docs.copilotkit.ai/a2a-protocol) | Partnership |
-
-### Specification (standard)
-
-| Framework | Status | AG-UI Resources |
-| :------------------------------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
-| [Oracle Agent Spec](http://oracle.github.io/agent-spec/) | Supported | [Docs](https://go.copilotkit.ai/copilotkit-oracle-docs), [Demos](https://dojo.ag-ui.com/agent-spec-langgraph/feature/tool_based_generative_ui) |
-
-### SDKs
-
-| SDK | Status | AG-UI Resources | Integrations |
-| :----------- | ----------- | ------------------------------------------------------------------------------------------------------------ | ------------ |
-| [Kotlin]() | Supported | [Getting Started](https://github.com/ag-ui-protocol/ag-ui/blob/main/docs/sdk/kotlin/overview.mdx) | Community |
-| [Golang]() | Supported | [Getting Started](https://github.com/ag-ui-protocol/ag-ui/blob/main/docs/sdk/go/overview.mdx) | Community |
-| [Dart]() | Supported | [Getting Started](https://github.com/ag-ui-protocol/ag-ui/tree/main/sdks/community/dart) | Community |
-| [Java]() | Supported | [Getting Started](https://github.com/ag-ui-protocol/ag-ui/blob/main/docs/sdk/java/overview.mdx) | Community |
-| [Rust]() | Supported | [Getting Started](https://github.com/ag-ui-protocol/ag-ui/tree/main/sdks/community/rust/crates/ag-ui-client) | Community |
-| [.NET]() | In Progress | [PR](https://github.com/ag-ui-protocol/ag-ui/pull/38) | Community |
-| [Nim]() | In Progress | [PR](https://github.com/ag-ui-protocol/ag-ui/pull/29) | Community |
-| [Flowise]() | In Progress | [GitHub Source](https://github.com/ag-ui-protocol/ag-ui/issues/367) | Community |
-| [Langflow]() | In Progress | [GitHub Source](https://github.com/ag-ui-protocol/ag-ui/issues/366) | Community |
-
-### Clients
-
-| Client | Status | AG-UI Resources | Integrations |
-| :----------------------------------------------------- | ----------- | ----------------------------------------------------------------------------- | ------------ |
-| [CopilotKit](https://github.com/CopilotKit/CopilotKit) | Supported | [Getting Started](https://docs.copilotkit.ai/direct-to-llm/guides/quickstart) | 1st Party |
-| [Terminal + Agent]() | Supported | [Getting Started](https://docs.ag-ui.com/quickstart/clients) | Community |
-| [React Native](https://reactnative.dev/) | Help Wanted | [GitHub Source](https://github.com/ag-ui-protocol/ag-ui/issues/510) | Community |
-
-***
-
-## Quick Start
-
-Choose the path that fits your needs:
-
-
-
- Build agentic applications powered by AG-UI compatible agents.
-
-
-
- Build integrations for new agent frameworks, custom in-house solutions, or use AG-UI without any agent framework.
-
-
-
- Build new clients for AG-UI-compatible agents (web, mobile, slack, messaging, etc.)
-
-
-
-## Explore AG-UI
-
-Dive deeper into AG-UI's core concepts and capabilities:
-
-
-
- Understand how AG-UI connects agents, protocols, and front-ends
-
-
-
- Learn about AG-UI's event-driven protocol
-
-
-
-## Resources
-
-Explore guides, tools, and integrations to help you build, optimize, and extend
-your AG-UI implementation. These resources cover everything from practical
-development workflows to debugging techniques.
-
-
-
- Use Cursor to build AG-UI implementations faster
-
-
-
- Fix common issues when working with AG-UI servers and clients
-
-
-
-## Contributing
-
-Want to contribute? Check out our
-[Contributing Guide](/development/contributing) to learn how you can help
-improve AG-UI.
-
-## Support and Feedback
-
-Here's how to get help or provide feedback:
-
-* For bug reports and feature requests related to the AG-UI specification, SDKs,
- or documentation (open source), please
- [create a GitHub issue](https://github.com/ag-ui-protocol/ag-ui/issues)
-* For discussions or Q\&A about AG-UI, please join the [Discord community](https://discord.gg/Jd3FzfdJa8)
-
-
-# Build applications
-Source: https://docs.ag-ui.com/quickstart/applications
-
-Build agentic applications utilizing compatible event AG-UI event streams
-
-# Introduction
-
-AG-UI provides a concise, event-driven protocol that lets any agent stream rich,
-structured output to any client. It can be used to connect any agentic system to
-any client.
-
-A client is defined as any system that can receieve, display, and respond to
-AG-UI events. For more information on existing clients and integrations, see
-the [integrations](/integrations) page.
-
-# Automatic Setup
-
-AG-UI provides a CLI tool to automatically create or scaffold a new application with any client and server.
-
-```sh theme={null}
-npx create-ag-ui-app@latest
-```
-
-
-
-Once the setup is done, start the server with
-
-```sh theme={null}
-npm run dev
-```
-
-For the copilotkit example you can head to [http://localhost:3000/copilotkit](http://localhost:3000/copilotkit) to see the app in action.
-
-
-# Build clients
-Source: https://docs.ag-ui.com/quickstart/clients
-
-Showcase: build a conversational CLI agent from scratch using AG-UI and Mastra
-
-# Introduction
-
-A client implementation allows you to **build conversational applications that
-leverage AG-UI's event-driven protocol**. This approach creates a direct
-interface between your users and AI agents, demonstrating direct access to the
-AG-UI protocol.
-
-## When to use a client implementation
-
-Building your own client is useful if you want to explore/hack on the AG-UI
-protocol. For production use, use a full-featured client like
-[CopilotKit](https://copilotkit.ai).
-
-## What you'll build
-
-In this guide, we'll create a CLI client that:
-
-1. Uses the `MastraAgent` from `@ag-ui/mastra`
-2. Connects to OpenAI's GPT-4o model
-3. Implements a weather tool for real-world functionality
-4. Provides an interactive chat interface in the terminal
-
-Let's get started!
-
-## Prerequisites
-
-Before we begin, make sure you have:
-
-* [Node.js](https://nodejs.org/) **22.13.0 or later**
-* An **OpenAI API key**
-* [pnpm](https://pnpm.io/) package manager
-
-### 1. Provide your OpenAI API key
-
-First, let's set up your API key:
-
-```bash theme={null}
-# Set your OpenAI API key
-export OPENAI_API_KEY=your-api-key-here
-```
-
-### 2. Install pnpm
-
-If you don't have pnpm installed:
-
-```bash theme={null}
-# Install pnpm
-npm install -g pnpm
-```
-
-## Step 1 – Initialize your project
-
-Create a new directory for your AG-UI client:
-
-```bash theme={null}
-mkdir my-ag-ui-client
-cd my-ag-ui-client
-```
-
-Initialize a new Node.js project:
-
-```bash theme={null}
-pnpm init
-```
-
-### Set up TypeScript and basic configuration
-
-Install TypeScript and essential development dependencies:
-
-```bash theme={null}
-pnpm add -D typescript @types/node tsx
-```
-
-Create a `tsconfig.json` file:
-
-```json theme={null}
-{
- "compilerOptions": {
- "target": "ES2022",
- "module": "commonjs",
- "lib": ["ES2022"],
- "outDir": "./dist",
- "rootDir": "./src",
- "strict": true,
- "esModuleInterop": true,
- "skipLibCheck": true,
- "forceConsistentCasingInFileNames": true,
- "resolveJsonModule": true
- },
- "include": ["src/**/*"],
- "exclude": ["node_modules", "dist"]
-}
-```
-
-Update your `package.json` scripts:
-
-```json theme={null}
-{
- "scripts": {
- "start": "tsx src/index.ts",
- "dev": "tsx --watch src/index.ts",
- "build": "tsc",
- "clean": "rm -rf dist"
- }
-}
-```
-
-## Step 2 – Install AG-UI and dependencies
-
-Install the core AG-UI packages and dependencies:
-
-```bash theme={null}
-# Core AG-UI packages
-pnpm add @ag-ui/client @ag-ui/core @ag-ui/mastra
-
-# Mastra ecosystem packages
-pnpm add @mastra/core @mastra/client-js @mastra/memory @mastra/libsql
-
-# Mastra peer dependencies
-pnpm add zod
-```
-
-## Step 3 – Create your agent
-
-Let's create a basic conversational agent. Create `src/agent.ts`:
-
-```typescript theme={null}
-import { Agent } from "@mastra/core/agent"
-import { MastraAgent } from "@ag-ui/mastra"
-import { Memory } from "@mastra/memory"
-import { LibSQLStore } from "@mastra/libsql"
-
-export const agent = new MastraAgent({
- resourceId: "cliExample",
- agent: new Agent({
- id: "ag-ui-assistant",
- name: "AG-UI Assistant",
- instructions: `
- You are a helpful AI assistant. Be friendly, conversational, and helpful.
- Answer questions to the best of your ability and engage in natural conversation.
- `,
- model: "openai/gpt-4o",
- memory: new Memory({
- storage: new LibSQLStore({
- id: "storage-memory",
- url: "file:./assistant.db",
- }),
- }),
- }),
- threadId: "main-conversation",
-})
-```
-
-### What's happening in the agent?
-
-1. **MastraAgent** – We wrap a Mastra Agent with the AG-UI protocol adapter
-2. **Model Configuration** – We use OpenAI's GPT-4o for high-quality responses
-3. **Memory Setup** – We configure persistent memory using LibSQL for
- conversation context
-4. **Instructions** – We give the agent basic guidelines for helpful
- conversation
-
-## Step 4 – Create the CLI interface
-
-Now let's create the interactive chat interface. Create `src/index.ts`:
-
-```typescript theme={null}
-import * as readline from "readline"
-import { agent } from "./agent"
-import { randomUUID } from "@ag-ui/client"
-
-const rl = readline.createInterface({
- input: process.stdin,
- output: process.stdout,
-})
-
-async function chatLoop() {
- console.log("🤖 AG-UI Assistant started!")
- console.log("Type your messages and press Enter. Press Ctrl+D to quit.\n")
-
- return new Promise((resolve) => {
- const promptUser = () => {
- rl.question("> ", async (input) => {
- if (input.trim() === "") {
- promptUser()
- return
- }
- console.log("")
-
- // Pause input while processing
- rl.pause()
-
- // Add user message to conversation
- agent.messages.push({
- id: randomUUID(),
- role: "user",
- content: input.trim(),
- })
-
- try {
- // Run the agent with event handlers
- await agent.runAgent(
- {}, // No additional configuration needed
- {
- onTextMessageStartEvent() {
- process.stdout.write("🤖 Assistant: ")
- },
- onTextMessageContentEvent({ event }) {
- process.stdout.write(event.delta)
- },
- onTextMessageEndEvent() {
- console.log("\n")
- },
- }
- )
- } catch (error) {
- console.error("❌ Error:", error)
- }
-
- // Resume input
- rl.resume()
- promptUser()
- })
- }
-
- // Handle Ctrl+D to quit
- rl.on("close", () => {
- console.log("\n👋 Thanks for using AG-UI Assistant!")
- resolve()
- })
-
- promptUser()
- })
-}
-
-async function main() {
- await chatLoop()
-}
-
-main().catch(console.error)
-```
-
-### What's happening in the CLI interface?
-
-1. **Readline Interface** – We create an interactive prompt for user input
-2. **Message Management** – We add each user input to the agent's conversation
- history
-3. **Event Handling** – We listen to AG-UI events to provide real-time feedback
-4. **Streaming Display** – We show the agent's response as it's being generated
-
-## Step 5 – Test your assistant
-
-Let's run your new AG-UI client:
-
-```bash theme={null}
-pnpm dev
-```
-
-You should see:
-
-```
-🤖 AG-UI Assistant started!
-Type your messages and press Enter. Press Ctrl+D to quit.
-
->
-```
-
-Try asking questions like:
-
-* "Hello! How are you?"
-* "What can you help me with?"
-* "Tell me a joke"
-* "Explain quantum computing in simple terms"
-
-You'll see the agent respond with streaming text in real-time!
-
-## Step 6 – Understanding the AG-UI event flow
-
-Let's break down what happens when you send a message:
-
-1. **User Input** – You type a question and press Enter
-2. **Message Added** – Your input is added to the conversation history
-3. **Agent Processing** – The agent analyzes your request and formulates a
- response
-4. **Response Generation** – The agent streams its response back
-5. **Streaming Output** – You see the response appear word by word
-
-### Event types you're handling:
-
-* `onTextMessageStartEvent` – Agent starts responding
-* `onTextMessageContentEvent` – Each chunk of the response
-* `onTextMessageEndEvent` – Response is complete
-
-## Step 7 – Add tool functionality
-
-Now that you have a working chat interface, let's add some real-world
-capabilities by creating tools. We'll start with a weather tool.
-
-### Create your first tool
-
-Let's create a weather tool that your agent can use. Create the directory
-structure:
-
-```bash theme={null}
-mkdir -p src/tools
-```
-
-Create `src/tools/weather.tool.ts`:
-
-```typescript theme={null}
-import { createTool } from "@mastra/core/tools"
-import { z } from "zod"
-
-interface GeocodingResponse {
- results: {
- latitude: number
- longitude: number
- name: string
- }[]
-}
-
-interface WeatherResponse {
- current: {
- time: string
- temperature_2m: number
- apparent_temperature: number
- relative_humidity_2m: number
- wind_speed_10m: number
- wind_gusts_10m: number
- weather_code: number
- }
-}
-
-export const weatherTool = createTool({
- id: "get-weather",
- description: "Get current weather for a location",
- inputSchema: z.object({
- location: z.string().describe("City name"),
- }),
- outputSchema: z.object({
- temperature: z.number(),
- feelsLike: z.number(),
- humidity: z.number(),
- windSpeed: z.number(),
- windGust: z.number(),
- conditions: z.string(),
- location: z.string(),
- }),
- execute: async (inputData) => {
- return await getWeather(inputData.location)
- },
-})
-
-const getWeather = async (location: string) => {
- const geocodingUrl = `https://geocoding-api.open-meteo.com/v1/search?name=${encodeURIComponent(
- location
- )}&count=1`
- const geocodingResponse = await fetch(geocodingUrl)
- const geocodingData = (await geocodingResponse.json()) as GeocodingResponse
-
- if (!geocodingData.results?.[0]) {
- throw new Error(`Location '${location}' not found`)
- }
-
- const { latitude, longitude, name } = geocodingData.results[0]
-
- const weatherUrl = `https://api.open-meteo.com/v1/forecast?latitude=${latitude}&longitude=${longitude}¤t=temperature_2m,apparent_temperature,relative_humidity_2m,wind_speed_10m,wind_gusts_10m,weather_code`
-
- const response = await fetch(weatherUrl)
- const data = (await response.json()) as WeatherResponse
-
- return {
- temperature: data.current.temperature_2m,
- feelsLike: data.current.apparent_temperature,
- humidity: data.current.relative_humidity_2m,
- windSpeed: data.current.wind_speed_10m,
- windGust: data.current.wind_gusts_10m,
- conditions: getWeatherCondition(data.current.weather_code),
- location: name,
- }
-}
-
-function getWeatherCondition(code: number): string {
- const conditions: Record = {
- 0: "Clear sky",
- 1: "Mainly clear",
- 2: "Partly cloudy",
- 3: "Overcast",
- 45: "Foggy",
- 48: "Depositing rime fog",
- 51: "Light drizzle",
- 53: "Moderate drizzle",
- 55: "Dense drizzle",
- 56: "Light freezing drizzle",
- 57: "Dense freezing drizzle",
- 61: "Slight rain",
- 63: "Moderate rain",
- 65: "Heavy rain",
- 66: "Light freezing rain",
- 67: "Heavy freezing rain",
- 71: "Slight snow fall",
- 73: "Moderate snow fall",
- 75: "Heavy snow fall",
- 77: "Snow grains",
- 80: "Slight rain showers",
- 81: "Moderate rain showers",
- 82: "Violent rain showers",
- 85: "Slight snow showers",
- 86: "Heavy snow showers",
- 95: "Thunderstorm",
- 96: "Thunderstorm with slight hail",
- 99: "Thunderstorm with heavy hail",
- }
- return conditions[code] || "Unknown"
-}
-```
-
-### What's happening in the weather tool?
-
-1. **Tool Definition** – We use `createTool` from Mastra to define the tool's
- interface
-2. **Input Schema** – We specify that the tool accepts a location string
-3. **Output Schema** – We define the structure of the weather data returned
-4. **API Integration** – We fetch data from Open-Meteo's free weather API
-5. **Data Processing** – We convert weather codes to human-readable conditions
-
-### Update your agent
-
-Now let's update our agent to use the weather tool. Update `src/agent.ts`:
-
-```typescript theme={null}
-import { weatherTool } from "./tools/weather.tool" // <--- Import the tool
-
-export const agent = new MastraAgent({
- agent: new Agent({
- // ...
-
- tools: { weatherTool }, // <--- Add the tool to the agent
-
- // ...
- }),
- threadId: "main-conversation",
-})
-```
-
-### Update your CLI to handle tools
-
-Update your CLI interface in `src/index.ts` to handle tool events:
-
-```typescript theme={null}
-// Add these new event handlers to your agent.runAgent call:
-await agent.runAgent(
- {}, // No additional configuration needed
- {
- // ... existing event handlers ...
-
- onToolCallStartEvent({ event }) {
- console.log("🔧 Tool call:", event.toolCallName)
- },
- onToolCallArgsEvent({ event }) {
- process.stdout.write(event.delta)
- },
- onToolCallEndEvent() {
- console.log("")
- },
- onToolCallResultEvent({ event }) {
- if (event.content) {
- console.log("🔍 Tool call result:", event.content)
- }
- },
- }
-)
-```
-
-### Test your weather tool
-
-Now restart your application and try asking about weather:
-
-```bash theme={null}
-pnpm dev
-```
-
-Try questions like:
-
-* "What's the weather like in London?"
-* "How's the weather in Tokyo today?"
-* "Is it raining in Seattle?"
-
-You'll see the agent use the weather tool to fetch real data and provide
-detailed responses!
-
-## Step 8 – Add more functionality
-
-### Create a browser tool
-
-Let's add a web browsing capability. First install the `open` package:
-
-```bash theme={null}
-pnpm add open
-```
-
-Create `src/tools/browser.tool.ts`:
-
-```typescript theme={null}
-import { createTool } from "@mastra/core/tools"
-import { z } from "zod"
-import { open } from "open"
-
-export const browserTool = createTool({
- id: "open-browser",
- description: "Open a URL in the default web browser",
- inputSchema: z.object({
- url: z.url().describe("The URL to open"),
- }),
- outputSchema: z.object({
- success: z.boolean(),
- message: z.string(),
- }),
- execute: async (inputData) => {
- try {
- await open(inputData.url)
- return {
- success: true,
- message: `Opened ${inputData.url} in your default browser`,
- }
- } catch (error) {
- return {
- success: false,
- message: `Failed to open browser: ${error}`,
- }
- }
- },
-})
-```
-
-### Update your agent with both tools
-
-Update `src/agent.ts` to include both tools:
-
-```typescript theme={null}
-import { Agent } from "@mastra/core/agent"
-import { MastraAgent } from "@ag-ui/mastra"
-import { Memory } from "@mastra/memory"
-import { LibSQLStore } from "@mastra/libsql"
-import { weatherTool } from "./tools/weather.tool"
-import { browserTool } from "./tools/browser.tool"
-
-export const agent = new MastraAgent({
- resourceId: "cliExample",
- agent: new Agent({
- id: "ag-ui-assistant",
- name: "AG-UI Assistant",
- instructions: `
- You are a helpful assistant with weather and web browsing capabilities.
-
- For weather queries:
- - Always ask for a location if none is provided
- - Use the weatherTool to fetch current weather data
-
- For web browsing:
- - Always use full URLs (e.g., "https://www.google.com")
- - Use the browserTool to open web pages
-
- Be friendly and helpful in all interactions!
- `,
- model: "openai/gpt-4o",
- tools: { weatherTool, browserTool }, // Add both tools
- memory: new Memory({
- storage: new LibSQLStore({
- id: "storage-memory",
- url: "file:./assistant.db",
- }),
- }),
- }),
- threadId: "main-conversation",
-})
-```
-
-Now you can ask your assistant to open websites: "Open Google for me" or "Show
-me the weather website".
-
-## Step 9 – Deploy your client
-
-### Building your client
-
-Create a production build:
-
-```bash theme={null}
-pnpm build
-```
-
-### Create a startup script
-
-Add to your `package.json`:
-
-```json theme={null}
-{
- "bin": {
- "weather-assistant": "./dist/index.js"
- }
-}
-```
-
-Add a shebang to your built `dist/index.js`:
-
-```javascript theme={null}
-#!/usr/bin/env node
-// ... rest of your compiled code
-```
-
-Make it executable:
-
-```bash theme={null}
-chmod +x dist/index.js
-```
-
-### Link globally
-
-Install your CLI globally:
-
-```bash theme={null}
-pnpm link --global
-```
-
-Now you can run `weather-assistant` from anywhere!
-
-## Extending your client
-
-Your AG-UI client is now a solid foundation. Here are some ideas for
-enhancement:
-
-### Add more tools
-
-* **Calculator tool** – For mathematical operations
-* **File system tool** – For reading/writing files
-* **API tools** – For connecting to other services
-* **Database tools** – For querying data
-
-### Improve the interface
-
-* **Rich formatting** – Use libraries like `chalk` for colored output
-* **Progress indicators** – Show loading states for long operations
-* **Configuration files** – Allow users to customize settings
-* **Command-line arguments** – Support different modes and options
-
-### Add persistence
-
-* **Conversation history** – Save and restore chat sessions
-* **User preferences** – Remember user settings
-* **Tool results caching** – Cache expensive API calls
-
-## Share your client
-
-Built something useful? Consider sharing it with the community:
-
-1. **Open source it** – Publish your code on GitHub
-2. **Publish to npm** – Make it installable via `npm install`
-3. **Create documentation** – Help others understand and extend your work
-4. **Join discussions** – Share your experience in the
- [AG-UI GitHub Discussions](https://github.com/orgs/ag-ui-protocol/discussions)
-
-## Conclusion
-
-You've built a complete AG-UI client from scratch! Your weather assistant
-demonstrates the core concepts:
-
-* **Event-driven architecture** with real-time streaming
-* **Tool integration** for real-world functionality
-* **Conversation memory** for context retention
-* **Interactive CLI interface** for user engagement
-
-From here, you can extend your client to support any use case – from simple CLI
-tools to complex conversational applications. The AG-UI protocol provides the
-foundation, and your creativity provides the possibilities.
-
-Happy building! 🚀
-
-
-# Introduction
-Source: https://docs.ag-ui.com/quickstart/introduction
-
-Learn how to get started building an AG-UI integration
-
-
-
-# What is an Integration?
-
-An AG-UI integration makes your agent speak the AG-UI protocol. This means your agent can work with any AG-UI compatible client application - like chat interfaces, copilots, or custom AI tools.
-
-Think of it like adding a universal translator to your agent. Instead of building custom APIs for each client, you implement AG-UI once and instantly work with any compatible application.
-
-Agents integrating with AG-UI can:
-
-* **Stream responses** - Real-time text that appears as it's generated
-* **Call client-side tools** - Your agent can use functions and services defined by clients
-* **Share state** - Your agent's state is bidirectional shared state
-* **Execute universally** - Integrate with any AG-UI compatible client application
-* **And much more!** - Check out the full specification [here](/concepts/events).
-
-### When should I make any integration?
-
-If the integration you're looking for is not listed on our [integrations page](/integrations), you'll need to make an integration. We've got a few guides on this below!
-
-However, if you're looking to utilize an existing integration (like LangGraph, CrewAI, Mastra, etc.), you can skip this step and go straight to [building an application](/quickstart/applications).
-
-# Types of Integrations
-
-So you've decided you need an integration! Great, there are **two main ways** to implement an AG-UI integration:
-
-
-
- Emit AG-UI events **directly from your agent** or server.
-
-
-
- **Translate existing protocols** and applications to AG-UI events.
-
-
-
-### When to use a server implementation
-
-Server implementations allow you to directly emit AG-UI events from your agent or server. If you are not using an
-agent framework or haven't created a protocol for your agent framework yet, this is the best way to get started.
-
-Server implementations are also great for:
-
-* Building a **new agent frameworks** from scratch
-* **Maximum control** over how and what events are emitted
-* Exposing your agent as a **standalone API**
-
-### When to use a middleware implementation
-
-Middleware is the flexible option. It allows you to translate existing protocols and applications to AG-UI events
-creating a bridge between your existing system and AG-UI.
-
-Middleware is great for:
-
-* Taking your **existing protocol or API** and **translating it universally**
-* Working within the confines of **an existing system or framework**
-* **When you don't have direct control** over the agent framework or system
-
-
-# Middleware
-Source: https://docs.ag-ui.com/quickstart/middleware
-
-Connect to existing protocols, in process agents or custom solutions via AG-UI
-
-# Introduction
-
-A middleware implementation allows you to **translate existing protocols and
-applications to AG-UI events**. This approach creates a bridge between your
-existing system and AG-UI, making it perfect for adding agent capabilities to
-current applications.
-
-## When to use a middleware implementation
-
-Middleware is the flexible option. It allows you to translate existing protocols
-and applications to AG-UI events creating a bridge between your existing system
-and AG-UI.
-
-Middleware is great for:
-
-* Taking your **existing protocol or API** and **translating it universally**
-* Working within the confines of **an existing system or framework**
-* **When you don't have direct control** over the agent framework or system
-
-## What you'll build
-
-In this guide, we'll create a middleware agent that:
-
-1. Extends the `AbstractAgent` class
-2. Connects to OpenAI's GPT-4o model
-3. Translates OpenAI responses to AG-UI events
-4. Runs in-process with your application
-
-This approach gives you maximum flexibility to integrate with existing codebases
-while maintaining the full power of the AG-UI protocol.
-
-Let's get started!
-
-## Prerequisites
-
-Before we begin, make sure you have:
-
-* [Node.js](https://nodejs.org/) **v16 or later**
-* An **OpenAI API key**
-
-### 1. Provide your OpenAI API key
-
-First, let's set up your API key:
-
-```bash theme={null}
-# Set your OpenAI API key
-export OPENAI_API_KEY=your-api-key-here
-```
-
-### 2. Install build utilities
-
-Install the following tools:
-
-```bash theme={null}
-brew install protobuf
-```
-
-```bash theme={null}
-npm i nx
-```
-
-```bash theme={null}
-curl -fsSL https://get.pnpm.io/install.sh | sh -
-```
-
-## Step 1 – Scaffold your integration
-
-Start by cloning the repo
-
-```bash theme={null}
-git clone git@github.com:ag-ui-protocol/ag-ui.git
-cd ag-ui/
-```
-
-Copy the middleware-starter template to create your OpenAI integration:
-
-```bash theme={null}
-cp -r integrations/middleware-starter integrations/openai
-```
-
-### Update metadata
-
-Open `integrations/openai/package.json` and update the fields to match your new
-folder:
-
-```json theme={null}
-{
- "name": "@ag-ui/openai",
- "author": "Your Name ",
- "version": "0.0.1",
-
- ... rest of package.json
-}
-```
-
-Next, update the class name inside `integrations/openai/src/index.ts`:
-
-```ts theme={null}
-// change the name to OpenAIAgent
-export class OpenAIAgent extends AbstractAgent {}
-```
-
-Finally, introduce your integration to the dojo by adding it to
-`apps/dojo/src/menu.ts`:
-
-```ts theme={null}
-// ...
-export const menuIntegrations: MenuIntegrationConfig[] = [
- // ...
-
- {
- id: "openai",
- name: "OpenAI",
- features: ["agentic_chat"],
- },
-]
-```
-
-And `apps/dojo/src/agents.ts`:
-
-```ts theme={null}
-// ...
-import { OpenAIAgent } from "@ag-ui/openai"
-
-export const agentsIntegrations: AgentIntegrationConfig[] = [
- // ...
-
- {
- id: "openai",
- agents: async () => {
- return {
- agentic_chat: new OpenAIAgent(),
- }
- },
- },
-]
-```
-
-## Step 2 – Add package to dojo dependencies
-
-Open `apps/dojo/package.json` and add the package `@ag-ui/openai`:
-
-```json theme={null}
-{
- "name": "demo-viewer",
- "version": "0.1.0",
- "private": true,
- "scripts": {
- "dev": "next dev",
- "build": "next build",
- "start": "next start",
- "lint": "next lint"
- },
- "dependencies": {
- "@ag-ui/agno": "workspace:*",
- "@ag-ui/langgraph": "workspace:*",
- "@ag-ui/mastra": "workspace:*",
- "@ag-ui/middleware-starter": "workspace:*",
- "@ag-ui/server-starter": "workspace:*",
- "@ag-ui/server-starter-all-features": "workspace:*",
- "@ag-ui/vercel-ai-sdk": "workspace:*",
- "@ag-ui/openai": "workspace:*", <- Add this line
-
- ... rest of package.json
-}
-```
-
-## Step 3 – Start the dojo
-
-Now let's see your work in action:
-
-```bash theme={null}
-# Install dependencies
-pnpm install
-
-# Compile the project and run the dojo
-pnpm dev
-```
-
-Head over to [http://localhost:3000](http://localhost:3000) and choose
-**OpenAI** from the drop-down. You'll see the stub agent replies with **Hello
-world!** for now.
-
-Here's what's happening with that stub agent:
-
-```ts theme={null}
-// integrations/openai/src/index.ts
-import {
- AbstractAgent,
- BaseEvent,
- EventType,
- RunAgentInput,
-} from "@ag-ui/client"
-import { Observable } from "rxjs"
-
-export class OpenAIAgent extends AbstractAgent {
- run(input: RunAgentInput): Observable {
- const messageId = Date.now().toString()
- return new Observable((observer) => {
- observer.next({
- type: EventType.RUN_STARTED,
- threadId: input.threadId,
- runId: input.runId,
- } as any)
-
- observer.next({
- type: EventType.TEXT_MESSAGE_START,
- messageId,
- } as any)
-
- observer.next({
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId,
- delta: "Hello world!",
- } as any)
-
- observer.next({
- type: EventType.TEXT_MESSAGE_END,
- messageId,
- } as any)
-
- observer.next({
- type: EventType.RUN_FINISHED,
- threadId: input.threadId,
- runId: input.runId,
- } as any)
-
- observer.complete()
- })
- }
-}
-```
-
-## Step 4 – Bridge OpenAI with AG-UI
-
-Let's transform our stub into a real agent that streams completions from OpenAI.
-
-### Install the OpenAI SDK
-
-First, we need the OpenAI SDK:
-
-```bash theme={null}
-cd integrations/openai
-pnpm install openai
-```
-
-### AG-UI recap
-
-An AG-UI agent extends `AbstractAgent` and emits a sequence of events to signal:
-
-* lifecycle events (`RUN_STARTED`, `RUN_FINISHED`, `RUN_ERROR`)
-* content events (`TEXT_MESSAGE_*`, `TOOL_CALL_*`, and more)
-
-### Implement the streaming agent
-
-Now we'll transform our stub agent into a real OpenAI integration. The key
-difference is that instead of sending a hardcoded "Hello world!" message, we'll
-connect to OpenAI's API and stream the response back through AG-UI events.
-
-The implementation follows the same event flow as our stub, but we'll add the
-OpenAI client initialization in the constructor and replace our mock response
-with actual API calls. We'll also handle tool calls if they're present in the
-response, making our agent fully capable of using functions when needed.
-
-```typescript theme={null}
-// integrations/openai/src/index.ts
-import {
- AbstractAgent,
- RunAgentInput,
- EventType,
- BaseEvent,
-} from "@ag-ui/client"
-import { Observable } from "rxjs"
-
-import { OpenAI } from "openai"
-
-export class OpenAIAgent extends AbstractAgent {
- private openai: OpenAI
-
- constructor(openai?: OpenAI) {
- super()
- // Initialize OpenAI client - uses OPENAI_API_KEY from environment if not provided
- this.openai = openai ?? new OpenAI()
- }
-
- run(input: RunAgentInput): Observable {
- return new Observable((observer) => {
- // Same as before - emit RUN_STARTED to begin
- observer.next({
- type: EventType.RUN_STARTED,
- threadId: input.threadId,
- runId: input.runId,
- } as any)
-
- // NEW: Instead of hardcoded response, call OpenAI's API
- this.openai.chat.completions
- .create({
- model: "gpt-4o",
- stream: true, // Enable streaming for real-time responses
- // Convert AG-UI tools format to OpenAI's expected format
- tools: input.tools.map((tool) => ({
- type: "function",
- function: {
- name: tool.name,
- description: tool.description,
- parameters: tool.parameters,
- },
- })),
- // Transform AG-UI messages to OpenAI's message format
- messages: input.messages.map((message) => ({
- role: message.role as any,
- content: message.content ?? "",
- // Include tool calls if this is an assistant message with tools
- ...(message.role === "assistant" && message.toolCalls
- ? {
- tool_calls: message.toolCalls,
- }
- : {}),
- // Include tool call ID if this is a tool result message
- ...(message.role === "tool"
- ? { tool_call_id: message.toolCallId }
- : {}),
- })),
- })
- .then(async (response) => {
- const messageId = Date.now().toString()
-
- // NEW: Stream each chunk from OpenAI's response
- for await (const chunk of response) {
- // Handle text content chunks
- if (chunk.choices[0].delta.content) {
- observer.next({
- type: EventType.TEXT_MESSAGE_CHUNK, // Chunk events open and close messages automatically
- messageId,
- delta: chunk.choices[0].delta.content,
- } as any)
- }
- // Handle tool call chunks (when the model wants to use a function)
- else if (chunk.choices[0].delta.tool_calls) {
- let toolCall = chunk.choices[0].delta.tool_calls[0]
-
- observer.next({
- type: EventType.TOOL_CALL_CHUNK,
- toolCallId: toolCall.id,
- toolCallName: toolCall.function?.name,
- parentMessageId: messageId,
- delta: toolCall.function?.arguments,
- } as any)
- }
- }
-
- // Same as before - emit RUN_FINISHED when complete
- observer.next({
- type: EventType.RUN_FINISHED,
- threadId: input.threadId,
- runId: input.runId,
- } as any)
-
- observer.complete()
- })
- // NEW: Handle errors from the API
- .catch((error) => {
- observer.next({
- type: EventType.RUN_ERROR,
- message: error.message,
- } as any)
-
- observer.error(error)
- })
- })
- }
-}
-```
-
-### What happens under the hood?
-
-Let's break down what your agent is doing:
-
-1. **Setup** – We create an OpenAI client and emit `RUN_STARTED`
-2. **Request** – We send the user's messages to `chat.completions` with
- `stream: true`
-3. **Streaming** – We forward each chunk as either `TEXT_MESSAGE_CHUNK` or
- `TOOL_CALL_CHUNK`
-4. **Finish** – We emit `RUN_FINISHED` (or `RUN_ERROR` if something goes wrong)
- and complete the observable
-
-## Step 4 – Chat with your agent
-
-Reload the dojo page and start typing. You'll see GPT-4o streaming its answer in
-real-time, word by word.
-
-## Bridging AG-UI to any protocol
-
-The pattern you just implemented—translate inputs, forward streaming chunks,
-emit AG-UI events—works for virtually any backend:
-
-* REST or GraphQL APIs
-* WebSockets
-* IoT protocols such as MQTT
-
-## Connect your agent to a frontend
-
-Tools like [CopilotKit](https://docs.copilotkit.ai) already understand AG-UI and
-provide plug-and-play React components. Point them at your agent endpoint and
-you get a full-featured chat UI out of the box.
-
-## Share your integration
-
-Did you build a custom adapter that others could reuse? We welcome community
-contributions!
-
-1. Fork the [AG-UI repository](https://github.com/ag-ui-protocol/ag-ui)
-2. Add your package under `integrations`. See
- [Contributing](../development/contributing) for more details and naming
- conventions.
-3. Open a pull request describing your use-case and design decisions
-
-If you have questions, need feedback, or want to validate an idea first, start a
-thread in the GitHub Discussions board:
-[AG-UI GitHub Discussions board](https://github.com/orgs/ag-ui-protocol/discussions).
-
-Your integration might ship in the next release and help the entire AG-UI
-ecosystem grow.
-
-## Conclusion
-
-You now have a fully-functional AG-UI adapter for OpenAI and a local playground
-to test it. From here you can:
-
-* Add tool calls to enhance your agent
-* Publish your integration to npm
-* Bridge AG-UI to any other model or service
-
-Happy building!
-
-
-# Server
-Source: https://docs.ag-ui.com/quickstart/server
-
-Implement AG-UI compatible servers
-
-# Introduction
-
-A server implementation allows you to **emit AG-UI events directly from your
-agent or server**. This approach is ideal when you're building a new agent from
-scratch or want a dedicated service for your agent capabilities.
-
-## When to use a server implementation
-
-Server implementations allow you to directly emit AG-UI events from your agent
-or server. If you are not using an agent framework or haven't created a protocol
-for your agent framework yet, this is the best way to get started.
-
-Server implementations are also great for:
-
-* Building a **new agent frameworks** from scratch
-* **Maximum control** over how and what events are emitted
-* Exposing your agent as a **standalone API**
-
-## What you'll build
-
-In this guide, we'll create a standalone HTTP server that:
-
-1. Accepts AG-UI protocol requests
-2. Connects to OpenAI's GPT-4o model
-3. Streams responses back as AG-UI events
-4. Handles tool calls and state management
-
-Let's get started!
-
-## Prerequisites
-
-Before we begin, make sure you have:
-
-* [Python](https://www.python.org/downloads/) **3.12 or later**
-* [Poetry](https://python-poetry.org/docs/#installation) for dependency
- management
-* An **OpenAI API key**
-
-### 1. Provide your OpenAI API key
-
-First, let's set up your API key:
-
-```bash theme={null}
-# Set your OpenAI API key
-export OPENAI_API_KEY=your-api-key-here
-```
-
-### 2. Install build utilities
-
-Install the following tools:
-
-```bash theme={null}
-brew install protobuf
-```
-
-```bash theme={null}
-npm i nx
-```
-
-```bash theme={null}
-curl -fsSL https://get.pnpm.io/install.sh | sh -
-```
-
-## Step 1 – Scaffold your server
-
-Start by cloning the repo:
-
-```bash theme={null}
-git clone git@github.com:ag-ui-protocol/ag-ui.git
-cd ag-ui
-```
-
-Copy the server-starter template to create your OpenAI server:
-
-```bash theme={null}
-cp -r integrations/server-starter integrations/openai-server
-```
-
-### Update metadata
-
-Open `integrations/openai-server/package.json` and update the fields to match
-your new folder:
-
-```json theme={null}
-{
- "name": "@ag-ui/openai-server",
- "author": "Your Name ",
- "version": "0.0.1",
-
- ... rest of package.json
-}
-```
-
-Next, update the class name inside `integrations/openai-server/src/index.ts`:
-
-```ts theme={null}
-// Change the name to OpenAIServerAgent to add a minimal middleware for your integration.
-// You can use this later on to add configuration etc.
-export class OpenAIServerAgent extends HttpAgent {}
-```
-
-Finally, introduce your integration to the dojo by adding it to
-`apps/dojo/src/menu.ts`:
-
-```ts theme={null}
-// ...
-export const menuIntegrations: MenuIntegrationConfig[] = [
- // ...
-
- {
- id: "openai-server",
- name: "OpenAI Server",
- features: ["agentic_chat"],
- },
-]
-```
-
-And `apps/dojo/src/agents.ts`:
-
-```ts theme={null}
-// ...
-import { OpenAIServerAgent } from "@ag-ui/openai-server"
-
-export const agentsIntegrations: AgentIntegrationConfig[] = [
- // ...
-
- {
- id: "openai-server",
- agents: async () => {
- return {
- agentic_chat: new OpenAIServerAgent(),
- }
- },
- },
-]
-```
-
-## Step 2 – Add package to dojo dependencies
-
-Open `apps/dojo/package.json` and add the package `@ag-ui/openai-server`:
-
-```json theme={null}
-{
- "name": "demo-viewer",
- "version": "0.1.0",
- "private": true,
- "scripts": {
- "dev": "next dev",
- "build": "next build",
- "start": "next start",
- "lint": "next lint"
- },
- "dependencies": {
- "@ag-ui/agno": "workspace:*",
- "@ag-ui/langgraph": "workspace:*",
- "@ag-ui/mastra": "workspace:*",
- "@ag-ui/middleware-starter": "workspace:*",
- "@ag-ui/server-starter": "workspace:*",
- "@ag-ui/server-starter-all-features": "workspace:*",
- "@ag-ui/vercel-ai-sdk": "workspace:*",
- "@ag-ui/openai-server": "workspace:*", <- Add this line
-
- ... rest of package.json
-}
-```
-
-## Step 3 – Start the dojo and server
-
-Now let's see your work in action. First, start your Python server:
-
-```bash theme={null}
-cd integrations/openai-server/server/python
-poetry install && poetry run dev
-```
-
-In another terminal, start the dojo:
-
-```bash theme={null}
-# Install dependencies
-pnpm install
-
-# Compile the project and run the dojo
-pnpm dev
-```
-
-Head over to [http://localhost:3000](http://localhost:3000) and choose
-**OpenAI** from the drop-down. You'll see the stub server replies with **Hello
-world!** for now.
-
-Here's what's happening with that stub server:
-
-```python theme={null}
-# integrations/openai-server/server/python/example_server/__init__.py
-@app.post("/")
-async def agentic_chat_endpoint(input_data: RunAgentInput, request: Request):
- """Agentic chat endpoint"""
- # Get the accept header from the request
- accept_header = request.headers.get("accept")
-
- # Create an event encoder to properly format SSE events
- encoder = EventEncoder(accept=accept_header)
-
- async def event_generator():
-
- # Send run started event
- yield encoder.encode(
- RunStartedEvent(
- type=EventType.RUN_STARTED,
- thread_id=input_data.thread_id,
- run_id=input_data.run_id
- ),
- )
-
- message_id = str(uuid.uuid4())
-
- yield encoder.encode(
- TextMessageStartEvent(
- type=EventType.TEXT_MESSAGE_START,
- message_id=message_id,
- role="assistant"
- )
- )
-
- yield encoder.encode(
- TextMessageContentEvent(
- type=EventType.TEXT_MESSAGE_CONTENT,
- message_id=message_id,
- delta="Hello world!"
- )
- )
-
- yield encoder.encode(
- TextMessageEndEvent(
- type=EventType.TEXT_MESSAGE_END,
- message_id=message_id
- )
- )
-
- # Send run finished event
- yield encoder.encode(
- RunFinishedEvent(
- type=EventType.RUN_FINISHED,
- thread_id=input_data.thread_id,
- run_id=input_data.run_id
- ),
- )
-
- return StreamingResponse(
- event_generator(),
- media_type=encoder.get_content_type()
- )
-```
-
-## Step 4 – Bridge OpenAI with AG-UI
-
-Let's transform our stub into a real server that streams completions from
-OpenAI.
-
-### Install the OpenAI SDK
-
-First, we need the OpenAI SDK:
-
-```bash theme={null}
-cd integrations/openai-server/server/python
-poetry add openai
-```
-
-### AG-UI recap
-
-An AG-UI server implements the endpoint and emits a sequence of events to
-signal:
-
-* lifecycle events (`RUN_STARTED`, `RUN_FINISHED`, `RUN_ERROR`)
-* content events (`TEXT_MESSAGE_*`, `TOOL_CALL_*`, and more)
-
-### Implement the streaming server
-
-Now we'll transform our stub server into a real OpenAI integration. The key
-difference is that instead of sending a hardcoded "Hello world!" message, we'll
-connect to OpenAI's API and stream the response back through AG-UI events.
-
-The implementation follows the same event flow as our stub, but we'll add the
-OpenAI client initialization and replace our mock response with actual API
-calls. We'll also handle tool calls if they're present in the response, making
-our server fully capable of using functions when needed.
-
-```python theme={null}
-import os
-import uuid
-import uvicorn
-from fastapi import FastAPI, Request
-from fastapi.responses import StreamingResponse
-from ag_ui.core import (
- RunAgentInput,
- EventType,
- RunStartedEvent,
- RunFinishedEvent,
- RunErrorEvent,
-)
-from ag_ui.encoder import EventEncoder
-from openai import OpenAI
-
-app = FastAPI(title="AG-UI OpenAI Server")
-
-# Initialize OpenAI client - uses OPENAI_API_KEY from environment
-client = OpenAI()
-
-@app.post("/")
-async def agentic_chat_endpoint(input_data: RunAgentInput, request: Request):
- """OpenAI agentic chat endpoint"""
- accept_header = request.headers.get("accept")
- encoder = EventEncoder(accept=accept_header)
-
- async def event_generator():
- try:
- yield encoder.encode(
- RunStartedEvent(
- type=EventType.RUN_STARTED,
- thread_id=input_data.thread_id,
- run_id=input_data.run_id
- )
- )
-
- # Call OpenAI's API with streaming enabled
- stream = client.chat.completions.create(
- model="gpt-4o",
- stream=True,
- # Convert AG-UI tools format to OpenAI's expected format
- tools=[
- {
- "type": "function",
- "function": {
- "name": tool.name,
- "description": tool.description,
- "parameters": tool.parameters,
- }
- }
- for tool in input_data.tools
- ] if input_data.tools else None,
- # Transform AG-UI messages to OpenAI's message format
- messages=[
- {
- "role": message.role,
- "content": message.content or "",
- # Include tool calls if this is an assistant message with tools
- **({"tool_calls": message.tool_calls} if message.role == "assistant" and hasattr(message, 'tool_calls') and message.tool_calls else {}),
- # Include tool call ID if this is a tool result message
- **({"tool_call_id": message.tool_call_id} if message.role == "tool" and hasattr(message, 'tool_call_id') else {}),
- }
- for message in input_data.messages
- ],
- )
-
- message_id = str(uuid.uuid4())
-
- # Stream each chunk from OpenAI's response
- for chunk in stream:
- # Handle text content chunks
- if chunk.choices[0].delta.content:
- yield encoder.encode({
- "type": EventType.TEXT_MESSAGE_CHUNK,
- "message_id": message_id,
- "delta": chunk.choices[0].delta.content,
- })
- # Handle tool call chunks
- elif chunk.choices[0].delta.tool_calls:
- tool_call = chunk.choices[0].delta.tool_calls[0]
-
- yield encoder.encode({
- "type": EventType.TOOL_CALL_CHUNK,
- "tool_call_id": tool_call.id,
- "tool_call_name": tool_call.function.name if tool_call.function else None,
- "parent_message_id": message_id,
- "delta": tool_call.function.arguments if tool_call.function else None,
- })
-
- yield encoder.encode(
- RunFinishedEvent(
- type=EventType.RUN_FINISHED,
- thread_id=input_data.thread_id,
- run_id=input_data.run_id
- )
- )
-
- except Exception as error:
- yield encoder.encode(
- RunErrorEvent(
- type=EventType.RUN_ERROR,
- message=str(error)
- )
- )
-
- return StreamingResponse(
- event_generator(),
- media_type=encoder.get_content_type()
- )
-
-def main():
- """Run the uvicorn server."""
- port = int(os.getenv("PORT", "8000"))
- uvicorn.run(
- "example_server:app",
- host="0.0.0.0",
- port=port,
- reload=True
- )
-
-if __name__ == "__main__":
- main()
-```
-
-### What happens under the hood?
-
-Let's break down what your server is doing:
-
-1. **Setup** – We create an OpenAI client and emit `RUN_STARTED`
-2. **Request** – We send the user's messages to `chat.completions` with
- `stream=True`
-3. **Streaming** – We forward each chunk as either `TEXT_MESSAGE_CHUNK` or
- `TOOL_CALL_CHUNK`
-4. **Finish** – We emit `RUN_FINISHED` (or `RUN_ERROR` if something goes wrong)
-
-## Step 5 – Chat with your server
-
-Reload the dojo page and start typing. You'll see GPT-4o streaming its answer in
-real-time, word by word.
-
-Tools like [CopilotKit](https://docs.copilotkit.ai) already understand AG-UI and
-provide plug-and-play React components. Point them at your server endpoint and
-you get a full-featured chat UI out of the box.
-
-## Share your integration
-
-Did you build a custom server that others could reuse? We welcome community
-contributions!
-
-1. Fork the [AG-UI repository](https://github.com/ag-ui-protocol/ag-ui)
-2. Add your package under `integrations/`. See
- [Contributing](../development/contributing) for more details and naming
- conventions.
-3. Open a pull request describing your use-case and design decisions
-
-If you have questions, need feedback, or want to validate an idea first, start a
-thread in the GitHub Discussions board:
-[AG-UI GitHub Discussions board](https://github.com/orgs/ag-ui-protocol/discussions).
-
-Your integration might ship in the next release and help the entire AG-UI
-ecosystem grow.
-
-## Conclusion
-
-You now have a fully-functional AG-UI server for OpenAI and a local playground
-to test it. From here you can:
-
-* Add tool calls to enhance your server
-* Deploy your server to production
-* Bring AG-UI to any other model or service
-
-Happy building!
-
-
-# AbstractAgent
-Source: https://docs.ag-ui.com/sdk/js/client/abstract-agent
-
-Base agent implementation with core event handling
-
-# AbstractAgent
-
-The `AbstractAgent` class provides the foundation for all agent implementations
-in the Agent User Interaction Protocol. It handles the core event stream
-processing, state management, and message history.
-
-```typescript theme={null}
-import { AbstractAgent } from "@ag-ui/client"
-```
-
-## Configuration
-
-By default, all agents are configured by providing an optional `AgentConfig`
-object to the constructor.
-
-```typescript theme={null}
-interface AgentConfig {
- agentId?: string // The identifier of the agent
- description?: string // A description of the agent, used by the LLM
- threadId?: string // The conversation thread identifier
- initialMessages?: Message[] // An array of initial messages
- initialState?: State // The initial state of the agent
-}
-```
-
-### Adding Configuration Options in your Subclass
-
-To add additional configuration options, it is recommended to extend the
-`AgentConfig` interface and call the super constructor with the extended config
-from your subclass like this:
-
-```typescript theme={null}
-interface MyAgentConfig extends AgentConfig {
- myConfigOption: string
-}
-
-class MyAgent extends AbstractAgent {
- private myConfigOption: string
-
- constructor(config: MyAgentConfig) {
- super(config)
- this.myConfigOption = config.myConfigOption
- }
-}
-```
-
-## Core Methods
-
-### runAgent()
-
-The primary method for executing an agent and processing the result.
-
-```typescript theme={null}
-runAgent(parameters?: RunAgentParameters, subscriber?: AgentSubscriber): Promise
-```
-
-#### Parameters
-
-```typescript theme={null}
-interface RunAgentParameters {
- runId?: string // Unique ID for this execution run
- tools?: Tool[] // Available tools for the agent
- context?: Context[] // Contextual information
- forwardedProps?: Record // Additional properties to forward
-}
-```
-
-The optional `subscriber` parameter allows you to provide an
-[AgentSubscriber](/sdk/js/client/subscriber) for handling events during this
-specific run.
-
-#### Return Value
-
-```typescript theme={null}
-interface RunAgentResult {
- result: any // The final result returned by the agent
- newMessages: Message[] // New messages added during this run
-}
-```
-
-### subscribe()
-
-Adds an [AgentSubscriber](/sdk/js/client/subscriber) to handle events across
-multiple agent runs.
-
-```typescript theme={null}
-subscribe(subscriber: AgentSubscriber): { unsubscribe: () => void }
-```
-
-Returns an object with an `unsubscribe()` method to remove the subscriber when
-no longer needed.
-
-### use()
-
-Adds middleware to the agent's event processing pipeline.
-
-```typescript theme={null}
-use(...middlewares: (Middleware | MiddlewareFunction)[]): this
-```
-
-Middleware can be either:
-
-* **Function middleware**: Simple functions that transform the event stream
-* **Class middleware**: Instances of the `Middleware` class for stateful operations
-
-```typescript theme={null}
-// Function middleware
-agent.use((input, next) => {
- console.log("Processing:", input.runId);
- return next.run(input);
-});
-
-// Class middleware
-agent.use(new FilterToolCallsMiddleware({
- allowedToolCalls: ["search"]
-}));
-
-// Chain multiple middleware
-agent.use(loggingMiddleware, authMiddleware, filterMiddleware);
-```
-
-Middleware executes in the order added, with each wrapping the next. Middleware is applied in `runAgent()`; `connectAgent()` currently calls `connect()` directly. See the [Middleware documentation](/sdk/js/client/middleware) for more details.
-
-### abortRun()
-
-Cancels the current agent execution.
-
-```typescript theme={null}
-abortRun(): void
-```
-
-### clone()
-
-Creates a deep copy of the agent instance.
-
-```typescript theme={null}
-clone(): AbstractAgent
-```
-
-### connectAgent()
-
-Establishes a persistent connection with an agent that implements the
-`connect()` method.
-
-```typescript theme={null}
-connectAgent(parameters?: RunAgentParameters, subscriber?: AgentSubscriber): Promise
-```
-
-Similar to `runAgent()` but uses the `connect()` method internally. The agent
-must implement `connect()` or this functionality must be provided by a framework
-like [CopilotKit](https://copilotkit.ai).
-
-## Observable Properties
-
-### events\$
-
-An observable stream of all events emitted during agent execution.
-
-```typescript theme={null}
-events$: Observable
-```
-
-This property provides direct access to the agent's event stream. Events are
-stored using a `ReplaySubject`, allowing late subscribers will receive all
-historical events.
-
-## Properties
-
-* `agentId`: Unique identifier for the agent instance
-* `description`: Human-readable description
-* `threadId`: Conversation thread identifier
-* `messages`: Array of conversation messages
-* `state`: Current agent state object
-* `events$`: Observable stream of all `BaseEvent` objects emitted during agent
- execution (replayed for late subscribers)
-
-## Protected Methods
-
-These methods are meant to be implemented or extended by subclasses:
-
-### run()
-
-Executes the agent and returns an observable event stream.
-
-```typescript theme={null}
-protected abstract run(input: RunAgentInput): RunAgent
-```
-
-### connect()
-
-Establishes a persistent connection and returns an observable event stream.
-
-```typescript theme={null}
-protected connect(input: RunAgentInput): RunAgent
-```
-
-Override this method to implement persistent connections. Default implementation
-throws `ConnectNotImplementedError`.
-
-### apply()
-
-Processes events from the run and updates the agent state.
-
-```typescript theme={null}
-protected apply(input: RunAgentInput): ApplyEvents
-```
-
-### prepareRunAgentInput()
-
-Prepares the input parameters for the agent execution.
-
-```typescript theme={null}
-protected prepareRunAgentInput(parameters?: RunAgentParameters): RunAgentInput
-```
-
-### onError() and onFinalize()
-
-Lifecycle hooks for error handling and cleanup operations.
-
-```typescript theme={null}
-protected onError(error: Error): void
-protected onFinalize(): void
-```
-
-
-# Stream Compaction
-Source: https://docs.ag-ui.com/sdk/js/client/compaction
-
-compactEvents utility for reducing verbose streaming sequences
-
-# compactEvents
-
-`compactEvents` reduces verbose streaming sequences in an event array while
-preserving semantics. Use it to shrink logs before persistence or to simplify
-post‑processing of Server‑Sent Events (SSE) streams.
-
-```ts theme={null}
-import { compactEvents, EventType, type BaseEvent } from "@ag-ui/client"
-
-const compacted: BaseEvent[] = compactEvents(events)
-```
-
-## API
-
-```ts theme={null}
-function compactEvents(events: BaseEvent[]): BaseEvent[]
-```
-
-## What it does
-
-* Text messages: Groups `TEXT_MESSAGE_START` → `TEXT_MESSAGE_CONTENT*` →
- `TEXT_MESSAGE_END` for the same `messageId`, concatenating all `delta`
- chunks into a single `TEXT_MESSAGE_CONTENT` event.
-* Tool calls: Groups `TOOL_CALL_START` → `TOOL_CALL_ARGS*` → `TOOL_CALL_END`
- for the same `toolCallId`, concatenating all `delta` chunks into a single
- `TOOL_CALL_ARGS` event.
-* Interleaved events: Any events that occur between a start/end pair are moved
- after that sequence so the streaming block remains contiguous.
-* Pass‑through: All other events (state, custom, etc.) are preserved unchanged.
-
-## Example
-
-Before:
-
-```ts theme={null}
-[
- { type: EventType.TEXT_MESSAGE_START, messageId: "m1", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "m1", delta: "Hello" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "m1", delta: " " },
- { type: EventType.CUSTOM, name: "thinking" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "m1", delta: "world" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "m1" },
-]
-```
-
-After:
-
-```ts theme={null}
-[
- { type: EventType.TEXT_MESSAGE_START, messageId: "m1", role: "assistant" },
- { type: EventType.TEXT_MESSAGE_CONTENT, messageId: "m1", delta: "Hello world" },
- { type: EventType.TEXT_MESSAGE_END, messageId: "m1" },
- { type: EventType.CUSTOM, name: "thinking" },
-]
-```
-
-Tool call compaction works analogously for `TOOL_CALL_ARGS` chunks.
-
-## When to use
-
-* Persisting event history (store fewer frames with the same meaning)
-* Preparing snapshots for analytics or export
-* Reducing noise in tests or debugging output
-
-## Notes & limitations
-
-* This utility focuses on message and tool‑call streams. It does not modify
- state events (`STATE_SNAPSHOT`/`STATE_DELTA`) or generate message snapshots.
-* For background and broader patterns (branching, normalization), see
- [Serialization](/concepts/serialization).
-
-
-# HttpAgent
-Source: https://docs.ag-ui.com/sdk/js/client/http-agent
-
-HTTP-based agent for connecting to remote AI agents
-
-# HttpAgent
-
-The `HttpAgent` extends `AbstractAgent` to provide HTTP-based connectivity to
-remote AI agents. It handles the request/response cycle and transforms the HTTP
-event stream into standard Agent User Interaction Protocol events.
-
-```typescript theme={null}
-import { HttpAgent } from "@ag-ui/client"
-```
-
-## Configuration
-
-When creating an HTTP agent, you need to provide an `HttpAgentConfig` object:
-
-```typescript theme={null}
-interface HttpAgentConfig extends AgentConfig {
- url: string // Endpoint URL for the agent service
- headers?: Record // Optional HTTP headers
-}
-```
-
-## Creating an HttpAgent
-
-```typescript theme={null}
-const agent = new HttpAgent({
- url: "https://api.example.com/v1/agent",
- headers: {
- Authorization: "Bearer your-api-key",
- },
-})
-```
-
-## Methods
-
-### runAgent()
-
-Executes the agent by making an HTTP request to the configured endpoint.
-
-```typescript theme={null}
-runAgent(parameters?: RunAgentParameters, subscriber?: AgentSubscriber): Promise
-```
-
-#### Parameters
-
-The `parameters` argument follows the standard `RunAgentParameters` interface.
-The optional `subscriber` parameter allows you to provide an
-[AgentSubscriber](/sdk/js/client/subscriber) for handling events during this
-specific run.
-
-#### Return Value
-
-```typescript theme={null}
-interface RunAgentResult {
- result: any // The final result returned by the agent
- newMessages: Message[] // New messages added during this run
-}
-```
-
-### subscribe()
-
-Adds an [AgentSubscriber](/sdk/js/client/subscriber) to handle events across
-multiple agent runs.
-
-```typescript theme={null}
-subscribe(subscriber: AgentSubscriber): { unsubscribe: () => void }
-```
-
-Returns an object with an `unsubscribe()` method to remove the subscriber when
-no longer needed.
-
-### abortRun()
-
-Cancels the current HTTP request using the AbortController.
-
-```typescript theme={null}
-abortRun(): void
-```
-
-## Protected Methods
-
-### requestInit()
-
-Configures the HTTP request. Override this method to customize how requests are
-made.
-
-```typescript theme={null}
-protected requestInit(input: RunAgentInput): RequestInit
-```
-
-Default implementation:
-
-```typescript theme={null}
-{
- method: "POST",
- headers: {
- ...this.headers,
- "Content-Type": "application/json",
- Accept: "text/event-stream",
- },
- body: JSON.stringify(input),
- signal: this.abortController.signal,
-}
-```
-
-### run()
-
-Implements the abstract `run()` method from `AbstractAgent` using HTTP requests.
-
-```typescript theme={null}
-run(input: RunAgentInput): RunAgent
-```
-
-## Properties
-
-* `url`: The endpoint URL for the agent service
-* `headers`: HTTP headers to include with requests
-* `abortController`: AbortController instance for request cancellation
-
-
-# Middleware
-Source: https://docs.ag-ui.com/sdk/js/client/middleware
-
-Event stream transformation and filtering for AG-UI agents
-
-# Middleware
-
-The middleware system in `@ag-ui/client` provides a powerful way to transform, filter, and augment event streams flowing through agents. Middleware can intercept and modify events, add logging, implement authentication, filter tool calls, and more.
-
-```typescript theme={null}
-import {
- AbstractAgent,
- BaseEvent,
- EventType,
- FilterToolCallsMiddleware,
- Message,
- Middleware,
- MiddlewareFunction,
- RunAgentInput
-} from "@ag-ui/client"
-import { Observable } from "rxjs"
-```
-
-Examples below assume the relevant RxJS operators/utilities (`map`, `tap`, `filter`, `finalize`, `catchError`, `switchMap`, `timer`, `of`, etc.) are imported.
-
-## Types
-
-### MiddlewareFunction
-
-A function that transforms the event stream.
-
-```typescript theme={null}
-type MiddlewareFunction = (
- input: RunAgentInput,
- next: AbstractAgent
-) => Observable
-```
-
-Function middleware receives events exactly as emitted by the next middleware or agent.
-
-### Middleware
-
-Abstract base class for creating middleware.
-
-```typescript theme={null}
-interface EventWithState {
- event: BaseEvent
- messages: Message[]
- state: unknown
-}
-
-abstract class Middleware {
- abstract run(
- input: RunAgentInput,
- next: AbstractAgent
- ): Observable
-
- protected runNext(
- input: RunAgentInput,
- next: AbstractAgent
- ): Observable
-
- protected runNextWithState(
- input: RunAgentInput,
- next: AbstractAgent
- ): Observable
-}
-```
-
-* `runNext()` runs `next.run(...)` and normalizes chunk events into complete `TEXT_MESSAGE_*` / `TOOL_CALL_*` sequences.
-* `runNextWithState()` does the same and also provides accumulated `messages` and `state` after each event is applied.
-
-## Function-Based Middleware
-
-The simplest way to create middleware is with a function. Function middleware is ideal for stateless transformations.
-
-### Basic Example
-
-```typescript theme={null}
-const loggingMiddleware: MiddlewareFunction = (input, next) => {
- console.log(`[${new Date().toISOString()}] Starting run ${input.runId}`)
-
- return next.run(input).pipe(
- tap(event => console.log(`Event: ${event.type}`)),
- finalize(() => console.log(`Run ${input.runId} completed`))
- )
-}
-
-agent.use(loggingMiddleware)
-```
-
-### Transforming Events
-
-```typescript theme={null}
-const timestampMiddleware: MiddlewareFunction = (input, next) => {
- return next.run(input).pipe(
- map(event => {
- if (event.type === EventType.RUN_STARTED) {
- return {
- ...event,
- timestamp: Date.now()
- }
- }
- return event
- })
- )
-}
-```
-
-### Error Handling
-
-```typescript theme={null}
-const errorMiddleware: MiddlewareFunction = (input, next) => {
- return next.run(input).pipe(
- catchError(error => {
- console.error("Agent error:", error)
-
- // Return error event
- return of({
- type: EventType.RUN_ERROR,
- message: error.message
- } as BaseEvent)
- })
- )
-}
-```
-
-## Class-Based Middleware
-
-For stateful operations or complex logic, extend the `Middleware` class.
-
-### Basic Implementation
-
-```typescript theme={null}
-class CounterMiddleware extends Middleware {
- private totalEvents = 0
-
- run(input: RunAgentInput, next: AbstractAgent): Observable {
- let runEvents = 0
-
- return this.runNext(input, next).pipe(
- tap(() => {
- runEvents++
- this.totalEvents++
- }),
- finalize(() => {
- console.log(`Run events: ${runEvents}, Total: ${this.totalEvents}`)
- })
- )
- }
-}
-
-agent.use(new CounterMiddleware())
-```
-
-### Configuration-Based Middleware
-
-```typescript theme={null}
-class AuthMiddleware extends Middleware {
- constructor(
- private apiKey: string,
- private headerName: string = "Authorization"
- ) {
- super()
- }
-
- run(input: RunAgentInput, next: AbstractAgent): Observable {
- // Attach auth data in forwardedProps for downstream transport/agent logic
- const authenticatedInput: RunAgentInput = {
- ...input,
- forwardedProps: {
- ...input.forwardedProps,
- auth: {
- headerName: this.headerName,
- value: `Bearer ${this.apiKey}`
- }
- }
- }
-
- return this.runNext(authenticatedInput, next)
- }
-}
-
-const apiKey = process.env.API_KEY ?? ""
-agent.use(new AuthMiddleware(apiKey))
-```
-
-## Accumulator Helpers (Class Middleware)
-
-Class middleware can use helper methods from `Middleware` to work with normalized events and accumulated state.
-
-### `runNext()`
-
-`runNext()` forwards execution and normalizes chunk events into full `TEXT_MESSAGE_*` and `TOOL_CALL_*` events.
-
-### `runNextWithState()`
-
-`runNextWithState()` returns `{ event, messages, state }`, where `messages` and `state` are the accumulated values after each event has been applied.
-
-```typescript theme={null}
-class MetricsWithStateMiddleware extends Middleware {
- run(input: RunAgentInput, next: AbstractAgent): Observable {
- return this.runNextWithState(input, next).pipe(
- tap(({ event, messages, state }) => {
- if (event.type === EventType.RUN_FINISHED) {
- const stateKeyCount =
- state && typeof state === "object" ? Object.keys(state).length : 0
-
- console.log("Assistant messages:", messages.filter(m => m.role === "assistant").length)
- console.log("Final state keys:", stateKeyCount)
- }
- }),
- map(({ event }) => event)
- )
- }
-}
-```
-
-## Built-in Middleware
-
-### FilterToolCallsMiddleware
-
-Filters tool calls based on allowed or disallowed lists.
-
-`FilterToolCallsMiddleware` filters emitted `TOOL_CALL_*` events (including args/results for blocked calls). It does not prevent tool execution in the upstream model/runtime.
-
-```typescript theme={null}
-import { FilterToolCallsMiddleware } from "@ag-ui/client"
-```
-
-#### Configuration
-
-```typescript theme={null}
-type FilterToolCallsConfig =
- | { allowedToolCalls: string[]; disallowedToolCalls?: never }
- | { disallowedToolCalls: string[]; allowedToolCalls?: never }
-```
-
-#### Allow Specific Tools
-
-```typescript theme={null}
-const allowFilter = new FilterToolCallsMiddleware({
- allowedToolCalls: ["search", "calculate", "summarize"]
-})
-
-agent.use(allowFilter)
-```
-
-You can also use `disallowedToolCalls` instead of `allowedToolCalls`.
-
-## Middleware Patterns
-
-### Timing Middleware
-
-```typescript theme={null}
-const timingMiddleware: MiddlewareFunction = (input, next) => {
- const startTime = performance.now()
-
- return next.run(input).pipe(
- finalize(() => {
- const duration = performance.now() - startTime
- console.log(`Execution time: ${duration.toFixed(2)}ms`)
- })
- )
-}
-```
-
-### Rate Limiting
-
-```typescript theme={null}
-class RateLimitMiddleware extends Middleware {
- private lastCall = 0
-
- constructor(private minInterval: number) {
- super()
- }
-
- run(input: RunAgentInput, next: AbstractAgent): Observable {
- const now = Date.now()
- const elapsed = now - this.lastCall
-
- if (elapsed < this.minInterval) {
- // Delay the execution
- return timer(this.minInterval - elapsed).pipe(
- switchMap(() => {
- this.lastCall = Date.now()
- return this.runNext(input, next)
- })
- )
- }
-
- this.lastCall = now
- return this.runNext(input, next)
- }
-}
-
-// Limit to one request per second
-agent.use(new RateLimitMiddleware(1000))
-```
-
-Other common patterns include retry logic and response caching.
-
-## Chaining Middleware
-
-Multiple middleware can be combined to create sophisticated processing pipelines.
-
-```typescript theme={null}
-const logger = loggingMiddleware
-const auth = new AuthMiddleware(apiKey)
-const filter = new FilterToolCallsMiddleware({ allowedToolCalls: ["search"] })
-
-agent.use(logger, auth, filter)
-
-// Execution flow:
-// logger → auth → filter → agent → filter → auth → logger
-```
-
-## Advanced Usage
-
-### Conditional Middleware
-
-```typescript theme={null}
-const debugMiddleware: MiddlewareFunction = (input, next) => {
- const isDebug = input.forwardedProps?.debug === true
-
- if (!isDebug) {
- return next.run(input)
- }
-
- return next.run(input).pipe(
- tap(event => {
- console.debug("[DEBUG]", JSON.stringify(event, null, 2))
- })
- )
-}
-```
-
-## Lifecycle Notes
-
-Middleware added with `agent.use(...)` runs in `runAgent()` (and the legacy bridge path). `connectAgent()` currently calls `connect()` directly and does not run middleware.
-
-## Best Practices
-
-1. **Single Responsibility**: Each middleware should focus on one concern
-2. **Error Handling**: Always handle errors gracefully and consider recovery strategies
-3. **Performance**: Be mindful of processing overhead in high-throughput scenarios
-4. **State Management**: Use class-based middleware when state is required
-5. **Testing**: Write unit tests for each middleware independently
-6. **Documentation**: Document middleware behavior and side effects
-
-## TypeScript Support
-
-The middleware system is fully typed for excellent IDE support:
-
-```typescript theme={null}
-import {
- AbstractAgent,
- BaseEvent,
- MiddlewareFunction,
- RunAgentInput
-} from "@ag-ui/client"
-import { Observable } from "rxjs"
-
-// Type-safe middleware function
-const typedMiddleware: MiddlewareFunction = (
- input: RunAgentInput,
- next: AbstractAgent
-): Observable => {
- return next.run(input)
-}
-```
-
-
-# Overview
-Source: https://docs.ag-ui.com/sdk/js/client/overview
-
-Client package overview
-
-# @ag-ui/client
-
-The Agent User Interaction Protocol Client SDK provides agent connectivity
-options for AI systems. This package builds on the core types and events to
-deliver flexible connection methods to agent implementations.
-
-```bash theme={null}
-npm install @ag-ui/client
-```
-
-## AbstractAgent
-
-`AbstractAgent` is the base agent class for implementing custom agent
-connectivity. Extending this class and implementing `run()` lets you bridge your
-own service or agent implementation to AG-UI.
-
-* [Configuration](/sdk/js/client/abstract-agent#configuration) - Setup with
- agent ID, messages, and state
-* [Core Methods](/sdk/js/client/abstract-agent#core-methods) - Run, abort, and
- clone functionality
-* [Protected Methods](/sdk/js/client/abstract-agent#protected-methods) -
- Extensible hooks for custom implementations
-* [Properties](/sdk/js/client/abstract-agent#properties) - State and message
- tracking
-
-
- Base class for creating custom agent connections
-
-
-## HttpAgent
-
-Concrete implementation for HTTP-based agent connectivity:
-
-* [Configuration](/sdk/js/client/http-agent#configuration) - URL and header
- setup
-* [Methods](/sdk/js/client/http-agent#methods) - HTTP-specific execution and
- cancellation
-* [Protected Methods](/sdk/js/client/http-agent#protected-methods) -
- Customizable HTTP request handling
-* [Properties](/sdk/js/client/http-agent#properties) - Connection management
-
-
- Ready-to-use HTTP implementation for agent connectivity, using a highly
- efficient event encoding format
-
-
-## Middleware
-
-Transform and intercept event streams flowing through agents with a flexible
-middleware system:
-
-* [Function Middleware](/sdk/js/client/middleware#function-based-middleware) - Simple
- transformations with plain functions
-* [Class Middleware](/sdk/js/client/middleware#class-based-middleware) - Stateful
- middleware with configuration
-* [Built-in Middleware](/sdk/js/client/middleware#built-in-middleware) -
- FilterToolCallsMiddleware and more
-* [Middleware Patterns](/sdk/js/client/middleware#middleware-patterns) - Common
- use cases and examples
-
-
- Powerful event stream transformation and filtering for AG-UI agents
-
-
-## AgentSubscriber
-
-Event-driven subscriber system for handling agent lifecycle events and state
-mutations during agent execution:
-
-* [Event Handlers](/sdk/js/client/subscriber#event-handlers) - Lifecycle,
- message, tool call, and state events
-* [State Management](/sdk/js/client/subscriber#state-management) - Mutation
- control and propagation handling
-* [Usage Examples](/sdk/js/client/subscriber#usage-examples) - Logging,
- persistence, and error handling patterns
-* [Integration](/sdk/js/client/subscriber#integration-with-agents) - Registering
- and using subscribers with agents
-
-
- Comprehensive event system for reactive agent interaction and middleware-style
- functionality
-
-
-
-# AgentSubscriber
-Source: https://docs.ag-ui.com/sdk/js/client/subscriber
-
-Event-driven subscriber system for agent lifecycle and event handling
-
-# AgentSubscriber
-
-The `AgentSubscriber` interface provides a comprehensive event-driven system for
-handling agent lifecycle events, message updates, and state mutations during
-agent execution. It allows you to hook into various stages of the agent's
-operation and modify its behavior.
-
-```typescript theme={null}
-import { AgentSubscriber } from "@ag-ui/client"
-```
-
-## Overview
-
-`AgentSubscriber` defines a collection of optional event handlers and lifecycle
-hooks that can respond to different stages of agent execution. All methods in
-the interface are optional, allowing you to implement only the events you need
-to handle.
-
-All subscriber methods can be either synchronous or asynchronous - if they
-return a Promise, the agent will await their completion before proceeding.
-
-## Adding Subscribers to Agents
-
-Subscribers can be added to agents in two ways:
-
-### Permanent Subscription
-
-Use the `subscribe()` method to add a subscriber that will persist across
-multiple agent runs:
-
-```typescript theme={null}
-const agent = new HttpAgent({ url: "https://api.example.com/agent" })
-
-const subscriber: AgentSubscriber = {
- onTextMessageContentEvent: ({ textMessageBuffer }) => {
- console.log("Streaming text:", textMessageBuffer)
- },
-}
-
-// Add permanent subscriber
-const subscription = agent.subscribe(subscriber)
-
-// Later, remove the subscriber if needed
-subscription.unsubscribe()
-```
-
-### Temporary Subscription
-
-Pass a subscriber directly to `runAgent()` for one-time use:
-
-```typescript theme={null}
-const temporarySubscriber: AgentSubscriber = {
- onRunFinishedEvent: ({ result }) => {
- console.log("Run completed with result:", result)
- },
-}
-
-// Use subscriber for this run only
-await agent.runAgent({ tools: [myTool] }, temporarySubscriber)
-```
-
-## Core Interfaces
-
-### AgentSubscriber
-
-The main interface that defines all available event handlers and lifecycle
-hooks. All methods in the interface are optional, allowing you to implement only
-the events you need to handle.
-
-### AgentStateMutation
-
-Event handlers can return an `AgentStateMutation` object to modify the agent's
-state and control event processing:
-
-```typescript theme={null}
-interface AgentStateMutation {
- messages?: Message[] // Update the message history
- state?: State // Update the agent state
- stopPropagation?: boolean // Prevent further subscribers from processing this event
-}
-```
-
-When a subscriber returns a mutation:
-
-* **messages**: Replaces the current message history
-* **state**: Replaces the current agent state
-* **stopPropagation**: If `true`, prevents subsequent subscribers from handling
- the event (useful for overriding default behavior)
-
-### AgentSubscriberParams
-
-Common parameters passed to most subscriber methods:
-
-```typescript theme={null}
-interface AgentSubscriberParams {
- messages: Message[] // Current message history
- state: State // Current agent state
- agent: AbstractAgent // The agent instance
- input: RunAgentInput // The original input parameters
-}
-```
-
-## Event Handlers
-
-### Lifecycle Events
-
-#### onRunInitialized()
-
-Called when the agent run is first initialized, before any processing begins.
-
-```typescript theme={null}
-onRunInitialized?(params: AgentSubscriberParams): MaybePromise | void>
-```
-
-#### onRunFailed()
-
-Called when the agent run encounters an error.
-
-```typescript theme={null}
-onRunFailed?(params: { error: Error } & AgentSubscriberParams): MaybePromise | void>
-```
-
-#### onRunFinalized()
-
-Called when the agent run completes, regardless of success or failure.
-
-```typescript theme={null}
-onRunFinalized?(params: AgentSubscriberParams): MaybePromise | void>
-```
-
-### Event Handlers
-
-#### onEvent()
-
-General event handler that receives all events during agent execution.
-
-```typescript theme={null}
-onEvent?(params: { event: BaseEvent } & AgentSubscriberParams): MaybePromise
-```
-
-#### onRunStartedEvent()
-
-Triggered when an agent run begins execution.
-
-```typescript theme={null}
-onRunStartedEvent?(params: { event: RunStartedEvent } & AgentSubscriberParams): MaybePromise
-```
-
-#### onRunFinishedEvent()
-
-Called when an agent run completes successfully.
-
-```typescript theme={null}
-onRunFinishedEvent?(params: { event: RunFinishedEvent; result?: any } & AgentSubscriberParams): MaybePromise
-```
-
-#### onRunErrorEvent()
-
-Triggered when an agent run encounters an error.
-
-```typescript theme={null}
-onRunErrorEvent?(params: { event: RunErrorEvent } & AgentSubscriberParams): MaybePromise
-```
-
-#### onStepStartedEvent()
-
-Called when a step within an agent run begins.
-
-```typescript theme={null}
-onStepStartedEvent?(params: { event: StepStartedEvent } & AgentSubscriberParams): MaybePromise
-```
-
-#### onStepFinishedEvent()
-
-Triggered when a step within an agent run completes.
-
-```typescript theme={null}
-onStepFinishedEvent?(params: { event: StepFinishedEvent } & AgentSubscriberParams): MaybePromise
-```
-
-### Message Events
-
-#### onTextMessageStartEvent()
-
-Triggered when a text message starts being generated.
-
-```typescript theme={null}
-onTextMessageStartEvent?(params: { event: TextMessageStartEvent } & AgentSubscriberParams): MaybePromise
-```
-
-#### onTextMessageContentEvent()
-
-Called for each chunk of text content as it's generated.
-
-```typescript theme={null}
-onTextMessageContentEvent?(params: { event: TextMessageContentEvent; textMessageBuffer: string } & AgentSubscriberParams): MaybePromise
-```
-
-#### onTextMessageEndEvent()
-
-Called when a text message generation is complete.
-
-```typescript theme={null}
-onTextMessageEndEvent?(params: { event: TextMessageEndEvent; textMessageBuffer: string } & AgentSubscriberParams): MaybePromise
-```
-
-### Tool Call Events
-
-#### onToolCallStartEvent()
-
-Triggered when a tool call begins.
-
-```typescript theme={null}
-onToolCallStartEvent?(params: { event: ToolCallStartEvent } & AgentSubscriberParams): MaybePromise
-```
-
-#### onToolCallArgsEvent()
-
-Called as tool call arguments are being parsed, providing both raw and parsed
-argument data.
-
-```typescript theme={null}
-onToolCallArgsEvent?(params: { event: ToolCallArgsEvent; toolCallBuffer: string; toolCallName: string; partialToolCallArgs: Record } & AgentSubscriberParams): MaybePromise
-```
-
-#### onToolCallEndEvent()
-
-Called when a tool call is complete with final arguments.
-
-```typescript theme={null}
-onToolCallEndEvent?(params: { event: ToolCallEndEvent; toolCallName: string; toolCallArgs: Record } & AgentSubscriberParams): MaybePromise
-```
-
-#### onToolCallResultEvent()
-
-Triggered when a tool call result is received.
-
-```typescript theme={null}
-onToolCallResultEvent?(params: { event: ToolCallResultEvent } & AgentSubscriberParams): MaybePromise
-```
-
-### State Events
-
-#### onStateSnapshotEvent()
-
-Called when a complete state snapshot is provided.
-
-```typescript theme={null}
-onStateSnapshotEvent?(params: { event: StateSnapshotEvent } & AgentSubscriberParams): MaybePromise
-```
-
-#### onStateDeltaEvent()
-
-Triggered when partial state changes are applied.
-
-```typescript theme={null}
-onStateDeltaEvent?(params: { event: StateDeltaEvent } & AgentSubscriberParams): MaybePromise
-```
-
-#### onMessagesSnapshotEvent()
-
-Called when a complete message history snapshot is provided.
-
-```typescript theme={null}
-onMessagesSnapshotEvent?(params: { event: MessagesSnapshotEvent } & AgentSubscriberParams): MaybePromise
-```
-
-#### onActivitySnapshotEvent()
-
-Called when an activity snapshot is received. The handler receives both the raw
-event and any existing `ActivityMessage` (if present) so you can inspect or
-replace it before the default client logic runs.
-
-```typescript theme={null}
-onActivitySnapshotEvent?(params: {
- event: ActivitySnapshotEvent
- activityMessage?: ActivityMessage
- existingMessage?: Message
-} & AgentSubscriberParams): MaybePromise
-```
-
-#### onActivityDeltaEvent()
-
-Triggered for each activity delta. Use this hook to transform or debounce the
-incoming JSON Patch operations before they update the conversation transcript.
-
-```typescript theme={null}
-onActivityDeltaEvent?(params: {
- event: ActivityDeltaEvent
- activityMessage?: ActivityMessage
-} & AgentSubscriberParams): MaybePromise
-```
-
-#### onRawEvent()
-
-Handler for raw, unprocessed events.
-
-```typescript theme={null}
-onRawEvent?(params: { event: RawEvent } & AgentSubscriberParams): MaybePromise
-```
-
-#### onCustomEvent()
-
-Handler for custom application-specific events.
-
-```typescript theme={null}
-onCustomEvent?(params: { event: CustomEvent } & AgentSubscriberParams): MaybePromise
-```
-
-### State Change Handlers
-
-#### onMessagesChanged()
-
-Called when the agent's message history is updated.
-
-```typescript theme={null}
-onMessagesChanged?(params: Omit & { input?: RunAgentInput }): MaybePromise
-```
-
-#### onStateChanged()
-
-Triggered when the agent's state is modified.
-
-```typescript theme={null}
-onStateChanged?(params: Omit & { input?: RunAgentInput }): MaybePromise
-```
-
-#### onNewMessage()
-
-Called when a new message is added to the conversation.
-
-```typescript theme={null}
-onNewMessage?(params: { message: Message } & Omit & { input?: RunAgentInput }): MaybePromise
-```
-
-#### onNewToolCall()
-
-Triggered when a new tool call is added to a message.
-
-```typescript theme={null}
-onNewToolCall?(params: { toolCall: ToolCall } & Omit & { input?: RunAgentInput }): MaybePromise
-```
-
-## Async Support
-
-All subscriber methods support both synchronous and asynchronous execution:
-
-```typescript theme={null}
-const subscriber: AgentSubscriber = {
- // Synchronous handler
- onTextMessageContentEvent: ({ textMessageBuffer }) => {
- updateUI(textMessageBuffer)
- },
-
- // Asynchronous handler
- onStateChanged: async ({ state }) => {
- await saveStateToDatabase(state)
- },
-
- // Async handler with mutation
- onRunInitialized: async ({ messages, state }) => {
- const enrichedState = await loadUserPreferences()
- return {
- state: { ...state, ...enrichedState },
- }
- },
-}
-```
-
-## Multiple Subscribers
-
-Agents can have multiple subscribers, which are processed in the order they were
-added:
-
-```typescript theme={null}
-// First subscriber modifies state
-const stateEnricher: AgentSubscriber = {
- onRunInitialized: ({ state }) => ({
- state: { ...state, timestamp: new Date().toISOString() },
- }),
-}
-
-// Second subscriber sees the modified state
-const logger: AgentSubscriber = {
- onRunInitialized: ({ state }) => {
- console.log("State after enrichment:", state)
- },
-}
-
-agent.subscribe(stateEnricher)
-agent.subscribe(logger)
-```
-
-## Integration with Agents
-
-Basic usage pattern:
-
-```typescript theme={null}
-const agent = new HttpAgent({ url: "https://api.example.com/agent" })
-
-// Add persistent subscriber
-agent.subscribe({
- onTextMessageContentEvent: ({ textMessageBuffer }) => {
- updateStreamingUI(textMessageBuffer)
- },
- onRunFinishedEvent: ({ result }) => {
- displayFinalResult(result)
- },
-})
-
-// Run agent (subscriber will be called automatically)
-const result = await agent.runAgent({
- tools: [myTool],
-})
-```
-
-
-# Events
-Source: https://docs.ag-ui.com/sdk/js/core/events
-
-Documentation for the events used in the Agent User Interaction Protocol SDK
-
-# Events
-
-The Agent User Interaction Protocol SDK uses a streaming event-based
-architecture. Events are the fundamental units of communication between agents
-and the frontend. This section documents the event types and their properties.
-
-## EventType Enum
-
-The `EventType` enum defines all possible event types in the system:
-
-```typescript theme={null}
-enum EventType {
- TEXT_MESSAGE_START = "TEXT_MESSAGE_START",
- TEXT_MESSAGE_CONTENT = "TEXT_MESSAGE_CONTENT",
- TEXT_MESSAGE_END = "TEXT_MESSAGE_END",
- TOOL_CALL_START = "TOOL_CALL_START",
- TOOL_CALL_ARGS = "TOOL_CALL_ARGS",
- TOOL_CALL_END = "TOOL_CALL_END",
- TOOL_CALL_RESULT = "TOOL_CALL_RESULT",
- STATE_SNAPSHOT = "STATE_SNAPSHOT",
- STATE_DELTA = "STATE_DELTA",
- MESSAGES_SNAPSHOT = "MESSAGES_SNAPSHOT",
- ACTIVITY_SNAPSHOT = "ACTIVITY_SNAPSHOT",
- ACTIVITY_DELTA = "ACTIVITY_DELTA",
- RAW = "RAW",
- CUSTOM = "CUSTOM",
- RUN_STARTED = "RUN_STARTED",
- RUN_FINISHED = "RUN_FINISHED",
- RUN_ERROR = "RUN_ERROR",
- STEP_STARTED = "STEP_STARTED",
- STEP_FINISHED = "STEP_FINISHED",
- REASONING_START = "REASONING_START",
- REASONING_MESSAGE_START = "REASONING_MESSAGE_START",
- REASONING_MESSAGE_CONTENT = "REASONING_MESSAGE_CONTENT",
- REASONING_MESSAGE_END = "REASONING_MESSAGE_END",
- REASONING_MESSAGE_CHUNK = "REASONING_MESSAGE_CHUNK",
- REASONING_END = "REASONING_END",
- REASONING_ENCRYPTED_VALUE = "REASONING_ENCRYPTED_VALUE",
-}
-```
-
-## BaseEvent
-
-All events inherit from the `BaseEvent` type, which provides common properties
-shared across all event types.
-
-```typescript theme={null}
-type BaseEvent = {
- type: EventType // Discriminator field
- timestamp?: number
- rawEvent?: any
-}
-```
-
-| Property | Type | Description |
-| ----------- | ------------------- | ----------------------------------------------------- |
-| `type` | `EventType` | The type of event (discriminator field for the union) |
-| `timestamp` | `number` (optional) | Timestamp when the event was created |
-| `rawEvent` | `any` (optional) | Original event data if this event was transformed |
-
-## Lifecycle Events
-
-These events represent the lifecycle of an agent run.
-
-### RunStartedEvent
-
-Signals the start of an agent run.
-
-```typescript theme={null}
-type RunStartedEvent = BaseEvent & {
- type: EventType.RUN_STARTED
- threadId: string
- runId: string
- parentRunId?: string
- input?: RunAgentInput
-}
-```
-
-| Property | Type | Description |
-| ------------- | -------------------------- | -------------------------------------------------------------------------------------------------------------- |
-| `threadId` | `string` | ID of the conversation thread |
-| `runId` | `string` | ID of the agent run |
-| `parentRunId` | `string` (optional) | (Optional) Lineage pointer for branching/time travel. If present, refers to a prior run within the same thread |
-| `input` | `RunAgentInput` (optional) | (Optional) The exact agent input payload sent to the agent for this run. May omit messages already in history |
-
-### RunFinishedEvent
-
-Signals the successful completion of an agent run.
-
-```typescript theme={null}
-type RunFinishedEvent = BaseEvent & {
- type: EventType.RUN_FINISHED
- threadId: string
- runId: string
- result?: any
-}
-```
-
-| Property | Type | Description |
-| ---------- | ---------------- | ------------------------------ |
-| `threadId` | `string` | ID of the conversation thread |
-| `runId` | `string` | ID of the agent run |
-| `result` | `any` (optional) | Result data from the agent run |
-
-### RunErrorEvent
-
-Signals an error during an agent run.
-
-```typescript theme={null}
-type RunErrorEvent = BaseEvent & {
- type: EventType.RUN_ERROR
- message: string
- code?: string
-}
-```
-
-| Property | Type | Description |
-| --------- | ------------------- | ------------- |
-| `message` | `string` | Error message |
-| `code` | `string` (optional) | Error code |
-
-### StepStartedEvent
-
-Signals the start of a step within an agent run.
-
-```typescript theme={null}
-type StepStartedEvent = BaseEvent & {
- type: EventType.STEP_STARTED
- stepName: string
-}
-```
-
-| Property | Type | Description |
-| ---------- | -------- | ---------------- |
-| `stepName` | `string` | Name of the step |
-
-### StepFinishedEvent
-
-Signals the completion of a step within an agent run.
-
-```typescript theme={null}
-type StepFinishedEvent = BaseEvent & {
- type: EventType.STEP_FINISHED
- stepName: string
-}
-```
-
-| Property | Type | Description |
-| ---------- | -------- | ---------------- |
-| `stepName` | `string` | Name of the step |
-
-## Text Message Events
-
-These events represent the lifecycle of text messages in a conversation.
-
-### TextMessageStartEvent
-
-Signals the start of a text message.
-
-```typescript theme={null}
-type TextMessageStartEvent = BaseEvent & {
- type: EventType.TEXT_MESSAGE_START
- messageId: string
- role: "assistant"
-}
-```
-
-| Property | Type | Description |
-| ----------- | ------------- | --------------------------------- |
-| `messageId` | `string` | Unique identifier for the message |
-| `role` | `"assistant"` | Role is always "assistant" |
-
-### TextMessageContentEvent
-
-Represents a chunk of content in a streaming text message.
-
-```typescript theme={null}
-type TextMessageContentEvent = BaseEvent & {
- type: EventType.TEXT_MESSAGE_CONTENT
- messageId: string
- delta: string // Non-empty string
-}
-```
-
-| Property | Type | Description |
-| ----------- | -------- | ----------------------------------------- |
-| `messageId` | `string` | Matches the ID from TextMessageStartEvent |
-| `delta` | `string` | Text content chunk (non-empty) |
-
-### TextMessageEndEvent
-
-Signals the end of a text message.
-
-```typescript theme={null}
-type TextMessageEndEvent = BaseEvent & {
- type: EventType.TEXT_MESSAGE_END
- messageId: string
-}
-```
-
-| Property | Type | Description |
-| ----------- | -------- | ----------------------------------------- |
-| `messageId` | `string` | Matches the ID from TextMessageStartEvent |
-
-### TextMessageChunkEvent
-
-Convenience event that expands to `TextMessageStart` → `TextMessageContent` →
-`TextMessageEnd` automatically in the JS/TS client.
-
-```typescript theme={null}
-type TextMessageChunkEvent = BaseEvent & {
- type: EventType.TEXT_MESSAGE_CHUNK
- messageId?: string // required on the first chunk for a message
- role?: "developer" | "system" | "assistant" | "user"
- delta?: string
-}
-```
-
-Behavior
-
-* Omit start/end: The client transforms chunk sequences into the standard
- start/content/end triad, so you don’t need to emit them manually.
-* First chunk requirements: The first chunk for a message must include
- `messageId`. When `role` is omitted, it defaults to `assistant`.
-* Streaming: Subsequent chunks with the same `messageId` emit
- `TextMessageContent` events. `TextMessageEnd` is emitted automatically when a
- different message starts or when the stream completes.
-
-## Tool Call Events
-
-These events represent the lifecycle of tool calls made by agents.
-
-### ToolCallStartEvent
-
-Signals the start of a tool call.
-
-```typescript theme={null}
-type ToolCallStartEvent = BaseEvent & {
- type: EventType.TOOL_CALL_START
- toolCallId: string
- toolCallName: string
- parentMessageId?: string
-}
-```
-
-| Property | Type | Description |
-| ----------------- | ------------------- | ----------------------------------- |
-| `toolCallId` | `string` | Unique identifier for the tool call |
-| `toolCallName` | `string` | Name of the tool being called |
-| `parentMessageId` | `string` (optional) | ID of the parent message |
-
-### ToolCallArgsEvent
-
-Represents a chunk of argument data for a tool call.
-
-```typescript theme={null}
-type ToolCallArgsEvent = BaseEvent & {
- type: EventType.TOOL_CALL_ARGS
- toolCallId: string
- delta: string
-}
-```
-
-| Property | Type | Description |
-| ------------ | -------- | -------------------------------------- |
-| `toolCallId` | `string` | Matches the ID from ToolCallStartEvent |
-| `delta` | `string` | Argument data chunk |
-
-### ToolCallEndEvent
-
-Signals the end of a tool call.
-
-```typescript theme={null}
-type ToolCallEndEvent = BaseEvent & {
- type: EventType.TOOL_CALL_END
- toolCallId: string
-}
-```
-
-| Property | Type | Description |
-| ------------ | -------- | -------------------------------------- |
-| `toolCallId` | `string` | Matches the ID from ToolCallStartEvent |
-
-### ToolCallResultEvent
-
-Provides the result of a tool call execution.
-
-```typescript theme={null}
-type ToolCallResultEvent = BaseEvent & {
- type: EventType.TOOL_CALL_RESULT
- messageId: string
- toolCallId: string
- content: string
- role?: "tool"
-}
-```
-
-| Property | Type | Description |
-| ------------ | ------------------- | ----------------------------------------------------------- |
-| `messageId` | `string` | ID of the conversation message this result belongs to |
-| `toolCallId` | `string` | Matches the ID from the corresponding ToolCallStartEvent |
-| `content` | `string` | The actual result/output content from the tool execution |
-| `role` | `"tool"` (optional) | Optional role identifier, typically "tool" for tool results |
-
-## State Management Events
-
-These events are used to manage agent state.
-
-### StateSnapshotEvent
-
-Provides a complete snapshot of an agent's state.
-
-```typescript theme={null}
-type StateSnapshotEvent = BaseEvent & {
- type: EventType.STATE_SNAPSHOT
- snapshot: any // StateSchema
-}
-```
-
-| Property | Type | Description |
-| ---------- | ----- | ----------------------- |
-| `snapshot` | `any` | Complete state snapshot |
-
-### StateDeltaEvent
-
-Provides a partial update to an agent's state using JSON Patch.
-
-```typescript theme={null}
-type StateDeltaEvent = BaseEvent & {
- type: EventType.STATE_DELTA
- delta: any[] // JSON Patch operations (RFC 6902)
-}
-```
-
-| Property | Type | Description |
-| -------- | ------- | ------------------------------ |
-| `delta` | `any[]` | Array of JSON Patch operations |
-
-### MessagesSnapshotEvent
-
-Provides a snapshot of all messages in a conversation.
-
-```typescript theme={null}
-type MessagesSnapshotEvent = BaseEvent & {
- type: EventType.MESSAGES_SNAPSHOT
- messages: Message[]
-}
-```
-
-| Property | Type | Description |
-| ---------- | ----------- | ------------------------ |
-| `messages` | `Message[]` | Array of message objects |
-
-### ActivitySnapshotEvent
-
-Delivers a complete snapshot of an activity message.
-
-```typescript theme={null}
-type ActivitySnapshotEvent = BaseEvent & {
- type: EventType.ACTIVITY_SNAPSHOT
- messageId: string
- activityType: string
- content: Record
- replace?: boolean
-}
-```
-
-| Property | Type | Description |
-| -------------- | --------------------- | ----------------------------------------------------------------------------------------------------- |
-| `messageId` | `string` | Identifier for the target `ActivityMessage` |
-| `activityType` | `string` | Activity discriminator such as `"PLAN"` or `"SEARCH"` |
-| `content` | `Record` | Structured payload describing the full activity state |
-| `replace` | `boolean` (optional) | Defaults to `true`; when `false` the snapshot is ignored if a message with the same ID already exists |
-
-### ActivityDeltaEvent
-
-Provides incremental updates to an activity snapshot using JSON Patch.
-
-```typescript theme={null}
-type ActivityDeltaEvent = BaseEvent & {
- type: EventType.ACTIVITY_DELTA
- messageId: string
- activityType: string
- patch: any[] // RFC 6902 JSON Patch operations
-}
-```
-
-| Property | Type | Description |
-| -------------- | -------- | ---------------------------------------------------------------- |
-| `messageId` | `string` | Identifier for the target `ActivityMessage` |
-| `activityType` | `string` | Activity discriminator mirroring the most recent snapshot |
-| `patch` | `any[]` | JSON Patch operations applied to the structured activity payload |
-
-## Reasoning Events
-
-These events represent the lifecycle of reasoning/thinking processes within an
-agent. Reasoning events allow agents to expose their internal thought process to
-the frontend, creating `ReasoningMessage` objects that persist in the message
-history with the role `"reasoning"`.
-
-### ReasoningStartEvent
-
-Signals the start of a reasoning phase. This is a pass-through event that
-notifies subscribers but does not create messages.
-
-```typescript theme={null}
-type ReasoningStartEvent = BaseEvent & {
- type: EventType.REASONING_START
- messageId: string
-}
-```
-
-| Property | Type | Description |
-| ----------- | -------- | ---------------------------------- |
-| `messageId` | `string` | Identifier for the reasoning phase |
-
-### ReasoningMessageStartEvent
-
-Signals the start of a reasoning message. Creates a new `ReasoningMessage` in
-the message history.
-
-```typescript theme={null}
-type ReasoningMessageStartEvent = BaseEvent & {
- type: EventType.REASONING_MESSAGE_START
- messageId: string
- role: "assistant"
-}
-```
-
-| Property | Type | Description |
-| ----------- | ------------- | --------------------------------- |
-| `messageId` | `string` | Unique identifier for the message |
-| `role` | `"assistant"` | Role is always "assistant" |
-
-### ReasoningMessageContentEvent
-
-Represents a chunk of content in a streaming reasoning message.
-
-```typescript theme={null}
-type ReasoningMessageContentEvent = BaseEvent & {
- type: EventType.REASONING_MESSAGE_CONTENT
- messageId: string
- delta: string
-}
-```
-
-| Property | Type | Description |
-| ----------- | -------- | ---------------------------------------------- |
-| `messageId` | `string` | Matches the ID from ReasoningMessageStartEvent |
-| `delta` | `string` | Reasoning content chunk |
-
-### ReasoningMessageEndEvent
-
-Signals the end of a reasoning message.
-
-```typescript theme={null}
-type ReasoningMessageEndEvent = BaseEvent & {
- type: EventType.REASONING_MESSAGE_END
- messageId: string
-}
-```
-
-| Property | Type | Description |
-| ----------- | -------- | ---------------------------------------------- |
-| `messageId` | `string` | Matches the ID from ReasoningMessageStartEvent |
-
-### ReasoningMessageChunkEvent
-
-Convenience event that expands to `ReasoningMessageStart` →
-`ReasoningMessageContent` → `ReasoningMessageEnd` automatically in the JS/TS
-client.
-
-```typescript theme={null}
-type ReasoningMessageChunkEvent = BaseEvent & {
- type: EventType.REASONING_MESSAGE_CHUNK
- messageId?: string // required on the first chunk for a message
- delta?: string
-}
-```
-
-Behavior
-
-* Omit start/end: The client transforms chunk sequences into the standard
- start/content/end triad.
-* First chunk requirements: The first chunk for a message must include
- `messageId`.
-* Streaming: Subsequent chunks with the same `messageId` emit
- `ReasoningMessageContent` events. `ReasoningMessageEnd` is emitted
- automatically when a different message starts or when the stream completes.
-
-### ReasoningEndEvent
-
-Signals the end of a reasoning phase. This is a pass-through event that notifies
-subscribers but does not modify messages.
-
-```typescript theme={null}
-type ReasoningEndEvent = BaseEvent & {
- type: EventType.REASONING_END
- messageId: string
-}
-```
-
-| Property | Type | Description |
-| ----------- | -------- | ---------------------------------- |
-| `messageId` | `string` | Identifier for the reasoning phase |
-
-### ReasoningEncryptedValueEvent
-
-Attaches an encrypted value to a message or tool call. When this event is
-emitted, it finds the referenced entity by `entityId` and sets its
-`encryptedValue` field.
-
-```typescript theme={null}
-type ReasoningEncryptedValueEvent = BaseEvent & {
- type: EventType.REASONING_ENCRYPTED_VALUE
- subtype: "tool-call" | "message"
- entityId: string
- encryptedValue: string
-}
-```
-
-| Property | Type | Description |
-| ---------------- | -------------------------- | -------------------------------------------------- |
-| `subtype` | `"tool-call" \| "message"` | The type of entity this value belongs to |
-| `entityId` | `string` | ID of the tool call or message to attach the value |
-| `encryptedValue` | `string` | The encrypted value to attach to the entity |
-
-## Special Events
-
-### RawEvent
-
-Used to pass through events from external systems.
-
-```typescript theme={null}
-type RawEvent = BaseEvent & {
- type: EventType.RAW
- event: any
- source?: string
-}
-```
-
-| Property | Type | Description |
-| -------- | ------------------- | ------------------- |
-| `event` | `any` | Original event data |
-| `source` | `string` (optional) | Source of the event |
-
-### CustomEvent
-
-Used for application-specific custom events.
-
-```typescript theme={null}
-type CustomEvent = BaseEvent & {
- type: EventType.CUSTOM
- name: string
- value: any
-}
-```
-
-| Property | Type | Description |
-| -------- | -------- | ------------------------------- |
-| `name` | `string` | Name of the custom event |
-| `value` | `any` | Value associated with the event |
-
-## Deprecated Events
-
-
- The `THINKING_*` events are deprecated and will be removed in version 1.0.0.
- New implementations should use `REASONING_*` events instead.
-
-
-### Thinking Events (Deprecated)
-
-The following event types are deprecated:
-
-| Deprecated Event | Replacement |
-| ------------------------------- | --------------------------- |
-| `THINKING_START` | `REASONING_START` |
-| `THINKING_END` | `REASONING_END` |
-| `THINKING_TEXT_MESSAGE_START` | `REASONING_MESSAGE_START` |
-| `THINKING_TEXT_MESSAGE_CONTENT` | `REASONING_MESSAGE_CONTENT` |
-| `THINKING_TEXT_MESSAGE_END` | `REASONING_MESSAGE_END` |
-
-See [Reasoning Migration](/concepts/reasoning#migration-from-thinking-events)
-for detailed migration guidance.
-
-## Event Schemas
-
-The SDK uses Zod schemas to validate events:
-
-```typescript theme={null}
-const EventSchemas = z.discriminatedUnion("type", [
- TextMessageStartEventSchema,
- TextMessageContentEventSchema,
- TextMessageEndEventSchema,
- ToolCallStartEventSchema,
- ToolCallArgsEventSchema,
- ToolCallEndEventSchema,
- ToolCallResultEventSchema,
- StateSnapshotEventSchema,
- StateDeltaEventSchema,
- MessagesSnapshotEventSchema,
- ActivitySnapshotEventSchema,
- ActivityDeltaEventSchema,
- RawEventSchema,
- CustomEventSchema,
- RunStartedEventSchema,
- RunFinishedEventSchema,
- RunErrorEventSchema,
- StepStartedEventSchema,
- StepFinishedEventSchema,
- ReasoningStartEventSchema,
- ReasoningMessageStartEventSchema,
- ReasoningMessageContentEventSchema,
- ReasoningMessageEndEventSchema,
- ReasoningMessageChunkEventSchema,
- ReasoningEndEventSchema,
- ReasoningEncryptedValueEventSchema,
-])
-```
-
-This allows for runtime validation of events and provides TypeScript type
-inference.
-
-### ToolCallChunkEvent
-
-Convenience event that expands to `ToolCallStart` → `ToolCallArgs` →
-`ToolCallEnd` automatically in the JS/TS client.
-
-```typescript theme={null}
-type ToolCallChunkEvent = BaseEvent & {
- type: EventType.TOOL_CALL_CHUNK
- toolCallId?: string // required on the first chunk for a tool call
- toolCallName?: string // required on the first chunk for a tool call
- parentMessageId?: string
- delta?: string
-}
-```
-
-Behavior
-
-* Omit start/end: The client transforms chunk sequences into the standard
- start/args/end triad.
-* First chunk requirements: The first chunk must include both `toolCallId` and
- `toolCallName`; `parentMessageId` is propagated to `ToolCallStart` if given.
-* Streaming: Subsequent chunks with the same `toolCallId` emit `ToolCallArgs`.
- `ToolCallEnd` is emitted automatically when the tool call changes or when the
- stream completes.
-
-
-# Overview
-Source: https://docs.ag-ui.com/sdk/js/core/overview
-
-Core concepts in the Agent User Interaction Protocol SDK
-
-# @ag-ui/core
-
-The Agent User Interaction Protocol SDK uses a streaming event-based
-architecture with strongly typed data structures. This package provides the
-foundation for connecting to agent systems.
-
-```bash theme={null}
-npm install @ag-ui/core
-```
-
-## Types
-
-Core data structures that represent the building blocks of the system:
-
-* [RunAgentInput](/sdk/js/core/types#runagentinput) - Input parameters for
- running agents
-* [Message](/sdk/js/core/types#message-types) - User assistant communication and
- tool usage
-* [Context](/sdk/js/core/types#context) - Contextual information provided to
- agents
-* [Tool](/sdk/js/core/types#tool) - Defines functions that agents can call
-* [State](/sdk/js/core/types#state) - Agent state management
-
-
- Complete documentation of all types in the @ag-ui/core package
-
-
-## Events
-
-Events that power communication between agents and frontends:
-
-* [Lifecycle Events](/sdk/js/core/events#lifecycle-events) - Run and step
- tracking
-* [Text Message Events](/sdk/js/core/events#text-message-events) - Assistant
- message streaming
-* [Tool Call Events](/sdk/js/core/events#tool-call-events) - Function call
- lifecycle
-* [State Management Events](/sdk/js/core/events#state-management-events) - Agent
- state updates
-* [Special Events](/sdk/js/core/events#special-events) - Raw and custom events
-
-
- Complete documentation of all events in the @ag-ui/core package
-
-
-
-# Types
-Source: https://docs.ag-ui.com/sdk/js/core/types
-
-Documentation for the core types used in the Agent User Interaction Protocol SDK
-
-# Core Types
-
-The Agent User Interaction Protocol SDK is built on a set of core types that
-represent the fundamental structures used throughout the system. This page
-documents these types and their properties.
-
-## RunAgentInput
-
-Input parameters for running an agent. In the HTTP API, this is the body of the
-`POST` request.
-
-```typescript theme={null}
-type RunAgentInput = {
- threadId: string
- runId: string
- parentRunId?: string
- state: any
- messages: Message[]
- tools: Tool[]
- context: Context[]
- forwardedProps: any
-}
-```
-
-| Property | Type | Description |
-| ---------------- | ------------------- | ---------------------------------------------- |
-| `threadId` | `string` | ID of the conversation thread |
-| `runId` | `string` | ID of the current run |
-| `parentRunId` | `string (optional)` | ID of the run that spawned this run |
-| `state` | `any` | Current state of the agent |
-| `messages` | `Message[]` | Array of messages in the conversation |
-| `tools` | `Tool[]` | Array of tools available to the agent |
-| `context` | `Context[]` | Array of context objects provided to the agent |
-| `forwardedProps` | `any` | Additional properties forwarded to the agent |
-
-## Message Types
-
-The SDK includes several message types that represent different kinds of
-messages in the system.
-
-### Role
-
-Represents the possible roles a message sender can have.
-
-```typescript theme={null}
-type Role =
- | "developer"
- | "system"
- | "assistant"
- | "user"
- | "tool"
- | "activity"
- | "reasoning"
-```
-
-### DeveloperMessage
-
-Represents a message from a developer.
-
-```typescript theme={null}
-type DeveloperMessage = {
- id: string
- role: "developer"
- content: string
- name?: string
-}
-```
-
-| Property | Type | Description |
-| --------- | ------------- | ------------------------------------------------ |
-| `id` | `string` | Unique identifier for the message |
-| `role` | `"developer"` | Role of the message sender, fixed as "developer" |
-| `content` | `string` | Text content of the message (required) |
-| `name` | `string` | Optional name of the sender |
-
-### SystemMessage
-
-Represents a system message.
-
-```typescript theme={null}
-type SystemMessage = {
- id: string
- role: "system"
- content: string
- name?: string
-}
-```
-
-| Property | Type | Description |
-| --------- | ---------- | --------------------------------------------- |
-| `id` | `string` | Unique identifier for the message |
-| `role` | `"system"` | Role of the message sender, fixed as "system" |
-| `content` | `string` | Text content of the message (required) |
-| `name` | `string` | Optional name of the sender |
-
-### AssistantMessage
-
-Represents a message from an assistant.
-
-```typescript theme={null}
-type AssistantMessage = {
- id: string
- role: "assistant"
- content?: string
- name?: string
- toolCalls?: ToolCall[]
-}
-```
-
-| Property | Type | Description |
-| ----------- | ----------------------- | ------------------------------------------------ |
-| `id` | `string` | Unique identifier for the message |
-| `role` | `"assistant"` | Role of the message sender, fixed as "assistant" |
-| `content` | `string` (optional) | Text content of the message |
-| `name` | `string` (optional) | Name of the sender |
-| `toolCalls` | `ToolCall[]` (optional) | Tool calls made in this message |
-
-### UserMessage
-
-Represents a message from a user.
-
-```typescript theme={null}
-type UserMessage = {
- id: string
- role: "user"
- content: string | InputContent[]
- name?: string
-}
-```
-
-| Property | Type | Description |
-| --------- | -------------------------- | --------------------------------------------------------------------- |
-| `id` | `string` | Unique identifier for the message |
-| `role` | `"user"` | Role of the message sender, fixed as "user" |
-| `content` | `string \| InputContent[]` | Either plain text or an ordered array of multimodal content fragments |
-| `name` | `string` | Optional name of the sender |
-
-### InputContent
-
-Union of supported multimodal fragments.
-
-```typescript theme={null}
-type InputContent = TextInputContent | BinaryInputContent
-```
-
-### TextInputContent
-
-```typescript theme={null}
-type TextInputContent = {
- type: "text"
- text: string
-}
-```
-
-### BinaryInputContent
-
-```typescript theme={null}
-type BinaryInputContent = {
- type: "binary"
- mimeType: string
- id?: string
- url?: string
- data?: string
- filename?: string
-}
-```
-
-> At least one of `id`, `url`, or `data` must be provided.
-
-### ToolMessage
-
-Represents a message from a tool.
-
-```typescript theme={null}
-type ToolMessage = {
- id: string
- content: string
- role: "tool"
- toolCallId: string
- error?: string
- encryptedValue?: string
-}
-```
-
-| Property | Type | Description |
-| ---------------- | ------------------- | ----------------------------------------------- |
-| `id` | `string` | Unique identifier for the message |
-| `content` | `string` | Text content of the message |
-| `role` | `"tool"` | Role of the message sender, fixed as "tool" |
-| `toolCallId` | `string` | ID of the tool call this message responds to |
-| `error` | `string` (optional) | Error message if the tool call failed |
-| `encryptedValue` | `string` (optional) | Optional encrypted value attached via signature |
-
-### ActivityMessage
-
-Represents structured activity progress emitted between chat messages.
-
-```typescript theme={null}
-type ActivityMessage = {
- id: string
- role: "activity"
- activityType: string
- content: Record
-}
-```
-
-| Property | Type | Description |
-| -------------- | --------------------- | ------------------------------------------------------- |
-| `id` | `string` | Unique identifier for the activity message |
-| `role` | `"activity"` | Fixed discriminator identifying the message as activity |
-| `activityType` | `string` | Activity discriminator used for renderer selection |
-| `content` | `Record` | Structured payload representing the activity state |
-
-### ReasoningMessage
-
-Represents a reasoning/thinking message from an agent's internal thought
-process.
-
-```typescript theme={null}
-type ReasoningMessage = {
- id: string
- role: "reasoning"
- content: string
- encryptedValue?: string
-}
-```
-
-| Property | Type | Description |
-| ---------------- | ------------------- | -------------------------------------------------- |
-| `id` | `string` | Unique identifier for the reasoning message |
-| `role` | `"reasoning"` | Fixed discriminator identifying the reasoning role |
-| `content` | `string` | The reasoning/thinking content |
-| `encryptedValue` | `string` (optional) | Optional encrypted value attached via signature |
-
-### Message
-
-A union type representing any type of message in the system.
-
-```typescript theme={null}
-type Message =
- | DeveloperMessage
- | SystemMessage
- | AssistantMessage
- | UserMessage
- | ToolMessage
- | ActivityMessage
- | ReasoningMessage
-```
-
-### ToolCall
-
-Represents a tool call made by an agent.
-
-```typescript theme={null}
-type ToolCall = {
- id: string
- type: "function"
- function: FunctionCall
- encryptedValue?: string
-}
-```
-
-| Property | Type | Description |
-| ---------------- | ------------------- | ----------------------------------------------- |
-| `id` | `string` | Unique identifier for the tool call |
-| `type` | `"function"` | Type of the tool call, always "function" |
-| `function` | `FunctionCall` | Details about the function being called |
-| `encryptedValue` | `string` (optional) | Optional encrypted value attached via signature |
-
-#### FunctionCall
-
-Represents function name and arguments in a tool call.
-
-```typescript theme={null}
-type FunctionCall = {
- name: string
- arguments: string
-}
-```
-
-| Property | Type | Description |
-| ----------- | -------- | ------------------------------------------------ |
-| `name` | `string` | Name of the function to call |
-| `arguments` | `string` | JSON-encoded string of arguments to the function |
-
-## Context
-
-Represents a piece of contextual information provided to an agent.
-
-```typescript theme={null}
-type Context = {
- description: string
- value: string
-}
-```
-
-| Property | Type | Description |
-| ------------- | -------- | ------------------------------------------- |
-| `description` | `string` | Description of what this context represents |
-| `value` | `string` | The actual context value |
-
-## Tool
-
-Defines a tool that can be called by an agent.
-
-```typescript theme={null}
-type Tool = {
- name: string
- description: string
- parameters: any // JSON Schema
-}
-```
-
-| Property | Type | Description |
-| ------------- | -------- | ------------------------------------------------ |
-| `name` | `string` | Name of the tool |
-| `description` | `string` | Description of what the tool does |
-| `parameters` | `any` | JSON Schema defining the parameters for the tool |
-
-## State
-
-Represents the state of an agent during execution.
-
-```typescript theme={null}
-type State = any
-```
-
-The state type is flexible and can hold any data structure needed by the agent
-implementation.
-
-
-# @ag-ui/encoder
-Source: https://docs.ag-ui.com/sdk/js/encoder
-
-
-
-
-
-# @ag-ui/proto
-Source: https://docs.ag-ui.com/sdk/js/proto
-
-
-
-
-
-# Events
-Source: https://docs.ag-ui.com/sdk/python/core/events
-
-Documentation for the events used in the Agent User Interaction Protocol Python SDK
-
-# Events
-
-The Agent User Interaction Protocol Python SDK uses a streaming event-based
-architecture. Events are the fundamental units of communication between agents
-and the frontend. This section documents the event types and their properties.
-
-## EventType Enum
-
-`from ag_ui.core import EventType`
-
-The `EventType` enum defines all possible event types in the system:
-
-```python theme={null}
-class EventType(str, Enum):
- TEXT_MESSAGE_START = "TEXT_MESSAGE_START"
- TEXT_MESSAGE_CONTENT = "TEXT_MESSAGE_CONTENT"
- TEXT_MESSAGE_END = "TEXT_MESSAGE_END"
- TOOL_CALL_START = "TOOL_CALL_START"
- TOOL_CALL_ARGS = "TOOL_CALL_ARGS"
- TOOL_CALL_END = "TOOL_CALL_END"
- TOOL_CALL_RESULT = "TOOL_CALL_RESULT"
- STATE_SNAPSHOT = "STATE_SNAPSHOT"
- STATE_DELTA = "STATE_DELTA"
- MESSAGES_SNAPSHOT = "MESSAGES_SNAPSHOT"
- ACTIVITY_SNAPSHOT = "ACTIVITY_SNAPSHOT"
- ACTIVITY_DELTA = "ACTIVITY_DELTA"
- RAW = "RAW"
- CUSTOM = "CUSTOM"
- RUN_STARTED = "RUN_STARTED"
- RUN_FINISHED = "RUN_FINISHED"
- RUN_ERROR = "RUN_ERROR"
- STEP_STARTED = "STEP_STARTED"
- STEP_FINISHED = "STEP_FINISHED"
- REASONING_START = "REASONING_START"
- REASONING_MESSAGE_START = "REASONING_MESSAGE_START"
- REASONING_MESSAGE_CONTENT = "REASONING_MESSAGE_CONTENT"
- REASONING_MESSAGE_END = "REASONING_MESSAGE_END"
- REASONING_MESSAGE_CHUNK = "REASONING_MESSAGE_CHUNK"
- REASONING_END = "REASONING_END"
- REASONING_ENCRYPTED_VALUE = "REASONING_ENCRYPTED_VALUE"
-```
-
-## BaseEvent
-
-`from ag_ui.core import BaseEvent`
-
-All events inherit from the `BaseEvent` class, which provides common properties
-shared across all event types.
-
-```python theme={null}
-class BaseEvent(ConfiguredBaseModel):
- type: EventType
- timestamp: Optional[int] = None
- raw_event: Optional[Any] = None
-```
-
-| Property | Type | Description |
-| ----------- | --------------- | ----------------------------------------------------- |
-| `type` | `EventType` | The type of event (discriminator field for the union) |
-| `timestamp` | `Optional[int]` | Timestamp when the event was created |
-| `raw_event` | `Optional[Any]` | Original event data if this event was transformed |
-
-## Lifecycle Events
-
-These events represent the lifecycle of an agent run.
-
-### RunStartedEvent
-
-`from ag_ui.core import RunStartedEvent`
-
-Signals the start of an agent run.
-
-```python theme={null}
-class RunStartedEvent(BaseEvent):
- type: Literal[EventType.RUN_STARTED]
- thread_id: str
- run_id: str
- parent_run_id: Optional[str] = None
- input: Optional[RunAgentInput] = None
-```
-
-| Property | Type | Description |
-| --------------- | ------------------------- | -------------------------------------------------------------------------------------------------------------- |
-| `thread_id` | `str` | ID of the conversation thread |
-| `run_id` | `str` | ID of the agent run |
-| `parent_run_id` | `Optional[str]` | (Optional) Lineage pointer for branching/time travel. If present, refers to a prior run within the same thread |
-| `input` | `Optional[RunAgentInput]` | (Optional) The exact agent input payload sent to the agent for this run. May omit messages already in history |
-
-### RunFinishedEvent
-
-`from ag_ui.core import RunFinishedEvent`
-
-Signals the successful completion of an agent run.
-
-```python theme={null}
-class RunFinishedEvent(BaseEvent):
- type: Literal[EventType.RUN_FINISHED]
- thread_id: str
- run_id: str
- result: Optional[Any] = None
-```
-
-| Property | Type | Description |
-| ----------- | --------------- | ------------------------------ |
-| `thread_id` | `str` | ID of the conversation thread |
-| `run_id` | `str` | ID of the agent run |
-| `result` | `Optional[Any]` | Result data from the agent run |
-
-### RunErrorEvent
-
-`from ag_ui.core import RunErrorEvent`
-
-Signals an error during an agent run.
-
-```python theme={null}
-class RunErrorEvent(BaseEvent):
- type: Literal[EventType.RUN_ERROR]
- message: str
- code: Optional[str] = None
-```
-
-| Property | Type | Description |
-| --------- | --------------- | ------------- |
-| `message` | `str` | Error message |
-| `code` | `Optional[str]` | Error code |
-
-### StepStartedEvent
-
-`from ag_ui.core import StepStartedEvent`
-
-Signals the start of a step within an agent run.
-
-```python theme={null}
-class StepStartedEvent(BaseEvent):
- type: Literal[EventType.STEP_STARTED]
- step_name: str
-```
-
-| Property | Type | Description |
-| ----------- | ----- | ---------------- |
-| `step_name` | `str` | Name of the step |
-
-### StepFinishedEvent
-
-`from ag_ui.core import StepFinishedEvent`
-
-Signals the completion of a step within an agent run.
-
-```python theme={null}
-class StepFinishedEvent(BaseEvent):
- type: Literal[EventType.STEP_FINISHED]
- step_name: str
-```
-
-| Property | Type | Description |
-| ----------- | ----- | ---------------- |
-| `step_name` | `str` | Name of the step |
-
-## Text Message Events
-
-These events represent the lifecycle of text messages in a conversation.
-
-### TextMessageStartEvent
-
-`from ag_ui.core import TextMessageStartEvent`
-
-Signals the start of a text message.
-
-```python theme={null}
-class TextMessageStartEvent(BaseEvent):
- type: Literal[EventType.TEXT_MESSAGE_START]
- message_id: str
- role: Literal["assistant"]
-```
-
-| Property | Type | Description |
-| ------------ | ---------------------- | --------------------------------- |
-| `message_id` | `str` | Unique identifier for the message |
-| `role` | `Literal["assistant"]` | Role is always "assistant" |
-
-### TextMessageContentEvent
-
-`from ag_ui.core import TextMessageContentEvent`
-
-Represents a chunk of content in a streaming text message.
-
-```python theme={null}
-class TextMessageContentEvent(BaseEvent):
- type: Literal[EventType.TEXT_MESSAGE_CONTENT]
- message_id: str
- delta: str # Non-empty string
-
- def model_post_init(self, __context):
- if len(self.delta) == 0:
- raise ValueError("Delta must not be an empty string")
-```
-
-| Property | Type | Description |
-| ------------ | ----- | ----------------------------------------- |
-| `message_id` | `str` | Matches the ID from TextMessageStartEvent |
-| `delta` | `str` | Text content chunk (non-empty) |
-
-### TextMessageEndEvent
-
-`from ag_ui.core import TextMessageEndEvent`
-
-Signals the end of a text message.
-
-```python theme={null}
-class TextMessageEndEvent(BaseEvent):
- type: Literal[EventType.TEXT_MESSAGE_END]
- message_id: str
-```
-
-| Property | Type | Description |
-| ------------ | ----- | ----------------------------------------- |
-| `message_id` | `str` | Matches the ID from TextMessageStartEvent |
-
-## Tool Call Events
-
-These events represent the lifecycle of tool calls made by agents.
-
-### ToolCallStartEvent
-
-`from ag_ui.core import ToolCallStartEvent`
-
-Signals the start of a tool call.
-
-```python theme={null}
-class ToolCallStartEvent(BaseEvent):
- type: Literal[EventType.TOOL_CALL_START]
- tool_call_id: str
- tool_call_name: str
- parent_message_id: Optional[str] = None
-```
-
-| Property | Type | Description |
-| ------------------- | --------------- | ----------------------------------- |
-| `tool_call_id` | `str` | Unique identifier for the tool call |
-| `tool_call_name` | `str` | Name of the tool being called |
-| `parent_message_id` | `Optional[str]` | ID of the parent message |
-
-### ToolCallArgsEvent
-
-`from ag_ui.core import ToolCallArgsEvent`
-
-Represents a chunk of argument data for a tool call.
-
-```python theme={null}
-class ToolCallArgsEvent(BaseEvent):
- type: Literal[EventType.TOOL_CALL_ARGS]
- tool_call_id: str
- delta: str
-```
-
-| Property | Type | Description |
-| -------------- | ----- | -------------------------------------- |
-| `tool_call_id` | `str` | Matches the ID from ToolCallStartEvent |
-| `delta` | `str` | Argument data chunk |
-
-### ToolCallEndEvent
-
-`from ag_ui.core import ToolCallEndEvent`
-
-Signals the end of a tool call.
-
-```python theme={null}
-class ToolCallEndEvent(BaseEvent):
- type: Literal[EventType.TOOL_CALL_END]
- tool_call_id: str
-```
-
-| Property | Type | Description |
-| -------------- | ----- | -------------------------------------- |
-| `tool_call_id` | `str` | Matches the ID from ToolCallStartEvent |
-
-### ToolCallResultEvent
-
-`from ag_ui.core import ToolCallResultEvent`
-
-Provides the result of a tool call execution.
-
-```python theme={null}
-class ToolCallResultEvent(BaseEvent):
- message_id: str
- type: Literal[EventType.TOOL_CALL_RESULT]
- tool_call_id: str
- content: str
- role: Optional[Literal["tool"]] = None
-```
-
-| Property | Type | Description |
-| -------------- | --------------------------- | ----------------------------------------------------------- |
-| `message_id` | `str` | ID of the conversation message this result belongs to |
-| `tool_call_id` | `str` | Matches the ID from the corresponding ToolCallStartEvent |
-| `content` | `str` | The actual result/output content from the tool execution |
-| `role` | `Optional[Literal["tool"]]` | Optional role identifier, typically "tool" for tool results |
-
-## State Management Events
-
-These events are used to manage agent state.
-
-### StateSnapshotEvent
-
-`from ag_ui.core import StateSnapshotEvent`
-
-Provides a complete snapshot of an agent's state.
-
-```python theme={null}
-class StateSnapshotEvent(BaseEvent):
- type: Literal[EventType.STATE_SNAPSHOT]
- snapshot: State
-```
-
-| Property | Type | Description |
-| ---------- | ------- | ----------------------- |
-| `snapshot` | `State` | Complete state snapshot |
-
-### StateDeltaEvent
-
-`from ag_ui.core import StateDeltaEvent`
-
-Provides a partial update to an agent's state using JSON Patch.
-
-```python theme={null}
-class StateDeltaEvent(BaseEvent):
- type: Literal[EventType.STATE_DELTA]
- delta: List[Any] # JSON Patch (RFC 6902)
-```
-
-| Property | Type | Description |
-| -------- | ----------- | ------------------------------ |
-| `delta` | `List[Any]` | Array of JSON Patch operations |
-
-### MessagesSnapshotEvent
-
-`from ag_ui.core import MessagesSnapshotEvent`
-
-Provides a snapshot of all messages in a conversation.
-
-```python theme={null}
-class MessagesSnapshotEvent(BaseEvent):
- type: Literal[EventType.MESSAGES_SNAPSHOT]
- messages: List[Message]
-```
-
-| Property | Type | Description |
-| ---------- | --------------- | ------------------------ |
-| `messages` | `List[Message]` | Array of message objects |
-
-### ActivitySnapshotEvent
-
-`from ag_ui.core import ActivitySnapshotEvent`
-
-Delivers a complete snapshot of an activity message.
-
-```python theme={null}
-class ActivitySnapshotEvent(BaseEvent):
- type: Literal[EventType.ACTIVITY_SNAPSHOT]
- message_id: str
- activity_type: str
- content: Any
- replace: bool = True
-```
-
-| Property | Type | Description |
-| --------------- | ----------------------- | ---------------------------------------------------------------------------------- |
-| `message_id` | `str` | Identifier for the target `ActivityMessage` |
-| `activity_type` | `str` | Activity discriminator such as `"PLAN"` or `"SEARCH"` |
-| `content` | `Any` | Structured payload describing the full activity state |
-| `replace` | `bool` (default `True`) | When `False`, the snapshot is ignored if a message with the same ID already exists |
-
-### ActivityDeltaEvent
-
-`from ag_ui.core import ActivityDeltaEvent`
-
-Provides incremental updates to an activity snapshot using JSON Patch.
-
-```python theme={null}
-class ActivityDeltaEvent(BaseEvent):
- type: Literal[EventType.ACTIVITY_DELTA]
- message_id: str
- activity_type: str
- patch: List[Any]
-```
-
-| Property | Type | Description |
-| --------------- | ----------- | ---------------------------------------------------------------- |
-| `message_id` | `str` | Identifier for the target `ActivityMessage` |
-| `activity_type` | `str` | Activity discriminator mirroring the most recent snapshot |
-| `patch` | `List[Any]` | JSON Patch operations applied to the structured activity content |
-
-## Special Events
-
-### RawEvent
-
-`from ag_ui.core import RawEvent`
-
-Used to pass through events from external systems.
-
-```python theme={null}
-class RawEvent(BaseEvent):
- type: Literal[EventType.RAW]
- event: Any
- source: Optional[str] = None
-```
-
-| Property | Type | Description |
-| -------- | --------------- | ------------------- |
-| `event` | `Any` | Original event data |
-| `source` | `Optional[str]` | Source of the event |
-
-### CustomEvent
-
-`from ag_ui.core import CustomEvent`
-
-Used for application-specific custom events.
-
-```python theme={null}
-class CustomEvent(BaseEvent):
- type: Literal[EventType.CUSTOM]
- name: str
- value: Any
-```
-
-| Property | Type | Description |
-| -------- | ----- | ------------------------------- |
-| `name` | `str` | Name of the custom event |
-| `value` | `Any` | Value associated with the event |
-
-## Reasoning Events
-
-These events represent the lifecycle of reasoning/thinking processes within an
-agent. Reasoning events allow agents to expose their internal thought process to
-the frontend, creating `ReasoningMessage` objects that persist in the message
-history with the role `"reasoning"`.
-
-### ReasoningStartEvent
-
-`from ag_ui.core import ReasoningStartEvent`
-
-Signals the start of a reasoning phase. This is a pass-through event that
-notifies subscribers but does not create messages.
-
-```python theme={null}
-class ReasoningStartEvent(BaseEvent):
- type: Literal[EventType.REASONING_START]
- message_id: str
-```
-
-| Property | Type | Description |
-| ------------ | ----- | ---------------------------------- |
-| `message_id` | `str` | Identifier for the reasoning phase |
-
-### ReasoningMessageStartEvent
-
-`from ag_ui.core import ReasoningMessageStartEvent`
-
-Signals the start of a reasoning message. Creates a new `ReasoningMessage` in
-the message history.
-
-```python theme={null}
-class ReasoningMessageStartEvent(BaseEvent):
- type: Literal[EventType.REASONING_MESSAGE_START]
- message_id: str
- role: Literal["assistant"]
-```
-
-| Property | Type | Description |
-| ------------ | ---------------------- | --------------------------------- |
-| `message_id` | `str` | Unique identifier for the message |
-| `role` | `Literal["assistant"]` | Role is always "assistant" |
-
-### ReasoningMessageContentEvent
-
-`from ag_ui.core import ReasoningMessageContentEvent`
-
-Represents a chunk of content in a streaming reasoning message.
-
-```python theme={null}
-class ReasoningMessageContentEvent(BaseEvent):
- type: Literal[EventType.REASONING_MESSAGE_CONTENT]
- message_id: str
- delta: str
-```
-
-| Property | Type | Description |
-| ------------ | ----- | ---------------------------------------------- |
-| `message_id` | `str` | Matches the ID from ReasoningMessageStartEvent |
-| `delta` | `str` | Reasoning content chunk |
-
-### ReasoningMessageEndEvent
-
-`from ag_ui.core import ReasoningMessageEndEvent`
-
-Signals the end of a reasoning message.
-
-```python theme={null}
-class ReasoningMessageEndEvent(BaseEvent):
- type: Literal[EventType.REASONING_MESSAGE_END]
- message_id: str
-```
-
-| Property | Type | Description |
-| ------------ | ----- | ---------------------------------------------- |
-| `message_id` | `str` | Matches the ID from ReasoningMessageStartEvent |
-
-### ReasoningMessageChunkEvent
-
-`from ag_ui.core import ReasoningMessageChunkEvent`
-
-Convenience event for complete reasoning messages without manually emitting
-`ReasoningMessageStart`/`ReasoningMessageEnd`.
-
-```python theme={null}
-class ReasoningMessageChunkEvent(BaseEvent):
- type: Literal[EventType.REASONING_MESSAGE_CHUNK]
- message_id: Optional[str] = None # required on first chunk for a message
- delta: Optional[str] = None
-```
-
-Behavior
-
-* Convenience: Some consumers (e.g., the JS/TS client) expand chunk events into
- the standard start/content/end sequence automatically.
-* First chunk requirements: The first chunk for a given message must include
- `message_id`.
-* Streaming: Subsequent chunks with the same `message_id` correspond to content
- pieces; completion triggers an implied end in clients that perform expansion.
-
-### ReasoningEndEvent
-
-`from ag_ui.core import ReasoningEndEvent`
-
-Signals the end of a reasoning phase. This is a pass-through event that notifies
-subscribers but does not modify messages.
-
-```python theme={null}
-class ReasoningEndEvent(BaseEvent):
- type: Literal[EventType.REASONING_END]
- message_id: str
-```
-
-| Property | Type | Description |
-| ------------ | ----- | ---------------------------------- |
-| `message_id` | `str` | Identifier for the reasoning phase |
-
-### ReasoningEncryptedValueEvent
-
-`from ag_ui.core import ReasoningEncryptedValueEvent`
-
-Attaches an encrypted value to a message or tool call. When this event is
-emitted, it finds the referenced entity by `entity_id` and sets its
-`encrypted_value` field.
-
-```python theme={null}
-ReasoningEncryptedValueSubtype = Literal["tool-call", "message"]
-
-class ReasoningEncryptedValueEvent(BaseEvent):
- type: Literal[EventType.REASONING_ENCRYPTED_VALUE]
- subtype: ReasoningEncryptedValueSubtype
- entity_id: str
- encrypted_value: str
-```
-
-| Property | Type | Description |
-| ----------------- | -------------------------------- | -------------------------------------------------- |
-| `subtype` | `ReasoningEncryptedValueSubtype` | The type of entity this value belongs to |
-| `entity_id` | `str` | ID of the tool call or message to attach the value |
-| `encrypted_value` | `str` | The encrypted value to attach to the entity |
-
-## Deprecated Events
-
-
- The `THINKING_*` events are deprecated and will be removed in version 1.0.0.
- New implementations should use `REASONING_*` events instead.
-
-
-### Thinking Events (Deprecated)
-
-The following event types are deprecated:
-
-| Deprecated Event | Replacement |
-| ------------------------------- | --------------------------- |
-| `THINKING_START` | `REASONING_START` |
-| `THINKING_END` | `REASONING_END` |
-| `THINKING_TEXT_MESSAGE_START` | `REASONING_MESSAGE_START` |
-| `THINKING_TEXT_MESSAGE_CONTENT` | `REASONING_MESSAGE_CONTENT` |
-| `THINKING_TEXT_MESSAGE_END` | `REASONING_MESSAGE_END` |
-
-See [Reasoning Migration](/concepts/reasoning#migration-from-thinking-events)
-for detailed migration guidance.
-
-## Event Discrimination
-
-`from ag_ui.core import Event`
-
-The SDK uses Pydantic's discriminated unions for event validation:
-
-```python theme={null}
-Event = Annotated[
- Union[
- TextMessageStartEvent,
- TextMessageContentEvent,
- TextMessageEndEvent,
- ToolCallStartEvent,
- ToolCallArgsEvent,
- ToolCallEndEvent,
- ToolCallResultEvent,
- StateSnapshotEvent,
- StateDeltaEvent,
- MessagesSnapshotEvent,
- ActivitySnapshotEvent,
- ActivityDeltaEvent,
- RawEvent,
- CustomEvent,
- RunStartedEvent,
- RunFinishedEvent,
- RunErrorEvent,
- StepStartedEvent,
- StepFinishedEvent,
- ReasoningStartEvent,
- ReasoningMessageStartEvent,
- ReasoningMessageContentEvent,
- ReasoningMessageEndEvent,
- ReasoningMessageChunkEvent,
- ReasoningEndEvent,
- ReasoningEncryptedValueEvent,
- ],
- Field(discriminator="type")
-]
-```
-
-This allows for runtime validation of events and type checking at development
-time.
-
-### TextMessageChunkEvent
-
-Convenience event for complete text messages without manually emitting
-`TextMessageStart`/`TextMessageEnd`.
-
-```python theme={null}
-from ag_ui.core import TextMessageChunkEvent
-
-class TextMessageChunkEvent(BaseEvent):
- type: Literal[EventType.TEXT_MESSAGE_CHUNK]
- message_id: Optional[str] = None # required on first chunk for a message
- role: Optional[TextMessageRole] = None # defaults to "assistant" in JS client
- delta: Optional[str] = None
-```
-
-Behavior
-
-* Convenience: Some consumers (e.g., the JS/TS client) expand chunk events into
- the standard start/content/end sequence automatically, allowing producers to
- omit explicit start/end events when using chunks.
-* First chunk requirements: The first chunk for a given message must include
- `message_id`.
-* Streaming: Subsequent chunks with the same `message_id` correspond to content
- pieces; completion triggers an implied end in clients that perform expansion.
-
-### ToolCallChunkEvent
-
-Convenience event for tool calls without manually emitting
-`ToolCallStart`/`ToolCallEnd`.
-
-```python theme={null}
-from ag_ui.core import ToolCallChunkEvent
-
-class ToolCallChunkEvent(BaseEvent):
- type: Literal[EventType.TOOL_CALL_CHUNK]
- tool_call_id: Optional[str] = None # required on first chunk
- tool_call_name: Optional[str] = None # required on first chunk
- parent_message_id: Optional[str] = None
- delta: Optional[str] = None
-```
-
-Behavior
-
-* Convenience: Consumers may expand chunk sequences into the standard
- start/args/end triad (the JS/TS client does this automatically).
-* First chunk requirements: Include both `tool_call_id` and `tool_call_name` on
- the first chunk.
-* Streaming: Subsequent chunks with the same `tool_call_id` correspond to args
- pieces; completion triggers an implied end in clients that perform expansion.
-
-
-# Overview
-Source: https://docs.ag-ui.com/sdk/python/core/overview
-
-Core concepts in the Agent User Interaction Protocol SDK
-
-```bash theme={null}
-pip install ag-ui-protocol
-```
-
-# ag\_ui.core
-
-The Agent User Interaction Protocol SDK uses a streaming event-based
-architecture with strongly typed data structures. This package provides the
-foundation for connecting to agent systems.
-
-```python theme={null}
-from ag_ui.core import ...
-```
-
-## Types
-
-Core data structures that represent the building blocks of the system:
-
-* [RunAgentInput](/sdk/python/core/types#runagentinput) - Input parameters for
- running agents
-* [Message](/sdk/python/core/types#message-types) - User assistant communication
- and tool usage
-* [Context](/sdk/python/core/types#context) - Contextual information provided to
- agents
-* [Tool](/sdk/python/core/types#tool) - Defines functions that agents can call
-* [State](/sdk/python/core/types#state) - Agent state management
-
-
- Complete documentation of all types in the ag\_ui.core package
-
-
-## Events
-
-Events that power communication between agents and frontends:
-
-* [Lifecycle Events](/sdk/python/core/events#lifecycle-events) - Run and step
- tracking
-* [Text Message Events](/sdk/python/core/events#text-message-events) - Assistant
- message streaming
-* [Tool Call Events](/sdk/python/core/events#tool-call-events) - Function call
- lifecycle
-* [State Management Events](/sdk/python/core/events#state-management-events) -
- Agent state updates
-* [Special Events](/sdk/python/core/events#special-events) - Raw and custom
- events
-
-
- Complete documentation of all events in the ag\_ui.core package
-
-
-
-# Types
-Source: https://docs.ag-ui.com/sdk/python/core/types
-
-Documentation for the core types used in the Agent User Interaction Protocol Python SDK
-
-# Core Types
-
-The Agent User Interaction Protocol Python SDK is built on a set of core types
-that represent the fundamental structures used throughout the system. This page
-documents these types and their properties.
-
-## RunAgentInput
-
-`from ag_ui.core import RunAgentInput`
-
-Input parameters for running an agent. In the HTTP API, this is the body of the
-`POST` request.
-
-```python theme={null}
-class RunAgentInput(ConfiguredBaseModel):
- thread_id: str
- run_id: str
- parent_run_id: Optional[str] = None
- state: Any
- messages: List[Message]
- tools: List[Tool]
- context: List[Context]
- forwarded_props: Any
-```
-
-| Property | Type | Description |
-| ----------------- | --------------- | ---------------------------------------------- |
-| `thread_id` | `str` | ID of the conversation thread |
-| `run_id` | `str` | ID of the current run |
-| `parent_run_id` | `Optional[str]` | (Optional) ID of the run that spawned this run |
-| `state` | `Any` | Current state of the agent |
-| `messages` | `List[Message]` | List of messages in the conversation |
-| `tools` | `List[Tool]` | List of tools available to the agent |
-| `context` | `List[Context]` | List of context objects provided to the agent |
-| `forwarded_props` | `Any` | Additional properties forwarded to the agent |
-
-## Message Types
-
-The SDK includes several message types that represent different kinds of
-messages in the system.
-
-### Role
-
-`from ag_ui.core import Role`
-
-Represents the possible roles a message sender can have.
-
-```python theme={null}
-Role = Literal["developer", "system", "assistant", "user", "tool", "activity", "reasoning"]
-```
-
-### DeveloperMessage
-
-`from ag_ui.core import DeveloperMessage`
-
-Represents a message from a developer.
-
-```python theme={null}
-class DeveloperMessage(BaseMessage):
- role: Literal["developer"]
- content: str
-```
-
-| Property | Type | Description |
-| --------- | ---------------------- | ------------------------------------------------ |
-| `id` | `str` | Unique identifier for the message |
-| `role` | `Literal["developer"]` | Role of the message sender, fixed as "developer" |
-| `content` | `str` | Text content of the message (required) |
-| `name` | `Optional[str]` | Optional name of the sender |
-
-### SystemMessage
-
-`from ag_ui.core import SystemMessage`
-
-Represents a system message.
-
-```python theme={null}
-class SystemMessage(BaseMessage):
- role: Literal["system"]
- content: str
-```
-
-| Property | Type | Description |
-| --------- | ------------------- | --------------------------------------------- |
-| `id` | `str` | Unique identifier for the message |
-| `role` | `Literal["system"]` | Role of the message sender, fixed as "system" |
-| `content` | `str` | Text content of the message (required) |
-| `name` | `Optional[str]` | Optional name of the sender |
-
-### AssistantMessage
-
-`from ag_ui.core import AssistantMessage`
-
-Represents a message from an assistant.
-
-```python theme={null}
-class AssistantMessage(BaseMessage):
- role: Literal["assistant"]
- content: Optional[str] = None
- tool_calls: Optional[List[ToolCall]] = None
-```
-
-| Property | Type | Description |
-| ------------ | -------------------------- | ------------------------------------------------ |
-| `id` | `str` | Unique identifier for the message |
-| `role` | `Literal["assistant"]` | Role of the message sender, fixed as "assistant" |
-| `content` | `Optional[str]` | Text content of the message |
-| `name` | `Optional[str]` | Name of the sender |
-| `tool_calls` | `Optional[List[ToolCall]]` | Tool calls made in this message |
-
-### UserMessage
-
-`from ag_ui.core import UserMessage`
-
-Represents a message from a user.
-
-```python theme={null}
-class UserMessage(BaseMessage):
- role: Literal["user"]
- content: Union[str, List["InputContent"]]
-```
-
-| Property | Type | Description |
-| --------- | ---------------------------------- | --------------------------------------------------------------------- |
-| `id` | `str` | Unique identifier for the message |
-| `role` | `Literal["user"]` | Role of the message sender, fixed as "user" |
-| `content` | `Union[str, List["InputContent"]]` | Either a plain text string or an ordered list of multimodal fragments |
-| `name` | `Optional[str]` | Optional name of the sender |
-
-### TextInputContent
-
-Represents a text fragment inside a multimodal user message.
-
-```python theme={null}
-class TextInputContent(ConfiguredBaseModel):
- type: Literal["text"]
- text: str
-```
-
-| Property | Type | Description |
-| -------- | ----------------- | ---------------------------- |
-| `type` | `Literal["text"]` | Identifies the fragment type |
-| `text` | `str` | Text content |
-
-### BinaryInputContent
-
-Represents binary data such as images, audio, or files.
-
-```python theme={null}
-class BinaryInputContent(ConfiguredBaseModel):
- type: Literal["binary"]
- mime_type: str
- id: Optional[str] = None
- url: Optional[str] = None
- data: Optional[str] = None
- filename: Optional[str] = None
-```
-
-| Property | Type | Description |
-| ----------- | ------------------- | --------------------------------------------- |
-| `type` | `Literal["binary"]` | Identifies the fragment type |
-| `mime_type` | `str` | MIME type, for example `"image/png"` |
-| `id` | `Optional[str]` | Reference to previously uploaded content |
-| `url` | `Optional[str]` | Remote URL where the content can be retrieved |
-| `data` | `Optional[str]` | Base64 encoded content |
-| `filename` | `Optional[str]` | Optional filename hint |
-
-> **Validation:** At least one of `id`, `url`, or `data` must be provided.
-
-### ToolMessage
-
-`from ag_ui.core import ToolMessage`
-
-Represents a message from a tool.
-
-```python theme={null}
-class ToolMessage(ConfiguredBaseModel):
- id: str
- role: Literal["tool"]
- content: str
- tool_call_id: str
- error: Optional[str] = None
- encrypted_value: Optional[str] = None
-```
-
-| Property | Type | Description |
-| ----------------- | ----------------- | ----------------------------------------------- |
-| `id` | `str` | Unique identifier for the message |
-| `content` | `str` | Text content of the message |
-| `role` | `Literal["tool"]` | Role of the message sender, fixed as "tool" |
-| `tool_call_id` | `str` | ID of the tool call this message responds to |
-| `error` | `Optional[str]` | Error message if the tool call failed |
-| `encrypted_value` | `Optional[str]` | Optional encrypted value attached via signature |
-
-### ActivityMessage
-
-`from ag_ui.core import ActivityMessage`
-
-Represents structured activity progress emitted between chat messages.
-
-```python theme={null}
-class ActivityMessage(ConfiguredBaseModel):
- id: str
- role: Literal["activity"]
- activity_type: str
- content: Dict[str, Any]
-```
-
-| Property | Type | Description |
-| --------------- | --------------------- | ------------------------------------------------------- |
-| `id` | `str` | Unique identifier for the activity message |
-| `role` | `Literal["activity"]` | Fixed discriminator identifying the message as activity |
-| `activity_type` | `str` | Activity discriminator used for renderer selection |
-| `content` | `Dict[str, Any]` | Structured payload representing the activity state |
-
-### ReasoningMessage
-
-`from ag_ui.core import ReasoningMessage`
-
-Represents a reasoning/thinking message from an agent's internal thought
-process.
-
-```python theme={null}
-class ReasoningMessage(ConfiguredBaseModel):
- id: str
- role: Literal["reasoning"]
- content: str
- encrypted_value: Optional[str] = None
-```
-
-| Property | Type | Description |
-| ----------------- | ---------------------- | -------------------------------------------------- |
-| `id` | `str` | Unique identifier for the reasoning message |
-| `role` | `Literal["reasoning"]` | Fixed discriminator identifying the reasoning role |
-| `content` | `str` | The reasoning/thinking content |
-| `encrypted_value` | `Optional[str]` | Optional encrypted value attached via signature |
-
-### Message
-
-`from ag_ui.core import Message`
-
-A union type representing any type of message in the system.
-
-```python theme={null}
-Message = Annotated[
- Union[
- DeveloperMessage,
- SystemMessage,
- AssistantMessage,
- UserMessage,
- ToolMessage,
- ActivityMessage,
- ReasoningMessage,
- ],
- Field(discriminator="role")
-]
-```
-
-### ToolCall
-
-`from ag_ui.core import ToolCall`
-
-Represents a tool call made by an agent.
-
-```python theme={null}
-class ToolCall(ConfiguredBaseModel):
- id: str
- type: Literal["function"]
- function: FunctionCall
- encrypted_value: Optional[str] = None
-```
-
-| Property | Type | Description |
-| ----------------- | --------------------- | ----------------------------------------------- |
-| `id` | `str` | Unique identifier for the tool call |
-| `type` | `Literal["function"]` | Type of the tool call, always "function" |
-| `function` | `FunctionCall` | Details about the function being called |
-| `encrypted_value` | `Optional[str]` | Optional encrypted value attached via signature |
-
-#### FunctionCall
-
-`from ag_ui.core import FunctionCall`
-
-Represents function name and arguments in a tool call.
-
-```python theme={null}
-class FunctionCall(ConfiguredBaseModel):
- name: str
- arguments: str
-```
-
-| Property | Type | Description |
-| ----------- | ----- | ------------------------------------------------ |
-| `name` | `str` | Name of the function to call |
-| `arguments` | `str` | JSON-encoded string of arguments to the function |
-
-## Context
-
-`from ag_ui.core import Context`
-
-Represents a piece of contextual information provided to an agent.
-
-```python theme={null}
-class Context(ConfiguredBaseModel):
- description: str
- value: str
-```
-
-| Property | Type | Description |
-| ------------- | ----- | ------------------------------------------- |
-| `description` | `str` | Description of what this context represents |
-| `value` | `str` | The actual context value |
-
-## Tool
-
-`from ag_ui.core import Tool`
-
-Defines a tool that can be called by an agent.
-
-```python theme={null}
-class Tool(ConfiguredBaseModel):
- name: str
- description: str
- parameters: Any # JSON Schema
-```
-
-| Property | Type | Description |
-| ------------- | ----- | ------------------------------------------------ |
-| `name` | `str` | Name of the tool |
-| `description` | `str` | Description of what the tool does |
-| `parameters` | `Any` | JSON Schema defining the parameters for the tool |
-
-## State
-
-`from ag_ui.core import State`
-
-Represents the state of an agent during execution.
-
-```python theme={null}
-State = Any
-```
-
-The state type is flexible and can hold any data structure needed by the agent
-implementation.
-
-
-# Overview
-Source: https://docs.ag-ui.com/sdk/python/encoder/overview
-
-Documentation for encoding Agent User Interaction Protocol events
-
-```bash theme={null}
-pip install ag-ui-protocol
-```
-
-# Event Encoder
-
-The Agent User Interaction Protocol uses a streaming approach to send events
-from agents to clients. The `EventEncoder` class provides the functionality to
-encode events into a format that can be sent over HTTP.
-
-## EventEncoder
-
-`from ag_ui.encoder import EventEncoder`
-
-The `EventEncoder` class is responsible for encoding `BaseEvent` objects into
-string representations that can be transmitted to clients.
-
-```python theme={null}
-from ag_ui.core import BaseEvent
-from ag_ui.encoder import EventEncoder
-
-# Initialize the encoder
-encoder = EventEncoder()
-
-# Encode an event
-encoded_event = encoder.encode(event)
-```
-
-### Usage
-
-The `EventEncoder` is typically used in HTTP handlers to convert event objects
-into a stream of data. The current implementation encodes events as Server-Sent
-Events (SSE), which can be consumed by clients using the EventSource API.
-
-### Methods
-
-#### `__init__(accept: str = None)`
-
-Creates a new encoder instance.
-
-| Parameter | Type | Description |
-| --------- | ---------------- | ----------------------------------- |
-| `accept` | `str` (optional) | Content type accepted by the client |
-
-#### `encode(event: BaseEvent) -> str`
-
-Encodes an event into a string representation.
-
-| Parameter | Type | Description |
-| --------- | ----------- | ------------------- |
-| `event` | `BaseEvent` | The event to encode |
-
-**Returns**: A string representation of the event in SSE format.
-
-### Example
-
-```python theme={null}
-from ag_ui.core import TextMessageContentEvent, EventType
-from ag_ui.encoder import EventEncoder
-
-# Create an event
-event = TextMessageContentEvent(
- type=EventType.TEXT_MESSAGE_CONTENT,
- message_id="msg_123",
- delta="Hello, world!"
-)
-
-# Initialize the encoder
-encoder = EventEncoder()
-
-# Encode the event
-encoded_event = encoder.encode(event)
-print(encoded_event)
-# Output: data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"msg_123","delta":"Hello, world!"}\n\n
-```
-
-### Implementation Details
-
-Internally, the encoder converts events to JSON and formats them as Server-Sent
-Events with the following structure:
-
-```
-data: {json-serialized event}\n\n
-```
-
-This format allows clients to receive a continuous stream of events and process
-them as they arrive.
-
-
-# Developing with Cursor
-Source: https://docs.ag-ui.com/tutorials/cursor
-
-Use Cursor to build AG-UI implementations faster
-
-This guide will help you set up Cursor to help you build custom Agent User
-Interaction Protocol (AG-UI) servers and clients faster. The same principles
-apply to other IDE's like Windsurf, VSCode, etc.
-
-## Adding the documentation to Cursor
-
-1. Open up the Cursor settings
-2. Go to Features > Docs and click "+ Add new Doc"
-3. Paste in the following URL: [https://docs.ag-ui.com/llms-full.txt](https://docs.ag-ui.com/llms-full.txt)
-4. Click "Add"
-
-## Using the documentation
-
-Now you can use the documentation to help you build your AG-UI project. Load the
-docs into the current prompt by typing the `@` symbol, selecting "Docs" and then
-selecting "Agent User Interaction Protocol" from the list. Happy coding!
-
-## Best practices
-
-When building AG-UI servers with Cursor:
-
-* Break down complex problems into smaller steps
-* Have a look at what the agent was doing by checking which files it edited
- (above the chat input)
-* Let the agent write unit tests to verify your implementation
-* Follow AG-UI protocol specifications carefully
-
-
-# Debugging
-Source: https://docs.ag-ui.com/tutorials/debugging
-
-A comprehensive guide to debugging Agent User Interaction Protocol (AG-UI) integrations
-
-# Debugging AG-UI Integrations
-
-Debugging agent-based applications can be challenging, especially when working
-with real-time, event-driven protocols like AG-UI. This guide introduces you to
-the AG-UI Dojo, a powerful tool for learning, testing, and debugging your AG-UI
-implementations.
-
-## The AG-UI Dojo
-
-The AG-UI Dojo is the best way to bring AG-UI to a new surface, and is also an
-excellent resource for learning about the protocol's basic capabilities. It
-provides a structured environment where you can test and validate each component
-of the AG-UI protocol.
-
-### What is the Dojo?
-
-The Dojo consists of a series of "hello world"-sized demonstrations for the
-different building blocks available via AG-UI. Each demonstration:
-
-1. Shows a specific AG-UI capability in action
-2. Presents both the user-visible interaction and the underlying code side by
- side
-3. Allows you to test and verify your implementation
-
-### Using the Dojo as an Implementation Checklist
-
-When working on bringing AG-UI to a new surface or platform, you can use the
-Dojo as a comprehensive "todo list":
-
-1. Work through each demonstration one by one
-2. Implement and test each AG-UI building block in your environment
-3. When all demonstrations work correctly in your implementation, you can be
- confident that full-featured copilots and agent-native applications can be
- built on your new surface
-
-This methodical approach ensures you've covered all the necessary functionality
-required for a complete AG-UI implementation.
-
-### Using the Dojo as a Learning Resource
-
-For developers new to AG-UI, the Dojo serves as an interactive learning
-resource:
-
-* Each item demonstrates a specific AG-UI capability
-* You can see both what the interaction looks like from a user perspective
-* The underlying code is shown alongside, helping you understand how it works
-* The incremental complexity helps build understanding from basics to advanced
- features
-
-### Common Debugging Patterns
-
-When using the Dojo for debugging your AG-UI implementation, keep these patterns
-in mind:
-
-1. **Event Sequence Issues**: Verify that events are being emitted in the
- correct order and with proper nesting (e.g., `TEXT_MESSAGE_START` before
- `TEXT_MESSAGE_CONTENT`)
-
-2. **Data Format Problems**: Ensure your event payloads match the expected
- structure for each event type
-
-3. **Transport Layer Debugging**: Check that your chosen transport mechanism
- (SSE, WebSockets, etc.) is correctly delivering events
-
-4. **State Synchronization**: Confirm that state updates are correctly applied
- using snapshots and deltas
-
-5. **Tool Execution**: Verify that tool calls and responses are properly
- formatted and processed
-
-## Getting Started with the Dojo
-
-To start using the AG-UI Dojo:
-
-1. Clone the repository from
- [github.com/ag-ui-protocol/ag-ui](https://github.com/ag-ui-protocol/ag-ui)
-2. Follow the setup instructions in the README
-3. Start working through the demonstrations in order
-4. Use the provided test cases to validate your implementation
-
-The Dojo's structured approach makes it an invaluable resource for both learning
-AG-UI and ensuring your implementation meets all requirements.
diff --git a/.opencode/skills/ag-ui/modules/agents.md b/.opencode/skills/ag-ui/modules/agents.md
deleted file mode 100644
index 5f4c5cd..0000000
--- a/.opencode/skills/ag-ui/modules/agents.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Agents
-
-**作用**: 介绍 AG-UI 中 Agent 的概念、架构、类型和实现方式。
-
-**源文件**: `llms-full.txt`
-**行号范围**: 35-451
-
-**内容索引**:
-- 什么是 Agent (行 47-62)
-- Agent Architecture - AbstractAgent, 核心组件 (行 63-91)
-- Agent Types - HttpAgent, Custom Agents (行 93-130)
-- Implementing Agents - 基本实现示例 (行 132-197)
-- Agent Capabilities - 交互通信、工具使用、状态管理、多 Agent 协作、人机协作、对话记忆 (行 199-358)
-- 使用 Agent (行 360-399)
-- Agent Configuration (行 401-424)
-- Agent State Management (行 426-439)
diff --git a/.opencode/skills/ag-ui/modules/architecture.md b/.opencode/skills/ag-ui/modules/architecture.md
deleted file mode 100644
index 2a70cb9..0000000
--- a/.opencode/skills/ag-ui/modules/architecture.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# Core Architecture
-
-**作用**: 介绍 AG-UI 的核心架构、设计原则和运行机制。
-
-**源文件**: `llms-full.txt`
-**行号范围**: 453-679
-
-**内容索引**:
-- Design Principles - 事件驱动、双向交互、灵活中间件 (行 463-489)
-- Architectural Overview - 客户端-服务器架构 (行 491-534)
-- Protocol layer - run(input) -> Observable (行 537-567)
-- Standard HTTP client - HttpAgent, SSE/HTTP binary (行 569-585)
-- Message types - Lifecycle, Text, Tool, State, Special 事件 (行 587-609)
-- Running Agents (行 611-640)
-- State Management - STATE_SNAPSHOT, STATE_DELTA (行 642-652)
-- Tools and Handoff (行 653-662)
-- Base Event 属性 (行 664-677)
diff --git a/.opencode/skills/ag-ui/modules/contributing.md b/.opencode/skills/ag-ui/modules/contributing.md
deleted file mode 100644
index 829bbdb..0000000
--- a/.opencode/skills/ag-ui/modules/contributing.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# Contributing & Roadmap
-
-**作用**: 贡献指南、路线图和更新日志。
-
-**源文件**: `llms-full.txt`
-**行号范围**: 3443-3485
-
-**内容索引**:
-- Contributing (行 3443-3460):
- - Naming conventions - integrations/, wip-, community- 前缀 (行 3448-3459)
-- Roadmap (行 3462-3481):
- - 公开路线图链接 (行 3467-3468)
- - Get Involved - 贡献方式 (行 3470-3474)
-- What's New (行 3477-3485):
- - 2025-04-09: AG-UI 仓库公开发布 (行 3482-3484)
diff --git a/.opencode/skills/ag-ui/modules/drafts.md b/.opencode/skills/ag-ui/modules/drafts.md
deleted file mode 100644
index 315a5e4..0000000
--- a/.opencode/skills/ag-ui/modules/drafts.md
+++ /dev/null
@@ -1,53 +0,0 @@
-# Drafts
-
-**作用**: 介绍 AG-UI 协议中正在考虑或开发中的提案功能。
-
-**源文件**: `llms-full.txt`
-**行号范围**: 3492-3854 (Generative UI), 3860-4105 (Interrupts), 4111-4349 (Meta Events), 4355-4846 (Multimodal)
-
-**Drafts 概述** (行 4847-4887):
-- Drafts 状态定义 - Draft/Under Review/Accepted/Implemented/Withdrawn (行 4880-4886)
-
-**Generative User Interfaces** (行 3492-3854):
- - Summary - 问题陈述与动机 (行 3494-3508)
- - Challenges and Limitations - 工具描述长度、JSON Schema 约束 (行 3515-3531)
- - Detailed Specification:
- - Two-Step Generation Process - 两步生成流程图 (行 3535-3543)
- - Step 1: What to Generate? - generateUserInterface 工具 (行 3545-3596)
- - Step 2: How to Generate? - 次级 LLM 生成实际 UI (行 3598-3612)
- - Implementation Examples:
- - UISchemaGenerator - JSON Schema 输出 (行 3615-3673)
- - ReactFormHookGenerator - React Hook Form 代码生成 (行 3675-3795)
- - Implementation Considerations - SDK 变更 (行 3797-3819)
- - Use Cases - 动态表单、数据可视化、交互式工作流 (行 3821-3838)
-
-**Interrupt-Aware Run Lifecycle** (行 3860-4105):
- - Summary - 人机协作暂停机制 (行 3862-3875)
- - Updates to RUN_FINISHED Event - outcome, interrupt 字段 (行 3897-3920)
- - Updates to RunAgentInput - resume 字段 (行 3922-3937)
- - Contract Rules (行 3939-3945)
- - Implementation Examples (行 3947-4026)
- - Use Cases - 人类批准、信息收集、策略强制 (行 4028-4051)
- - Implementation Considerations (行 4052-4091)
-
-**Meta Events** (行 4111-4349):
- - Summary - 独立于 Agent 运行的事件注解 (行 4115-4127)
- - MetaEvent Type - metaType, payload (行 4145-4170)
- - Implementation Examples:
- - User Feedback - thumbs_up, thumbs_down (行 4174-4206)
- - Annotations - note, tag (行 4208-4239)
- - External System Events - analytics, moderation (行 4241-4276)
- - Common Meta Event Types 表 (行 4278-4292)
- - Use Cases (行 4294-4318)
-
-**Multimodal Messages** (行 4355-4846):
- - Summary - 支持多模态输入消息 (行 4357-4371)
- - Status: Implemented (行 4373-4376)
- - Detailed Specification:
- - Modality Types 表 - text, image, audio, video, document (行 4473-4483)
- - Source Types - InputContentDataSource, InputContentUrlSource (行 4485-4509)
- - Content Part Types - TextInputPart, ImageInputPart, AudioInputPart, VideoInputPart, DocumentInputPart (行 4511-4561)
- - Provider Metadata (行 4562-4571)
- - Implementation Examples (行 4573-4764)
- - Implementation Considerations (行 4766-4798)
- - Use Cases (行 4800-4827)
diff --git a/.opencode/skills/ag-ui/modules/events.md b/.opencode/skills/ag-ui/modules/events.md
deleted file mode 100644
index cf6c928..0000000
--- a/.opencode/skills/ag-ui/modules/events.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# Events
-
-**作用**: 详细介绍 AG-UI 协议中的所有事件类型,包括生命周期、文本、工具调用、状态管理、推理等事件。
-
-**源文件**: `llms-full.txt`
-**行号范围**: 680-1475
-
-**内容索引**:
-- Event Types Overview - 事件分类表 (行 692-703)
-- Base Event Properties (行 705-713)
-- Lifecycle Events - RunStarted, RunFinished, RunError, StepStarted, StepFinished (行 715-754)
-- Text Message Events - TextMessageStart, TextMessageContent, TextMessageEnd, TextMessageChunk (行 835-937)
-- Tool Call Events - ToolCallStart, ToolCallArgs, ToolCallEnd, ToolCallResult, ToolCallChunk (行 938-1066)
-- State Management Events - StateSnapshot, StateDelta, MessagesSnapshot (行 1067-1155)
-- Activity Events - ActivitySnapshot, ActivityDelta (行 1156-1189)
-- Special Events - Raw, Custom (行 1191-1233)
-- Reasoning Events - ReasoningStart, ReasoningMessageStart/Content/End/Chunk, ReasoningEnd, ReasoningEncryptedValue (行 1234-1368)
-- Deprecated Events - THINKING_* 事件迁移 (行 1369-1389)
-- Draft Events - Meta Events, Modified Lifecycle Events (行 1391-1446)
-- Event Flow Patterns - Start-Content-End, Snapshot-Delta, Lifecycle (行 1447-1474)
diff --git a/.opencode/skills/ag-ui/modules/generative-ui.md b/.opencode/skills/ag-ui/modules/generative-ui.md
deleted file mode 100644
index aee800d..0000000
--- a/.opencode/skills/ag-ui/modules/generative-ui.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# Generative UI Specs
-
-**作用**: 介绍 AG-UI 与生成式 UI 规范的关系(A2UI、MCP-UI、Open-JSON-UI)。
-
-**源文件**: `llms-full.txt`
-**行号范围**: 1476-1496
-
-**内容索引**:
-- AG-UI and Generative UI Specs - AG-UI 不是生成式 UI 规范,而是用户交互协议 (行 1476-1496)
-- AG-UI 与 A2UI、MCP-UI、Open-JSON-UI 的关系说明
-- Generative UI 实现详情见 [drafts](drafts.md) 的 Generative User Interfaces 章节 (行 3492-3854)
diff --git a/.opencode/skills/ag-ui/modules/messages.md b/.opencode/skills/ag-ui/modules/messages.md
deleted file mode 100644
index 3d85435..0000000
--- a/.opencode/skills/ag-ui/modules/messages.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# Messages
-
-**作用**: 介绍 AG-UI 中消息的结构、类型和同步机制。
-
-**源文件**: `llms-full.txt`
-**行号范围**: 1498-1952
-
-**内容索引**:
-- Message Structure - BaseMessage 接口, role, encryptedContent (行 1510-1537)
-- Message Types:
- - UserMessage - 用户消息, 支持多模态 InputContent (行 1543-1576)
- - AssistantMessage - 助手消息, 含 toolCalls (行 1578-1591)
- - SystemMessage - 系统消息 (行 1593-1604)
- - ToolMessage - 工具结果消息 (行 1606-1627)
- - ActivityMessage - 前端专用活动消息 (行 1628-1653)
- - DeveloperMessage - 开发/调试消息 (行 1654-1665)
- - ReasoningMessage - 推理消息 (行 1667-1704)
-- Vendor Neutrality - 供应商中立性, 格式转换示例 (行 1705-1735)
-- Message Synchronization - MESSAGES_SNAPSHOT, 流式消息 (行 1736-1794)
-- Tool Integration - ToolCall, ToolResult 结构 (行 1795-1889)
-- Practical Example - 完整对话示例 (行 1891-1939)
diff --git a/.opencode/skills/ag-ui/modules/middleware.md b/.opencode/skills/ag-ui/modules/middleware.md
deleted file mode 100644
index 36b1297..0000000
--- a/.opencode/skills/ag-ui/modules/middleware.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# Middleware
-
-**作用**: 介绍 AG-UI 中间件,用于转换、过滤和增强事件流。
-
-**源文件**: `llms-full.txt`
-**行号范围**: 1954-2158
-
-**内容索引**:
-- What is Middleware? - 中间件的作用 (行 1965-1973)
-- How Middleware Works - 中间件链式调用 (行 1975-1991)
-- Function-Based Middleware - 函数式中间件示例 (行 1993-2019)
-- Class-Based Middleware - 类中间件示例 (行 2021-2055)
-- Built-in Middleware - FilterToolCallsMiddleware (行 2062-2086)
-- Middleware Patterns - 日志、认证、限流 (行 2088-2090)
-- Combining Middleware (行 2092-2103)
-- Execution Order - 中间件执行顺序 (行 2104-2124)
-- Best Practices (行 2126-2134)
-- Conditional Middleware (行 2136-2153)
diff --git a/.opencode/skills/ag-ui/modules/overview.md b/.opencode/skills/ag-ui/modules/overview.md
deleted file mode 100644
index 51f9f3b..0000000
--- a/.opencode/skills/ag-ui/modules/overview.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# AG-UI Overview
-
-**作用**: AG-UI 协议总体介绍,包括协议定位、核心特性、与其他协议的关系、以及构建块概览。
-
-**源文件**: `llms-full.txt`
-**行号范围**: 4894-5261
-
-**内容索引**:
-- 协议定义 - 开放、轻量、事件驱动的 Agent-User 交互协议 (行 4894-4901)
-- Agentic Protocols - MCP/A2A/AG-UI 三层协议栈 (行 4910-4923)
-- Building Blocks (行 4926-5088):
- - Streaming chat - 流式对话 (行 4930-4941)
- - Tool calling - 工具调用 (行 4943-4953)
- - Structured state - 结构化状态 (行 4955-4965)
- - Generative UI - 生成式 UI (行 4967-4977)
- - Contextual context - 上下文管理 (行 4979-4989)
- - Client-side tools - 客户端工具 (行 4991-5001)
- - Auth & multi-tenancy - 认证与多租户 (行 5003-5013)
- - Debugging & evals - 调试与评估 (行 5015-5025)
- - Upcoming: Reasoning continuity - 推理连续性 (行 5027-5037)
- - Upcoming: Multi-modal - 多模态 (行 5039-5049)
- - Upcoming: Generative UI - 生成式 UI (行 5051-5061)
- - Upcoming: Interrupts & approval flows - 中断与审批流程 (行 5063-5073)
- - Upcoming: Meta events - 元事件 (行 5075-5085)
-- Protocol Basics (行 5090-5261):
- - Agent Definition - Agent 定义 (行 5095-5109)
- - Event Stream - 事件流 (行 5111-5129)
- - Common Patterns - 常见模式 (行 5131-5151)
diff --git a/.opencode/skills/ag-ui/modules/protocol.md b/.opencode/skills/ag-ui/modules/protocol.md
deleted file mode 100644
index cbf3a3b..0000000
--- a/.opencode/skills/ag-ui/modules/protocol.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# Protocol
-
-**作用**: 介绍 AG-UI 与 MCP、A2A 协议的关系,以及 AG-UI 作为连接 Agent 与用户应用的协议定位。
-
-**源文件**: `llms-full.txt`
-**行号范围**: 1-33
-
-**内容索引**:
-- Agentic Protocols 概述 (MCP, A2A, AG-UI)
-- AG-UI 与 MCP、A2A 的握手
-- Generative UI Specs 介绍
diff --git a/.opencode/skills/ag-ui/modules/reasoning.md b/.opencode/skills/ag-ui/modules/reasoning.md
deleted file mode 100644
index fa513a2..0000000
--- a/.opencode/skills/ag-ui/modules/reasoning.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# Reasoning
-
-**作用**: 介绍 AG-UI 对 LLM 推理的支持,包括链式思维可视化和加密推理内容。
-
-**源文件**: `llms-full.txt`
-**行号范围**: 2160-2638
-
-**内容索引**:
-- Overview - 推理可见性、状态连续性、隐私合规 (行 2171-2188)
-- ReasoningMessage - 推理消息结构 (行 2190-2217)
-- Reasoning Events:
- - Event Flow - 推理事件流程图 (行 2223-2246)
- - Event Types 表 (行 2248-2258)
-- Privacy and Compliance:
- - Zero Data Retention (ZDR) - 零数据保留 (行 2264-2273)
- - Visibility Control - 可见性控制 (行 2274-2284)
- - Compliance Considerations 表 - GDPR, SOC 2, HIPAA (行 2285-2293)
-- Example Implementations:
- - Basic Reasoning Flow (行 2296-2348)
- - Encrypted Content for State Continuity (行 2350-2396)
- - Attaching Encrypted Reasoning to Tool Calls (行 2398-2430)
- - ZDR-Compliant Implementation (行 2432-2475)
- - Using Convenience Chunk Event (行 2477-2503)
-- Client Integration - 处理推理事件, 传递加密推理 (行 2505-2563)
-- Migration from Thinking Events - THINKING_* 迁移到 REASONING_* (行 2565-2617)
-- Best Practices (行 2619-2632)
diff --git a/.opencode/skills/ag-ui/modules/serialization.md b/.opencode/skills/ag-ui/modules/serialization.md
deleted file mode 100644
index 28d16a0..0000000
--- a/.opencode/skills/ag-ui/modules/serialization.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# Serialization
-
-**作用**: 介绍 AG-UI 事件流的序列化,用于历史恢复、分支和时间旅行。
-
-**源文件**: `llms-full.txt`
-**行号范围**: 2640-2827
-
-**内容索引**:
-- Core Concepts:
- - Stream serialization - 事件流转为 JSON (行 2660-2662)
- - Event compaction - 压缩事件流 (行 2662-2663)
- - Run lineage - parentRunId 实现 git 类日志 (行 2664-2665)
-- Updated Event Fields - RunStarted 新增 parentRunId, input (行 2667-2685)
-- Event Compaction - compactEvents 函数, 压缩规则 (行 2686-2704)
-- Branching and Time Travel - parentRunId 创建分支, git 类日志 (行 2705-2729)
-- Examples:
- - Basic Serialization (行 2732-2744)
- - Event Compaction - 压缩前后示例 (行 2746-2774)
- - Branching With parentRunId (行 2776-2795)
- - Normalized Input (行 2797-2814)
-- Implementation Notes (行 2816-2822)
diff --git a/.opencode/skills/ag-ui/modules/state.md b/.opencode/skills/ag-ui/modules/state.md
deleted file mode 100644
index e7e4b9f..0000000
--- a/.opencode/skills/ag-ui/modules/state.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# State Management
-
-**作用**: 介绍 AG-UI 中 Agent 与前端之间的状态同步机制。
-
-**源文件**: `llms-full.txt`
-**行号范围**: 2829-3080
-
-**内容索引**:
-- Shared State Architecture - 共享状态架构, 双向通信 (行 2842-2857)
-- State Synchronization Methods:
- - State Snapshots - STATE_SNAPSHOT 事件 (行 2862-2882)
- - State Deltas - STATE_DELTA 事件, JSON Patch (行 2884-2902)
-- JSON Patch Format:
- - RFC 6902 操作: add, replace, remove, move, copy, test (行 2903-2944)
-- State Processing in AG-ui - fast-json-patch 使用示例 (行 2946-2977)
-- Human-in-the-Loop Collaboration - 人机协作示例 (行 2978-3005)
-- CopilotKit Implementation - useCoAgent, copilotkit_emit_state (行 3007-3050)
-- Best Practices (行 3052-3068)
diff --git a/.opencode/skills/ag-ui/modules/tools.md b/.opencode/skills/ag-ui/modules/tools.md
deleted file mode 100644
index 3b8f7d9..0000000
--- a/.opencode/skills/ag-ui/modules/tools.md
+++ /dev/null
@@ -1,24 +0,0 @@
-# Tools
-
-**作用**: 介绍 AG-UI 中工具的定义、使用和人在环工作流。
-
-**源文件**: `llms-full.txt`
-**行号范围**: 3082-3441
-
-**内容索引**:
-- What Are Tools? - 工具的作用 (行 3095-3105)
-- Tool Structure - Tool 接口定义 (行 3107-3130)
-- Frontend-Defined Tools - 工具由前端定义并传递给 Agent (行 3132-3175)
-- Tool Call Lifecycle:
- - ToolCallStart (行 3179-3191)
- - ToolCallArgs - 流式参数 (行 3193-3217)
- - ToolCallEnd (行 3219-3229)
-- Tool Results - ToolMessage 结构 (行 3231-3246)
-- Human-in-the-Loop Workflows - 人机协作工作流 (行 3248-3270)
-- CopilotKit Integration - useCopilotAction hook (行 3272-3304)
-- Tool Examples:
- - User Confirmation (行 3310-3332)
- - Data Retrieval (行 3334-3358)
- - User Interface Control (行 3360-3381)
- - Content Generation (行 3383-3412)
-- Best Practices (行 3414-3428)
diff --git a/.opencode/skills/ag-ui/scripts/README.md b/.opencode/skills/ag-ui/scripts/README.md
deleted file mode 100644
index 4557c29..0000000
--- a/.opencode/skills/ag-ui/scripts/README.md
+++ /dev/null
@@ -1,163 +0,0 @@
-# AG-UI 示例脚本
-
-本目录包含 AG-UI 协议的实现示例,帮助开发者快速上手。
-
-## 前置要求
-
-```bash
-# 安装依赖
-npm install @ag-ui/client rxjs
-
-# 或
-pnpm add @ag-ui/client rxjs
-```
-
-## 示例列表
-
-### 1. minimal_agent.ts - 最小 Agent 实现
-
-展示如何创建一个最基本的 AG-UI Agent,实现事件流。
-
-**核心概念**:
-- 继承 `AbstractAgent` 类
-- 实现 `run()` 方法返回 Observable 事件流
-- 发送生命周期事件 (RUN_STARTED/RUN_FINISHED)
-- 发送文本消息事件 (TEXT_MESSAGE_START/CONTENT/END)
-
-**运行**:
-```bash
-# 使用 ts-node
-npx ts-node scripts/minimal_agent.ts
-
-# 或编译后运行
-npx tsc scripts/minimal_agent.ts --esModuleInterop
-node scripts/minimal_agent.js
-```
-
-**参考文档**: [modules/agents.md](../modules/agents.md) 行 132-197
-
----
-
-### 2. tool_call_example.ts - 工具调用流程
-
-展示 Agent 如何调用工具并流式传输参数和结果。
-
-**核心概念**:
-- 定义工具 (Tool)
-- 工具调用事件流: ToolCallStart → ToolCallArgs → ToolCallEnd → ToolCallResult
-- 流式传输工具参数(分块发送)
-- 基于工具结果生成响应
-
-**事件流**:
-```
-ToolCallStart (工具名称)
- ↓
-ToolCallArgs (参数片段 1)
-ToolCallArgs (参数片段 2)
-ToolCallArgs (参数片段 3)
- ↓
-ToolCallEnd (参数传输完成)
- ↓
-ToolCallResult (工具执行结果)
-```
-
-**运行**:
-```bash
-npx ts-node scripts/tool_call_example.ts
-```
-
-**参考文档**: [modules/events.md](../modules/events.md) 行 938-1066
-
----
-
-### 3. state_sync_example.ts - 状态同步
-
-展示 Agent 与前端的 Snapshot-Delta 状态同步模式。
-
-**核心概念**:
-- StateSnapshot - 完整状态快照
-- StateDelta - 增量更新 (JSON Patch RFC 6902)
-- MessagesSnapshot - 消息历史快照
-- 前端状态管理器实现
-
-**状态同步模式**:
-```
-初始同步:
- StateSnapshot (完整状态)
- MessagesSnapshot (消息历史)
- ↓
-增量更新:
- StateDelta (JSON Patch 操作)
- StateDelta (另一个更新)
- ↓
-周期性刷新:
- StateSnapshot (确保一致性)
-```
-
-**JSON Patch 操作类型**:
-- `replace` - 替换值
-- `add` - 添加字段
-- `remove` - 删除字段
-
-**运行**:
-```bash
-npx ts-node scripts/state_sync_example.ts
-```
-
-**参考文档**: [modules/events.md](../modules/events.md) 行 1067-1155
-
----
-
-## 常见问题
-
-### Q: 这些示例可以直接用于生产环境吗?
-
-A: 这些示例仅用于教学目的。生产环境应考虑:
-- 错误处理和重试机制
-- 认证和授权
-- 日志和监控
-- 性能优化(如事件节流)
-
-### Q: 如何处理工具调用的并发?
-
-A: 每个工具调用有唯一的 `toolCallId`,可以并发执行多个工具:
-```typescript
-// 工具调用 1
-ToolCallStart(toolCallId: "tool_1")
-ToolCallArgs(toolCallId: "tool_1", delta: "...")
-ToolCallEnd(toolCallId: "tool_1")
-
-// 工具调用 2(并发)
-ToolCallStart(toolCallId: "tool_2")
-ToolCallArgs(toolCallId: "tool_2", delta: "...")
-ToolCallEnd(toolCallId: "tool_2")
-```
-
-### Q: StateDelta 的 JSON Patch 格式如何工作?
-
-A: JSON Patch (RFC 6902) 是标准的增量更新格式:
-```json
-[
- { "op": "replace", "path": "/session/currentPage", "value": 2 },
- { "op": "add", "path": "/formData", "value": {...} },
- { "op": "remove", "path": "/tempField" }
-]
-```
-
-推荐使用 [fast-json-patch](https://github.com/Starcounter-Jack/Fast-JSON-Patch) 库处理。
-
----
-
-## 进阶示例
-
-需要更复杂的示例?查看官方仓库:
-- [AG-UI GitHub](https://github.com/ag-ui/ag-ui)
-- [CopilotKit Examples](https://github.com/CopilotKit/CopilotKit/tree/main/examples)
-
----
-
-## 相关资源
-
-- [AG-UI 协议文档](../llms-full.txt) - 完整协议规范
-- [模块索引](../SKILL.md#模块索引) - 按功能查找文档
-- [常见事件速查](../SKILL.md#常见事件速查) - 高频事件流程
diff --git a/.opencode/skills/ag-ui/scripts/minimal_agent.ts b/.opencode/skills/ag-ui/scripts/minimal_agent.ts
deleted file mode 100644
index ff2f29d..0000000
--- a/.opencode/skills/ag-ui/scripts/minimal_agent.ts
+++ /dev/null
@@ -1,99 +0,0 @@
-/**
- * 最小 AG-UI Agent 实现示例
- *
- * 展示如何创建一个自定义 Agent,实现基本的事件流
- *
- * 参考文档: modules/agents.md (行 132-197)
- */
-
-import {
- AbstractAgent,
- RunAgent,
- RunAgentInput,
- EventType,
- BaseEvent,
-} from "@ag-ui/client"
-import { Observable } from "rxjs"
-
-class MinimalAgent extends AbstractAgent {
- /**
- * 实现 run 方法,返回事件流
- */
- run(input: RunAgentInput): RunAgent {
- const { threadId, runId } = input
-
- return () =>
- new Observable((observer) => {
- // 1. 发送 RUN_STARTED 事件
- observer.next({
- type: EventType.RUN_STARTED,
- threadId,
- runId,
- })
-
- // 2. 发送文本消息
- const messageId = Date.now().toString()
-
- // 消息开始
- observer.next({
- type: EventType.TEXT_MESSAGE_START,
- messageId,
- role: "assistant",
- })
-
- // 消息内容(流式)
- observer.next({
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId,
- delta: "Hello! ",
- })
-
- observer.next({
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId,
- delta: "I'm a minimal AG-UI agent.",
- })
-
- // 消息结束
- observer.next({
- type: EventType.TEXT_MESSAGE_END,
- messageId,
- })
-
- // 3. 发送 RUN_FINISHED 事件
- observer.next({
- type: EventType.RUN_FINISHED,
- threadId,
- runId,
- })
-
- // 完成流
- observer.complete()
- })
- }
-}
-
-// 使用示例
-const agent = new MinimalAgent({
- agentId: "minimal-agent",
- description: "A minimal AG-UI agent example",
-})
-
-// 运行 Agent 并订阅事件流
-agent
- .runAgent({
- runId: "run_123",
- threadId: "thread_456",
- messages: [],
- tools: [],
- context: [],
- })
- .subscribe({
- next: (event) => {
- console.log(`[${event.type}]`, event)
- },
- error: (error) => console.error("Error:", error),
- complete: () => console.log("Agent run completed"),
- })
-
-export { MinimalAgent }
diff --git a/.opencode/skills/ag-ui/scripts/state_sync_example.ts b/.opencode/skills/ag-ui/scripts/state_sync_example.ts
deleted file mode 100644
index a377fc6..0000000
--- a/.opencode/skills/ag-ui/scripts/state_sync_example.ts
+++ /dev/null
@@ -1,255 +0,0 @@
-/**
- * AG-UI 状态同步示例
- *
- * 展示 Agent 与前端的 Snapshot-Delta 状态同步模式
- *
- * 参考文档: modules/events.md (行 1067-1155)
- *
- * 状态管理模式:
- * 1. StateSnapshot - 完整状态快照(初始同步/周期性刷新)
- * 2. StateDelta - 增量更新(JSON Patch RFC 6902)
- * 3. MessagesSnapshot - 消息历史快照
- */
-
-import {
- AbstractAgent,
- RunAgent,
- RunAgentInput,
- EventType,
- BaseEvent,
-} from "@ag-ui/client"
-import { Observable } from "rxjs"
-
-/**
- * Agent 状态定义示例
- */
-interface AgentState {
- user: {
- name: string
- preferences: {
- theme: "light" | "dark"
- language: string
- }
- }
- session: {
- currentPage: number
- itemsPerPage: number
- totalItems: number
- }
- formData?: {
- [key: string]: any
- }
-}
-
-class StateSyncAgent extends AbstractAgent {
- private state: AgentState = {
- user: {
- name: "Alice",
- preferences: {
- theme: "light",
- language: "en",
- },
- },
- session: {
- currentPage: 1,
- itemsPerPage: 10,
- totalItems: 100,
- },
- }
-
- run(input: RunAgentInput): RunAgent {
- const { threadId, runId } = input
-
- return () =>
- new Observable((observer) => {
- observer.next({
- type: EventType.RUN_STARTED,
- threadId,
- runId,
- })
-
- // 1. 发送初始状态快照
- observer.next({
- type: EventType.STATE_SNAPSHOT,
- snapshot: this.state,
- })
-
- // 2. 发送消息历史快照
- observer.next({
- type: EventType.MESSAGES_SNAPSHOT,
- messages: [
- {
- id: "msg_1",
- role: "user",
- content: "Show me page 2",
- },
- {
- id: "msg_2",
- role: "assistant",
- content: "Loading page 2...",
- },
- ],
- })
-
- // 3. 模拟状态变化 - 分页更新
- setTimeout(() => {
- // 发送 Delta 更新(JSON Patch 格式)
- observer.next({
- type: EventType.STATE_DELTA,
- delta: [
- { op: "replace", path: "/session/currentPage", value: 2 },
- ],
- })
- }, 500)
-
- // 4. 模拟用户偏好更新
- setTimeout(() => {
- observer.next({
- type: EventType.STATE_DELTA,
- delta: [
- { op: "replace", path: "/user/preferences/theme", value: "dark" },
- ],
- })
- }, 1000)
-
- // 5. 添加新字段(表单数据)
- setTimeout(() => {
- observer.next({
- type: EventType.STATE_DELTA,
- delta: [
- {
- op: "add",
- path: "/formData",
- value: {
- searchQuery: "AG-UI tutorial",
- filters: ["beginner", "typescript"],
- },
- },
- ],
- })
- }, 1500)
-
- // 6. 周期性完整快照(确保状态一致性)
- setTimeout(() => {
- const updatedState: AgentState = {
- ...this.state,
- session: {
- ...this.state.session,
- currentPage: 2,
- },
- user: {
- ...this.state.user,
- preferences: {
- ...this.state.user.preferences,
- theme: "dark",
- },
- },
- formData: {
- searchQuery: "AG-UI tutorial",
- filters: ["beginner", "typescript"],
- },
- }
-
- observer.next({
- type: EventType.STATE_SNAPSHOT,
- snapshot: updatedState,
- })
-
- observer.next({
- type: EventType.RUN_FINISHED,
- threadId,
- runId,
- })
-
- observer.complete()
- }, 2000)
- })
- }
-}
-
-/**
- * 前端状态管理示例(接收端)
- */
-class StateManager {
- private state: AgentState | null = null
-
- handleEvent(event: BaseEvent) {
- switch (event.type) {
- case EventType.STATE_SNAPSHOT:
- // 完整替换状态
- this.state = (event as any).snapshot as AgentState
- console.log("[State] Snapshot received:", this.state)
- break
-
- case EventType.STATE_DELTA:
- // 应用 JSON Patch 增量更新
- if (this.state) {
- const patches = (event as any).delta
- this.state = this.applyPatches(this.state, patches)
- console.log("[State] Delta applied:", patches)
- console.log("[State] Current state:", this.state)
- }
- break
-
- case EventType.MESSAGES_SNAPSHOT:
- console.log("[Messages] Snapshot:", (event as any).messages)
- break
- }
- }
-
- /**
- * 应用 JSON Patch 操作(简化实现)
- * 生产环境应使用 json-patch 库
- */
- private applyPatches(state: AgentState, patches: any[]): AgentState {
- const newState = JSON.parse(JSON.stringify(state))
-
- for (const patch of patches) {
- const { op, path, value } = patch
- const pathParts = path.split("/").filter(Boolean)
- let target: any = newState
-
- // 导航到目标对象的父级
- for (let i = 0; i < pathParts.length - 1; i++) {
- target = target[pathParts[i]]
- }
-
- const lastKey = pathParts[pathParts.length - 1]
-
- switch (op) {
- case "replace":
- target[lastKey] = value
- break
- case "add":
- target[lastKey] = value
- break
- case "remove":
- delete target[lastKey]
- break
- }
- }
-
- return newState
- }
-}
-
-// 使用示例
-const agent = new StateSyncAgent()
-const stateManager = new StateManager()
-
-agent
- .runAgent({
- runId: "run_state_sync",
- threadId: "thread_123",
- messages: [],
- tools: [],
- context: [],
- })
- .subscribe({
- next: (event) => {
- stateManager.handleEvent(event)
- },
- complete: () => console.log("\n[Complete] State sync demo finished"),
- })
-
-export { StateSyncAgent, StateManager, AgentState }
diff --git a/.opencode/skills/ag-ui/scripts/tool_call_example.ts b/.opencode/skills/ag-ui/scripts/tool_call_example.ts
deleted file mode 100644
index 8194200..0000000
--- a/.opencode/skills/ag-ui/scripts/tool_call_example.ts
+++ /dev/null
@@ -1,201 +0,0 @@
-/**
- * AG-UI 工具调用示例
- *
- * 展示 Agent 如何调用工具并流式传输参数和结果
- *
- * 参考文档: modules/events.md (行 938-1066)
- *
- * 事件流:
- * 1. ToolCallStart - 工具调用开始
- * 2. ToolCallArgs (多次) - 流式传输参数
- * 3. ToolCallEnd - 参数传输完成
- * 4. ToolCallResult - 工具执行结果
- */
-
-import {
- AbstractAgent,
- RunAgent,
- RunAgentInput,
- EventType,
- BaseEvent,
-} from "@ag-ui/client"
-import { Observable } from "rxjs"
-
-/**
- * 工具定义示例
- */
-interface Tool {
- name: string
- description: string
- parameters: Record
-}
-
-const weatherTool: Tool = {
- name: "get_weather",
- description: "Get current weather for a location",
- parameters: {
- type: "object",
- properties: {
- location: {
- type: "string",
- description: "City name",
- },
- unit: {
- type: "string",
- enum: ["celsius", "fahrenheit"],
- },
- },
- required: ["location"],
- },
-}
-
-class ToolCallingAgent extends AbstractAgent {
- run(input: RunAgentInput): RunAgent {
- const { threadId, runId } = input
-
- return () =>
- new Observable((observer) => {
- observer.next({
- type: EventType.RUN_STARTED,
- threadId,
- runId,
- })
-
- // 模拟 Agent 分析用户请求后决定调用工具
- const toolCallId = `tool_${Date.now()}`
- const messageId = `msg_${Date.now()}`
-
- // 1. 发送文本消息说明
- observer.next({
- type: EventType.TEXT_MESSAGE_START,
- messageId,
- role: "assistant",
- })
-
- observer.next({
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId,
- delta: "Let me check the weather for you.",
- })
-
- observer.next({
- type: EventType.TEXT_MESSAGE_END,
- messageId,
- })
-
- // 2. 开始工具调用
- observer.next({
- type: EventType.TOOL_CALL_START,
- toolCallId,
- toolCallName: "get_weather",
- parentMessageId: messageId,
- })
-
- // 3. 流式传输参数(分块发送)
- observer.next({
- type: EventType.TOOL_CALL_ARGS,
- toolCallId,
- delta: '{"loc', // 参数片段 1
- })
-
- observer.next({
- type: EventType.TOOL_CALL_ARGS,
- toolCallId,
- delta: 'ation":', // 参数片段 2
- })
-
- observer.next({
- type: EventType.TOOL_CALL_ARGS,
- toolCallId,
- delta: ' "San Francisco"}', // 参数片段 3
- })
-
- // 4. 参数传输完成
- observer.next({
- type: EventType.TOOL_CALL_END,
- toolCallId,
- })
-
- // 5. 工具执行结果(模拟)
- setTimeout(() => {
- observer.next({
- type: EventType.TOOL_CALL_RESULT,
- toolCallId,
- content: JSON.stringify({
- location: "San Francisco",
- temperature: "18°C",
- condition: "Partly cloudy",
- }),
- })
-
- // 6. 基于工具结果的响应
- const responseMsgId = `msg_${Date.now()}_response`
- observer.next({
- type: EventType.TEXT_MESSAGE_START,
- messageId: responseMsgId,
- role: "assistant",
- })
-
- observer.next({
- type: EventType.TEXT_MESSAGE_CONTENT,
- messageId: responseMsgId,
- delta: "The current weather in San Francisco is 18°C and partly cloudy.",
- })
-
- observer.next({
- type: EventType.TEXT_MESSAGE_END,
- messageId: responseMsgId,
- })
-
- observer.next({
- type: EventType.RUN_FINISHED,
- threadId,
- runId,
- })
-
- observer.complete()
- }, 1000)
- })
- }
-}
-
-// 使用示例
-const agent = new ToolCallingAgent()
-
-agent
- .runAgent({
- runId: "run_tool_example",
- threadId: "thread_123",
- messages: [
- {
- id: "user_1",
- role: "user",
- content: "What's the weather in San Francisco?",
- },
- ],
- tools: [weatherTool as any],
- context: [],
- })
- .subscribe({
- next: (event) => {
- switch (event.type) {
- case EventType.TOOL_CALL_START:
- console.log(`[Tool Call] Starting: ${(event as any).toolCallName}`)
- break
- case EventType.TOOL_CALL_ARGS:
- process.stdout.write((event as any).delta)
- break
- case EventType.TOOL_CALL_END:
- console.log("\n[Tool Call] Arguments complete")
- break
- case EventType.TOOL_CALL_RESULT:
- console.log("[Tool Result]", (event as any).content)
- break
- default:
- console.log(`[${event.type}]`)
- }
- },
- complete: () => console.log("Tool call flow completed"),
- })
-
-export { ToolCallingAgent, weatherTool }
diff --git a/.opencode/skills/crewai/SKILL.md b/.opencode/skills/crewai/SKILL.md
deleted file mode 100644
index ee0be19..0000000
--- a/.opencode/skills/crewai/SKILL.md
+++ /dev/null
@@ -1,93 +0,0 @@
----
-name: crewai
-description: CrewAI framework for multi-agent orchestration. Use when building multi-agent systems, agent collaboration, task automation, crew orchestration, agent teams, delegation, or any CrewAI-related development.
----
-
-# CrewAI Skills
-
-CrewAI 框架开发权威指南。**必须使用**场景:构建多 Agent 协作系统、编排 Agent 团队、任务自动化、工具集成、知识管理、LLM 应用开发。提供完整模块索引与源文件行号映射。
-
-## 何时使用
-
-**必须使用**的场景:
-- 创建和管理 AI Agent 团队
-- 实现 Agent 间的协作和任务委托
-- 编排多步骤工作流和任务流程
-- 集成 RAG、向量存储和知识管理
-- 配置和管理 LLM 提供商
-- 构建自动化任务和工具
-- 实现 Agent 记忆和推理能力
-- 训练和微调 Agent 性能
-
-**查询模式**:
-- "如何创建 crewai agent"
-- "agent collaboration 委托任务"
-- "crew kickoff 执行流程"
-- "crewai tools 集成"
-- "knowledge RAG 配置"
-- "llm 多模型切换"
-
-## 模块索引
-
-按功能模块查看源文件对应章节:
-
-| 模块 | 作用 | 源文件行号 |
-|------|------|------------|
-| [agents](modules/agents.md) | Agent 概念、属性、创建、高级特性 | 1-1276 |
-| [collaboration](modules/collaboration.md) | Agent 协作、委托、层级管理 | 1277-1655 |
-| [crews](modules/crews.md) | Crew 概念、创建、执行流程 | 1656-2658 |
-| [flows](modules/flows.md) | Flow 流程控制、状态管理 | 2659-3712 |
-| [knowledge](modules/knowledge.md) | 知识管理、向量存储、RAG | 3713-4838 |
-| [llms](modules/llms.md) | LLM 配置、多模型支持 | 4839-6469 |
-| [memory](modules/memory.md) | Memory 记忆系统 | 6470-7341 |
-| [planning](modules/planning.md) | Planning 任务规划 | 7342-7729 |
-| [reasoning](modules/reasoning.md) | Reasoning 推理和反思 | 7730-7877 |
-| [tasks](modules/tasks.md) | Task 概念、属性、执行流程 | 7878-9005 |
-| [tools](modules/tools.md) | Tool 概念、创建、内置工具 | 9006-9292 |
-| [training](modules/training.md) | Training 训练和微调 | 9293-12843 |
-| [installation](modules/installation.md) | 安装、配置、项目创建 | 12844-14875 |
-| [quickstart-tools](modules/quickstart-tools.md) | **快速开始 + 50+ 工具参考** | 14876-53221 |
-
-## 源文件
-
-- `llms-full.md` - CrewAI 完整文档(唯一信源,53221 行)
-
-## 核心概念速查
-
-| 概念 | 说明 | 详见 |
-|------|------|------|
-| **Agent** | 自主单元,执行任务、使用工具、协作 | [agents](modules/agents.md) |
-| **Task** | Agent 完成的具体任务 | [tasks](modules/tasks.md) |
-| **Crew** | Agent 团队,协作完成任务 | [crews](modules/crews.md) |
-| **Tool** | Agent 可用的能力或功能 | [tools](modules/tools.md) |
-| **Flow** | 工作流编排和状态管理 | [flows](modules/flows.md) |
-| **Knowledge** | 知识存储和 RAG 检索 | [knowledge](modules/knowledge.md) |
-
-## 快速路径
-
-**新手入门**:
-1. [installation](modules/installation.md) - 安装和项目创建
-2. [agents](modules/agents.md) - 理解 Agent 核心概念
-3. [tasks](modules/tasks.md) - 创建第一个 Task
-4. [crews](modules/crews.md) - 组建 Crew 并执行
-5. [quickstart-tools](modules/quickstart-tools.md) - 完整快速开始示例
-
-**实现功能**:
-- Agent 协作 → [collaboration](modules/collaboration.md) (委托、层级)
-- 任务编排 → [crews](modules/crews.md) + [flows](modules/flows.md)
-- 知识管理 → [knowledge](modules/knowledge.md) (RAG、向量存储)
-- 工具集成 → [tools](modules/tools.md) + [quickstart-tools](modules/quickstart-tools.md)
-- LLM 配置 → [llms](modules/llms.md)
-
-**高级特性**:
-- Agent 记忆 → [memory](modules/memory.md)
-- 任务规划 → [planning](modules/planning.md)
-- 推理能力 → [reasoning](modules/reasoning.md)
-- 性能优化 → [training](modules/training.md)
-
-## 建议使用方式
-
-1. 先阅读 [installation](modules/installation.md) 了解安装和项目结构
-2. 根据需求查看核心概念模块(agents/tasks/crews/tools)
-3. 高级功能参考对应模块(collaboration/knowledge/flows)
-4. 工具集成参考 [quickstart-tools](modules/quickstart-tools.md)
diff --git a/.opencode/skills/crewai/llms-full.md b/.opencode/skills/crewai/llms-full.md
deleted file mode 100644
index 8b44a33..0000000
--- a/.opencode/skills/crewai/llms-full.md
+++ /dev/null
@@ -1,53221 +0,0 @@
-# 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
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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
-
-
-## 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.
-
-
- 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'})
- ```
-
-
-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
- )
-```
-
-
- The names you use in your YAML files (`agents.yaml`) should match the method
- names in your Python code.
-
-
-### 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)
-
-
- 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.
-
-
-#### 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
-
-
- 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.
-
-
-
- When using custom templates, you can use variables like `{role}`, `{goal}`,
- and `{backstory}` in your templates. These will be automatically populated
- during execution.
-
-
-## 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
-)
-```
-
-
- When `memory` is enabled, the agent will maintain context across multiple
- interactions, improving its ability to handle complex, multi-step tasks.
-
-
-## 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
-)
-```
-
-
- 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!
-
-
-## 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())
-```
-
-
- 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.).
-
-
-## 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.
-
-
- 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.
-
-
-## 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
-```
-
-
- 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.
-
-
-
- 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.
-
-
-### 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
-```
-
-
- Ensure you execute these commands from your CrewAI project's root directory.
-
-
-
- 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
- )
- ```
-
-
-### 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
-```
-
-
- You must be authenticated to CrewAI AMP to use these organization management
- commands.
-
-
-* **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.
-
-
-
-### 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
-```
-
-* `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
-```
-
-
- After resetting configuration, re-run `crewai login` to authenticate again.
-
-
-### 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
-
-
- **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.
-
-
-
- For more information about tracing, see the [Tracing
- documentation](/observability/tracing).
-
-
-
- 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.
-
-
-
- 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.
-
-
-
-# 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`. | |
-
-
- **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.
-
-
-## 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"})
-```
-
-
- Tasks will be executed in the order they are defined.
-
-
-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 |
-
-
- For high-concurrency workloads, `akickoff()` and `akickoff_for_each()` are recommended as they use native async for task execution, memory operations, and knowledge retrieval.
-
-
-```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 `, 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
-```
-
-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.
-
-
- 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.
-
-
-
- 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
-
-
-## 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.
-
-
- File support requires the optional `crewai-files` package. Install it with:
-
- ```bash theme={null}
- uv add 'crewai[file-processing]'
- ```
-
-
-
- The file processing API is currently in early access.
-
-
-## 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) | ✓ | | ✓ | | |
-
-
- Google Gemini models support all file types including video (up to 1 hour, 2GB). Use Gemini when you need to process video content.
-
-
-
- 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.
-
-
-## 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** | ✓ | | ✓ |
-
-
- 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.
-
-
-## 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}")
-```
-
-
-
-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:
-
-
- ```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
- ```
-
-
-
-
-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:
-
-
- ```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'
- ```
-
-
-
-
-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()
-```
-
-
-
-**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()
-```
-
-
-
-**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.
-
-
- ```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
- ```
-
-
-
-
-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.
-
-
- ```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.'}
- ```
-
-
-
-
-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.
-
-
- ```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
- ```
-
-
-
-
-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)
-
-
- The `@human_feedback` decorator requires **CrewAI version 1.8.0 or higher**.
-
-
-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())
-```
-
-
-
-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.
-
-
-
-### 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!
-
-
-
-## 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.
-
-
- 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
-
-
-## Quickstart Examples
-
-
- 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.
-
-
-### 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
-
-
- You need to install `docling` for the following example to work: `uv add docling`
-
-
-```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:
-
-
-
- * Raw strings
- * Text files (.txt)
- * PDF documents
-
-
-
- * CSV files
- * Excel spreadsheets
- * JSON documents
-
-
-
-### 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"]
-)
-```
-
-
- 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.
-
-
-## Agent vs Crew Knowledge: Complete Guide
-
-
- **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.
-
-
-### 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
-```
-
-
- 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.
-
-
-## 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
-)
-```
-
-
- `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.
-
-
-## Supported Knowledge Parameters
-
-
- List of knowledge sources that provide content to be stored and queried. Can include PDF, CSV, Excel, JSON, text files, or string content.
-
-
-
- Name of the collection where the knowledge will be stored. Used to identify different sets of knowledge. Defaults to "knowledge" if not provided.
-
-
-
- Custom storage configuration for managing how the knowledge is stored and retrieved. If not provided, a default storage will be created.
-
-
-## Knowledge Storage Transparency
-
-
- **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.
-
-
-### 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
-
-
- **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.
-
-
-#### 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
-
-
-
- By focusing on key concepts and removing irrelevant content, query rewriting helps retrieve more relevant information.
-
-
-
- The rewritten queries are designed to be more specific and context-aware for vector database retrieval.
-
-
-
-#### 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.
-
-
- 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.
-
-
-### 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
-
-
- ```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/)
- ```
-
-
-## 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
-
-
-
- * Keep chunk sizes appropriate for your content type
- * Consider content overlap for context preservation
- * Organize related information into separate knowledge sources
-
-
-
- * Adjust chunk sizes based on content complexity
- * Configure appropriate embedding models
- * Consider using local embedding providers for faster processing
-
-
-
- * 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)
-
-
-
- * 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
-
-
-
- * 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
-
-
-
-
-# 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:
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
-## 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.
-
-
-
- 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.
- ```
-
-
- Never commit API keys to version control. Use environment files (.env) or your system's secret management.
-
-
-
-
- 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)
- ```
-
-
- 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
-
-
-
-
- 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
- )
- ```
-
-
- 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
-
-
-
-
-
- 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]'
- ```
-
-
-## 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.
-
-
-
- CrewAI provides native integration with OpenAI through the OpenAI Python SDK.
-
- ```toml Code theme={null}
- # Required
- OPENAI_API_KEY=sk-...
-
- # Optional
- OPENAI_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
-
-
- 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).
-
-
- **Note:** To use OpenAI, install the required dependencies:
-
- ```bash theme={null}
- uv add "crewai[openai]"
- ```
-
-
-
- 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]'
- ```
-
-
-
- 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]"
- ```
-
-
-
- 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=
- GEMINI_API_KEY=
-
- # For Vertex AI Express mode (API key authentication)
- GOOGLE_GENAI_USE_VERTEXAI=true
- GOOGLE_API_KEY=
-
- # For Vertex AI with service account
- GOOGLE_CLOUD_PROJECT=
- GOOGLE_CLOUD_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=
- ```
-
- 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
- )
- ```
-
-
- 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).
-
-
- **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).
-
-
-
- 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]'
- ```
-
-
-
- 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=
- AZURE_ENDPOINT=
-
- # Optional
- AZURE_API_VERSION= # Defaults to 2024-06-01
- ```
-
- **Endpoint URL Formats:**
-
- For Azure OpenAI deployments:
-
- ```
- https://.openai.azure.com/openai/deployments/
- ```
-
- For Azure AI Inference endpoints:
-
- ```
- https://.inference.azure.com
- ```
-
- **Basic Usage:**
-
- ```python Code theme={null}
- llm = LLM(
- model="azure/gpt-4",
- api_key="", # Or set AZURE_API_KEY
- endpoint="",
- 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]"
- ```
-
-
-
- CrewAI provides native integration with AWS Bedrock through the boto3 SDK using the Converse API.
-
- ```toml Code theme={null}
- # Required
- AWS_ACCESS_KEY_ID=
- AWS_SECRET_ACCESS_KEY=
-
- # Optional
- AWS_SESSION_TOKEN= # For temporary credentials
- AWS_DEFAULT_REGION= # Defaults to us-east-1
- AWS_REGION_NAME= # 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]"
- ```
-
-
-
- ```toml Code theme={null}
- AWS_ACCESS_KEY_ID=
- AWS_SECRET_ACCESS_KEY=
- AWS_DEFAULT_REGION=
- ```
-
- Example usage in your CrewAI project:
-
- ```python Code theme={null}
- llm = LLM(
- model="sagemaker/"
- )
- ```
-
- **Note:** This provider uses LiteLLM. Add it as a dependency to your project:
-
- ```bash theme={null}
- uv add 'crewai[litellm]'
- ```
-
-
-
- Set the following environment variables in your `.env` file:
-
- ```toml Code theme={null}
- MISTRAL_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]'
- ```
-
-
-
- Set the following environment variables in your `.env` file:
-
- ```toml Code theme={null}
- NVIDIA_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]'
- ```
-
-
-
- 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="", # 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]'
- ```
-
-
-
- Set the following environment variables in your `.env` file:
-
- ```toml Code theme={null}
- GROQ_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]'
- ```
-
-
-
- Set the following environment variables in your `.env` file:
-
- ```toml Code theme={null}
- # Required
- WATSONX_URL=
- WATSONX_APIKEY=
- WATSONX_PROJECT_ID=
-
- # Optional
- WATSONX_TOKEN=
- WATSONX_DEPLOYMENT_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]'
- ```
-
-
-
- 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]'
- ```
-
-
-
- Set the following environment variables in your `.env` file:
-
- ```toml Code theme={null}
- FIREWORKS_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]'
- ```
-
-
-
- Set the following environment variables in your `.env` file:
-
- ```toml Code theme={null}
- PERPLEXITY_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]'
- ```
-
-
-
- Set the following environment variables in your `.env` file:
-
- ```toml Code theme={null}
- HF_TOKEN=
- ```
-
- 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]'
- ```
-
-
-
- Set the following environment variables in your `.env` file:
-
- ```toml Code theme={null}
- SAMBANOVA_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]'
- ```
-
-
-
- Set the following environment variables in your `.env` file:
-
- ```toml Code theme={null}
- # Required
- CEREBRAS_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
- )
- ```
-
-
- Cerebras features:
-
- * Fast inference speeds
- * Competitive pricing
- * Good balance of speed and quality
- * Support for long context windows
-
-
- **Note:** This provider uses LiteLLM. Add it as a dependency to your project:
-
- ```bash theme={null}
- uv add 'crewai[litellm]'
- ```
-
-
-
- Set the following environment variables in your `.env` file:
-
- ```toml Code theme={null}
- OPENROUTER_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
- )
- ```
-
-
- Open Router models:
-
- * openrouter/deepseek/deepseek-r1
- * openrouter/deepseek/deepseek-chat
-
-
- **Note:** This provider uses LiteLLM. Add it as a dependency to your project:
-
- ```bash theme={null}
- uv add 'crewai[litellm]'
- ```
-
-
-
- Set the following environment variables in your `.env` file:
-
- ```toml Code theme={null}
- NEBIUS_API_KEY=
- ```
-
- Example usage in your CrewAI project:
-
- ```python Code theme={null}
- llm = LLM(
- model="nebius/Qwen/Qwen3-30B-A3B"
- )
- ```
-
-
- Nebius AI Studio features:
-
- * Large collection of open source models
- * Higher rate limits
- * Competitive pricing
- * Good balance of speed and quality
-
-
- **Note:** This provider uses LiteLLM. Add it as a dependency to your project:
-
- ```bash theme={null}
- uv add 'crewai[litellm]'
- ```
-
-
-
-## Streaming Responses
-
-CrewAI supports streaming responses from LLMs, allowing your application to receive and process outputs in real-time as they're generated.
-
-
-
- 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.
-
-
-
- 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()
- ```
-
-
- [Click here](/en/concepts/event-listener#event-listeners) for more details
-
-
-
-
- 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": "..."}
- )
- ```
-
-
- 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
-
-
-
-
-## 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.
-
-
-
- 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.
-
-
-
- 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())
- ```
-
-
-
-## 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:
-
-
-
- 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
- )
- ```
-
-
- 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
-
-
-
-
-
-
- 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
- )
- ```
-
-
- * Lower temperature (0.1 to 0.3) for factual responses
- * Higher temperature (0.7 to 0.9) for creative tasks
-
-
-
-
- 1. Monitor token usage
- 2. Implement rate limiting
- 3. Use caching when possible
- 4. Set appropriate max\_tokens limits
-
-
-
-
- Remember to regularly monitor your token usage and adjust your configuration as needed to optimize costs and performance.
-
-
-
-
- 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 stop parameter, you can simply omit it from your LLM call:
-
- ```python theme={null}
- from crewai import LLM
- import os
-
- os.environ["OPENAI_API_KEY"] = ""
-
- o3_llm = LLM(
- model="o3",
- drop_params=True,
- additional_drop_params=["stop"]
- )
- ```
-
-
-
- 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
-
-
- Interceptors operate at the transport layer. This is particularly useful for:
-
- * Message transformation and filtering
- * Debugging API interactions
-
-
-
-
-## Common Issues and Solutions
-
-
-
-
- Most authentication issues can be resolved by checking API key format and environment variable names.
-
-
- ```bash theme={null}
- # OpenAI
- OPENAI_API_KEY=sk-...
-
- # Anthropic
- ANTHROPIC_API_KEY=sk-ant-...
- ```
-
-
-
-
- Always include the provider prefix in model names
-
-
- ```python theme={null}
- # Correct
- llm = LLM(model="openai/gpt-4")
-
- # Incorrect
- llm = LLM(model="gpt-4")
- ```
-
-
-
-
- Use larger context models for extensive tasks
-
-
- ```python theme={null}
- # Large context model
- llm = LLM(model="openai/gpt-4o") # 128K tokens
- ```
-
-
-
-
-# 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
-
-
-
- ```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
- },
- })
- ```
-
-
-
- ```python theme={null}
- memory = Memory(embedder={
- "provider": "ollama",
- "config": {
- "model_name": "mxbai-embed-large",
- "url": "http://localhost:11434/api/embeddings",
- },
- })
- ```
-
-
-
- ```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",
- },
- })
- ```
-
-
-
- ```python theme={null}
- memory = Memory(embedder={
- "provider": "google-generativeai",
- "config": {
- "model_name": "gemini-embedding-001",
- # "api_key": "...", # or set GOOGLE_API_KEY env var
- },
- })
- ```
-
-
-
- ```python theme={null}
- memory = Memory(embedder={
- "provider": "google-vertex",
- "config": {
- "model_name": "gemini-embedding-001",
- "project_id": "your-gcp-project-id",
- "location": "us-central1",
- },
- })
- ```
-
-
-
- ```python theme={null}
- memory = Memory(embedder={
- "provider": "cohere",
- "config": {
- "model_name": "embed-english-v3.0",
- # "api_key": "...", # or set COHERE_API_KEY env var
- },
- })
- ```
-
-
-
- ```python theme={null}
- memory = Memory(embedder={
- "provider": "voyageai",
- "config": {
- "model": "voyage-3",
- # "api_key": "...", # or set VOYAGE_API_KEY env var
- },
- })
- ```
-
-
-
- ```python theme={null}
- memory = Memory(embedder={
- "provider": "amazon-bedrock",
- "config": {
- "model_name": "amazon.titan-embed-text-v1",
- # Uses default AWS credentials (boto3 session)
- },
- })
- ```
-
-
-
- ```python theme={null}
- memory = Memory(embedder={
- "provider": "huggingface",
- "config": {
- "model_name": "sentence-transformers/all-MiniLM-L6-v2",
- },
- })
- ```
-
-
-
- ```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
- },
- })
- ```
-
-
-
- ```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",
- },
- })
- ```
-
-
-
- ```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)
- ```
-
-
-
-### 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:
-
-
- ```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,
- )
- ```
-
-
-From this point on, your crew will have planning enabled, and the tasks will be planned before each iteration.
-
-
- 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.
-
-
-#### 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.
-
-
- ```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 '```'.
- ````
-
-
-
-# Processes
-Source: https://docs.crewai.com/en/concepts/processes
-
-Detailed guide on workflow management through processes in CrewAI, with updated implementation details.
-
-## Overview
-
-
- 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.
-
-
-## 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
-
-
- Enable or disable reasoning
-
-
-
- Maximum number of attempts to refine the plan before proceeding with execution. If None (default), the agent will continue refining until it's ready.
-
-
-## 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.
-
-
- 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.
-
-
-
- The Visual Task Builder enables:
-
- * Drag-and-drop task creation
- * Visual task dependencies and flow
- * Real-time testing and validation
- * Easy sharing and collaboration
-
-
-### 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. |
-
-
- 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.
-
-
-## 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.
-
-
- 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'})
- ```
-
-
-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
- )
-```
-
-
- The names you use in your YAML files (`agents.yaml` and `tasks.yaml`) should
- match the method names in your Python code.
-
-
-### 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"
-)
-```
-
-
- Directly specify an `agent` for assignment or let the `hierarchical` CrewAI's
- process decide based on roles, availability, etc.
-
-
-## 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
-
-
- 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.
-
-
-## 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
-
-
- 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.
-
-
-### 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:
-
-
-
-## 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:
-
-
**Tasks Scores (1-10 Higher is better)**
-
-| 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.
-
-
- 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
-
-
-## 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
-
-
- Developers can craft `custom tools` tailored for their agent's needs or
- utilize pre-built options.
-
-
-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
-
-
- 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.
-
-
-```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 `, 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 -f
-```
-
-
- Replace `` with the desired number of training iterations and `` with the appropriate filename ending with `.pkl`.
-
-
-
- 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.
-
-
-### 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 CLI: crewai train -n -f or Python: crew.train(...)"] --> B["Setup training mode - task.human_input = true - disable delegation - init training_data.pkl + trained file"]
-
- subgraph "Iterations"
- direction LR
- C["Iteration i initial_output"] --> D["User human_feedback"]
- D --> E["improved_output"]
- E --> F["Append to training_data.pkl by agent_id and iteration"]
- end
-
- B --> C
- F --> G{"More iterations?"}
- G -- "Yes" --> C
- G -- "No" --> H["Evaluate per agent aggregate iterations"]
-
- H --> I["Consolidate suggestions[] + quality + final_summary"]
- I --> J["Save by agent role to trained file (default: trained_agents_data.pkl)"]
-
- J --> K["Normal (non-training) runs"]
- K --> L["Auto-load suggestions from trained_agents_data.pkl"]
- L --> M["Append to prompt 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
-
-
- 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.
-
-
-### Limitations of Small Models in Training Evaluation
-
-
-
- Smaller models often struggle with producing valid JSON responses needed for structured training evaluations, leading to parsing errors and incomplete data.
-
-
-
- Models under 7B parameters may provide less nuanced evaluations with limited reasoning depth compared to larger models.
-
-
-
- Complex training evaluation criteria may not be fully followed or considered by smaller models.
-
-
-
- Evaluations across multiple training iterations may lack consistency with smaller models.
-
-
-
-### Recommendations for Training
-
-
-
- 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
- )
- ```
-
-
- More powerful models provide higher quality feedback with better reasoning, leading to more effective training iterations.
-
-
-
-
- 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")
- ```
-
-
- While CrewAI includes optimizations for small models, expect less reliable and less nuanced evaluation results that may require more human intervention during training.
-
-
-
-
-### 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
-
-
- **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.
-
-
-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
-
-
- 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.
-
-
-## 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.
-
-
- 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.
-
-
-
-# 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.
-
-
- 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.
-
-
-## 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:
-
-
-
-
-
-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.
-
-
- 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.
-
-
-## 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
-
-
-
-
-
-## 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
-```
-
-## 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
-
-
- 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.
-
-
-
-# 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.
-
-
-
-
-
-## 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
-
-
- 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.
-
-
-
-# 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.
-
-
- 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.
-
-
-## 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:
-
-
-
-## Text Tutorial
-
-
- **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)
-
-
-
- **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.
-
-
-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**.
-
-
-
- * **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.
-
-
-
- * Run the following command to install `crewai` CLI:
-
- ```shell theme={null}
- uv tool install crewai
- ```
-
-
- If you encounter a `PATH` warning, run this command to update your shell:
-
- ```shell theme={null}
- uv tool update-shell
- ```
-
-
-
- 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++*.
-
-
- * 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
- ```
-
- Installation successful! You're ready to create your first crew! 🎉
-
-
-
-# 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:
-
-
-
- * Run the `crewai` CLI command:
- ```shell theme={null}
- crewai create crew
- ```
-
- * 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
- ```
-
-
-
- * 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`.
-
-
-
- * 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
- ```
- * To run your crew, execute the following command in the root of your project:
- ```bash theme={null}
- crewai run
- ```
-
-
-
-## Enterprise Installation Options
-
-
- 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
-
-
- Learn about CrewAI's enterprise offerings and schedule a demo
-
-
-
-## Next Steps
-
-
-
- Follow our quickstart guide to create your first CrewAI agent and get
- hands-on experience.
-
-
-
- Connect with other developers, get help, and share your CrewAI experiences.
-
-
-
-
-# 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
-
-
- 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.
-
-
-
-
-
-
-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
-
-
- 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.
-
-
-
-
-
-
-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
-
-
-
- Build reliable, stateful workflows that can handle long-running processes and complex logic.
-
-
-
- Deploy teams of agents that can plan, execute, and collaborate to achieve high-level goals.
-
-
-
- Connect your agents to any API, database, or local tool.
-
-
-
- Designed with security and compliance in mind for enterprise deployments.
-
-
-
-## 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?
-
-
-
- Learn how to create structured, event-driven workflows with precise control over execution.
-
-
-
- Step-by-step tutorial to create a collaborative AI team that works together to solve complex problems.
-
-
-
-
-
- Get started with CrewAI in your development environment.
-
-
-
- Follow our quickstart guide to create your first CrewAI agent and get hands-on experience.
-
-
-
- Connect with other developers, get help, and share your CrewAI experiences.
-
-
-
-
-# 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.
-
-
- This is the **recommended approach** for most MCP use cases. For advanced
- scenarios requiring manual connection management, see
- [MCPServerAdapter](/en/mcp/overview#advanced-mcpserveradapter).
-
-
-## 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:
-
-
-
-## 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 ...
-```
-
-
- 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.
-
-
-### 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
-
-
-
- **Recommended**: Use the simple `mcps=[]` field syntax for effortless MCP
- integration.
-
-
-
- Connect to local MCP servers via standard input/output. Ideal for scripts
- and local executables.
-
-
-
- Integrate with remote MCP servers using Server-Sent Events for real-time
- data streaming.
-
-
-
- Utilize flexible Streamable HTTP for robust communication with remote MCP
- servers.
-
-
-
- Aggregate tools from several MCP servers simultaneously using a single
- adapter.
-
-
-
- Review important security best practices for MCP integration to keep your
- agents safe.
-
-
-
-Checkout this repository for full demos and examples of MCP integration with CrewAI! 👇
-
-
- CrewAI MCP Demo
-
-
-## Staying Safe with MCP
-
-Always ensure that you trust an MCP Server before using it.
-
-#### 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
-
-
- The most critical aspect of MCP security is **trust**. You should **only** connect your CrewAI agents to MCP servers that you fully trust.
-
-
-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
-
-
- **Only connect to MCP servers that you trust.**
-
-
-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)
-
-
- **Protect against DNS Rebinding Attacks.**
-
-
-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.")
-
-```
-
-
- Replace `"http://localhost:8000/sse"` with the actual URL of your SSE MCP server.
-
-
-### 2. Manual Connection Lifecycle
-
-If you need finer-grained control, you can manage the `MCPServerAdapter` connection lifecycle manually.
-
-
- 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.
-
-
-```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
-
-
- **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.
-
-
-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.
-
-
- 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.
-
-
-```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.
-
-
- 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.
-
-
-```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! 🚣♂️
-
-
-
- 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.
-
-
- ```shell Terminal theme={null}
- crewai create crew latest-ai-development
- ```
-
-
-
-
-
- ```shell Terminal theme={null}
- cd latest_ai_development
- ```
-
-
-
-
-
- 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.
-
-
- ```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.
- ```
-
-
-
- ````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
- ````
-
-
-
- ```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,
- )
- ```
-
-
-
- ```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
- ```
-
-
-
- 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)
- ```
-
-
-
- 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.
-
-
-
- * Lock the dependencies and install them by using the CLI command:
-
- ```shell Terminal theme={null}
- crewai install
- ```
-
- * If you have additional packages that you want to install, you can do so by running:
-
- ```shell Terminal theme={null}
- uv add
- ```
-
-
-
-
- * To run your crew, execute the following command in the root of your project:
-
- ```bash Terminal theme={null}
- crewai run
- ```
-
-
-
-
- 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"
-
-
-
-
- Start your free account at CrewAI AMP
-
-
-
-
- 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:
-
-
- ```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.
- ```
-
-
-
-
-
- Congratulations!
-
- You have successfully set up your crew project and are ready to start building your own agentic workflows!
-
-
-### 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
-
-
- 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.
-
-
-```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
-```
-
-
- 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.
-
-
-```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.
-
-
-
-
-
- Get started with CrewAI AMP and deploy your crew in a production environment
- with just a few clicks.
-
-
-
- Join our open source community to discuss ideas, share your projects, and
- connect with other CrewAI developers.
-
-
-
-
-# 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`
-
-
- 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.
-
-
-```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=
-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**
-
-
-
- Generate AI images using OpenAI's DALL-E model.
-
-
-
- Process and analyze images with computer vision capabilities.
-
-
-
- Advanced AI reasoning and decision-making capabilities.
-
-
-
- Build knowledge bases and retrieval systems with LlamaIndex.
-
-
-
- Integrate with LangChain for complex AI workflows.
-
-
-
- Implement Retrieval-Augmented Generation systems.
-
-
-
- Execute Python code and perform data analysis.
-
-
-
-## **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
-
-
-
- ```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`
-
-
-
- ```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`
-
-
-
- ```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`
-
-
-
- ```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`
-
-
-
- ```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`)
-
-
-
- ```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`
-
-
-
- ```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`
-
-
-
- ```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`
-
-
-
- ```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`
-
-
-
- ```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`
-
-
-
- ```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`
-
-
-
- ```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`
-
-
-
- ```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)
-
-
-
- ```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`
-
-
-
- ```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`
-
-
-
- ```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`
-
-
-
- ```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`
-
-
-
- ```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.
-
-
-
-### 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**
-
-
-
- Read files and data from Amazon S3 buckets.
-
-
-
- Write and upload files to Amazon S3 storage.
-
-
-
- Invoke Amazon Bedrock agents for AI-powered tasks.
-
-
-
- Retrieve information from Amazon Bedrock knowledge bases.
-
-
-
-## **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="",
-)
-```
-
-### 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="",
- 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="",
-)
-
-# 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.
-
-
-
-
-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.
-
-
-
-
-
-
-
-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**
-
-
-
- Connect to and query MySQL databases with SQL operations.
-
-
-
- Search and query PostgreSQL databases efficiently.
-
-
-
- Access Snowflake data warehouse for analytics and reporting.
-
-
-
- Convert natural language queries to SQL statements automatically.
-
-
-
- Search vector embeddings using Qdrant vector database.
-
-
-
- Perform semantic search with Weaviate vector database.
-
-
-
- Vector similarity search on MongoDB Atlas with indexing helpers.
-
-
-
- Safe SELECT/SHOW queries on SingleStore with pooling and validation.
-
-
-
-## **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
-
-
- 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.
-
-
-## 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]'
-```
-
-
- 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.
-
-
-## 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`
-
-
- **Experimental**: We are still working on improving tools, so there might be unexpected behavior or changes in the future.
-
-
-## 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`
-
-
- We are still working on improving tools, so there might be unexpected behavior or changes in the future.
-
-
-## 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`
-
-
- **Experimental**: The DirectorySearchTool is under continuous development. Features and functionalities might evolve, and unexpected behavior may occur as we refine the tool.
-
-
-## 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`
-
-
- We are still working on improving tools, so there might be unexpected behavior or changes in the future.
-
-
-## 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
-
-
- We are still working on improving tools, so there might be unexpected behavior or changes in the future.
-
-
-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`
-
-
- 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.
-
-
-## 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`
-
-
- The MDXSearchTool is in continuous development. Features may be added or removed, and functionality could change unpredictably as we refine the tool.
-
-
-## 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**
-
-
-
- Read content from any file type including text, markdown, and more.
-
-
-
- Write content to files, create new documents, and save processed data.
-
-
-
- Search and extract text content from PDF documents efficiently.
-
-
-
- Search through Microsoft Word documents and extract relevant content.
-
-
-
- Parse and search through JSON files with advanced query capabilities.
-
-
-
- Process and search through CSV files, extract specific rows and columns.
-
-
-
- Parse XML files and search for specific elements and attributes.
-
-
-
- Search through MDX files and extract content from documentation.
-
-
-
- Search through plain text files with pattern matching capabilities.
-
-
-
- Search for files and folders within directory structures.
-
-
-
- Read and list directory contents, file structures, and metadata.
-
-
-
- Extract text from images (local files or URLs) using a vision‑capable LLM.
-
-
-
- Write text at specific coordinates in PDFs, with optional custom fonts.
-
-
-
-## **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`
-
-
- We are still working on improving tools, so there might be unexpected behavior or changes in the future.
-
-
-## 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
-
-
- We are still working on improving tools, so there might be unexpected behavior or changes in the future.
-
-
-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`
-
-
- We are still working on improving tools, so there might be unexpected behavior or changes in the future.
-
-
-## 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**
-
-
-
- Read, write, and search through various file formats including PDF, DOCX, JSON, CSV, and more. Perfect for document processing workflows.
-
-
-
- Extract data from websites, automate browser interactions, and scrape content at scale with tools like Firecrawl, Selenium, and more.
-
-
-
- Perform web searches, find code repositories, research YouTube content, and discover information across the internet.
-
-
-
- Connect to SQL databases, vector stores, and data warehouses. Query MySQL, PostgreSQL, Snowflake, Qdrant, and Weaviate.
-
-
-
- Generate images with DALL-E, process vision tasks, integrate with LangChain, build RAG systems, and leverage code interpreters.
-
-
-
- Interact with cloud services including AWS S3, Amazon Bedrock, and other cloud storage and AI services.
-
-
-
- Automate workflows with Apify, Composio, and other platforms to connect your agents with external services.
-
-
-
- Integrate CrewAI with external systems like Amazon Bedrock and the CrewAI Automation toolkit.
-
-
-
-## **Quick Access**
-
-Need a specific tool? Here are some popular choices:
-
-
-
- Implement Retrieval-Augmented Generation
-
-
-
- Google search API
-
-
-
- Read any file type
-
-
-
- Extract web content
-
-
-
- Execute Python code
-
-
-
- Access AWS S3 files
-
-
-
-## **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`
-
-
- **Experimental**: We are still working on improving tools, so there might be unexpected behavior or changes in the future.
-
-
-## 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')
-```
-
-
- 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.
-
-
-## 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:
-
-
-
- Confirm that the `crewai[tools]` package is installed in your Python environment.
-
-
-
- Acquire a [exa.ai](https://exa.ai/) API key by registering for a free account at [exa.ai](https://exa.ai/).
-
-
-
- Store your obtained API key in an environment variable named `EXA_API_KEY` to facilitate its use by the tool.
-
-
-
-## 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`
-
-
- We are still working on improving tools, so there might be unexpected behavior or changes in the future.
-
-
-## 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**
-
-
-
- Google search API integration for comprehensive web search capabilities.
-
-
-
- Privacy-focused search with Brave's independent search index.
-
-
-
- AI-powered search for finding specific and relevant content.
-
-
-
- Real-time web search with fresh content indexing.
-
-
-
- Search GitHub repositories, code, issues, and documentation.
-
-
-
- Search within specific websites and domains.
-
-
-
- Search through code documentation and technical resources.
-
-
-
- Search YouTube channels for specific content and creators.
-
-
-
- Find and analyze YouTube videos by topic, keyword, or criteria.
-
-
-
- Comprehensive web search using Tavily's AI-powered search API.
-
-
-
- Extract structured content from web pages using the Tavily API.
-
-
-
- Search arXiv and optionally download PDFs.
-
-
-
- Google search via SerpApi with structured results.
-
-
-
- Google Shopping queries via SerpApi.
-
-
-
-## **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`
-
-
- 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.
-
-
-## 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`
-
-
- We are still working on improving tools, so there might be unexpected behavior or changes in the future.
-
-
-## 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`
-
-
- We are still working on improving tools, so there might be unexpected behavior or changes in the future.
-
-
-## 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**
-
-
-
- General-purpose web scraping tool for extracting content from any website.
-
-
-
- Target specific elements on web pages with precision scraping capabilities.
-
-
-
- Crawl entire websites systematically with Firecrawl's powerful engine.
-
-
-
- High-performance web scraping with Firecrawl's advanced capabilities.
-
-
-
- Search and extract specific content using Firecrawl's search features.
-
-
-
- Browser automation and scraping with Selenium WebDriver capabilities.
-
-
-
- Professional web scraping with ScrapFly's premium scraping service.
-
-
-
- Graph-based web scraping for complex data relationships.
-
-
-
- Comprehensive web crawling and data extraction capabilities.
-
-
-
- Cloud-based browser automation with BrowserBase infrastructure.
-
-
-
- Fast browser interactions with HyperBrowser's optimized engine.
-
-
-
- Intelligent browser automation with natural language commands.
-
-
-
- Access web data at scale with Oxylabs.
-
-
-
- SERP search, Web Unlocker, and Dataset API integrations.
-
-
-
-## **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`
-
-
- We are still working on improving tools, so there might be unexpected behavior or changes in the future.
-
-
-## 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`
-
-
- 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.
-
-
-## 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)
-
-
- The context manager approach is recommended as it ensures proper cleanup of resources even if exceptions occur.
-
-
-```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.
-
-
-
-
-
-
Ship multi‑agent systems with confidence
-
-
- Design agents, orchestrate crews, and automate flows with guardrails, memory, knowledge, and observability baked in.
-
-
-
-
-## Get started
-
-
-
- Overview of CrewAI concepts, architecture, and what you can build with agents, crews, and flows.
-
-
-
- Install via `uv`, configure API keys, and set up the CLI for local development.
-
-
-
- Spin up your first crew in minutes. Learn the core runtime, project layout, and dev loop.
-
-
-
-## Build the basics
-
-
-
- Compose agents with tools, memory, knowledge, and structured outputs using Pydantic. Includes templates and best practices.
-
-
-
- Orchestrate start/listen/router steps, manage state, persist execution, and resume long-running workflows.
-
-
-
- Define sequential, hierarchical, or hybrid processes with guardrails, callbacks, and human-in-the-loop triggers.
-
-
-
-## Enterprise journey
-
-
-
- Manage environments, redeploy safely, and monitor live runs directly from the Enterprise console.
-
-
-
- Connect Gmail, Slack, Salesforce, and more. Pass trigger payloads into crews and flows automatically.
-
-
-
- Invite teammates, configure RBAC, and control access to production automations.
-
-
-
-## What’s new
-
-
-
- Unified overview for Gmail, Drive, Outlook, Teams, OneDrive, HubSpot, and more — now with sample payloads and crews.
-
-
-
- Call existing CrewAI automations or Amazon Bedrock Agents directly from your crews using the updated integration toolkit.
-
-
-
-
- Browse the examples and cookbooks for end-to-end reference implementations across agents, flows, and enterprise automations.
-
-
-## Stay connected
-
-
-
- If CrewAI helps you ship faster, give us a star and share your builds with the community.
-
-
-
- Ask questions, showcase workflows, and request features alongside other builders.
-
-
-
-
-# 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.
-
-
-
-
-
-## 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.
-
-
-
-
-
-### 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
-
-# List all available organizations
-crewai org list
-```
-
-
- 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.
-
-
-
-# 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.
-
-
-
-
-
-## Deployment Methods
-
-### Deploy from GitHub
-
-Use this for version‑controlled projects and continuous deployment.
-
-
-
- Click Configure GitHub and authorize access.
-
-
-
- Choose the Repository and Branch you want to deploy from.
-
-
-
- Turn on Automatically deploy new commits to ship updates on every push.
-
-
-
- Add secrets individually or use Bulk View for multiple variables.
-
-
-
- Click Deploy to create your live automation.
-
-
-
-
-
-
-
-### Deploy from ZIP
-
-Ship quickly without Git—upload a compressed package of your project.
-
-
-
- Select the ZIP archive from your computer.
-
-
-
- Provide any required variables or keys.
-
-
-
- Click Deploy to create your live automation.
-
-
-
-
-
-
-
-## 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 Status
-* Filter by Source (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`.
-
-
-
-
-
-## 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
-
-
-
- Deploy a Crew from GitHub or ZIP file.
-
-
-
- Trigger automations via webhooks or API.
-
-
-
- Stream real-time events and updates to your systems.
-
-
-
-
-# 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.
-
-
-
-
-
-## 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.
-
-
-
-
-
-## 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)
-
-
-
-
-
-## Execution & Debugging
-
-Switch to the Execution view to run and observe the workflow:
-
-* Event timeline
-* Detailed logs (Details, Messages, Raw Data)
-* Local test runs before publishing
-
-
-
-
-
-## Publish & Export
-
-* Publish to deploy a live automation
-* Download source as a ZIP for local development or customization
-
-
-
-
-
-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`.
-
-
-
-
-
-## 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
-
-
-
- Enable Crew Studio.
-
-
-
- Build a Crew.
-
-
-
- Deploy a Crew from GitHub or ZIP file.
-
-
-
- Export a React Component.
-
-
-
-
-# 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
-
-
- 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.
-
-
-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
-
-
-
- Responders can reply directly to notification emails to provide feedback
-
-
-
- Route requests to specific emails based on method patterns or flow state
-
-
-
- Configure automatic fallback responses when no human replies in time
-
-
-
-### 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**
-
-
-
-
-
-### Email Notifications
-
-Toggle to enable or disable email notifications for HITL requests.
-
-| Setting | Default | Description |
-| ------------------- | ------- | -------------------------------------- |
-| Email Notifications | Enabled | Send emails when feedback is requested |
-
-
- When disabled, responders must use the dashboard UI or you must configure webhooks for custom notification systems.
-
-
-### 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
-
-
-
- When a HITL request is created, an email is sent to the assigned responder with the review content and context.
-
-
-
- The email includes a special reply-to address with a signed token for authentication.
-
-
-
- The responder simply replies to the email with their feedback—no login required.
-
-
-
- The platform receives the reply, verifies the signed token, and matches the sender email.
-
-
-
- The feedback is recorded and the flow continues with the human's input.
-
-
-
-### 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.
-
-
-
-
-
-### 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.
-
-
- **Use Case**: Pull the assignee from your CRM, database, or previous flow step to dynamically route reviews to the right person.
-
-
-## 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) |
-
-
-
-
-
-### 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
-
-
- Use auto-response carefully. Only enable it for non-critical reviews where a default response is acceptable.
-
-
-## 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
-
-
-
-
-
-### 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
-
-
-
-
-
-
-
- Monitor average and median response times by reviewer or flow.
-
-
-
- Analyze review volume patterns to optimize team capacity.
-
-
-
- View approval/rejection rates across different review types.
-
-
-
- Track percentage of reviews completed within SLA targets.
-
-
-
-### 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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
-## 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
-
-
-
-
-
-### Configuring Webhooks
-
-
-
- Go to your **Deployment** → **Settings** → **Human in the Loop**
-
-
-
- Click to expand the **Webhooks** configuration
-
-
-
- Enter your webhook URL (must be HTTPS in production)
-
-
-
- Click **Save Configuration** to activate
-
-
-
-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
-
-
- All webhook requests are cryptographically signed using HMAC-SHA256 to ensure authenticity and prevent tampering.
-
-
-#### 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=` |
-| `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
-
-
- **Start Simple**: Begin with email notifications to deployment creator, then add routing rules as your workflows mature.
-
-
-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
-
-
-
- Implementation guide for the `@human_feedback` decorator
-
-
-
- Step-by-step guide for setting up HITL workflows
-
-
-
- Configure role-based access control for your organization
-
-
-
- Set up real-time event notifications
-
-
-
-
-# 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
-
-
-
- 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.
- """
- ```
-
-
-
- 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."
- ```
-
-
-
- Ensure your reference context reflects current, accurate information.
-
-
-
-### Threshold Selection
-
-
-
- Begin without custom thresholds to understand baseline performance.
-
-
-
- * **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
-
-
-
- Track validation results and adjust thresholds based on false positives/negatives.
-
-
-
-## 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
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- Contact our support team for assistance with hallucination guardrail configuration or troubleshooting.
-
-
-
-# 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.
-
-
-
-
-
-## 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
-
-
-
-
-
-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
-
-
-
- Connect external apps and manage internal tools your agents can use.
-
-
-
- Publish and install tools to enhance your crews' capabilities.
-
-
-
- Store, share, and reuse agent definitions across teams and projects.
-
-
-
-
-# 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.
-
-
- PII Redaction is available on the Enterprise plan.
- Deployment must be version 1.8.0 or higher.
-
-
-
-
-
-
-## 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 or call "
-```
-
-## Enabling PII Redaction
-
-
- You must be on the Enterprise plan and your deployment must be version 1.8.0 or higher to use this feature.
-
-
-
-
- In the CrewAI AMP dashboard, select your deployed crew and go to one of your deployments/automations, then navigate to **Settings** → **PII Protection**.
-
-
-
- Toggle on **PII Redaction for Traces**. This will enable automatic scanning and redaction of trace data.
-
-
- You need to manually enable PII Redaction for each deployment.
-
-
-
-
-
-
-
-
- Select which types of PII to detect and redact. Each entity can be individually enabled or disabled.
-
-
-
-
-
-
-
- Save your configuration. PII redaction will be active on all subsequent crew executions, no redeployment is needed.
-
-
-
-## 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 | `` |
-| `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.
-
-
-
-
-
-### 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
-
-
-
- Go to your Organization **Settings** → **Organization** → **Add Recognizer**.
-
-
-
-
-
-
-
- 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
-
-
-
- Save the recognizer. It will be available to enable on your deployments.
-
-
-
-### 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 "
-```
-
-### 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 placed order #12345.
-Contact email: , phone: .
-Payment processed for card ending in ."
-```
-
-Redacted values are clearly marked with angle brackets and the entity type label (e.g., ``), making it easy to understand what data was protected while still allowing you to debug and monitor crew behavior.
-
-## Best Practices
-
-### Performance Considerations
-
-
-
- Each enabled entity adds processing overhead. Only enable entities relevant to your data.
-
-
-
- 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.
-
-
-
- Context words improve accuracy by only triggering detection when surrounding text matches.
-
-
-
-## Troubleshooting
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-***
-
-## 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
-
-
-
-
-
-| 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 annually"
-
-Original: "Base salary:$50,000 with bonus potential"
-Redacted: "Base with bonus potential"
-```
-
-
- 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.
-
-
-### Enable the Recognizer for Your Deployments
-
-
- 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.
-
-
-After creating your custom recognizer, enable it for each deployment:
-
-
-
- Go to your deployment/automation and open **Settings** → **PII Protection**.
-
-
-
- Under **Mask Recognizers**, you'll see your organization-defined recognizers. Check the box next to the recognizers you want to enable.
-
-
-
-
-
-
-
- Save your changes. The recognizer will be active on all subsequent executions for this deployment.
-
-
-
-
- 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).
-
-
-
-# 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.
-
-
-
-
-
-## 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.
-
-
-
- Go to Settings → Roles in CrewAI AMP.
-
-
-
- Use a predefined role (Owner, Member) or click
- Create role to define a custom one.
-
-
-
- Select users and assign the role. You can change this anytime.
-
-
-
-### 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.
-
-
-
- Navigate to Automation → Settings → Visibility.
-
-
-
- Choose Private to restrict access. The organization owner always
- retains access.
-
-
-
- Add specific users and roles allowed to view, run, and access
- logs/metrics/settings.
-
-
-
- Save changes, then confirm that non‑whitelisted users cannot view or run the
- automation.
-
-
-
-### Private visibility: access outcomes
-
-| Action | Owner | Whitelisted user/role | Not whitelisted |
-| :--------------------------- | :---- | :-------------------- | :-------------- |
-| View automation | ✓ | ✓ | ✗ |
-| Run automation/API | ✓ | ✓ | ✗ |
-| Access logs/metrics/settings | ✓ | ✓ | ✗ |
-
-
- The organization owner always has access. In private mode, only whitelisted
- users and roles can view, run, and access logs/metrics/settings.
-
-
-
-
-
-
-
- Contact our support team for assistance with RBAC questions.
-
-
-
-# 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.
-
-
-
-
-
-## Explore
-
-
-
- ## Agent Apps (Integrations)
-
- Connect enterprise‑grade applications (e.g., Gmail, Google Drive, HubSpot, Slack) via OAuth to enable agent actions.
-
-
-
- Click Connect on an app and complete OAuth.
-
-
-
- Optionally adjust scopes, triggers, and action availability.
-
-
-
- Connected services become available as tools for your agents.
-
-
-
-
-
-
-
- ### Connect your Account
-
- 1. Go to Integrations
- 2. Click Connect on the desired service
- 3. Complete the OAuth flow and grant scopes
- 4. Copy your Enterprise Token from Integration Settings
-
-
-
-
-
- ### 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
- ```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
-
-
- Use the new streamlined approach to integrate enterprise apps. Simply specify
- the app and its actions directly in the Agent configuration.
-
-
- ```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.
-
-
-
-
-
- ### 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.
-
- Useful when different teams/users must keep data access separated.
-
- 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.
-
-
-
-
-
-
-
- ### 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!
-
-
-
- ## Internal Tools
-
- Create custom tools locally, publish them on CrewAI AMP Tool Repository and use them in your agents.
-
-
- Before running the commands below, make sure you log in to your CrewAI AMP
- account by running this command: `bash crewai login `
-
-
-
-
-
-
-
-
- Create a new tool locally. `bash crewai tool create your-tool `
-
-
-
- Publish the tool to the CrewAI AMP Tool Repository. `bash crewai tool
- publish `
-
-
-
- Install the tool from the CrewAI AMP Tool Repository. `bash crewai tool
- install your-tool `
-
-
-
- Manage:
-
- * Name and description
- * Visibility (Private / Public)
- * Required environment variables
- * Version history and downloads
- * Team and role access
-
-
-
-
-
-
-
-## Related
-
-
-
- Create, publish, and version custom tools for your organization.
-
-
-
- Automate workflows and integrate with external platforms and services.
-
-
-
-
-# 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
-
-
-
-
-
-## Accessing Traces
-
-
-
- Once in your CrewAI AMP dashboard, click on the **Traces** to view all execution records.
-
-
-
- You'll see a list of all crew executions, sorted by date. Click on any execution to view its detailed trace.
-
-
-
-## 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
-
-
-
-
-
-### 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
-
-
-
-
-
-### 3. Final Output
-
-Displays the final result produced by the crew after all tasks are completed.
-
-
-
-
-
-### 4. Execution Timeline
-
-A visual representation of when each task started and ended, helping you identify bottlenecks or parallel execution patterns.
-
-
-
-
-
-### 5. Detailed Task View
-
-When you click on a specific task in the timeline or task list, you'll see:
-
-
-
-
-
-* **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:
-
-
-
- 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
-
-
-
-
-
-
-
- Use execution metrics to identify performance bottlenecks:
-
- * Tasks that took longer than expected
- * Excessive token usage
- * Redundant tool operations
- * Unnecessary API calls
-
-
-
- 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
-
-
-
-## 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.
-
-
- Contact our support team for assistance with trace analysis or any other
- CrewAI AMP features.
-
-
-
-# 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.
-
-
-
- Full list of events
-
-
-
- Contact our support team for assistance with webhook integration or
- troubleshooting.
-
-
-
-
-# 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.
-
-
-
-
-
-### Integration Playbooks
-
-Deep-dive guides walk through setup and sample workflows for each integration:
-
-
-
- Enable crews when emails arrive or threads update.
-
-
-
-
- React to calendar events as they are created, updated, or cancelled.
-
-
-
-
-
- Handle Drive file uploads, edits, and deletions.
-
-
-
-
-
- Automate responses to new Outlook messages and calendar updates.
-
-
-
-
-
- Audit file activity and sharing changes in OneDrive.
-
-
-
-
-
- Kick off workflows when new Teams chats start.
-
-
-
-
-
- Launch automations from HubSpot workflows and lifecycle events.
-
-
-
-
-
- Connect Salesforce processes to CrewAI for CRM automation.
-
-
-
-
-
- Start crews directly from Slack slash commands.
-
-
-
-
- Bridge CrewAI with thousands of Zapier-supported apps.
-
-
-
-## 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
-
-
-
-
-
-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:
-
-
-
-
-
-* **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:
-
-
-
-
-
-## 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
-```
-
-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
-
-
- **Important Development Notes:**
-
- * Use `crewai triggers run ` 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
-
-
-### 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.
-
-
- 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
-
-
-### 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 ` 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 ` 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.
-
-
- Make sure Gmail is connected in Tools & Integrations and the trigger is
- enabled for your deployment.
-
-
-## 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
-
-
-
-
-
-## 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.
-
-
- 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.
-
-
-## Monitoring Executions
-
-Track history and performance of triggered runs:
-
-
-
-
-
-## 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.
-
-
- Make sure Google Calendar is connected in **Tools & Integrations** and enabled
- for the deployment you want to automate.
-
-
-## 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
-
-
-
-
-
-## 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.
-
-
- 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.
-
-
-## Monitoring Executions
-
-The **Executions** list in the deployment dashboard tracks every triggered run and surfaces payload metadata, output summaries, and errors.
-
-
-
-
-
-## 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.
-
-
- Connect Google Drive in **Tools & Integrations** and confirm the trigger is
- enabled for the automation you want to monitor.
-
-
-## 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
-
-
-
-
-
-## 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.
-
-
- 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.
-
-
-## Monitoring Executions
-
-Track history and performance of triggered runs with the **Executions** list in the deployment dashboard.
-
-
-
-
-
-## 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.
-
-
- Confirm Microsoft Teams is connected under **Tools & Integrations** and
- enabled in the **Triggers** tab for your deployment.
-
-
-## 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
-
-
-
-
-
-## 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.
-
-
- 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.
-
-
-## 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.
-
-
- Connect OneDrive in **Tools & Integrations** and toggle the trigger on for
- your deployment.
-
-
-## 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
-
-
-
-
-
-## 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.
-
-
- 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.
-
-
-## 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.
-
-
- Connect Outlook in **Tools & Integrations** and ensure the trigger is enabled
- for your deployment.
-
-
-## 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
-
-
-
-
-
-## 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.
-
-
- 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.
-
-
-## 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **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.").
-
-
-
- **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.").
-
-
-
- **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`
-
-
-
- **Description:** Get a project by ID in Asana.
-
- **Parameters:**
-
- * `projectFilterId` (string, required): Project ID.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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").
-
-
-
- **Description:** Get a list of tasks by ID in Asana.
-
- **Parameters:**
-
- * `taskId` (string, required): Task 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.
-
-
-
- **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").
-
-
-
- **Description:** Get a list of teams in Asana.
-
- **Parameters:**
-
- * `workspace` (string, required): Workspace - Returns the teams in this workspace visible to the authorized user.
-
-
-
- **Description:** Get a list of workspaces in Asana.
-
- **Parameters:** None required.
-
-
-
-## 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **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)").
-
-
-
- **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.
-
-
-
- **Description:** Get a file by ID in Box.
-
- **Parameters:**
-
- * `fileId` (string, required): File ID - The unique identifier that represents a file. (example: "12345").
-
-
-
- **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"
- }
- ]
- }
- ]
- }
- ```
-
-
-
- **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"
- }
- ```
-
-
-
- **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"
- }
- ```
-
-
-
- **Description:** Get a folder by ID in Box.
-
- **Parameters:**
-
- * `folderId` (string, required): Folder ID - The unique identifier that represents a folder. (example: "0").
-
-
-
- **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"
- }
- ]
- }
- ]
- }
- ```
-
-
-
- **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.
-
-
-
-## 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **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`
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **Description:** Delete a task in ClickUp.
-
- **Parameters:**
-
- * `taskId` (string, required): Task ID - The ID of the task to delete.
-
-
-
- **Description:** Get List information in ClickUp.
-
- **Parameters:**
-
- * `spaceId` (string, required): Space ID - The ID of the space containing the lists.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **Description:** Get Space information in ClickUp.
-
- **Parameters:**
-
- * `spaceId` (string, optional): Space ID - The ID of the space to retrieve.
-
-
-
- **Description:** Get Folders in ClickUp.
-
- **Parameters:**
-
- * `spaceId` (string, required): Space ID - The ID of the space containing the folders.
-
-
-
- **Description:** Get Member information in ClickUp.
-
- **Parameters:** None required.
-
-
-
-## 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
-
-
- Contact our support team for assistance with ClickUp integration setup or
- troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **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"]`).
-
-
-
- **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`
-
-
-
- **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.
-
-
-
- **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`
-
-
-
- **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`
-
-
-
- **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`
-
-
-
- **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`
-
-
-
- **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.
-
-
-
- **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").
-
-
-
- **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.
-
-
-
-## 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
-
-
- Contact our support team for assistance with GitHub integration setup or
- troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **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)
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
-## 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
-
-
- Contact our support team for assistance with Gmail integration setup or
- troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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.
-
-
-
- **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
-
-
-
- **Description:** Delete a specified event.
-
- **Parameters:**
-
- * `calendarId` (string, required): Calendar ID
- * `eventId` (string, required): Event ID to delete
-
-
-
- **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
-
-
-
-## 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
-
-
- Contact our support team for assistance with Google Calendar integration setup
- or troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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"
- }
- ]
- ```
-
-
-
- **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
-
-
-
- **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')
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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"
- }
- ]
- ```
-
-
-
- **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"
- }
- ]
- ```
-
-
-
- **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
-
-
-
-## 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
-
-
- Contact our support team for assistance with Google Contacts integration setup
- or troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **Description:** Create a new Google Document.
-
- **Parameters:**
-
- * `title` (string, optional): The title for the new 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`.
-
-
-
- **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).
-
-
-
- **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`.
-
-
-
- **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`.
-
-
-
- **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.
-
-
-
- **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`.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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"`.
-
-
-
- **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`.
-
-
-
- **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`.
-
-
-
- **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.
-
-
-
- **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`.
-
-
-
- **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.
-
-
-
- **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"]]`.
-
-
-
- **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`.
-
-
-
- **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`.
-
-
-
- **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`.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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`.
-
-
-
- **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).
-
-
-
- **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`.
-
-
-
- **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`.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
-## 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
-
-
- Contact our support team for assistance with Google Docs integration setup or
- troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **Description:** Get a file by ID from Google Drive.
-
- **Parameters:**
-
- * `file_id` (string, required): The ID of the file to retrieve.
-
-
-
- **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).
-
-
-
- **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.
-
-
-
- **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).
-
-
-
- **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.
-
-
-
- **Description:** Delete a file from Google Drive.
-
- **Parameters:**
-
- * `file_id` (string, required): The ID of the file to delete.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
-## 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **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.
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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"
- }
- }
- ]
- ```
-
-
-
-## 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
-
-
- Contact our support team for assistance with Google Sheets integration setup
- or troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **Description:** Creates a blank presentation with no content.
-
- **Parameters:**
-
- * `title` (string, required): The title of the presentation.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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"
- }
- ```
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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).
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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).
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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"]].
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **Description:** Deletes a presentation by ID.
-
- **Parameters:**
-
- * `presentationId` (string, required): The ID of the presentation to delete.
-
-
-
-## 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
-
-
- Contact our support team for assistance with Google Slides integration setup
- or troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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`.
-
-
-
- **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`)
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **Description:** Get a list of company records from HubSpot.
-
- **Parameters:**
-
- * `paginationParameters` (object, optional): Use `pageCursor` to fetch subsequent pages.
-
-
-
- **Description:** Get a list of contact records from HubSpot.
-
- **Parameters:**
-
- * `paginationParameters` (object, optional): Use `pageCursor` to fetch subsequent pages.
-
-
-
- **Description:** Get a list of deal records from HubSpot.
-
- **Parameters:**
-
- * `paginationParameters` (object, optional): Use `pageCursor` to fetch subsequent pages.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **Description:** Get a single company record by its ID.
-
- **Parameters:**
-
- * `recordId` (string, required): The ID of the company to retrieve.
-
-
-
- **Description:** Get a single contact record by its ID.
-
- **Parameters:**
-
- * `recordId` (string, required): The ID of the contact to retrieve.
-
-
-
- **Description:** Get a single deal record by its ID.
-
- **Parameters:**
-
- * `recordId` (string, required): The ID of the deal to retrieve.
-
-
-
- **Description:** Get a single engagement record by its ID.
-
- **Parameters:**
-
- * `recordId` (string, required): The ID of the engagement to retrieve.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **Description:** Delete a company record by its ID.
-
- **Parameters:**
-
- * `recordId` (string, required): The ID of the company to delete.
-
-
-
- **Description:** Delete a contact record by its ID.
-
- **Parameters:**
-
- * `recordId` (string, required): The ID of the contact to delete.
-
-
-
- **Description:** Delete a deal record by its ID.
-
- **Parameters:**
-
- * `recordId` (string, required): The ID of the deal to delete.
-
-
-
- **Description:** Delete an engagement record by its ID.
-
- **Parameters:**
-
- * `recordId` (string, required): The ID of the engagement to delete.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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').
-
-
-
-## 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
-
-
- Contact our support team for assistance with HubSpot integration setup or
- troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **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"
- }
- ```
-
-
-
- **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.
-
-
-
- **Description:** Get an issue by key in Jira.
-
- **Parameters:**
-
- * `issueKey` (string, required): Issue Key (example: "TEST-1234").
-
-
-
- **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.
-
-
-
- **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"
- }
- ```
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **Description:** Get Projects in Jira.
-
- **Parameters:**
-
- * `paginationParameters` (object, optional): Pagination Parameters.
- ```json theme={null}
- {
- "pageCursor": "cursor_string"
- }
- ```
-
-
-
- **Description:** Get Issue Types by project in Jira.
-
- **Parameters:**
-
- * `project` (string, required): Project key.
-
-
-
- **Description:** Get all Issue Types in Jira.
-
- **Parameters:** None required.
-
-
-
- **Description:** Get issue statuses for a given project.
-
- **Parameters:**
-
- * `project` (string, required): Project key.
-
-
-
- **Description:** Get assignees for a given project.
-
- **Parameters:**
-
- * `project` (string, required): Project key.
-
-
-
-## 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
-
-
- Contact our support team for assistance with Jira integration setup or
- troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **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"]
- }
- ```
-
-
-
- **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"]
- }
- ```
-
-
-
- **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").
-
-
-
- **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").
-
-
-
- **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`
-
-
-
- **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").
-
-
-
- **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").
-
-
-
- **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"
- }
- ```
-
-
-
- **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": ""
- }
- ```
-
-
-
- **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": ""
- }
- ```
-
-
-
- **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").
-
-
-
- **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").
-
-
-
- **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`
-
-
-
-## 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
-
-
- Contact our support team for assistance with Linear integration setup or
- troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **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"
- }
- ]
- ```
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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')
-
-
-
- **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"]
- ]
- ```
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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"]
- ```
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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)
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **Description:** Get all named ranges in an Excel workbook.
-
- **Parameters:**
-
- * `file_id` (string, required): The ID of the Excel file
-
-
-
-## 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
-
-
- Contact our support team for assistance with Microsoft Excel integration setup
- or troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **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.
-
-
-
- **Description:** Get information about a specific file or folder.
-
- **Parameters:**
-
- * `item_id` (string, required): The ID of the file or folder.
-
-
-
- **Description:** Download a file from OneDrive.
-
- **Parameters:**
-
- * `item_id` (string, required): The ID of the file to download.
-
-
-
- **Description:** Upload a file to OneDrive.
-
- **Parameters:**
-
- * `file_name` (string, required): Name of the file to upload.
- * `content` (string, required): Base64 encoded file content.
-
-
-
- **Description:** Create a new folder in OneDrive.
-
- **Parameters:**
-
- * `folder_name` (string, required): Name of the folder to create.
-
-
-
- **Description:** Delete a file or folder from OneDrive.
-
- **Parameters:**
-
- * `item_id` (string, required): The ID of the file or folder to delete.
-
-
-
- **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).
-
-
-
- **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).
-
-
-
- **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`.
-
-
-
- **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`.
-
-
-
- **Description:** Get thumbnails for a file.
-
- **Parameters:**
-
- * `item_id` (string, required): The ID of the file.
-
-
-
- **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".
-
-
-
- **Description:** Get recently accessed files from OneDrive.
-
- **Parameters:**
-
- * `top` (integer, optional): Number of items to retrieve (max 200). Default is `25`.
-
-
-
- **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".
-
-
-
- **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').
-
-
-
- **Description:** Download a file from OneDrive by its path.
-
- **Parameters:**
-
- * `file_path` (string, required): The file path (e.g., 'Documents/report.docx').
-
-
-
-## 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
-
-
- Contact our support team for assistance with Microsoft OneDrive integration
- setup or troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **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.
-
-
-
- **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`.
-
-
-
- **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".
-
-
-
- **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.
-
-
-
- **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".
-
-
-
- **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.
-
-
-
- **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".
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **Description:** Delete an email message.
-
- **Parameters:**
-
- * `message_id` (string, required): The unique identifier of the message to delete. Obtain from get\_messages action.
-
-
-
- **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.
-
-
-
- **Description:** Delete a calendar event.
-
- **Parameters:**
-
- * `event_id` (string, required): The unique identifier of the event to delete. Obtain from get\_calendar\_events action.
-
-
-
-## 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
-
-
- Contact our support team for assistance with Microsoft Outlook integration
- setup or troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **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')
-
-
-
- **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')
-
-
-
- **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')
-
-
-
- **Description:** Get all lists in a SharePoint site.
-
- **Parameters:**
-
- * `site_id` (string, required): The ID of the SharePoint site
-
-
-
- **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
-
-
-
- **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')
-
-
-
- **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"
- }
- ```
-
-
-
- **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"
- }
- ```
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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')
-
-
-
- **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
-
-
-
- **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')
-
-
-
- **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
-
-
-
- **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')
-
-
-
- **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'
-
-
-
- **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')
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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)
-
-
-
- **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
-
-
-
- **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')
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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')
-
-
-
- **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')
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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])
-
-
-
- **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')
-
-
-
- **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'
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
-## 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
-
-
- Contact our support team for assistance with Microsoft SharePoint integration
- setup or troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **Description:** Get all teams the user is a member of.
-
- **Parameters:**
-
- * No parameters required.
-
-
-
- **Description:** Get channels in a specific team.
-
- **Parameters:**
-
- * `team_id` (string, required): The ID of the team.
-
-
-
- **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`.
-
-
-
- **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`.
-
-
-
- **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).
-
-
-
- **Description:** Search online meetings by Join Web URL.
-
- **Parameters:**
-
- * `join_web_url` (string, required): The join web URL of the meeting to search for.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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`.
-
-
-
- **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.
-
-
-
- **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`.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
-## 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
-
-
- Contact our support team for assistance with Microsoft Teams integration setup
- or troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **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.
-
-
-
- **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."
-
-
-
- **Description:** Get the content of a document (works best with text files).
-
- **Parameters:**
-
- * `file_id` (string, required): The ID of the document.
-
-
-
- **Description:** Get properties and metadata of a document.
-
- **Parameters:**
-
- * `file_id` (string, required): The ID of the document.
-
-
-
- **Description:** Delete a document.
-
- **Parameters:**
-
- * `file_id` (string, required): The ID of the document to delete.
-
-
-
- **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)
-
-
-
- **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
-
-
-
-## 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
-
-
- Contact our support team for assistance with Microsoft Word integration setup
- or troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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
-
-
-
- **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.
-
-
-
- **Description:** Retrieve a specific user by ID.
-
- **Parameters:**
-
- * `user_id` (string, required): The ID of the user to retrieve.
-
-
-
- **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"
- }
- }
- ]
- ```
-
-
-
-## 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
-
-
- Contact our support team for assistance with Notion integration setup or
- troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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**
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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.
-
-
-
-### **Record Updates**
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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.
-
-
-
-### **Record Retrieval**
-
-
-
- **Description:** Get a Contact record by its ID.
-
- **Parameters:**
-
- * `recordId` (string, required): Record ID of the Contact
-
-
-
- **Description:** Get a Lead record by its ID.
-
- **Parameters:**
-
- * `recordId` (string, required): Record ID of the Lead
-
-
-
- **Description:** Get an Opportunity record by its ID.
-
- **Parameters:**
-
- * `recordId` (string, required): Record ID of the Opportunity
-
-
-
- **Description:** Get a Task record by its ID.
-
- **Parameters:**
-
- * `recordId` (string, required): Record ID of the Task
-
-
-
- **Description:** Get an Account record by its ID.
-
- **Parameters:**
-
- * `recordId` (string, required): Record ID of the Account
-
-
-
- **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
-
-
-
-### **Record Search**
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
-### **List View Retrieval**
-
-
-
- **Description:** Get Contact records from a specific List View.
-
- **Parameters:**
-
- * `listViewId` (string, required): List View ID
- * `paginationParameters` (object, optional): Pagination settings with pageCursor
-
-
-
- **Description:** Get Lead records from a specific List View.
-
- **Parameters:**
-
- * `listViewId` (string, required): List View ID
- * `paginationParameters` (object, optional): Pagination settings with pageCursor
-
-
-
- **Description:** Get Opportunity records from a specific List View.
-
- **Parameters:**
-
- * `listViewId` (string, required): List View ID
- * `paginationParameters` (object, optional): Pagination settings with pageCursor
-
-
-
- **Description:** Get Task records from a specific List View.
-
- **Parameters:**
-
- * `listViewId` (string, required): List View ID
- * `paginationParameters` (object, optional): Pagination settings with pageCursor
-
-
-
- **Description:** Get Account records from a specific List View.
-
- **Parameters:**
-
- * `listViewId` (string, required): List View ID
- * `paginationParameters` (object, optional): Pagination settings with pageCursor
-
-
-
- **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
-
-
-
-### **Custom Fields**
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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
-
-
-
- **Description:** Deploy custom fields for any object type.
-
- **Note:** This is a flexible tool for creating custom fields on custom or unknown object types.
-
-
-
-### **Advanced Operations**
-
-
-
- **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'")
-
-
-
- **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")
-
-
-
- **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.
-
-
-
-## 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
-
-
- Contact our support team for assistance with Salesforce integration setup or
- troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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**
-
-
-
- **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)
-
-
-
- **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)
-
-
-
- **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
-
-
-
- **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
-
-
-
-### **Order Management**
-
-
-
- **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)
-
-
-
- **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
-
-
-
- **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
-
-
-
- **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)
-
-
-
-### **Product Management (REST API)**
-
-
-
- **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)
-
-
-
- **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
-
-
-
- **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
-
-
-
-### **Product Management (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
-
-
-
- **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
-
-
-
- **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
-
-
-
-## 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
-
-
- Contact our support team for assistance with Shopify integration setup or
- troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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**
-
-
-
- **Description:** List all members in a Slack channel.
-
- **Parameters:**
-
- * No parameters required - retrieves all channel members
-
-
-
- **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
-
-
-
- **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
-
-
-
-### **Channel Management**
-
-
-
- **Description:** List all channels in your Slack workspace.
-
- **Parameters:**
-
- * No parameters required - retrieves all accessible channels
-
-
-
-### **Messaging**
-
-
-
- **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)
-
-
-
- **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)
-
-
-
-### **Search & Discovery**
-
-
-
- **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
-
-
-
-## 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
-
-
- Contact our support team for assistance with Slack integration setup or
- troubleshooting.
-
-
-
-# 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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**
-
-
-
- **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}`)
-
-
-
- **Description:** Retrieve a specific customer by their Stripe customer ID.
-
- **Parameters:**
-
- * `idGetCustomer` (string, required): The Stripe customer ID to retrieve
-
-
-
- **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)
-
-
-
- **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
-
-
-
-### **Subscription Management**
-
-
-
- **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
-
-
-
- **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)
-
-
-
-### **Product Management**
-
-
-
- **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
-
-
-
- **Description:** Retrieve a specific product by its Stripe product ID.
-
- **Parameters:**
-
- * `productId` (string, required): The Stripe product ID to retrieve
-
-
-
- **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)
-
-
-
-### **Financial Operations**
-
-
-
- **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
-
-
-
- **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
-
-
-
-## 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
-
-
- To use integrations with `Agent(apps=[])`, you must set the
- `CREWAI_PLATFORM_INTEGRATION_TOKEN` environment variable with your Enterprise
- Token.
-
-
-```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**
-
-
-
- **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
-
-
-
- **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
-
-
-
- **Description:** Retrieve a specific ticket by its ID.
-
- **Parameters:**
-
- * `ticketId` (string, required): The ticket ID to retrieve (e.g., "35436")
-
-
-
- **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
-
-
-
- **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
-
-
-
-### **User Management**
-
-
-
- **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
-
-
-
- **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
-
-
-
- **Description:** Retrieve a specific user by their ID.
-
- **Parameters:**
-
- * `userId` (string, required): The user ID to retrieve
-
-
-
- **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
-
-
-
-### **Administrative Tools**
-
-
-
- **Description:** Retrieve all standard and custom fields available for tickets.
-
- **Parameters:**
-
- * `paginationParameters` (object, optional): Pagination settings
- * `pageCursor` (string, optional): Page cursor for pagination
-
-
-
- **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
-
-
-
-## 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.
-
-
-
-
-
-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
-
-
-
- Deploy your crews to a managed infrastructure with a few clicks
-
-
-
- Access your deployed crews via REST API for integration with existing
- systems
-
-
-
- Monitor your crews with detailed execution traces and logs
-
-
-
- Publish and install tools to enhance your crews' capabilities
-
-
-
- Stream real-time events and updates to your systems
-
-
-
- Create and customize crews using a no-code/low-code interface
-
-
-
-## Deployment Options
-
-
-
- Connect directly to your GitHub repositories to deploy code
-
-
-
- Deploy crews created through the no-code Crew Studio interface
-
-
-
- Use the CrewAI CLI for more advanced deployment workflows
-
-
-
-## Getting Started
-
-
-
- Create your account at [app.crewai.com](https://app.crewai.com)
-
-
- Sign Up
-
-
-
-
- Use code or Crew Studio to build your crew
-
-
- Build Crew
-
-
-
-
- Deploy your crew to the Enterprise platform
-
-
- Deploy Crew
-
-
-
-
- Integrate with your crew via the generated API endpoints
-
-
- Use the Crew API
-
-
-
-
-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 that `allow_code_execution` parameter defaults to `False`.
-
-
-## 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:
-
-
-
- The agent analyzes the task and determines that code execution is necessary.
-
-
-
- It formulates the Python code needed to solve the problem.
-
-
-
- The code is sent to the internal code execution tool (`CodeInterpreterTool`).
-
-
-
- The agent interprets the result and incorporates it into its response or uses it for further problem-solving.
-
-
-
-## 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
-)
-```
-
-
- Either `manager_agent` or `manager_llm` must be set when using the hierarchical process.
-
-
-
-# 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
-
-
-
- ```python theme={null}
- from crewai_tools import DallETool
- ```
-
-
-
- ```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
- )
- ```
-
-
-
-## 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.
-
-
-
-
-
-## 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
-
-
-
- The agent executes the task using the tool provided.
-
-
-
- The tool generates the output, which is captured as the task result.
-
-
-
- The agent may reflect and take learnings from the tool but the output is not modified.
-
-
-
- The tool output is returned as the task result without any modifications.
-
-
-
-
-# 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.
-
-
- The hierarchical process is designed to leverage advanced models like GPT-4, optimizing token usage while handling complex tasks with greater efficiency.
-
-
-## 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.
-
-
- 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.
-
-
-
- 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.
-
-
-```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,
-)
-```
-
-
- For more details on creating and customizing a manager agent, check out the [Custom Manager Agent documentation](/en/learn/custom-manager-agent).
-
-
-### 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
-
-
- The `@human_feedback` decorator requires **CrewAI version 1.8.0 or higher**. Make sure to update your installation before using this feature.
-
-
-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"`.
-
-
- 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.
-
-
-
- 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.
-
-
-## 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'}")
-```
-
-
- 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.
-
-
-## Complete Example: Content Approval Workflow
-
-Here's a full example implementing a content review and approval workflow with a revision loop:
-
-
- ```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
- ```
-
-
-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!"
-```
-
-
- 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.
-
-
-### 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
-```
-
-
- 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`.
-
-
-### 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.
-
-
- `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.
-
-
-## 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 | - |
-
-
- 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.
-
-
-## Setting Up Webhook-Based HITL Workflows
-
-
-
- Set up your task with human input enabled:
-
-
-
-
-
-
-
- When kicking off your crew, include a webhook URL for human input:
-
-
-
-
-
- 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"
- }
- }
- }'
- ```
-
-
-
- Once the crew completes the task requiring human input, you'll receive a webhook notification containing:
-
- * Execution ID
- * Task ID
- * Task output
-
-
-
- The system will pause in the `Pending Human Input` state. Review the task output carefully.
-
-
-
- Call the resume endpoint of your crew with the following information:
-
-
-
-
-
-
- **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.
-
-
- 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"
- }'
- ```
-
-
- **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.
-
-
- 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.
-
-
-
- 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.
-
-
-
- When you submit positive feedback, the execution will proceed to the next 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
-
-
- 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)
-
-
-
-# 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` |
-
-
- For high-concurrency workloads, `akickoff()` is recommended as it uses native async for task execution, memory operations, and knowledge retrieval.
-
-
-## 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.
-
-
- 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.
-
-
-## 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).
-
-
- 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).
-
-
-## Changing the LLM
-
-To use a different LLM with your CrewAI agents, you have several options:
-
-
-
- Pass the model name as a string when initializing the agent:
-
-
- ```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'
- )
- ```
-
-
-
-
- For more detailed configuration, use the LLM class:
-
-
- ```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
- )
- ```
-
-
-
-
-## 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:
-
-
-
-
- ```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/
- ```
-
-
-
-
-
- ```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, ...)
- ```
-
-
-
-
-## Using Local Models with Ollama
-
-For local models like those provided by Ollama:
-
-
-
- [Click here to download and install Ollama](https://ollama.com/download)
-
-
-
- For example, run `ollama pull llama3.2` to download the model.
-
-
-
-
- ```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")
- )
- ```
-
-
-
-
-## 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.
-
-
- This guide focuses on strategic thinking rather than specific model
- recommendations, as the LLM landscape evolves rapidly.
-
-
-## Quick Decision Framework
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
-## 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.
-
-
-
- * **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.
-
-
-
- * **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.
-
-
-
- * **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.
-
-
-
-### 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
-## Strategic Configuration Patterns
-
-### a. Multi-Model Approach
-
-
- Use different models for different purposes within the same crew to optimize
- both performance and cost.
-
-
-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
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
-## 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
-### b. Task Sequencing Strategy
-
-
-
- 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.
-
-
-
- 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.
-
-
-
-## Optimizing Agent Configuration for LLM Performance
-
-### a. Role-Driven LLM Selection
-
-
- Generic agent roles make it impossible to select the right LLM. Specific roles
- enable targeted model optimization.
-
-
-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
-
-
- Strategic backstories multiply your chosen LLM's effectiveness by providing
- domain-specific context that generic prompting cannot achieve.
-
-
-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:
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
-### When to Use Different Model Types
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
-## Common CrewAI Model Selection Pitfalls
-
-
-
- **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"))
- ```
-
-
-
- **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
- ```
-
-
-
- **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
- )
- ```
-
-
-
- **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
- ```
-
-
-
- **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.
-
-
-
-## Testing and Iteration Strategy
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
-
- 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.
-
-
-### 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.
-
-
-
-
-
-**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!
-
-
- 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.
-
-
-## Key Principles Summary
-
-
-
- Choose models based on what the task actually requires, not theoretical capabilities or general reputation.
-
-
-
- Align model strengths with agent roles and responsibilities for optimal
- performance.
-
-
-
- Maintain coherent model selection strategy across related components and
- workflows.
-
-
-
- Validate choices through real-world usage rather than benchmarks alone.
-
-
-
- Start simple and optimize based on actual performance and needs.
-
-
-
- Balance performance requirements with cost and complexity constraints.
-
-
-
-
- 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.
-
-
-## Current Model Landscape (June 2025)
-
-
- **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.
-
-
-### 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:
-
-
- 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.
-
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
-### Selection Framework for Current Models
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
- **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.
-
-
-
-### 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.
-
-
- **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.
-
-
-### Practical Implementation Strategy
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- Use different models for different agents based on their roles.
- High-capability models for managers and complex tasks, efficient models for
- routine operations.
-
-
-
- Track performance metrics relevant to your use case and be prepared to adjust model selections as new models are released or pricing changes.
-
-
-
-
-# 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
-
-
-
- Learn how to execute tasks in a sequential order for structured workflows.
-
-
-
- Implement hierarchical task execution with manager agents overseeing workflows.
-
-
-
- Create dynamic workflows with conditional task execution based on outcomes.
-
-
-
- Execute crews asynchronously for improved performance and concurrency.
-
-
-
-### Agent Development
-
-
-
- Learn how to customize agent behavior, roles, and capabilities.
-
-
-
- Build agents that can write, execute, and debug code automatically.
-
-
-
- Create agents that can process text, images, and other media types.
-
-
-
- Implement custom manager agents for complex hierarchical workflows.
-
-
-
-## Advanced Features
-
-### Workflow Control
-
-
-
- Integrate human oversight and intervention into agent workflows.
-
-
-
- Allow human input during task execution for dynamic decision making.
-
-
-
- Replay and resume tasks from previous crew executions.
-
-
-
- Execute crews multiple times with different inputs efficiently.
-
-
-
-### Customization & Integration
-
-
-
- Integrate custom language models and providers with CrewAI.
-
-
-
- Configure and manage connections to various LLM providers.
-
-
-
- Build custom tools to extend agent capabilities.
-
-
-
- Use Python annotations for cleaner, more maintainable code.
-
-
-
-## Specialized Applications
-
-### Content & Media
-
-
-
- Generate images using DALL-E integration with your agents.
-
-
-
- Integrate existing agents and models into CrewAI workflows.
-
-
-
-### Tool Management
-
-
-
- Configure tools to return their output directly as task results.
-
-
-
-## 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.
-
-
- 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.
-
-
-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:
-
-
-
-
-
-
-
- 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
- ```
-
-
-
-
- Ensure `crewai` is installed and configured correctly in your development environment.
-
-
-### Replaying from a Task Programmatically
-
-To replay from a task programmatically, use the following steps:
-
-
-
- Specify the `task_id` and input parameters for the replay process.
-
-
-
- Execute the replay command within a try-except block to handle potential errors.
-
-
- ```python Code theme={null}
- def replay():
- """
- Replay the crew execution from a specific task.
- """
- 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}")
- ```
-
-
-
-
-## 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.
-
-
- `@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.
-
-
-### 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.
-
-[](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.
-
-
-
-### 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:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-### 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=
-export DD_SITE=
-export DD_LLMOBS_ENABLED=true
-export DD_LLMOBS_ML_APP=
-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=
-export ANTHROPIC_API_KEY=
-export 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.
-
-
-
-
-
-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.
-
-
-
-
-
-## 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.
-
-
-
-## 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.
-
-
-
-
-
-**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
-
-
-
- Install the LangDB client with CrewAI feature flag:
-
- ```bash theme={null}
- pip install 'pylangdb[crewai]'
- ```
-
-
-
- Configure your LangDB credentials:
-
- ```bash theme={null}
- export LANGDB_API_KEY=""
- export LANGDB_PROJECT_ID=""
- export LANGDB_API_BASE_URL='https://api.us-east-1.langdb.ai'
- ```
-
-
-
- Import and initialize LangDB before configuring your CrewAI code:
-
- ```python theme={null}
- from pylangdb.crewai import init
- # Initialize LangDB
- init()
- ```
-
-
-
- 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")}
- )
- ```
-
-
-
-## 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=""
-export LANGDB_PROJECT_ID=""
-export LANGDB_API_BASE_URL='https://api.us-east-1.langdb.ai'
-
-# Additional API keys (optional)
-export 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:
-
-
-
-
-
-### 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
-
-
-
- Official LangDB documentation and guides
-
-
-
- Step-by-step tutorials for building AI agents
-
-
-
- Complete CrewAI integration examples
-
-
-
- Access your traces and analytics
-
-
-
- Browse 350+ available language models
-
-
-
- Self-hosted options and enterprise capabilities
-
-
-
-## 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.
-
-[](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.
-
-
-
-*[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.
-
-
-
-
-
-
-
-## Setup Instructions
-
-
-
- Sign up by visiting [https://langtrace.ai/signup](https://langtrace.ai/signup).
-
-
-
- Set the project type to `CrewAI` and generate an API key.
-
-
-
- Use the following command:
-
- ```bash theme={null}
- pip install langtrace-python-sdk
- ```
-
-
-
- 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='')
-
- # Now import CrewAI modules
- from crewai import Agent, Task, Crew
- ```
-
-
-
-### 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.
-
-
-
- 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.
-
-
-
-
-
- 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.
-
-
-
-
-
- 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.
-
-
-
-### Observability & Evals
-
-Maxim AI provides comprehensive observability & evaluation for your CrewAI agents, helping you understand exactly what's happening during each execution.
-
-
-
- Track your agent’s complete lifecycle, including tool calls, agent trajectories, and decision flows effortlessly.
-
-
-
-
-
- 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
-
-
-
-
-
-
- Evaluate captured logs automatically from the UI based on filters and sampling
-
-
-
-
-
- Use human evaluation or rating to assess the quality of your logs and evaluate them.
-
-
-
-
-
- Evaluate any component of your trace or log to gain insights into your agent’s behavior.
-
-
-
-
- ***
-
-
-
- Set thresholds on **error**, **cost, token usage, user feedback, latency** and get real-time alerts via Slack or PagerDuty.
-
-
-
-
-
- Visualize Traces over time, usage metrics, latency & error rates with ease.
-
-
-
-
-
-## 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
-
-
-
-## 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
-
-
-
- Official CrewAI documentation
-
-
-
- Official Maxim documentation
-
-
-
- Maxim Github
-
-
-
-
-# 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.
-
-
-
-### 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
-
-
-
- ```shell theme={null}
- # The crewAI integration is available in mlflow>=2.19.0
- pip install mlflow
- ```
-
-
-
- ```shell theme={null}
- # This process is optional, but it is recommended to use MLflow tracking server for better visualization and broader features.
- mlflow server
- ```
-
-
-
- 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.
-
-
-
- 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.
-
-
-
-
-
-
-
-
-# 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
-
-
-
-
-
-The best UX to view a CrewAI trace. Post comments anywhere you want. Use AI to debug.
-
-
-
-
-
-
-
-## 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
-
-
-
- Visit [neatlogs.com](https://neatlogs.com/?utm_source=crewAI-docs), create a project, copy the API key.
-
-
-
- ```bash theme={null}
- pip install neatlogs
- ```
-
- (Latest version 0.8.0, Python 3.8+; MIT license)
-
-
-
- Before starting Crew agents, add:
-
- ```python theme={null}
- import neatlogs
- neatlogs.init("YOUR_PROJECT_API_KEY")
- ```
-
- Agents run as usual. Neatlogs captures everything automatically.
-
-
-
-## 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)
-
-
-
-### ⚙️ CrewAI Integration (30 s)
-
-
-
-## 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.
-
-
-
-
-
-
-
-
-
-### 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
-
-
-
-
-
- ```shell theme={null}
- git clone git@github.com:openlit/openlit.git
- ```
-
-
-
- From the root directory of the [OpenLIT Repo](https://github.com/openlit/openlit), Run the below command:
-
- ```shell theme={null}
- docker compose up -d
- ```
-
-
-
-
-
- ```shell theme={null}
- pip install openlit
- ```
-
-
-
- Add the following two lines to your application code:
-
-
-
- ```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)
- ```
-
-
-
- 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())
- ```
-
-
-
- Refer to OpenLIT [Python SDK repository](https://github.com/openlit/openlit/tree/main/sdk/python) for more advanced configurations and use cases.
-
-
-
- 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`
-
-
-
-
-
-
-
-
-
-
-# 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.
-
-
-
-
-
-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.
-
-
-
- ```shell theme={null}
- pip install crewai crewai-tools opik --upgrade
- ```
-
-
-
- ```python theme={null}
- import opik
- opik.configure(use_local=False)
- ```
-
-
-
- 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: ")
- ```
-
-
-
- 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)
-
-
-
-## 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
-
-
-
- End-to-end tracing for CrewAI workflows with automatic agent interaction capture.
-
-
-
- OpenTelemetry-native monitoring with cost tracking and performance analytics.
-
-
-
- Machine learning lifecycle management with tracing and evaluation capabilities.
-
-
-
- LLM engineering platform with detailed tracing and analytics.
-
-
-
- Open-source observability for LLMs and agent frameworks.
-
-
-
- AI observability platform for monitoring and troubleshooting.
-
-
-
- AI gateway with comprehensive monitoring and reliability features.
-
-
-
- Debug, evaluate, and monitor LLM applications with comprehensive tracing.
-
-
-
- Weights & Biases platform for tracking and evaluating AI applications.
-
-
-
-### Evaluation & Quality Assurance
-
-
-
- Comprehensive evaluation platform for LLM outputs and agent behaviors.
-
-
-
-## 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
-
-
-
-## 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
-
-
-
- ```bash theme={null}
- pip install -U crewai portkey-ai
- ```
-
-
-
- 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.
-
-
-
- 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
- )
-
- ```
-
-
- **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).
-
-
-
-
-## Production Features
-
-### 1. Enhanced Observability
-
-Portkey provides comprehensive observability for your CrewAI agents, helping you understand exactly what's happening during each execution.
-
-
-
-
-
-
-
- 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
- )
- )
- ```
-
-
-
-
-
-
-
- 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.
-
-
-
-
-
-
-
- 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.
-
-
-
-
-
-
-
- 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.
-
-
-
-### 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.
-
-
-
- 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.
-
-
-
- Prevent your agents from hanging. Set timeouts to ensure you get responses (or can fail gracefully) within your required timeframes.
-
-
-
- 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.
-
-
-
- Keep running even if your primary provider fails. Automatically switch to backup providers to maintain availability.
-
-
-
- Spread requests across multiple API keys or providers. Great for high-volume crew operations and staying within rate limits.
-
-
-
-### 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.
-
-
- 
-
-
-
-
- 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.
-
-
-
- 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
- )
- ```
-
-
-
- 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"
- }
- )
- ```
-
-
-
- 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"
- }
- )
- ```
-
-
-
-
- Learn more about Portkey's prompt management features
-
-
-### 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
-
-
- Explore Portkey's guardrail features to enhance agent safety
-
-
-### 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:
-
-
-
-
-
-This enables:
-
-* Per-user cost tracking and budgeting
-* Personalized user analytics
-* Team or organization-level metrics
-* Environment-specific monitoring (staging vs. production)
-
-
- Explore how to use custom metadata to enhance your analytics
-
-
-### 6. Caching for Efficient Crews
-
-Implement caching to make your CrewAI agents more efficient and cost-effective:
-
-
-
- ```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.
-
-
-
- ```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.
-
-
-
-### 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
-
-
- See the full list of LLM providers supported by Portkey
-
-
-## 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.
-
-
-
- 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
-
-
-
-
-
-
- Save your virtual key ID - you'll need it for the next step.
-
-
-
-
- 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
-
-
-
-
-
-
-
- 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
-
-
-
-
-
-
-
- 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 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
-
-
-
-
-
-
-
- ### 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.
-
-
- Configs can be updated anytime to adjust controls without affecting running applications.
-
-
-
-
- ### 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).
-
-
-
- ### 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
-
-
-
-
- ### Enterprise Features Now Available
-
- **Your CrewAI integration now has:**
-
- * Departmental budget controls
- * Model access governance
- * Usage tracking & attribution
- * Security guardrails
- * Reliability features
-
-
-## Frequently Asked Questions
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
-## Resources
-
-
-
-
Official CrewAI documentation
-
-
-
-
Get personalized guidance on implementing this integration
-
-
-
-
-# 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).
-
-
-
-## 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)
-
-
-
-### 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
-
-
-
- ```bash theme={null}
- pip install crewai
- ```
-
-
-
- 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)
-
-
-
-
-
- ```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
- )
- ```
-
-
-
-### 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:
-
-
-
-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.
-
-
-
-
-# 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.
-
-
-
-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
-
-
-
- ```shell theme={null}
- pip install crewai weave
- ```
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- ```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)
- ```
-
-
-
- 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
-
-
-
-
-
-
-
-## 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
-
-
- 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.
-
-
-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. |
-
-
- "No" in the "Defaulted" column indicates that this data is only collected when `share_crew` is set to `true`.
-
-
-### 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.
-
-
- 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.
-
-
-
-# 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
-
-
-
- Install `crewai[tools]` and `langchain-apify` using pip: `pip install 'crewai[tools]' langchain-apify`.
-
-
-
- Sign up to [Apify Console](https://console.apify.com/) and get your [Apify API token](https://console.apify.com/settings/integrations)..
-
-
-
- Set your Apify API token as the `APIFY_API_TOKEN` environment variable to enable the tool's functionality.
-
-
-
-## 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
-
-
- ```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)
-
-
-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**
-
-
-
- Run Apify actors for web scraping and automation tasks.
-
-
-
- Integrate with hundreds of apps and services through Composio.
-
-
-
- Automate browser interactions and web-based workflows.
-
-
-
- Expose Zapier Actions as CrewAI tools for automation across thousands of apps.
-
-
-
-## **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**
-
-
-
- Securely access hundreds of third-party tools like Linear, GitHub, Slack, and more through Merge's unified API.
-
-
-
- Invoke live CrewAI Platform automations, pass custom inputs, and poll for results directly from your agent.
-
-
-
- Call Amazon Bedrock Agents from your crews, reuse AWS guardrails, and stream responses back into the workflow.
-
-
-
-## **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
-
-
-
- Navigate to your crew's detail page in the CrewAI AMP dashboard and copy your Bearer Token from the Status tab.
-
-
-
- Use the `GET /inputs` endpoint to see what parameters your crew expects.
-
-
-
- Call `POST /kickoff` with your inputs to start the crew execution and receive
- a `kickoff_id`.
-
-
-
- Use `GET /{kickoff_id}/status` to check execution status and retrieve results.
-
-
-
-## 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 |
-
-
- You can find both token types in the Status tab of your crew's detail page in
- the CrewAI AMP dashboard.
-
-
-## 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
-
-
- **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.
-
-
-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:**
-
-
-
- Copy the cURL examples and replace the URL + token with your real values
-
-
-
- Import the examples into your preferred API testing tool
-
-
-
-**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?
-
-
-
- Get help with API integration and troubleshooting
-
-
-
- Manage your crews and view execution logs
-
-
-
-
-# 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
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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)
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## v0.121.1
-
- [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.121.1)
-
- Bug fixes and better docs
-
-
-
- ## 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
-
-
-
- ## v0.120.1
-
- [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.120.1)
-
- ## Whats New
-
- * Fixes Interpolation with hyphens
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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.
-
-
-
- ## 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
-
-
-
- ## 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.
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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.
-
-
-
- ## 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.
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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\_(..., ..., ...))
-
-
-
- ## v0.76.2
-
- [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.76.2)
-
- Updating crewai create commadn
-
-
-
- ## 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
-
-
-
- ## v0.75.1
-
- [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.75.1)
-
- new `--provider` option on crewai crewat
-
-
-
- ## 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 `
- * Ensure original embedding config works
- * Fix bugs
- * Update docs - Including adding Cerebras LLM example configuration to LLM docs
- * Drop unnecessary tests
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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 ` command
- * Add Git validations for publishing tools
- * fix: JSON encoding date objects
- * New Docs
- * Update README
- * Bug fixes
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## v0.63.6
-
- [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.63.6)
-
- * Updating projects templates
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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`
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## v0.41.1
-
- [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.41.1)
-
- * Fix bug with planning feature
-
-
-
- ## 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
-
-
-
- ## 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)
-
-
-
- ## v0.35.8
-
- [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.35.8)
-
- * fixing embechain dependency issue
-
-
-
- ## 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
-
-
-
- ## v0.35.5
-
- [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.35.5)
-
- * Fix embedchain dependency
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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)
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## v0.30.11
-
- [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.30.11)
-
- * Updating project generation template
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## v0.28.8
-
- [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/0.28.8)
-
- * updating version used on crewai CLI
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## v0.28.2
-
- [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.28.2)
-
- * Major long term memory fix
-
-
-
- ## v0.28.1
-
- [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.28.1)
-
- * Updating crewai-tools to 0.1.15
-
-
-
- ## 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
-
-
-
- ## 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**
-
-
-
- ## 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
-
-
-
- ## v0.22.4
-
- [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.22.4)
-
- Fixing template issues
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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)
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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.
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## v0.5.3
-
- [View release on GitHub](https://github.com/crewAIInc/crewAI/releases/tag/v0.5.3)
-
- * quick Fix for hierarchical manager
-
-
-
- ## 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
-
-
-
- ## 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.
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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).
-
-
-
- ## 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
-
-
-
- ## 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
-
-
-
- ## 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.
-
-
-
-# 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
-
-
-
- 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.
-
-
-
-
-
-
- 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.
-
-
-
- 7. In `CrewAI AMP > Settings > Defaults > Crew Studio LLM Settings`, set the new LLM Connection and model as defaults.
-
-
-
- 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.
-
-
-
-## 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
-
-
-
-### Installation and Setup
-
-
- Follow our standard installation guide to set up CrewAI CLI and create your
- first project.
-
-
-### Building Your Crew
-
-
- Follow our quickstart guide to create your first agent crew using YAML
- configuration.
-
-
-## Support and Resources
-
-For Enterprise-specific support or questions, contact our dedicated support team at [support@crewai.com](mailto:support@crewai.com).
-
-
- Book time with our team to learn more about Enterprise features and how they
- can benefit your organization.
-
-
-
-# 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
-
-
-
- Your organization should have ENTERPRISE OTEL SETUP enabled
-
-
-
- Your organization should have an OTEL collector setup or a provider like
- Datadog log intake setup
-
-
-
-## 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.
-
-
-
-
-
-
-# Deploy to AMP
-Source: https://docs.crewai.com/en/enterprise/guides/deploy-to-amp
-
-Deploy your Crew or Flow to CrewAI AMP
-
-
- 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.
-
-
-## Prerequisites
-
-
-
- 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.
-
-
-
- Your code should be in a GitHub repository (for GitHub integration
- method)
-
-
-
-
- **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.
-
-
-## 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.
-
-
-
- If you haven't already, install the CrewAI CLI:
-
- ```bash theme={null}
- pip install crewai[tools]
- ```
-
-
- The CLI comes with the main CrewAI package, but the `[tools]` extra ensures you have all deployment dependencies.
-
-
-
-
- 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!
-
-
-
- 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
- ```
-
-
-
- Track the deployment status with:
-
- ```bash theme={null}
- crewai deploy status
- ```
-
- For detailed logs of the build process:
-
- ```bash theme={null}
- crewai deploy logs
- ```
-
-
- The first deployment typically takes 10-15 minutes as it builds the container images. Subsequent deployments are much faster.
-
-
-
-
-## 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
-```
-
-## 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.
-
-
-
- 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).
-
-
-
- 1. Log in to [CrewAI AMP](https://app.crewai.com)
- 2. Click on the button "Connect GitHub"
-
-
-
-
-
-
-
- After connecting your GitHub account, you'll be able to select which repository to deploy:
-
-
-
-
-
-
-
- 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)
-
-
-
-
-
-
- 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.
-
-
-
-
- 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
-
-
-
-
-
- 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
-
-
-
-## 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.
-
-
-
- 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
-
-
-
- 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
-
-
-
- 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"
- # }
- ```
-
-
- If your automation was first created connected to Git, the API will automatically pull the latest changes from your repository before redeploying.
-
-
-
-
- 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
- ```
-
-
- Add `CREWAI_PAT` and `CREWAI_AUTOMATION_UUID` as repository secrets. For PR deployments, add a "deploy" label to trigger the workflow.
-
-
-
-
-## 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
-```
-
-
- The `uv.lock` file is required for all deployments. Without it, the platform
- cannot reliably install your dependencies.
-
-
-#### 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
-```
-
-
- This applies to standalone Crews AND crews embedded inside Flow projects.
- Every crew class needs the decorator.
-
-
-#### 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
-
-
- Contact our support team for assistance with deployment issues or questions
- about the AMP platform.
-
-
-
-# Enable Crew Studio
-Source: https://docs.crewai.com/en/enterprise/guides/enable-crew-studio
-
-Enabling Crew Studio on CrewAI AMP
-
-
- Crew Studio is a powerful **no-code/low-code** tool that allows you to quickly
- scaffold or build Crews through a conversational interface.
-
-
-## What is Crew Studio?
-
-Crew Studio is an innovative way to create AI agent crews without writing code.
-
-
-
-
-
-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:
-
-
-
- Go to the **LLM Connections** tab in your CrewAI AMP dashboard and create a new LLM connection.
-
-
- Feel free to use any LLM provider you want that is supported by CrewAI.
-
-
- 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
-
-
-
-
-
-
-
- Once you complete the setup, you'll see your new connection added to the list of available connections.
-
-
-
-
-
-
-
- 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.
-
-
-
-
-
-
-
-## Using Crew Studio
-
-Now that you've configured your LLM connection and default settings, you're ready to start using Crew Studio!
-
-
-
- Navigate to the **Studio** section in your CrewAI AMP dashboard.
-
-
-
- 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.
-
-
-
- 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.
-
-
-
- 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
-
-
-
- After deployment, test your crew with sample inputs to ensure it performs as expected.
-
-
-
-
- For best results, provide clear, detailed descriptions of what you want your
- crew to accomplish. Include specific inputs and expected outputs in your
- description.
-
-
-## Example Workflow
-
-Here's a typical workflow for creating a crew with Crew Studio:
-
-
-
- Start by describing your problem:
-
- ```md theme={null}
- I need a crew that can analyze financial news and provide investment recommendations
- ```
-
-
-
- Respond to clarifying questions from the Crew Assistant to refine your
- requirements.
-
-
-
- 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
-
-
-
- Approve the plan or request changes if necessary.
-
-
-
- Download the code for customization or deploy directly to the platform.
-
-
-
- Test your crew with sample inputs and refine as needed.
-
-
-
-
- Contact our support team for assistance with Crew Studio or any other CrewAI
- AMP features.
-
-
-
-# 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
-
-
-
- * 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
-
-
-
- * 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
-
-
-
-
-
-
-
- * 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
-
-
-
-
-
- * Configure any additional actions as needed - Review your workflow
- steps to ensure everything is set up correctly - Activate the workflow
-
-
-
-
-
-
-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
-
-
- The `@human_feedback` decorator requires **CrewAI version 1.8.0 or higher**.
-
-
-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:
-
-
-
- Responders receive email notifications and can reply directly—no login required.
-
-
-
- Review and respond to HITL requests in the Enterprise dashboard when preferred.
-
-
-
- Route requests to specific emails based on method patterns or pull from flow state.
-
-
-
- Configure automatic fallback responses when no human replies within the timeout.
-
-
-
-### 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
-
-
- For implementation details on the `@human_feedback` decorator, see the [Human Feedback in Flows](/en/learn/human-feedback-in-flows) guide.
-
-
-## 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:
-
-
-
- Set up your task with human input enabled:
-
-
-
-
-
-
-
- When kicking off your crew, include a webhook URL for human input:
-
-
-
-
-
-
-
- Once the crew completes the task requiring human input, you'll receive a webhook notification containing:
-
- * **Execution ID**
- * **Task ID**
- * **Task output**
-
-
-
- The system will pause in the `Pending Human Input` state. Review the task output carefully.
-
-
-
- Call the resume endpoint of your crew with the following information:
-
-
-
-
-
-
- **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.
-
-
- 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"
- }'
- ```
-
-
- **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.
-
-
- 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.
-
-
-
- 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.
-
-
-
- When you submit positive feedback, the execution will proceed to the next 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
-
-
-
- Explore the full Enterprise Flow HITL platform capabilities including email notifications, routing rules, auto-response, and analytics.
-
-
-
- Implementation guide for the `@human_feedback` decorator in your Flows.
-
-
-
-
-# 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
-
-
-
-
-
-### 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
-
-
-
-
-
-#### 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
-
-
-
-
-
-### 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
-
-
-
-
-
-### 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
-
-
-
-
-
-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
-
-
- Contact our support team for assistance with execution issues or questions
- about the Enterprise platform.
-
-
-
-# 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
-
-
- 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.
-
-
-## 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
-
-
-
- Standalone AI agent teams with `crew.py` defining agents and tasks. Best for focused, collaborative tasks.
-
-
-
- Orchestrated workflows with embedded crews in a `crews/` folder. Best for complex, multi-stage processes.
-
-
-
-| 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
-```
-
-
- The nested `src/project_name/` structure is critical for Crews.
- Placing files at the wrong level will cause deployment failures.
-
-
-### 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
-```
-
-
- 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.
-
-
-## 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:
-
-
-
- ```toml theme={null}
- [tool.crewai]
- type = "crew"
- ```
-
-
-
- ```toml theme={null}
- [tool.crewai]
- type = "flow"
- ```
-
-
-
-
- If the `type` doesn't match your project structure, the build will fail or
- the automation won't run correctly.
-
-
-### 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,
- )
-```
-
-
- If you forget the `@CrewBase` decorator, your deployment will fail with
- errors about missing agents or tasks configurations.
-
-
-### 4. Check Project Entry Points
-
-Both Crews and Flows have their entry point in `src/project_name/main.py`:
-
-
-
- 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()
- ```
-
-
-
- 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()
- ```
-
-
-
-### 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.)
-
-
- 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.
-
-
-
- Test your project locally with the same environment variables before deploying
- to catch configuration issues early.
-
-
-## 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:
-
-
- Follow the deployment guide to deploy your Crew or Flow to CrewAI AMP using
- the CLI, web interface, or CI/CD integration.
-
-
-
-# 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
-
-
- 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.
-
-
-## 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
-```
-
-
- 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.
-
-
-### 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
-```
-
-
- 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).
-
-
-## 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 |
-
-
- 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.
-
-
-## 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 |
-
-
- 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.
-
-
-## Setting Environment Variables in AMP
-
-Private registry credentials must be configured as environment variables in CrewAI AMP.
-You have two options:
-
-
-
- 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.
-
-
-
- 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
- ```
-
-
-
-
- **Never** commit credentials to your repository. Use AMP environment variables for all secrets.
- The `.env` file should be listed in `.gitignore`.
-
-
-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:
-
-
-
- AMP pulls your repository and reads `pyproject.toml` and `uv.lock`.
-
-
-
- UV reads `[tool.uv.sources]` to determine which index each package should come from.
-
-
-
- For each private index, UV looks up `UV_INDEX_{NAME}_USERNAME` and `UV_INDEX_{NAME}_PASSWORD`
- from the environment variables you configured in AMP.
-
-
-
- UV downloads and installs all packages — both public (from PyPI) and private (from your registry).
-
-
-
- Your crew or flow starts with all dependencies available.
-
-
-
-## 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
-
-
-
- Verify project structure and dependencies before deploying.
-
-
-
- Deploy your crew or flow and configure environment variables.
-
-
-
- Update environment variables and push changes to a running deployment.
-
-
-
-
-# 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
-
-
-
- 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.
-
-
-
-
-
-
-
-## 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.
-
-
-
- * Download and install Node.js from the official website: [https://nodejs.org/](https://nodejs.org/)
- * Choose the LTS (Long Term Support) version for stability.
-
-
-
- * 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
- ```
-
-
-
- ```bash theme={null}
- npm install react-dom
- ```
-
-
-
- * Move the downloaded file `CrewLead.jsx` into the `src` folder of your project,
-
-
-
- * 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 (
-
-
-
- );
- }
-
- export default App;
- ```
-
- * Replace `YOUR_API_BASE_URL` and `YOUR_BEARER_TOKEN` with the actual values for your API.
-
-
-
- * 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.
-
-
-
-## Customization
-
-You can then customise the `CrewLead.jsx` to add color, title etc
-
-
-
-
-
-
-
-
-
-## 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
-
-
-
-## 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
-
-
-
- In the CrewAI dashboard, navigate to the **Triggers** section.
-
-
-
-
-
- Verify that Slack is listed and is connected.
-
-
-
- * 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:
-
-
-
- * Press Enter or select the "**Kickoff crew**" option. A dialog box titled "**Kickoff an AI Crew**" will appear.
-
-
-
- * 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:
-
-
-
- * If your crew requires any inputs, click the "**Add Inputs**" button to provide them.
-
- The "**Add Inputs**" button is shown in the example above but is not yet clicked.
-
-
-
-
- * Once you've selected the crew and added any necessary inputs, click "**Kickoff**" to start the crew.
-
-
-
- * The crew will start executing and you will see the results in the Slack channel.
-
-
-
-
-
-
-## 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
-
-
-
- * 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:
-
-
-
-
-
-
-
- * On the Settings page, you'll see a `Members` tab - Click on the `Members`
- tab to access the **Members** page:
-
-
-
-
-
-
-
- * 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
-
-
-
- * You can repeat this process to invite multiple team members - Each invited
- member will receive an email invitation to join your organization
-
-
-
-## Adding Roles
-
-You can add roles to your team members to control their access to different parts of the platform.
-
-
-
- * 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:
-
-
-
-
-
-
-
- * On the Settings page, you'll see a `Roles` tab - Click on the `Roles` tab
- to access the **Roles** page.
-
-
-
-
-
- * 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.
-
-
-
-
-
-
-
- * In the Members section, you'll see a list of current members (including
- yourself)
-
-
-
-
-
- * 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
-
-
-
-
-
-
-
-## 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
-```
-
-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
-```
-
-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**
-
-
- Deletion is permanent. Deleted tools cannot be restored or re-installed.
-
-
-## 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`
-
-
- Contact our support team for assistance with API integration or
- troubleshooting.
-
-
-
-# Update Crew
-Source: https://docs.crewai.com/en/enterprise/guides/update-crew
-
-Updating a Crew on CrewAI AMP
-
-
- 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.
-
-
-## 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
-
-
-
-
-
-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
-
-
-
-
-
-
- Resetting your bearer token will invalidate the previous token immediately.
- Make sure to update any applications or scripts that are using the old token.
-
-
-## 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
-
-
-
-
-
-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
-
-
-
-
-
-5. Finally, click the `Update Deployment` button at the bottom of the page to apply the changes
-
-
- Updating environment variables will trigger a new deployment, but this will
- only update the environment configuration and not the code itself.
-
-
-## 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
-
-
- If you encounter any issues after updating, you can view deployment logs in
- the platform or contact support for assistance.
-
-
-
- Contact our support team for assistance with updating your crew or
- troubleshooting deployment issues.
-
-
-
-# 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
-
-
-
- * Navigate to the CrewAI AMP dashboard
- * Look for the `/kickoff` section, which is used to start the crew execution
-
-
-
-
-
-
- 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)
-
-
-
- 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)
-
-
-
-
- 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`)
-
-
-
-
- * In the body, include the JSON content as configured in step 2
-
-
-
-
- * The crew will then kickoff at the pre-defined time.
-
-
-
- 1. Create a new flow in ActivePieces and name it
-
-
-
-
- 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
-
-
-
-
- * Configure the email to use crew webhook body text
-
-
-
-
-
-
-## 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.
-
-
-
- `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"
- }
- }
- ```
-
-
-
- `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"
- }
- }
- ```
-
-
-
- `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"
- }
- }
- ```
-
-
-
-
-# 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
-
-
-
- * In Zapier, create a new Zap.
-
-
-
-
-
-
-
-
-
-
-
- * Select `New Pushed Message` as the Trigger Event.
- * Connect your Slack account if you haven't already.
-
-
-
- * Add a new action step to your Zap.
- * Choose CrewAI+ as your action app and Kickoff as the Action Event
-
-
-
-
-
-
-
- * Connect your CrewAI AMP account.
- * Select the appropriate Crew for your workflow.
-
-
-
-
-
- * Configure the inputs for the Crew using the data from the Slack message.
-
-
-
- * Add another action step to format the text output from CrewAI AMP.
- * Use Zapier's formatting tools to convert the Markdown output to HTML.
-
-
-
-
-
-
-
-
-
-
-
- * 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.
-
-
-
-
-
-
-
- * Enter the text in your Slack channel
-
-
-
-
-
- * Select the 3 ellipsis button and then chose Push to Zapier
-
-
-
-
-
-
-
-
-
-
-
-
-
-## 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
-
-
-
- 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.
-
-
-
- The most up-to-date documentation for CrewAI is available on our official documentation website: [https://docs.crewai.com/](https://docs.crewai.com/)
- CrewAI Docs
-
-
-
- #### 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
-
-
-
- * **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
-
-
-
- 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.
-
-
-
- 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).
-
-
-
- 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
-
-
-
- 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
-
-
-
- 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:
- CrewAI Memory
-
-
-
- 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:
-
-
-
- ```python theme={null}
- from pydantic import BaseModel
-
- class User(BaseModel):
- name: str
- age: int
- ```
-
-
-
- ```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]
- )
- ```
-
-
-
- ```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
- )
- ```
-
-
-
- Here's a tutorial on how to consistently get structured outputs from your 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.
-
- CrewAI Tools Guide
-
-
-
- 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.
-
-
-
-
-# CrewAI Cookbooks
-Source: https://docs.crewai.com/en/examples/cookbooks
-
-Feature-focused quickstarts and notebooks for learning patterns fast.
-
-## Quickstarts & Demos
-
-
-
- Coordinate multiple agents on shared tasks. Includes notebook with end-to-end collaboration pattern.
-
-
-
- Teach agents to reason about multi-step plans before execution using the planning toolkit.
-
-
-
- Explore self-reflection loops, critique prompts, and structured thinking patterns.
-
-
-
-
-
- Apply task-level guardrails with retries, validation functions, and safe fallbacks.
-
-
-
- Connect CrewAI to Gemini with search grounding for factual, citation-rich outputs.
-
-
-
- Generate video recaps using Gemini multimodal LLM and CrewAI orchestration.
-
-
-
-
-
- View all notebooks and feature demos showcasing specific CrewAI capabilities.
-
-
-
- Missing a pattern? Drop a request in the community forum and we’ll expand the library.
-
-
-
-
- Use Cookbooks to learn a pattern quickly, then jump to Full Examples for production‑grade implementations.
-
-
-
-# CrewAI Examples
-Source: https://docs.crewai.com/en/examples/example
-
-Explore curated examples organized by Crews, Flows, Integrations, and Notebooks.
-
-## Crews
-
-
-
- Multi‑agent marketing campaign planning.
-
-
-
- Personalized surprise travel planning.
-
-
-
- CV‑to‑job matching with vector search.
-
-
-
- Automated job description creation.
-
-
-
- Multi‑agent team that designs and builds Python games.
-
-
-
- Candidate sourcing and evaluation.
-
-
-
- See the full list of crew examples.
-
-
-
-## Flows
-
-
-
- Multi‑crew content generation with routing.
-
-
-
- Automated email monitoring and replies.
-
-
-
- Lead qualification with human‑in‑the‑loop.
-
-
-
- Notes processing with integrations.
-
-
-
- Iterative self‑improvement workflows.
-
-
-
- Parallel chapter generation.
-
-
-
- See the full list of flow examples.
-
-
-
-## Integrations
-
-
-
- Integration with LangGraph framework.
-
-
-
- Using CrewAI with Azure OpenAI.
-
-
-
- NVIDIA ecosystem integrations.
-
-
-
- See all integration examples.
-
-
-
-## Notebooks
-
-
-
- Simple QA Crew + Flow.
-
-
-
- Interactive examples for learning and experimentation.
-
-
-
-
diff --git a/.opencode/skills/crewai/modules/agents.md b/.opencode/skills/crewai/modules/agents.md
deleted file mode 100644
index dced809..0000000
--- a/.opencode/skills/crewai/modules/agents.md
+++ /dev/null
@@ -1,18 +0,0 @@
-# Agents
-
-**作用**: 介绍 CrewAI 中 Agent 的概念、属性、创建方式和高级特性。
-
-**源文件**: `llms-full.md`
-**行号范围**: 1-1276
-
-**内容索引**:
-- Overview of an Agent - Agent 定义和核心能力 (行 6-22)
-- Agent Attributes - 完整属性表 (行 37-68)
-- Creating Agents (行 70-741):
- - YAML Configuration (推荐) (行 74-115)
- - Direct Code Definition (行 117-155)
- - 完整参数示例 (行 156-357)
- - Tools 配置 (行 358-365)
- - Context Management (行 366-543)
- - Structured Output (行 578-741)
-- CLI - 命令行工具 (行 742-1276)
diff --git a/.opencode/skills/crewai/modules/collaboration.md b/.opencode/skills/crewai/modules/collaboration.md
deleted file mode 100644
index 9683f5a..0000000
--- a/.opencode/skills/crewai/modules/collaboration.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# Collaboration
-
-**作用**: 介绍 Agent 间的协作机制,包括任务委托、层级管理和最佳实践。
-
-**源文件**: `llms-full.md`
-**行号范围**: 1277-1655
-
-**内容索引**:
-- Enable collaboration for agents - 启用协作 (行 1291-1323)
-- Delegation Tools - 委托工具 (行 1325-1343):
- - Delegate work to coworker (行 1326)
- - Ask question to coworker (行 1335)
-- Implementation Examples (行 1345-1445):
- - Collaborative agents 示例 (行 1345-1386)
- - Hierarchical crew 示例 (行 1447-1481)
-- Best Practices (行 1495-1597):
- - 角色定义 (行 1495-1514)
- - 任务依赖 (行 1525-1545)
- - 常见问题和解决方案 (行 1556-1597)
-- Collaboration Guidelines (行 1598-1655)
diff --git a/.opencode/skills/crewai/modules/crews.md b/.opencode/skills/crewai/modules/crews.md
deleted file mode 100644
index 3240073..0000000
--- a/.opencode/skills/crewai/modules/crews.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# Crews
-
-**作用**: 介绍 Crew 的概念、创建方式、执行流程和高级特性。
-
-**源文件**: `llms-full.md`
-**行号范围**: 1656-2658
-
-**内容索引**:
-- Crew Overview - Crew 定义 (行 1656-1891)
-- Example crew execution - 执行示例 (行 1892-1900)
-- Accessing crew output (行 1901-1918)
-- Save crew logs (行 1919-1938)
-- Usage metrics (行 1939-1954)
-- Execution Methods (行 1955-2024):
- - kickoff() - 同步执行 (行 1955-1988)
- - kickoff_for_each() - 批量执行 (行 1989-2010)
- - kickoff_async() - 异步执行 (行 1995-2024)
- - Streaming - 流式输出 (行 2025-2073)
-- Event Listeners - 事件监听器 (行 2074-2245)
-- Files - 文件处理 (行 2387-2658)
diff --git a/.opencode/skills/crewai/modules/flows.md b/.opencode/skills/crewai/modules/flows.md
deleted file mode 100644
index 8e97509..0000000
--- a/.opencode/skills/crewai/modules/flows.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Flows
-
-**作用**: 介绍 Flow 的概念、状态管理、流程控制和与 Crew 的集成。
-
-**源文件**: `llms-full.md`
-**行号范围**: 2659-3712
-
-**内容索引**:
-- Flow Overview - Flow 定义和用途 (行 2659-3293)
-- Structured Output - 结构化输出 (行 3294-3371)
-- Usage example (行 3372-3379)
-- Run the flow (行 3380-3538)
-- Streaming - 流式输出 (行 3539-3712)
diff --git a/.opencode/skills/crewai/modules/installation.md b/.opencode/skills/crewai/modules/installation.md
deleted file mode 100644
index b937a09..0000000
--- a/.opencode/skills/crewai/modules/installation.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Installation
-
-**作用**: 介绍 CrewAI 的安装、配置和项目创建。
-
-**源文件**: `llms-full.md`
-**行号范围**: 12844-14875
-
-**内容索引**:
-- Installation Guide - 安装指南 (行 12844-12944)
-- Creating a CrewAI Project - 项目创建 (行 12945-13047)
-- What is CrewAI? - 框架介绍 (行 13053-13179)
-- MCP Integration - MCP 集成 (行 13763-14450)
-- Quickstart Guide - 快速开始 (行 14876-15252)
diff --git a/.opencode/skills/crewai/modules/knowledge.md b/.opencode/skills/crewai/modules/knowledge.md
deleted file mode 100644
index d6cc20d..0000000
--- a/.opencode/skills/crewai/modules/knowledge.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# Knowledge
-
-**作用**: 介绍 Knowledge 的概念、知识源、向量存储和 RAG 集成。
-
-**源文件**: `llms-full.md`
-**行号范围**: 3713-4838
-
-**内容索引**:
-- Knowledge Overview - 知识管理概念 (行 3713-3750)
-- Vector Stores - 向量存储 (行 3751-3780):
- - ChromaDB (默认) (行 3751-3755)
- - Qdrant (行 3756-3760)
-- Knowledge Sources (行 3781-3952):
- - 创建知识源 (行 3781-3824)
- - Web content (行 3825-3835)
- - Agent-level vs Crew-level (行 3953-4000)
-- Advanced Usage (行 4001-4838)
diff --git a/.opencode/skills/crewai/modules/llms.md b/.opencode/skills/crewai/modules/llms.md
deleted file mode 100644
index 65de55d..0000000
--- a/.opencode/skills/crewai/modules/llms.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# LLMs
-
-**作用**: 介绍 LLM 配置、多模型支持、自定义 LLM 和最佳实践。
-
-**源文件**: `llms-full.md`
-**行号范围**: 4839-6469
-
-**内容索引**:
-- LLM Overview - LLM 配置概念 (行 4839-6281)
-- Supported Providers - 支持的 LLM 提供商 (行 6282-6469)
-- Custom LLM Integration (行 6990-7496)
diff --git a/.opencode/skills/crewai/modules/memory.md b/.opencode/skills/crewai/modules/memory.md
deleted file mode 100644
index fcd2a5c..0000000
--- a/.opencode/skills/crewai/modules/memory.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# Memory
-
-**作用**: 介绍 Memory 的概念、类型、配置和使用场景。
-
-**源文件**: `llms-full.md`
-**行号范围**: 6470-7341
-
-**内容索引**:
-- Memory Overview - 记忆系统概念 (行 6470-7341)
-- Memory Types - 记忆类型 (行 6470-7341)
-- Configuration and Usage (行 6470-7341)
diff --git a/.opencode/skills/crewai/modules/planning.md b/.opencode/skills/crewai/modules/planning.md
deleted file mode 100644
index bb202a5..0000000
--- a/.opencode/skills/crewai/modules/planning.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# Planning
-
-**作用**: 介绍 Planning 功能、任务规划和自动化流程设计。
-
-**源文件**: `llms-full.md`
-**行号范围**: 7342-7729
-
-**内容索引**:
-- Planning Overview - 任务规划概念 (行 7342-7571)
-- Flow-First Mindset - 流程优先思维 (行 7572-7729)
diff --git a/.opencode/skills/crewai/modules/quickstart-tools.md b/.opencode/skills/crewai/modules/quickstart-tools.md
deleted file mode 100644
index d99613d..0000000
--- a/.opencode/skills/crewai/modules/quickstart-tools.md
+++ /dev/null
@@ -1,52 +0,0 @@
-# Quickstart & Tools Reference
-
-**作用**: 快速开始指南和完整的工具集成参考。
-
-**源文件**: `llms-full.md`
-**行号范围**: 14876-53221
-
-**内容索引**:
-- Quickstart Guide - 快速开始 (行 14876-15252)
-- Core Tools (行 15253-16645):
- - AI Mind Tool (行 15253-15338)
- - Code Interpreter (行 15373-15582)
- - DALL-E Tool (行 15583-15635)
- - LangChain Tool (行 15636-15694)
- - LlamaIndex Tool (行 15695-15841)
- - RAG Tool (行 15906-16595)
- - Vision Tool (行 16596-16645)
-- Cloud & Database Tools (行 16646-18003):
- - MongoDB Vector Search (行 16698-16864)
- - MySQL RAG Search (行 16865-16934)
- - NL2SQL Tool (行 16935-17104)
- - PG RAG Search (行 17105-17187)
- - Qdrant Vector Search (行 17188-17542)
- - SingleStore Search (行 17543-17602)
- - Snowflake Search (行 17603-17732)
- - Weaviate Vector Search (行 17806-17973)
-- File Tools (行 17974-18868):
- - CSV RAG Search (行 17974-18051)
- - Directory Read (行 18052-18105)
- - Directory RAG Search (行 18106-18175)
- - DOCX RAG Search (行 18176-18255)
- - File Read (行 18256-18300)
- - File Write (行 18301-18351)
- - JSON RAG Search (行 18352-18427)
- - MDX RAG Search (行 18428-18499)
- - OCR Tool (行 18500-18684)
- - PDF Text Writing (行 18685-18759)
- - PDF RAG Search (行 18760-18868)
- - TXT RAG Search (行 18869-18966)
- - XML RAG Search (行 18967-19044)
-- Search & Research Tools (行 19045-20000+):
- - Tools Overview (行 19045-19128)
- - Arxiv Paper Tool (行 19151-19262)
- - Brave Search (行 19263-19341)
- - Code Docs RAG Search (行 19360-19445)
- - Databricks SQL Query (行 19446-19524)
- - EXA Search Web Loader (行 19525-19579)
- - Github Search (行 19580-19666)
- - Linkup Search (行 19667-19737)
- - SerpApi Tools (行 19738-20000+)
-
-**注**: 此章节包含 50+ 工具的详细文档,按类别组织
diff --git a/.opencode/skills/crewai/modules/reasoning.md b/.opencode/skills/crewai/modules/reasoning.md
deleted file mode 100644
index b1007e1..0000000
--- a/.opencode/skills/crewai/modules/reasoning.md
+++ /dev/null
@@ -1,10 +0,0 @@
-# Reasoning
-
-**作用**: 介绍 Reasoning 功能、反思机制和任务执行前的规划。
-
-**源文件**: `llms-full.md`
-**行号范围**: 7730-7877
-
-**内容索引**:
-- Reasoning Overview - 推理和反思概念 (行 7730-7877)
-- Configuration (行 7730-7877)
diff --git a/.opencode/skills/crewai/modules/tasks.md b/.opencode/skills/crewai/modules/tasks.md
deleted file mode 100644
index a84fb18..0000000
--- a/.opencode/skills/crewai/modules/tasks.md
+++ /dev/null
@@ -1,20 +0,0 @@
-# Tasks
-
-**作用**: 介绍 Task 的概念、属性、创建方式、执行流程和高级特性。
-
-**源文件**: `llms-full.md`
-**行号范围**: 7878-9005
-
-**内容索引**:
-- Task Overview - Task 定义 (行 7883-7902)
-- Task Execution Flow - 执行流程 (行 7904-7919)
-- Task Attributes - 完整属性表 (行 7921-7994)
-- Creating Tasks (行 7995-8277):
- - YAML Configuration (行 7995-8125)
- - Direct Code Definition (行 8126-8161)
- - Markdown formatting (行 8162-8277)
-- Advanced Features (行 8278-9005):
- - Guardrails - 任务护栏 (行 8396-8547)
- - Callbacks (行 8548-8657)
- - Output files (行 8658-8773)
- - Execute tasks (行 9112-9227)
diff --git a/.opencode/skills/crewai/modules/tools.md b/.opencode/skills/crewai/modules/tools.md
deleted file mode 100644
index 3958514..0000000
--- a/.opencode/skills/crewai/modules/tools.md
+++ /dev/null
@@ -1,13 +0,0 @@
-# Tools
-
-**作用**: 介绍 Tool 的概念、创建方式、内置工具和自定义工具。
-
-**源文件**: `llms-full.md`
-**行号范围**: 9006-9292
-
-**内容索引**:
-- Tools Overview - 工具概念 (行 9006-9292)
-- Creating Custom Tools (行 9006-9292)
-- Built-in Tools List (行 9006-9292)
-
-**注**: 完整的工具集成文档见 Quickstart 章节 (行 14876-53221)
diff --git a/.opencode/skills/crewai/modules/training.md b/.opencode/skills/crewai/modules/training.md
deleted file mode 100644
index c7ff1be..0000000
--- a/.opencode/skills/crewai/modules/training.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# Training
-
-**作用**: 介绍 Training 功能、模型训练、微调和性能优化。
-
-**源文件**: `llms-full.md`
-**行号范围**: 9293-12843
-
-**内容索引**:
-- Training Overview - 训练概念 (行 9293-9494)
-- Training Methods (行 9495-12843)
-- Best Practices (行 9616-9725)
-- Custom Templates (行 9953-10166)
diff --git a/docs/plans/2026-02-26-social-data-model-redesign.md b/docs/plans/2026-02-26-social-data-model-redesign.md
deleted file mode 100644
index 9f0cda1..0000000
--- a/docs/plans/2026-02-26-social-data-model-redesign.md
+++ /dev/null
@@ -1,651 +0,0 @@
-# Plan: social-app 数据库数据模型重设计(支持社交/事项/自动化)
-
-**Date:** 2026-02-26
-**Author:** AI Assistant
-**Status:** Draft
-
-## 枚举存储约定
-
-**统一使用枚举名称(字符串)存储,不使用整数值。**
-
-- 数据库层:`VARCHAR(20)` + `CHECK` 约束
-- 代码层:Python `Enum` 类继承 `str`
-- 优势:调试可读、易扩展(新增枚举值无需迁移旧数据)、ORM 友好
-
-```python
-class AgentType(str, Enum):
- INTENT_RECOGNITION = "INTENT_RECOGNITION"
- TASK_EXECUTION = "TASK_EXECUTION"
- RESULT_REPORTING = "RESULT_REPORTING"
-```
-
-```sql
--- Migration
-ALTER TABLE user_agents ADD CONSTRAINT chk_agent_type
- CHECK (agent_type IN ('INTENT_RECOGNITION', 'TASK_EXECUTION', 'RESULT_REPORTING'));
-```
-
-## Overview
-
-本方案面向 `social-app` 的下一阶段功能升级,重设计 PostgreSQL 数据模型,统一支持用户专属 agent、好友/群组协作、待处理消息、设置、可订阅且可授权编辑的日程事项、待办联动与自动化定时任务。目标是在 FastAPI + Flutter 协作场景下提供长期稳定的数据基础,降低后续 API 演进和跨端同步复杂度。
-
-## Requirements
-
-### Functional
-- [x] 每个用户有专属 agent,且模型可扩展到未来多 agent 能力
-- [x] 用户支持好友关系、群组创建与成员管理
-- [x] 用户支持 inbox/pending 待处理消息
-- [x] 用户支持个性化设置(偏好/隐私/通知)
-- [x] 用户支持“绑定日程的事项”,可多人订阅,且仅特定人可修改
-- [x] 用户支持待办事项(可由日程事项提取,也可手动创建)
-- [x] 用户支持自动化定时任务(循环触发)
-
-### Non-Functional
-- [x] 性能:核心读路径(inbox 列表、待办列表、事项列表)P95 < 150ms(单用户典型数据量)
-- [x] 安全:权限以后端业务授权为准;数据库层保留 RLS 防御边界
-- [x] 一致性:关键写路径(好友状态、权限变更、任务触发)使用事务保障
-- [x] 可演进:当前阶段采用重建库快速迭代;后续稳定后切换为增量迁移与灰度
-
-## Technical Approach
-
-采用“认证域(`auth.users`)+ 业务域(`public.*`)”分层建模。保持 `auth.users` 作为身份主键来源,业务表统一引用 `user_id UUID -> auth.users.id`。领域边界拆分为:Identity/Profile、Social Graph、Collaboration(事项/订阅/权限)、Inbox、Todo、Automation。通过“规范化主模型 + 局部物化/冗余快照”平衡一致性与查询性能。
-
-### Key Decisions
-
-| Decision | Rationale |
-|----------|-----------|
-| 用户与 agent 采用 1:1 主约束 + 可扩展结构 | 当前满足"每用户专属 agent",未来允许多 agent 形态演进 |
-| 记忆系统采用单表 + memory_type 区分 | user 类型可选 agent_id,work 类型必须绑定 agent_id |
-| 好友关系用单表双向规范化表示 | 避免 A-B / B-A 重复,降低去重成本 |
-| 事项权限采用 ACL 表而非仅 owner | 满足“仅特定人可修改”的协作场景 |
-| 待办采用主表 + 关联表 | `todos` + `todo_sources` 保证来源关系可校验 |
-| 自动化采用 Jobs 单表 + Sessions 关联 | `sessions` 通过 `session_type + job_id` 区分普通对话与自动化运行 |
-| inbox 采用单表接收者视角 | 发送者 + 消息类型 + 关联业务,一表搞定待处理消息 |
-
-## A. 设计原则与边界
-
-### 1) 核心实体与聚合边界
-- 用户聚合:`profiles`(含 settings JSONB), `user_agents`, `memories`
-- 社交聚合:`friendships`, `groups`, `group_members`
-- 协作事项聚合:`schedule_items`, `schedule_subscriptions`(当前仅用户主体)
-- 消息聚合:`inbox_messages`
-- 待办聚合:`todos`
-- 自动化聚合:`automation_jobs`
-
-### 2) 一致性分级
-- 强一致(同事务):好友关系状态迁移、群组成员角色变更、事项权限写入、定时任务抢占执行
-- 最终一致:inbox 衍生、待办同步、提醒派发(允许异步补偿)
-
-### 3) 多租户假设
-- 默认假设:单租户产品(同一业务库服务所有用户),以 `user_id` 做数据隔离
-- 扩展预留:各核心表可预留 `tenant_id UUID NULL`(需业务确认是否近期引入组织空间)
-
-## B. 领域模型与关系图(文字化)
-
-### 实体与关系
-- `auth.users (1) - (1) profiles`(settings 作为 JSONB 内嵌)
-- `auth.users (1) - (1) user_agents`
-- `auth.users (1) - (N) memories`
-- `user_agents (1) - (N) memories`(work 类型)
-- `auth.users (N) - (N) auth.users` 通过 `friendships`
-- `auth.users (1) - (N) groups`(创建者)
-- `groups (1) - (N) group_members`,`auth.users (1) - (N) group_members`
-- `auth.users (1) - (N) schedule_items`(创建者)
-- `schedule_items (1) - (N) schedule_subscriptions`,`auth.users (1) - (N) schedule_subscriptions`
-- `auth.users (1) - (N) inbox_messages`
-- `auth.users (1) - (N) todos`
-- `auth.users (1) - (N) automation_jobs`
-- `automation_jobs (1) - (N) sessions`(通过 `sessions.job_id` 关联)
-
-### 关键约束
-- 唯一性:
- - `user_agents.user_id` 唯一
- - `friendships(user_low_id, user_high_id)` 唯一
- - `group_members(group_id, user_id)` 唯一
- - `schedule_subscriptions(item_id, subscriber_id)` 唯一
-- CHECK:
- - `friendships`: `user_low_id < user_high_id` 且 `user_low_id <> user_high_id`
- - `schedule_subscriptions`: `permission BETWEEN 0 AND 7`
- - `memories`: `work` 类型必须有 `agent_id`,`user` 类型必须无 `agent_id`
- - `sessions`: `session_type/job_id` 组合一致
-- 外键:统一显式 `ON DELETE` 策略(见下)
-- 可空性:权限关键字段、状态字段默认 `NOT NULL`
-- 删除策略:
- - 用户删除:大部分 `CASCADE`(用户私有数据);跨用户协作数据优先软删
- - 事项删除:对子表 `CASCADE`;待办保留历史,改 `status = 'archived'`
-
-### 外键删除策略明细(必做)
-- `sessions.job_id -> automation_jobs.id`: `ON DELETE RESTRICT`
-- `todo_sources.todo_id -> todos.id`: `ON DELETE CASCADE`
-- `todo_sources.schedule_item_id -> schedule_items.id`: `ON DELETE CASCADE`
-- `inbox_messages.friendship_id -> friendships.id`: `ON DELETE CASCADE`
-- `inbox_messages.schedule_item_id -> schedule_items.id`: `ON DELETE CASCADE`
-- `inbox_messages.group_id -> groups.id`: `ON DELETE CASCADE`
-
-## C. 数据库表设计(PostgreSQL)
-
-以下为推荐主表(方案 1,规范化优先)。字段示例采用 `UUID + timestamptz + enum/text-check`。
-
-### 1) 用户与 agent
-
-#### `profiles`(已有,建议补齐)
-- PK: `id UUID` (`auth.users.id`)
-- 关键字段: `username`, `avatar_url`, `bio`
-- **新增 JSONB 字段**:
- - `settings JSONB`(用户自定义设置,含 `version`, `preferences`, `privacy`, `notification` 四大块)
-- 时间字段: `created_at`, `updated_at`, `deleted_at`
-- 索引:
- - `INDEX(username)`(允许重名,仅用于列表查询)
- - `GIN(settings)`(支持 JSONB 表达式查询)
- - 表达式索引:`(settings->'notification'->>'enabled')`(按需,对高频查询字段单独建)
-- 审计: `created_by`, `updated_by`(可等于 id)
-- 删除策略: 用户删除时 `CASCADE`
-
-#### `user_agents`
-- PK: `id UUID`
-- 关键字段:
- - `user_id UNIQUE`(每用户专属 agent)
- - `llm_id UUID NOT NULL`(关联绑定的 LLM 模型)
- - `agent_type VARCHAR(20) NOT NULL`(枚举限制:`INTENT_RECOGNITION` | `TASK_EXECUTION` | `RESULT_REPORTING`)
- - `config JSONB`(agent 配置参数)
-- 时间字段: `created_at`, `updated_at`, `deleted_at`
-- 状态字段: `status`(`active|paused|migrating`)
-- 索引:
- - `UNIQUE(user_id) WHERE deleted_at IS NULL`
- - `INDEX(status)`
- - `INDEX(agent_type)`
- - `GIN(config)`(按需)
-- 审计: `created_by`, `updated_by`
-
-#### `memories`
-- PK: `id UUID`
-- 关键字段:
- - `owner_id`(用户,NOT NULL)
- - `agent_id`(work 类型时必需)
- - `memory_type`(枚举:`user | work`)
- - `title`
- - `content`(JSONB,存储具体记忆结构)
- - `source`(`manual | agent | imported`)
-- 时间字段: `created_at`, `updated_at`
-- 状态字段: `status`(`active | disabled`)
-- 索引:
- - `INDEX(owner_id, memory_type, status)`
- - `INDEX(agent_id, memory_type, status)`
- - `GIN(content)`(支持 JSONB 内容查询)
-- 约束: `CHECK ((memory_type = 'work' AND agent_id IS NOT NULL) OR (memory_type = 'user' AND agent_id IS NULL))`
-
-**memory_type 说明**:
-| 类型 | agent_id | 说明 |
-|------|----------|------|
-| `user` | 可空 | 用户记忆:偏好、背景信息、实体等 |
-| `work` | 必需 | 工作记忆:长期运行后对工作流程的经验整理,避免重复错误 |
-
-**content JSONB 示例**:
-```json
-// 用户记忆
-{"type": "preference", "data": {"style": "concise", "language": "zh-CN"}}
-
-// 工作记忆
-{"type": "workflow_summary", "data": {"task": "代码审查", "learnings": ["优先检查安全漏洞", "关注性能热点"], "improvements": []}}
-```
-
-### 2) 社交关系
-
-#### `friendships`
-- PK: `id UUID`
-- 关键字段:
- - `user_low_id`(两者中较小的 UUID)
- - `user_high_id`(两者中较大的 UUID)
- - `initiator_id`(发起请求方的 user_id,用于追溯谁主动)
- - `status`, `requested_at`, `accepted_at`, `blocked_by`
-- 时间字段: `created_at`, `updated_at`
-- 状态字段: `status`(`pending|accepted|blocked|declined|canceled`)
-- 约束:
- - `CHECK(user_low_id < user_high_id)`(强制小值放 low,大值放 high,确保 A→B 和 B→A 是同一行)
- - `CHECK(initiator_id IN (user_low_id, user_high_id))`
- - `UNIQUE(user_low_id, user_high_id)`
-- 索引:
- - `INDEX(user_low_id, status)`
- - `INDEX(user_high_id, status)`
- - 部分索引 `INDEX(status) WHERE status='pending'`
-- 审计: `created_by`, `updated_by`
-
-**查询示例**:
-- 查询用户 A 的所有好友:`SELECT * FROM friendships WHERE user_low_id = A OR user_high_id = A`
-
-#### `groups`
-- PK: `id UUID`
-- 关键字段: `name`, `description`, `owner_id`
-- 时间字段: `created_at`, `updated_at`, `deleted_at`
-- 状态字段: `status`(`active|archived`)
-- 索引: `INDEX(owner_id, status)`
-- 审计: `created_by`, `updated_by`
-
-#### `group_members`
-- PK: `id UUID`
-- 关键字段:
- - `group_id`, `user_id`
- - `role`(枚举:`owner` | `admin` | `member`)
- - `join_source`(`invited|joined`)
- - `invited_by`, `joined_at`
-- 时间字段: `created_at`, `updated_at`, `removed_at`
-- 状态字段: `status`(`active|muted|removed`)
-- 约束: `UNIQUE(group_id, user_id)`
-- 索引:
- - `INDEX(group_id, role, status)`
- - `INDEX(user_id, status)`
-- 审计: `created_by`, `updated_by`
-
-**role 说明**:
-| role | 含义 |
-|------|------|
-| `owner` | 群主/创建者 |
-| `admin` | 管理员 |
-| `member` | 普通成员 |
-
-- 角色可升降:服务层变更 role 字段即可
-
-### 3) 用户设置(已合并至 profiles 表)
-
-用户设置采用 JSONB 内嵌方式,渐进式扩展无需改表结构:
-
-```json
-{
- "version": 1,
- "preferences": {
- "interface_language": "zh-CN",
- "ai_language": "zh-CN",
- "timezone": "Asia/Shanghai"
- },
- "privacy": {},
- "notification": {}
-}
-```
-- 索引策略:对高频查询字段使用表达式索引
-- 更新方式:服务层使用 JSONB merge 或字段级 UPDATE,避免读-改-写并发问题(建议用 `jsonb_set` 原子操作)
-
-### 4) 事项与订阅/权限
-
-#### `schedule_items`
-- PK: `id UUID`
-- 关键字段:
- - `owner_id`
- - `title`
- - `description`
- - `start_at`
- - `end_at`
- - `timezone`(用于将日程时间转换为用户本地时间显示)
- - `metadata`(JSONB,扩展字段)
- - `recurrence_rule`(可选,支持循环日程)
- - `source_type`(`manual | imported | agent_generated`)
-- 时间字段: `created_at`, `updated_at`
-- 状态字段: `status`(`active | completed | canceled | archived`)
-- 索引:
- - `INDEX(owner_id, start_at)`
- - `INDEX(status, start_at)`
-- 审计: `created_by`
-
-**metadata JSONB 示例**:
-```json
-{
- "color": "#FF6B6B",
- "location": "会议室A",
- "notes": "记得提前准备投影仪",
- "attachments": [
- {
- "name": "会议纪要.pdf",
- "url": "https://...",
- "visible_to": [],
- "type": "document"
- },
- {
- "name": "投影仪提醒",
- "visible_to": ["uuid1"],
- "type": "reminder",
- "content": "记得带投影仪"
- },
- {
- "name": "技术方案.docx",
- "url": "https://...",
- "visible_to": ["uuid2"],
- "type": "document",
- "note": "需要他确认预算"
- }
- ],
- "version": 1
-}
-```
-
-| type | 说明 | 特殊字段 |
-|------|------|----------|
-| document | 文档/文件 | url, note |
-| reminder | 提醒 | content |
-
-#### `schedule_subscriptions`
-- PK: `id UUID`
-- 关键字段:
- - `item_id`
- - `subscriber_id`
- - `permission`(INTEGER,用位运算存储权限组合,`NOT NULL DEFAULT 1`)
- - `notify_level`(`all | mentions | none`,`NOT NULL DEFAULT 'all'`)
-- 时间字段: `created_at`
-- 状态字段: `status`(`active | paused | unsubscribed`,`NOT NULL DEFAULT 'active'`)
-- 约束: `UNIQUE(item_id, subscriber_id)`
-- 约束补充: `CHECK(permission BETWEEN 0 AND 7)`(`view=1, invite=2, edit=4`,`0` 表示无权限)
-- 索引: `INDEX(subscriber_id, status)`, `INDEX(item_id, status)`
-- 审计: `created_by`
-
-**权柄说明(位运算)**:
-| 权柄 | 值 | 二进制 | 说明 |
-|------|-----|--------|------|
-| view | 1 | 001 | 查看事项详情 |
-| invite | 2 | 010 | 邀请其他人订阅此事项 |
-| edit | 4 | 100 | 修改事项内容、管理订阅 |
-
-- 权限检查:`permission & 2 = 2` 检查是否有 invite 权限
-- 权限添加:`permission | 2` 添加 invite 权限
-- 事项 owner 默认拥有全部权柄:`7`(111)
-- owner 权柄由服务层恒等判定为 `7`,不依赖 owner 是否在 `schedule_subscriptions` 中存在记录
-
-**当前版本边界**:
-- `schedule_subscriptions` 仅支持用户订阅(`subscriber_id -> auth.users.id`)
-- 事项协作暂不引入群主体授权
-
-### 5) 待处理消息(Inbox)
-
-#### `inbox_messages`
-- PK: `id UUID`
-- 关键字段:
- - `recipient_id`(接收者)
- - `sender_id`(发送者,系统消息可为 NULL)
- - `message_type`(枚举:`friend_request | calendar | system | group`)
- - `friendship_id`(可空,`friend_request` 时必填)
- - `schedule_item_id`(可空,`calendar` 时必填)
- - `group_id`(可空,`group` 时必填)
- - `content`(TEXT,消息内容,系统消息用)
-- 时间字段: `created_at`
-- 状态字段:
- - `is_read`(BOOLEAN,是否已读)
- - `status`(`pending | accepted | rejected | dismissed`)
-- 索引:
- - `INDEX(recipient_id, status, created_at DESC)`
- - 部分索引 `INDEX(recipient_id, created_at DESC) WHERE status='pending'`
-- 审计: `created_by`
-
-**message_type 与业务字段对应关系**:
-| message_type | 对应业务字段 |
-|--------------|-----------------|
-| friend_request | friendship_id -> friendships.id |
-| calendar | schedule_item_id -> schedule_items.id |
-| system | 三个业务字段均为 NULL(内容直接在 content) |
-| group | group_id -> groups.id |
-
-**说明**:一张表搞定,接收者视角,通过 `message_type + 对应业务字段` 直接定位要处理的业务,避免单列多态外键带来的引用不一致问题。
-
-**一致性约束(必做)**:
-- 使用 `CHECK` 保证不同 `message_type` 下仅允许对应业务字段非空(`system` 时业务字段全空)
-- 使用 `CHECK` 保证 `message_type='system'` 时 `sender_id IS NULL`,否则 `sender_id IS NOT NULL`
-- `friendship_id`、`schedule_item_id`、`group_id` 分别建立 FK,并显式声明 `ON DELETE` 策略
-
-### 6) 待办
-
-#### `todos`
-- PK: `id UUID`
-- 关键字段:
- - `owner_id`
- - `title`
- - `description`
- - `due_at`
- - `priority`(INTEGER,用于四象限:1=重要且紧急, 2=重要不紧急, 3=紧急不重要, 4=不重要不紧急)
-- 时间字段: `created_at`, `completed_at`
-- 状态字段: `status`(`pending | done | canceled`)
-- 索引:
- - `INDEX(owner_id, status, due_at)`
- - `INDEX(owner_id, created_at DESC)`
- - 部分索引 `INDEX(owner_id, due_at) WHERE status='pending'`
-- 审计: `created_by`
-
-#### `todo_sources`
-- PK: `id UUID`
-- 关键字段:
- - `todo_id`(FK -> todos.id)
- - `schedule_item_id`(FK -> schedule_items.id)
-- 时间字段: `created_at`
-- 约束: `UNIQUE(todo_id, schedule_item_id)`
-- 索引: `INDEX(todo_id)`, `INDEX(schedule_item_id)`
-
-**说明**:
-- 手动创建待办:不写 `todo_sources`
-- 从事项提取待办:写入 `todo_sources`,替代 JSONB 数组,保证来源关系可校验
-
-### 7) 自动化定时任务
-
-#### `automation_jobs`
-- PK: `id UUID`
-- 关键字段:
- - `owner_id`
- - `title`(任务标题)
- - `prompt`(AI 执行的 prompt)
- - `schedule_type`(枚举:`daily | weekly`)
- - `run_at`(首次运行时间)
- - `next_run_at`(下次运行时间,调度器扫描主字段)
- - `timezone`(时区,如 `Asia/Shanghai`)
- - `last_run_at`(最近运行时间,可空)
-- 时间字段: `created_at`, `updated_at`
-- 状态字段: `status`(`active | disabled`)
-- 索引: `INDEX(owner_id, status)`, `INDEX(status, next_run_at)`
-- 约束补充: `UNIQUE(id, owner_id)`(用于 `sessions(job_id, user_id)` 归属一致性外键)
-- 审计: `created_by`
-
-**说明**:定时任务执行时,在 sessions 表创建记录存储 AI 对话内容。
-
-### 8) 会话表扩展(已有 sessions)
-
-#### `sessions`(更新)
-- 新增字段:
- - `session_type`(`chat | automation`)
- - `job_id`(可空,FK -> automation_jobs.id)
-- 一致性约束:
- - `CHECK((session_type = 'chat' AND job_id IS NULL) OR (session_type = 'automation' AND job_id IS NOT NULL))`
- - 通过复合 FK 约束归属一致性:`FOREIGN KEY(job_id, user_id) -> automation_jobs(id, owner_id)`
-- 索引:
- - `INDEX(user_id, session_type, last_activity_at DESC)`
- - `INDEX(job_id)`
-
-## D. 权限与协作模型
-
-### 1) 事项权限落表
- - 权限直接存储在 `schedule_subscriptions.permission` 整数中(位运算)
- - owner 不写入 `schedule_subscriptions`,owner 权限仅由 `schedule_items.owner_id` 推导
-- 权限决策顺序:
- 1. `schedule_items.owner_id` → 服务层恒等全部权柄 `["view", "invite", "edit"]`(7)
- 2. `schedule_subscriptions` 中该用户的 `permission` 位图
- 3. 非 owner 且非 subscriber 默认无权限(0)
-
-### 2) 当前版本边界
-- 事项权限仅处理用户主体(owner + subscriber)
-- 群组与事项权限继承关系不在本期范围
-
-## E. 消息与待办联动
-
-### 1) inbox 关联业务对象
-- `inbox_messages.message_type` 枚举:
- - `friend_request`(好友请求)→ `friendship_id` 指向 friendships
- - `calendar`(日程邀请)→ `schedule_item_id` 指向 schedule_items
- - `system`(系统消息)→ 业务字段均为 NULL
- - `group`(群组邀请)→ `group_id` 指向 groups
-- 通过 `message_type + 对应业务字段` 直接定位业务对象,并用 `CHECK` 约束保证字段一致性
-
-### 2) 待办来源提取
-- 从事项提取待办时,写入 `todo_sources(todo_id, schedule_item_id)`
-- 手动创建的待办不写 `todo_sources`
-- 支持多来源:同一待办可关联多个日程事项(多行 `todo_sources`)
-- 待办完成时无需反向更新来源事项状态(简化设计)
-
-## F. 定时任务模型
-
-### 1) 调度规则
-- `schedule_type` 枚举:`daily`(每日) | `weekly`(每周)
-- `run_at` 用于首次执行时间,`next_run_at` 用于后续调度
-- 调度器扫描 `status='active' AND next_run_at <= now()` 的任务,执行后回写下一次 `next_run_at`
-- `timezone` 参与下一次执行时间计算,避免时区偏差
-
-### 2) 执行记录
-- 每次执行在 sessions 表创建记录,通过 `sessions.job_id` 关联 job
-- `sessions` 通过 `session_type` 区分 `chat` 与 `automation`
-- 执行失败时记录在 `automation_jobs`(如 `last_error`,可后续细化)
-
-## G. 数据库迁移思路
-
-### 策略:重建数据库 + Alembic ORM 迁移
-
-由于是全新设计的数据模型,且当前处于开发初期(可清除旧数据),采用**重建数据库**策略:
-
-**执行门禁(强制)**:
-- 仅允许在本地开发环境执行
-- 禁止在生产/共享环境执行 `rm backend/alembic/versions/*.py`
-- 执行前必须备份数据库或创建 git tag
-
-1. **删除所有旧 migration 脚本**(保留 `env.py`)
-2. **创建 ORM 模型文件**
-3. **生成 Alembic migration**
-4. **重建数据库并执行迁移**
-
-### 执行步骤
-
-1. 删除旧 migration 文件
- ```bash
- rm backend/alembic/versions/*.py
- ```
-
-2. 重建空数据库(确保以空库基线生成 initial migration)
- ```bash
- docker compose --env-file .env -f infra/docker/docker-compose.yml down -v
- docker compose --env-file .env -f infra/docker/docker-compose.yml up -d db
- ```
-
-3. 创建 ORM 模型文件(参考 `models/` 目录结构)
- - 新增:`user_agents.py`, `memories.py`, `friendships.py`, `groups.py`, `group_members.py`, `schedule_items.py`, `schedule_subscriptions.py`, `inbox_messages.py`, `todos.py`, `todo_sources.py`, `automation_jobs.py`
- - 更新:`profile.py` - 添加 `settings` 字段
- - 更新:`agent_chat_session.py` - 添加 `session_type`、`job_id` 字段
- - 重写:`create_profile_for_new_user` 触发器,确保 `profiles.settings` 有默认值
-
-4. 更新 `models/__init__.py` 导出所有模型
-
-5. 更新 `alembic/env.py` 添加模型导入
-
-6. 生成 initial migration(以空库为对比基线)
- ```bash
- cd backend && uv run alembic revision --autogenerate -m "initial schema"
- ```
-
-7. 为所有新建 `public` 业务表补齐 RLS(`SELECT/INSERT/UPDATE/DELETE` policy)
- - 每张表都执行 `ENABLE ROW LEVEL SECURITY`
- - 每张表都显式创建 `SELECT/INSERT/UPDATE/DELETE` policy
- - downgrade 必须可逆,不得弱化既定安全边界
- - `anon/authenticated` 默认全部 deny
-
- RLS 最小策略矩阵(本期统一模板):
- - `anon`:`SELECT/INSERT/UPDATE/DELETE` 全部 deny
- - `authenticated`:`SELECT/INSERT/UPDATE/DELETE` 全部 deny
- - `service_role`:由后端服务连接使用,不依赖 RLS 放行
-
-8. 执行迁移
- ```bash
- cd backend && uv run alembic upgrade head
- ```
-
-9. 验证表结构
-
-## H. 交付物
-
-### ORM 模型文件清单
-
-| 文件 | 说明 |
-|------|------|
-| `models/user_agents.py` | 用户专属 agent |
-| `models/memories.py` | 用户/工作记忆 |
-| `models/friendships.py` | 好友关系 |
-| `models/groups.py` | 群组 |
-| `models/group_members.py` | 群组成员 |
-| `models/schedule_items.py` | 日程事项 |
-| `models/schedule_subscriptions.py` | 日程订阅与权限 |
-| `models/inbox_messages.py` | 待处理消息 |
-| `models/todos.py` | 待办 |
-| `models/todo_sources.py` | 待办与事项来源关联 |
-| `models/automation_jobs.py` | 定时任务 |
-| `models/profile.py` | 更新:添加 `settings` 字段 |
-| `models/agent_chat_session.py` | 更新:添加 `session_type`、`job_id` 字段 |
-
-### 执行步骤
-
-1. 删除旧 migration 文件
- ```bash
- rm backend/alembic/versions/*.py
- ```
-
-2. 重建空数据库(确保以空库基线生成 initial migration)
- ```bash
- docker compose --env-file .env -f infra/docker/docker-compose.yml down -v
- docker compose --env-file .env -f infra/docker/docker-compose.yml up -d db
- ```
-
-3. 创建/更新 ORM 模型文件
-
-4. 更新 `models/__init__.py` 导出所有模型
-
-5. 更新 `alembic/env.py` 添加模型导入
-
-6. 生成 initial migration(以空库为对比基线)
- ```bash
- cd backend && uv run alembic revision --autogenerate -m "initial schema"
- ```
-
-7. 为所有新建 `public` 业务表补齐 RLS(`SELECT/INSERT/UPDATE/DELETE` policy)
- - 每张表都执行 `ENABLE ROW LEVEL SECURITY`
- - 每张表都显式创建 `SELECT/INSERT/UPDATE/DELETE` policy
- - downgrade 必须可逆,不得弱化既定安全边界
-
-8. 执行迁移
- ```bash
- cd backend && uv run alembic upgrade head
- ```
-
-9. 更新测试文件适配新表结构
-
-## I. 数据库表名规范与审计
-
-### 1) 命名规范(统一执行)
-- 使用 `snake_case`
-- 业务表统一使用复数名词(如 `profiles`, `friendships`, `automation_jobs`)
-- 关联表使用 `<主实体复数>_<从实体复数>` 或约定俗成复数短语(如 `group_members`, `todo_sources`)
-- 禁止过于泛化的表名(如 `messages`, `sessions`),必须带业务前缀
-- 存量历史表允许短期例外,但必须在审计表中登记并给出迁移计划
-- 缩写保持一致:LLM 统一使用 `llm` 前缀,不混用 `model`/`llm` 两套命名
-
-### 2) 表名审计结果
-
-| 当前表名 | 审计结论 | 建议表名 | 说明 |
-|----------|----------|----------|------|
-| `profiles` | 通过 | - | 符合复数名词规范 |
-| `user_agents` | 通过 | - | 语义清晰 |
-| `memories` | 通过 | - | 语义清晰 |
-| `friendships` | 通过 | - | 关系表命名清晰 |
-| `groups` | 通过 | - | 符合规范 |
-| `group_members` | 通过 | - | 关联表命名清晰 |
-| `schedule_items` | 通过 | - | 语义清晰 |
-| `schedule_subscriptions` | 通过 | - | 语义清晰 |
-| `inbox_messages` | 通过 | - | 带业务前缀,避免歧义 |
-| `todos` | 通过 | - | 简洁且清晰 |
-| `todo_sources` | 通过 | - | 关联关系明确 |
-| `automation_jobs` | 通过 | - | 语义清晰 |
-| `llms` | 通过 | - | 与 LLM 语义一致 |
-| `llm_factory` | 建议调整 | `llm_factories` | 当前为单数,建议改复数以统一规范 |
-| `sessions` | 建议调整 | `agent_chat_sessions` | 过于泛化,建议加业务前缀 |
-| `messages` | 建议调整 | `agent_chat_messages` | 过于泛化,建议加业务前缀 |
-
-### 3) 落地建议
-- 本期命名边界:不重命名 `llm_factory/sessions/messages`,仅在新表严格执行命名规范
-- 本期最小可行:先保持现有表名可运行,新增表全部遵循规范
-- 下期统一治理:通过一次性迁移将 `llm_factory/sessions/messages` 重命名到规范名
-- 若本期直接重命名,需同步 ORM 模型、外键、索引、RLS policy 名称与运行文档
diff --git a/docs/plans/2026-02-27-invite-code-design.md b/docs/plans/2026-02-27-invite-code-design.md
deleted file mode 100644
index fe31f5d..0000000
--- a/docs/plans/2026-02-27-invite-code-design.md
+++ /dev/null
@@ -1,161 +0,0 @@
-# 邀请码机制设计
-
-**Date**: 2026-02-27
-**Status**: Approved
-**Author**: User + AI
-
-## 背景
-
-为用户注册增加邀请码机制,支持:
-- 每个用户注册后自动获得专属邀请码
-- 注册时可填写他人邀请码
-- 记录邀请关系和使用统计
-- 支持运营邀请码(批量、限额、过期、禁用)
-- 预留奖励策略配置
-
-## 数据模型
-
-### invite_codes 表
-
-| 字段 | 类型 | 约束 | 说明 |
-|------|------|------|------|
-| id | UUID | PK | 主键 |
-| code | VARCHAR(8) | UNIQUE, NOT NULL | 邀请码 |
-| owner_id | UUID | FK → profiles.id, nullable | 所属用户,NULL 为运营码 |
-| max_uses | INT | nullable | 最大使用次数,NULL 无限制 |
-| used_count | INT | DEFAULT 0 | 已用次数 |
-| expires_at | TIMESTAMPTZ | nullable | 过期时间,NULL 永不过期 |
-| status | VARCHAR(20) | NOT NULL | active / disabled |
-| reward_config | JSONB | DEFAULT '{}' | 奖励策略配置 |
-| created_at | TIMESTAMPTZ | NOT NULL | 创建时间 |
-| updated_at | TIMESTAMPTZ | NOT NULL | 更新时间 |
-| deleted_at | TIMESTAMPTZ | nullable | 软删除 |
-
-**索引:**
-- `ix_invite_codes_code` ON (code) UNIQUE
-- `ix_invite_codes_owner_id` ON (owner_id)
-- `ix_invite_codes_status_expires` ON (status, expires_at)
-
-**CHECK 约束:**
-- `status IN ('active', 'disabled')`
-- `used_count >= 0`
-- `max_uses IS NULL OR max_uses > 0`
-
-### profiles 表变更
-
-| 字段 | 类型 | 约束 | 说明 |
-|------|------|------|------|
-| referred_by | UUID | FK → profiles.id, nullable | 被谁邀请 |
-
-**索引:**
-- `ix_profiles_referred_by` ON (referred_by)
-
-## API 变更
-
-### POST /auth/verifications
-
-**Request:**
-```json
-{
- "username": "string (3-30 chars)",
- "email": "string (email)",
- "password": "string (min 6 chars)",
- "redirect_to": "string?",
- "invite_code": "string (8 chars)?" // 新增,可选
-}
-```
-
-**Response:** 202 Accepted(不变)
-
-## 注册流程
-
-```
-┌─────────────────────────────────────────────────────────────────┐
-│ 1. POST /auth/verifications │
-│ - 存储 username + invite_code 到 Supabase metadata │
-│ - 发送 OTP 邮件 │
-└─────────────────────────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────────────────┐
-│ 2. POST /auth/verifications/verify │
-│ - 验证 OTP │
-│ - 创建 auth.users 记录 │
-│ - 触发 on_auth_user_created trigger │
-└─────────────────────────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────────────────┐
-│ 3. Trigger: on_auth_user_created │
-│ a. INSERT INTO profiles (id, username, ...) │
-│ b. 生成 8 位随机邀请码 │
-│ c. INSERT INTO invite_codes (code, owner_id, ...) │
-│ d. 从 metadata 取 invite_code,执行邀请校验逻辑 │
-└─────────────────────────────────────────────────────────────────┘
- ↓
-┌─────────────────────────────────────────────────────────────────┐
-│ 4. 邀请码校验逻辑 │
-│ IF invite_code 存在 AND │
-│ status = 'active' AND │
-│ (expires_at IS NULL OR expires_at > now()) AND │
-│ (max_uses IS NULL OR used_count < max_uses) │
-│ THEN │
-│ UPDATE profiles SET referred_by = invite_codes.owner_id │
-│ UPDATE invite_codes SET used_count = used_count + 1 │
-│ END IF │
-└─────────────────────────────────────────────────────────────────┘
-```
-
-## 邀请码生成规则
-
-- 8 位随机字符串
-- 字符集:`ABCDEFGHJKLMNPQRSTUVWXYZ23456789`(排除易混淆字符 0/O/1/I/L)
-- 唯一性:数据库 UNIQUE 约束 + 生成时冲突重试(最多 10 次)
-
-## 使用记录查询
-
-通过 profiles 表查询:
-
-```sql
--- 查询某个邀请码的使用记录
-SELECT p.id, p.username, p.created_at
-FROM profiles p
-JOIN invite_codes ic ON ic.owner_id = :owner_id
-WHERE p.referred_by = ic.owner_id
-ORDER BY p.created_at DESC;
-
--- 查询某个用户邀请了多少人
-SELECT COUNT(*) FROM profiles WHERE referred_by = :user_id;
-```
-
-## 边界情况
-
-| 场景 | 处理方式 |
-|------|----------|
-| 邀请码不存在 | 跳过邀请,注册正常成功 |
-| 邀请码已禁用 | 跳过邀请 |
-| 邀请码已过期 | 跳过邀请 |
-| 邀请码已达上限 | 跳过邀请 |
-| 用户自邀(用自己的码) | 不可能,用户注册时还没有邀请码 |
-| 重复使用同一邀请码 | 允许(until max_uses) |
-
-## 后续扩展
-
-1. **奖励系统**:通过 `reward_config` JSONB 字段配置不同奖励策略
-2. **运营批量码**:`owner_id = NULL` 的邀请码,支持市场推广
-3. **邀请排行榜**:基于 `used_count` 或 profiles 关联查询
-4. **邀请码回收**:软删除 `deleted_at`,保留历史记录
-
-## 迁移计划
-
-1. 新增迁移文件创建 `invite_codes` 表
-2. 新增迁移文件给 `profiles` 表添加 `referred_by` 字段
-3. 修改 `on_auth_user_created` trigger 增加邀请码逻辑
-4. 修改 `VerificationCreateRequest` schema 添加 `invite_code` 字段
-5. 修改 `create_verification` gateway 传递 `invite_code` 到 metadata
-
-## 测试用例
-
-1. 注册时不填邀请码 → 正常注册,生成专属邀请码
-2. 注册时填写有效邀请码 → 关联邀请关系,used_count +1
-3. 注册时填写无效邀请码 → 正常注册,无邀请关系
-4. 邀请码达上限后使用 → 正常注册,无邀请关系
-5. 运营邀请码使用 → 正常注册,无 referred_by(owner_id = NULL)
diff --git a/docs/plans/2026-02-27-invite-code-implementation-plan.md b/docs/plans/2026-02-27-invite-code-implementation-plan.md
deleted file mode 100644
index 2964e05..0000000
--- a/docs/plans/2026-02-27-invite-code-implementation-plan.md
+++ /dev/null
@@ -1,309 +0,0 @@
-# Invite Code Implementation Plan
-
-> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
-
-**Goal:** 在现有 OTP 注册链路中引入邀请码能力,支持用户自动生成专属邀请码、注册时可选填邀请码并记录邀请关系与使用次数。
-
-**Architecture:** 采用数据库中心实现:通过 Alembic 新增 `invite_codes` 表、扩展 `profiles` 字段,并在 `auth.users` 的现有 trigger 函数中完成邀请码校验与记账,保证注册与邀请关系写入尽量原子。应用层只负责透传 `invite_code` 到 Supabase `raw_user_meta_data`。
-
-**Tech Stack:** FastAPI, SQLAlchemy, Alembic, Supabase Auth, PostgreSQL PL/pgSQL, Pytest
-
----
-
-### Task 1: 更新注册请求 Schema(TDD)
-
-**Files:**
-- Modify: `backend/src/v1/auth/schemas.py`
-- Modify: `backend/tests/integration/test_auth_routes.py`
-
-**Step 1: Write the failing test**
-
-在 `test_signup_start_returns_pending_response` 基础上新增断言路径:请求体带 `invite_code` 时返回仍为 202,且未触发 422。
-
-**Step 2: Run test to verify it fails**
-
-Run: `cd backend && uv run pytest tests/integration/test_auth_routes.py -k signup_start_returns_pending_response -v`
-Expected: FAIL(`invite_code` 为额外字段或校验不通过)
-
-**Step 3: Write minimal implementation**
-
-在 `VerificationCreateRequest` 增加可选字段:
-
-```python
-invite_code: str | None = Field(default=None, min_length=8, max_length=8)
-```
-
-**Step 4: Run test to verify it passes**
-
-Run: `cd backend && uv run pytest tests/integration/test_auth_routes.py -k signup_start_returns_pending_response -v`
-Expected: PASS
-
-**Step 5: Commit**
-
-```bash
-git add backend/src/v1/auth/schemas.py backend/tests/integration/test_auth_routes.py
-git commit -m "feat: accept invite code in signup request"
-```
-
-### Task 2: 透传 invite_code 到 Supabase metadata(TDD)
-
-**Files:**
-- Modify: `backend/src/v1/auth/gateway.py`
-- Modify: `backend/tests/unit/v1/auth/test_auth_service.py`
-
-**Step 1: Write the failing test**
-
-在 `test_supabase_signup_passes_username_in_metadata` 增加 `invite_code` 并断言:
-
-```python
-assert captured_payload["data"] == {
- "username": "demo",
- "invite_code": "A1B2C3D4",
-}
-```
-
-**Step 2: Run test to verify it fails**
-
-Run: `cd backend && uv run pytest tests/unit/v1/auth/test_auth_service.py -k metadata -v`
-Expected: FAIL(metadata 未包含 `invite_code`)
-
-**Step 3: Write minimal implementation**
-
-在 `create_verification` 中构建 metadata:
-
-```python
-metadata = {"username": request.username}
-if request.invite_code:
- metadata["invite_code"] = request.invite_code
-payload = {
- "email": request.email,
- "password": request.password,
- "data": metadata,
-}
-```
-
-**Step 4: Run test to verify it passes**
-
-Run: `cd backend && uv run pytest tests/unit/v1/auth/test_auth_service.py -k metadata -v`
-Expected: PASS
-
-**Step 5: Commit**
-
-```bash
-git add backend/src/v1/auth/gateway.py backend/tests/unit/v1/auth/test_auth_service.py
-git commit -m "feat: pass invite code through signup metadata"
-```
-
-### Task 3: 新增 invite_codes 表与 profiles.referred_by(迁移先行)
-
-**Files:**
-- Create: `backend/alembic/versions/20260227_0006_invite_codes_and_profile_referral.py`
-- Modify: `backend/src/models/profile.py`
-- Create: `backend/src/models/invite_code.py`
-- Modify: `backend/src/models/__init__.py`
-
-**Step 1: Write the failing test**
-
-在 `backend/tests/unit/database/test_profile_models.py` 新增 `referred_by` 读写测试;新增 `backend/tests/unit/database/test_invite_code_models.py` 验证 `InviteCode` 基本创建与约束字段。
-
-**Step 2: Run test to verify it fails**
-
-Run: `cd backend && uv run pytest tests/unit/database/test_profile_models.py tests/unit/database/test_invite_code_models.py -v`
-Expected: FAIL(字段/模型不存在)
-
-**Step 3: Write minimal implementation**
-
-- Alembic 创建 `invite_codes`:
- - `code` 唯一索引
- - `owner_id` 外键到 `profiles.id`(可空)
- - `status`、`used_count`、`max_uses` check 约束
- - `max_uses` 默认 `NULL`(无限制)
- - `expires_at` 默认 `NULL`(无限制)
- - `reward_config` JSONB 默认 `{}`
- - 启用 RLS(按项目默认 deny-all)
-- **注意**:本期不开放 invite_codes 表直接读取,用户邀请码通过 profile 聚合接口返回(后续实现)
-
-- Alembic 给 `profiles` 增加 `referred_by` + 索引 + 外键
-- ORM 同步 `Profile.referred_by` 与 `InviteCode` 模型
-
-**Step 4: Run test to verify it passes**
-
-Run: `cd backend && uv run pytest tests/unit/database/test_profile_models.py tests/unit/database/test_invite_code_models.py -v`
-Expected: PASS
-
-**Step 5: Commit**
-
-```bash
-git add backend/alembic/versions/20260227_0006_invite_codes_and_profile_referral.py backend/src/models/profile.py backend/src/models/invite_code.py backend/src/models/__init__.py backend/tests/unit/database/test_profile_models.py backend/tests/unit/database/test_invite_code_models.py
-git commit -m "feat: add invite code schema and profile referral fields"
-```
-
-### Task 4: 扩展注册 trigger 生成邀请码并消费邀请(TDD)
-
-**Files:**
-- Modify: `backend/alembic/versions/20260227_0006_invite_codes_and_profile_referral.py`
-- Modify: `backend/tests/integration/test_auth_routes.py`
-
-**Step 1: Write the failing test**
-
-新增集成测试(建议通过测试替身/fixture 验证行为):
-- 注册不带邀请码时,profile 创建后存在 owner 邀请码
-- 注册带有效邀请码时,`referred_by` 生效且 `used_count + 1`
-
-**Step 2: Run test to verify it fails**
-
-Run: `cd backend && uv run pytest tests/integration/test_auth_routes.py -k invite -v`
-Expected: FAIL(触发器逻辑尚未实现)
-
-**Step 3: Write minimal implementation**
-
-在迁移 SQL 中:
-- 新增 helper function:生成 8 位随机码(排除易混淆字符 0/O/1/I/L,冲突重试)
-- 重建 `public.create_profile_for_new_user()`:
- 1. 插入 `profiles`
- 2. 创建该用户专属 `invite_codes`(`owner_id = NEW.id`)
- 3. 读取 `NEW.raw_user_meta_data ->> 'invite_code'`
- 4. 校验邀请码状态/过期/次数
- 5. 若有效:更新 `profiles.referred_by`,并 `used_count = used_count + 1`
-
-**Step 4: Run test to verify it passes**
-
-Run: `cd backend && uv run pytest tests/integration/test_auth_routes.py -k invite -v`
-Expected: PASS
-
-**Step 5: Commit**
-
-```bash
-git add backend/alembic/versions/20260227_0006_invite_codes_and_profile_referral.py backend/tests/integration/test_auth_routes.py
-git commit -m "feat: extend signup trigger for invite code generation and usage"
-```
-
-### Task 5: 覆盖邀请码边界场景(TDD)
-
-**Files:**
-- Modify: `backend/tests/integration/test_auth_routes.py`
-- Optional Modify: `backend/tests/e2e/test_auth_flow.py`
-
-**Step 1: Write the failing test**
-
-新增场景测试:
-- 邀请码不存在
-- 邀请码 disabled
-- 邀请码 expires_at 已过期
-- 邀请码达到 `max_uses`
-
-断言:注册仍成功(202/200 链路正常),仅邀请关系不建立。
-
-**Step 2: Run test to verify it fails**
-
-Run: `cd backend && uv run pytest tests/integration/test_auth_routes.py -k "invite and (expired or disabled or max_uses or invalid)" -v`
-Expected: FAIL
-
-**Step 3: Write minimal implementation**
-
-修正 trigger 判断顺序和条件,确保“邀请无效不影响注册”原则。
-
-**Step 4: Run test to verify it passes**
-
-Run: `cd backend && uv run pytest tests/integration/test_auth_routes.py -k invite -v`
-Expected: PASS
-
-**Step 5: Commit**
-
-```bash
-git add backend/tests/integration/test_auth_routes.py backend/alembic/versions/20260227_0006_invite_codes_and_profile_referral.py
-git commit -m "test: cover invite code edge cases in signup flow"
-```
-
-### Task 6: 文档同步与运行手册更新
-
-**Files:**
-- Modify: `docs/runtime/runtime-route.md`
-- Modify: `docs/runtime/runtime-runbook.md`
-
-**Step 1: Write the failing test**
-
-无自动化测试;改为文档一致性检查清单(手工):
-- 注册接口 request 字段包含 `invite_code`
-- 说明邀请码消费时机与“无效码不阻断注册”
-
-**Step 2: Run check to verify missing docs**
-
-Run: `cd backend && uv run pytest tests/integration/test_auth_routes.py -k signup_start -v`
-Expected: PASS(作为行为基线),文档尚未同步
-
-**Step 3: Write minimal implementation**
-
-- 更新 `POST /auth/verifications` 请求字段
-- 新增邀请码行为说明
-- 在 runbook 变更日志添加本次改动记录
-
-**Step 4: Run check after docs update**
-
-Run: `cd backend && uv run pytest tests/integration/test_auth_routes.py -k signup_start -v`
-Expected: PASS(行为与文档一致)
-
-**Step 5: Commit**
-
-```bash
-git add docs/runtime/runtime-route.md docs/runtime/runtime-runbook.md
-git commit -m "docs: document invite code behavior in signup flow"
-```
-
-### Task 7: 全量验证与风险审查(L2)
-
-**Files:**
-- Verify only
-
-**Step 1: Run lint/type checks**
-
-Run:
-- `cd backend && uv run ruff check src tests`
-- `cd backend && uv run basedpyright src`
-
-Expected: 全部通过
-
-**Step 2: Run test suites**
-
-Run:
-- `cd backend && uv run pytest tests/unit -v`
-- `cd backend && uv run pytest tests/integration -v`
-- `cd backend && uv run pytest tests/e2e/test_auth_flow.py -v`
-
-Expected: 通过
-
-**Step 3: Run mandatory review gates for L2**
-
-- `refactor-cleaner` agent:确认无死代码/重复代码
-- `code-reviewer` agent:检查 DB trigger、安全边界、可维护性
-
-Expected: CRITICAL/HIGH 为 0
-
-**Step 4: Security-specific sanity checks**
-
-检查项:
-- 未硬编码密钥
-- SQL 逻辑无注入风险(trigger 中仅参数/列操作)
-- 邀请码校验失败不泄露内部细节
-
-**Step 5: Commit verification evidence (if needed in docs/PR notes)**
-
-```bash
-git add
-git commit -m "chore: record invite code verification results"
-```
-
----
-
-## 交付验收标准
-
-1. 新用户注册后必有 1 条专属邀请码。
-2. 注册时传入有效邀请码会建立 `profiles.referred_by` 并增加 `used_count`。
-3. 无效邀请码不会阻断注册成功。
-4. 支持运营码(`owner_id IS NULL`)与后续奖励扩展(`reward_config`)。
-5. 文档已同步,测试与检查通过。
-
-## 备注
-
-- 本需求触发 L2(数据库迁移 + trigger + 多文件大改),必须走双审查 gate。
-- 不在本期实现运营后台批量发码 API;仅完成数据层与注册链路支撑。
diff --git a/docs/plans/2026-02-27-schedule-items-api-design.md b/docs/plans/2026-02-27-schedule-items-api-design.md
deleted file mode 100644
index ff67cf2..0000000
--- a/docs/plans/2026-02-27-schedule-items-api-design.md
+++ /dev/null
@@ -1,191 +0,0 @@
-# Design: Schedule Items API
-
-**Date:** 2026-02-27
-**Status:** Approved
-
-## Overview
-
-实现日历事项(Schedule Items)的后端 CRUD API,支持用户创建、查询、更新、删除日历事项。
-
-## Scope
-
-- 仅后端 API,不涉及前端
-- 全量 CRUD
-- 查询按时间范围筛选
-- 暂不支持重复日程(recurrence_rule 留空)
-
-## API Endpoints
-
-### 1. 创建日历事项
-
-```
-POST /api/v1/schedule-items
-```
-
-**Request:**
-```json
-{
- "title": "string (1-255 chars, required)",
- "description": "string? (max 2000 chars)",
- "start_at": "string (ISO 8601 datetime, required)",
- "end_at": "string? (ISO 8601 datetime, must be after start_at)",
- "timezone": "string? (default: UTC)",
- "metadata": {
- "color": "#FF6B6B",
- "location": "会议室A",
- "notes": "记得带身份证",
- "attachments": [],
- "version": 1
- }
-}
-```
-
-**Response:** 201 Created
-```json
-{
- "id": "uuid",
- "title": "string",
- "description": "string?",
- "start_at": "string",
- "end_at": "string?",
- "timezone": "string",
- "metadata": {...},
- "status": "active",
- "source_type": "manual",
- "created_at": "string",
- "updated_at": "string"
-}
-```
-
-### 2. 查询日历事项列表
-
-```
-GET /api/v1/schedule-items?start_at=2026-02-01&end_at=2026-02-28
-```
-
-**Query Parameters:**
-- `start_at`: ISO 8601 date/datetime(查询范围起始)
-- `end_at`: ISO 8601 date/datetime(查询范围结束)
-
-**Response:** 200 OK
-```json
-[
- {
- "id": "uuid",
- "title": "string",
- "start_at": "string",
- "end_at": "string?",
- "timezone": "string",
- "status": "active"
- }
-]
-```
-
-### 3. 获取单个事项
-
-```
-GET /api/v1/schedule-items/{id}
-```
-
-**Response:** 200 OK(完整字段,同创建响应)
-
-### 4. 更新事项
-
-```
-PATCH /api/v1/schedule-items/{id}
-```
-
-**Request:** 支持 `title`/`description`/`start_at`/`end_at`/`timezone`/`metadata`/`status` 部分更新
-
-**Response:** 200 OK
-
-### 5. 删除事项
-
-```
-DELETE /api/v1/schedule-items/{id}
-```
-
-**Response:** 204 No Content(软删除)
-
-## Data Models
-
-### Metadata 结构(Pydantic)
-
-```python
-from enum import Enum
-from pydantic import BaseModel
-from uuid import UUID
-
-class AttachmentType(str, Enum):
- DOCUMENT = "document"
- REMINDER = "reminder"
-
-class ScheduleItemMetadataAttachment(BaseModel):
- name: str
- type: AttachmentType
- visible_to: list[UUID] = []
- # document 类型
- url: str | None = None
- note: str | None = None
- # reminder 类型
- content: str | None = None
-
-class ScheduleItemMetadata(BaseModel):
- color: str | None = None
- location: str | None = None
- notes: str | None = None
- attachments: list[ScheduleItemMetadataAttachment] = []
- version: int = 1
-```
-
-### 数据库模型(已有)
-
-参见 `backend/src/models/schedule_items.py`:
-- `id`: UUID
-- `owner_id`: UUID
-- `title`: String(255)
-- `description`: Text
-- `start_at`: DateTime(timezone=True)
-- `end_at`: DateTime(timezone=True)
-- `timezone`: String(50)
-- `extra_metadata`: JSONB (mapped as "metadata")
-- `recurrence_rule`: String(255)
-- `source_type`: Enum (MANUAL/IMPORTED/AGENT_GENERATED)
-- `status`: Enum (ACTIVE/COMPLETED/CANCELED/ARCHIVED)
-- `created_by`: UUID
-
-## Architecture
-
-遵循项目 `schemas / repository / service / router` 分层模式:
-
-```
-backend/src/v1/schedule_items/
-├── __init__.py
-├── schemas.py # Pydantic 请求/响应模型
-├── repository.py # CRUD 操作(无 auth,无 commit)
-├── service.py # 业务逻辑 + 授权 + 事务边界
-├── router.py # FastAPI 路由定义
-└── dependencies.py # DI(如有)
-```
-
-## Security
-
-- 所有端点需要认证(JWT)
-- `owner_id` 从 JWT `sub` 提取,不从请求体读取
-- 用户只能操作自己的日历事项(`owner_id` 过滤)
-- RLS 已在数据库层启用(防御边界)
-
-## Error Handling
-
-使用 RFC 7807 `application/problem+json` 格式:
-- 400: 请求参数无效
-- 401: 未认证
-- 404: 事项不存在或无权限访问
-- 422: 验证失败
-
-## Out of Scope
-
-- 重复日程(recurrence_rule)
-- 日程订阅与协作(schedule_subscriptions)
-- 待办事项联动(todos/todo_sources)
-- 前端实现
diff --git a/docs/plans/2026-02-27-schedule-items-api-implementation.md b/docs/plans/2026-02-27-schedule-items-api-implementation.md
deleted file mode 100644
index 6513ce4..0000000
--- a/docs/plans/2026-02-27-schedule-items-api-implementation.md
+++ /dev/null
@@ -1,1244 +0,0 @@
-# Schedule Items API Implementation Plan
-
-> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
-
-**Goal:** 实现日历事项(Schedule Items)的后端 CRUD API,支持用户创建、查询、更新、删除日历事项。
-
-**Architecture:** 遵循项目 `schemas / repository / service / router` 分层模式,与现有 `/users` API 保持一致。
-
-**Tech Stack:** FastAPI, SQLAlchemy, Pydantic, PostgreSQL
-
----
-
-## Task 1: 创建目录结构和 __init__.py
-
-**Files:**
-- Create: `backend/src/v1/schedule_items/__init__.py`
-
-**Step 1: 创建目录和 __init__.py**
-
-```python
-# backend/src/v1/schedule_items/__init__.py
-```
-
-Run: `mkdir -p backend/src/v1/schedule_items && touch backend/src/v1/schedule_items/__init__.py`
-
----
-
-## Task 2: 创建 Pydantic Schemas
-
-**Files:**
-- Create: `backend/src/v1/schedule_items/schemas.py`
-
-**Step 1: 写入 schemas.py**
-
-```python
-from __future__ import annotations
-
-from datetime import datetime
-from enum import Enum
-from typing import ClassVar
-from uuid import UUID
-
-from pydantic import BaseModel, ConfigDict, Field, field_validator
-
-
-class AttachmentType(str, Enum):
- DOCUMENT = "document"
- REMINDER = "reminder"
-
-
-class ScheduleItemMetadataAttachment(BaseModel):
- name: str
- type: AttachmentType
- visible_to: list[UUID] = []
- url: str | None = None
- note: str | None = None
- content: str | None = None
-
-
-class ScheduleItemMetadata(BaseModel):
- color: str | None = None
- location: str | None = None
- notes: str | None = None
- attachments: list[ScheduleItemMetadataAttachment] = []
- version: int = 1
-
-
-class ScheduleItemStatus(str, Enum):
- ACTIVE = "active"
- COMPLETED = "completed"
- CANCELED = "canceled"
- ARCHIVED = "archived"
-
-
-class ScheduleItemSourceType(str, Enum):
- MANUAL = "manual"
- IMPORTED = "imported"
- AGENT_GENERATED = "agent_generated"
-
-
-class ScheduleItemCreateRequest(BaseModel):
- model_config: ClassVar[ConfigDict] = ConfigDict(extra="forbid")
-
- title: str = Field(min_length=1, max_length=255)
- description: str | None = Field(default=None, max_length=2000)
- start_at: datetime
- end_at: datetime | None = None
- timezone: str = "UTC"
- metadata: ScheduleItemMetadata | None = None
-
-
-class ScheduleItemUpdateRequest(BaseModel):
- model_config: ClassVar[ConfigDict] = ConfigDict(extra="forbid")
-
- title: str | None = Field(default=None, min_length=1, max_length=255)
- description: str | None = Field(default=None, max_length=2000)
- start_at: datetime | None = None
- end_at: datetime | None = None
- timezone: str | None = None
- metadata: ScheduleItemMetadata | None = None
- status: ScheduleItemStatus | None = None
-
- @field_validator("end_at", mode="before")
- @classmethod
- def validate_end_at(cls, v: datetime | None, info) -> datetime | None:
- return v
-
-
-class ScheduleItemResponse(BaseModel):
- model_config: ClassVar[ConfigDict] = ConfigDict(from_attributes=True)
-
- id: UUID
- title: str
- description: str | None = None
- start_at: datetime
- end_at: datetime | None = None
- timezone: str
- metadata: ScheduleItemMetadata | None = None
- status: ScheduleItemStatus
- source_type: ScheduleItemSourceType
- created_at: datetime
- updated_at: datetime
-
-
-class ScheduleItemListItem(BaseModel):
- model_config: ClassVar[ConfigDict] = ConfigDict(from_attributes=True)
-
- id: UUID
- title: str
- start_at: datetime
- end_at: datetime | None = None
- timezone: str
- status: ScheduleItemStatus
-
-
-class ScheduleItemListRequest(BaseModel):
- start_at: datetime
- end_at: datetime
-```
-
----
-
-## Task 3: 创建 Repository
-
-**Files:**
-- Create: `backend/src/v1/schedule_items/repository.py`
-
-**Step 1: 写入 repository.py**
-
-```python
-from __future__ import annotations
-
-from datetime import datetime
-from typing import TYPE_CHECKING, Protocol
-from uuid import UUID
-
-from sqlalchemy import select
-from sqlalchemy.exc import SQLAlchemyError
-
-from core.db.base_repository import BaseRepository
-from core.logging import get_logger
-from models.schedule_items import ScheduleItem
-
-if TYPE_CHECKING:
- from sqlalchemy.ext.asyncio import AsyncSession
-
-logger = get_logger("v1.schedule_items.repository")
-
-
-class ScheduleItemRepository(Protocol):
- async def get_by_id(self, item_id: UUID, owner_id: UUID) -> ScheduleItem | None: ...
- async def create(self, data: dict) -> ScheduleItem: ...
- async def update_by_id(self, item_id: UUID, owner_id: UUID, data: dict) -> ScheduleItem | None: ...
- async def delete_by_id(self, item_id: UUID, owner_id: UUID) -> ScheduleItem | None: ...
- async def list_by_date_range(self, owner_id: UUID, start_at: datetime, end_at: datetime) -> list[ScheduleItem]: ...
-
-
-class SQLAlchemyScheduleItemRepository(BaseRepository[ScheduleItem]):
- def __init__(self, session: AsyncSession) -> None:
- super().__init__(session, ScheduleItem)
-
- async def get_by_id(self, item_id: UUID, owner_id: UUID) -> ScheduleItem | None:
- try:
- stmt = (
- select(ScheduleItem)
- .where(ScheduleItem.id == item_id)
- .where(ScheduleItem.owner_id == owner_id)
- .where(ScheduleItem.deleted_at.is_(None))
- )
- result = await self._session.execute(stmt)
- return result.scalar_one_or_none()
- except SQLAlchemyError:
- logger.exception("Schedule item lookup failed", item_id=str(item_id), owner_id=str(owner_id))
- raise
-
- async def create(self, data: dict) -> ScheduleItem:
- try:
- item = ScheduleItem(**data)
- self._session.add(item)
- await self._session.flush()
- return item
- except SQLAlchemyError:
- logger.exception("Schedule item creation failed")
- raise
-
- async def update_by_id(
- self, item_id: UUID, owner_id: UUID, data: dict
- ) -> ScheduleItem | None:
- if not data:
- return await self.get_by_id(item_id, owner_id)
- try:
- return await self.update_by_id(item_id, data)
- except SQLAlchemyError:
- logger.exception("Schedule item update failed", item_id=str(item_id))
- raise
-
- async def delete_by_id(self, item_id: UUID, owner_id: UUID) -> ScheduleItem | None:
- try:
- return await self.soft_delete_by_id(item_id)
- except SQLAlchemyError:
- logger.exception("Schedule item delete failed", item_id=str(item_id))
- raise
-
- async def list_by_date_range(
- self, owner_id: UUID, start_at: datetime, end_at: datetime
- ) -> list[ScheduleItem]:
- try:
- stmt = (
- select(ScheduleItem)
- .where(ScheduleItem.owner_id == owner_id)
- .where(ScheduleItem.deleted_at.is_(None))
- .where(ScheduleItem.start_at >= start_at)
- .where(ScheduleItem.start_at <= end_at)
- .order_by(ScheduleItem.start_at.asc())
- )
- result = await self._session.execute(stmt)
- return list(result.scalars().all())
- except SQLAlchemyError:
- logger.exception("Schedule item list failed", owner_id=str(owner_id))
- raise
-```
-
----
-
-## Task 4: 创建 Service
-
-**Files:**
-- Create: `backend/src/v1/schedule_items/service.py`
-
-**Step 1: 写入 service.py**
-
-```python
-from __future__ import annotations
-
-from datetime import datetime
-from typing import TYPE_CHECKING
-from uuid import UUID
-
-from fastapi import HTTPException
-from sqlalchemy.exc import SQLAlchemyError
-
-from core.auth.models import CurrentUser
-from core.db.base_service import BaseService
-from core.logging import get_logger
-from models.schedule_items import ScheduleItem, ScheduleItemSourceType, ScheduleItemStatus
-from v1.schedule_items.repository import ScheduleItemRepository
-from v1.schedule_items.schemas import (
- ScheduleItemCreateRequest,
- ScheduleItemListRequest,
- ScheduleItemResponse,
- ScheduleItemUpdateRequest,
-)
-
-if TYPE_CHECKING:
- from sqlalchemy.ext.asyncio import AsyncSession
-
-logger = get_logger("v1.schedule_items.service")
-
-
-class ScheduleItemService(BaseService):
- _repository: ScheduleItemRepository
- _session: AsyncSession
-
- def __init__(
- self,
- repository: ScheduleItemRepository,
- session: AsyncSession,
- current_user: CurrentUser | None,
- ) -> None:
- super().__init__(current_user=current_user)
- self._repository = repository
- self._session = session
-
- async def create(self, request: ScheduleItemCreateRequest) -> ScheduleItemResponse:
- user_id = self.require_user_id()
-
- if request.end_at and request.end_at <= request.start_at:
- raise HTTPException(status_code=400, detail="end_at must be after start_at")
-
- data = {
- "owner_id": user_id,
- "title": request.title,
- "description": request.description,
- "start_at": request.start_at,
- "end_at": request.end_at,
- "timezone": request.timezone,
- "metadata": request.metadata.model_dump() if request.metadata else {},
- "source_type": ScheduleItemSourceType.MANUAL,
- "status": ScheduleItemStatus.ACTIVE,
- "created_by": user_id,
- }
-
- try:
- item = await self._repository.create(data)
- await self._session.commit()
- except SQLAlchemyError:
- await self._session.rollback()
- logger.exception("Failed to create schedule item")
- raise HTTPException(status_code=503, detail="Schedule item store unavailable")
-
- return self._to_response(item)
-
- async def get_by_id(self, item_id: UUID) -> ScheduleItemResponse:
- user_id = self.require_user_id()
-
- try:
- item = await self._repository.get_by_id(item_id, user_id)
- except SQLAlchemyError:
- logger.exception("Failed to get schedule item", item_id=str(item_id))
- raise HTTPException(status_code=503, detail="Schedule item store unavailable")
-
- if item is None:
- raise HTTPException(status_code=404, detail="Schedule item not found")
-
- return self._to_response(item)
-
- async def update(
- self, item_id: UUID, request: ScheduleItemUpdateRequest
- ) -> ScheduleItemResponse:
- user_id = self.require_user_id()
-
- existing = await self._repository.get_by_id(item_id, user_id)
- if existing is None:
- raise HTTPException(status_code=404, detail="Schedule item not found")
-
- update_data: dict = {}
- if request.title is not None:
- update_data["title"] = request.title
- if request.description is not None:
- update_data["description"] = request.description
- if request.start_at is not None:
- update_data["start_at"] = request.start_at
- if request.end_at is not None:
- update_data["end_at"] = request.end_at
- if request.timezone is not None:
- update_data["timezone"] = request.timezone
- if request.status is not None:
- update_data["status"] = request.status
- if request.metadata is not None:
- update_data["metadata"] = request.metadata.model_dump()
-
- if request.end_at and request.start_at and request.end_at <= request.start_at:
- raise HTTPException(status_code=400, detail="end_at must be after start_at")
-
- if not update_data:
- return self._to_response(existing)
-
- try:
- item = await self._repository.update_by_id(item_id, user_id, update_data)
- await self._session.commit()
- except SQLAlchemyError:
- await self._session.rollback()
- logger.exception("Failed to update schedule item", item_id=str(item_id))
- raise HTTPException(status_code=503, detail="Schedule item store unavailable")
-
- if item is None:
- raise HTTPException(status_code=404, detail="Schedule item not found")
-
- return self._to_response(item)
-
- async def delete(self, item_id: UUID) -> None:
- user_id = self.require_user_id()
-
- existing = await self._repository.get_by_id(item_id, user_id)
- if existing is None:
- raise HTTPException(status_code=404, detail="Schedule item not found")
-
- try:
- await self._repository.delete_by_id(item_id, user_id)
- await self._session.commit()
- except SQLAlchemyError:
- await self._session.rollback()
- logger.exception("Failed to delete schedule item", item_id=str(item_id))
- raise HTTPException(status_code=503, detail="Schedule item store unavailable")
-
- async def list_by_date_range(
- self, request: ScheduleItemListRequest
- ) -> list[ScheduleItemResponse]:
- user_id = self.require_user_id()
-
- if request.end_at <= request.start_at:
- raise HTTPException(status_code=400, detail="end_at must be after start_at")
-
- try:
- items = await self._repository.list_by_date_range(
- user_id, request.start_at, request.end_at
- )
- except SQLAlchemyError:
- logger.exception("Failed to list schedule items")
- raise HTTPException(status_code=503, detail="Schedule item store unavailable")
-
- return [self._to_response(item) for item in items]
-
- def _to_response(self, item: ScheduleItem) -> ScheduleItemResponse:
- return ScheduleItemResponse(
- id=item.id,
- title=item.title,
- description=item.description,
- start_at=item.start_at,
- end_at=item.end_at,
- timezone=item.timezone,
- metadata=item.extra_metadata,
- status=item.status,
- source_type=item.source_type,
- created_at=item.created_at,
- updated_at=item.updated_at,
- )
-```
-
----
-
-## Task 5: 创建 Dependencies
-
-**Files:**
-- Create: `backend/src/v1/schedule_items/dependencies.py`
-
-**Step 1: 写入 dependencies.py**
-
-```python
-from __future__ import annotations
-
-from typing import Annotated
-
-from fastapi import Depends
-from sqlalchemy.ext.asyncio import AsyncSession
-
-from core.db import get_db
-from core.auth.models import CurrentUser
-from v1.users.dependencies import get_current_user
-from v1.schedule_items.repository import SQLAlchemyScheduleItemRepository
-from v1.schedule_items.service import ScheduleItemService
-
-
-async def get_schedule_item_repository(
- session: Annotated[AsyncSession, Depends(get_db)],
-) -> SQLAlchemyScheduleItemRepository:
- return SQLAlchemyScheduleItemRepository(session)
-
-
-def get_schedule_item_service(
- session: Annotated[AsyncSession, Depends(get_db)],
- user: Annotated[CurrentUser, Depends(get_current_user)],
-) -> ScheduleItemService:
- repository = SQLAlchemyScheduleItemRepository(session)
- return ScheduleItemService(
- repository=repository,
- session=session,
- current_user=user,
- )
-```
-
----
-
-## Task 6: 创建 Router
-
-**Files:**
-- Create: `backend/src/v1/schedule_items/router.py`
-
-**Step 1: 写入 router.py**
-
-```python
-from __future__ import annotations
-
-from typing import Annotated
-from uuid import UUID
-
-from fastapi import APIRouter, Depends, Query
-
-from v1.schedule_items.dependencies import get_schedule_item_service
-from v1.schedule_items.schemas import (
- ScheduleItemCreateRequest,
- ScheduleItemListItem,
- ScheduleItemListRequest,
- ScheduleItemResponse,
- ScheduleItemUpdateRequest,
-)
-from v1.schedule_items.service import ScheduleItemService
-
-
-router = APIRouter(prefix="/schedule-items", tags=["schedule-items"])
-
-
-@router.post("", response_model=ScheduleItemResponse, status_code=201)
-async def create_schedule_item(
- request: ScheduleItemCreateRequest,
- service: Annotated[ScheduleItemService, Depends(get_schedule_item_service)],
-) -> ScheduleItemResponse:
- return await service.create(request)
-
-
-@router.get("", response_model=list[ScheduleItemListItem])
-async def list_schedule_items(
- start_at: datetime = Query(..., description="Start date/time for range query"),
- end_at: datetime = Query(..., description="End date/time for range query"),
- service: Annotated[ScheduleItemService, Depends(get_schedule_item_service)],
-) -> list[ScheduleItemListItem]:
- request = ScheduleItemListRequest(start_at=start_at, end_at=end_at)
- items = await service.list_by_date_range(request)
- return items
-
-
-@router.get("/{item_id}", response_model=ScheduleItemResponse)
-async def get_schedule_item(
- item_id: UUID,
- service: Annotated[ScheduleItemService, Depends(get_schedule_item_service)],
-) -> ScheduleItemResponse:
- return await service.get_by_id(item_id)
-
-
-@router.patch("/{item_id}", response_model=ScheduleItemResponse)
-async def update_schedule_item(
- item_id: UUID,
- request: ScheduleItemUpdateRequest,
- service: Annotated[ScheduleItemService, Depends(get_schedule_item_service)],
-) -> ScheduleItemResponse:
- return await service.update(item_id, request)
-
-
-@router.delete("/{item_id}", status_code=204)
-async def delete_schedule_item(
- item_id: UUID,
- service: Annotated[ScheduleItemService, Depends(get_schedule_item_service)],
-) -> None:
- await service.delete(item_id)
-```
-
----
-
-## Task 7: 注册 Router
-
-**Files:**
-- Modify: `backend/src/v1/router.py:9-16`
-
-**Step 1: 添加 router 导入和注册**
-
-在 `backend/src/v1/router.py` 中添加:
-
-```python
-from v1.schedule_items.router import router as schedule_items_router
-```
-
-在 `router.include_router` 部分添加:
-
-```python
-router.include_router(schedule_items_router)
-```
-
----
-
-## Task 8: 创建单元测试
-
-**Files:**
-- Create: `backend/tests/unit/v1/schedule_items/test_schemas.py`
-
-**Step 1: 写入 test_schemas.py**
-
-```python
-from datetime import datetime, timezone
-from uuid import UUID
-
-import pytest
-from pydantic import ValidationError
-
-from v1.schedule_items.schemas import (
- AttachmentType,
- ScheduleItemCreateRequest,
- ScheduleItemMetadata,
- ScheduleItemMetadataAttachment,
- ScheduleItemUpdateRequest,
-)
-
-
-def test_create_request_valid() -> None:
- request = ScheduleItemCreateRequest(
- title="Test Event",
- start_at=datetime(2026, 2, 28, 16, 0, 0, tzinfo=timezone.utc),
- )
- assert request.title == "Test Event"
- assert request.timezone == "UTC"
-
-
-def test_create_request_with_end_at() -> None:
- request = ScheduleItemCreateRequest(
- title="Test Event",
- start_at=datetime(2026, 2, 28, 16, 0, 0, tzinfo=timezone.utc),
- end_at=datetime(2026, 2, 28, 17, 30, 0, tzinfo=timezone.utc),
- )
- assert request.end_at is not None
-
-
-def test_create_request_invalid_title_empty() -> None:
- with pytest.raises(ValidationError):
- ScheduleItemCreateRequest(
- title="",
- start_at=datetime(2026, 2, 28, 16, 0, 0, tzinfo=timezone.utc),
- )
-
-
-def test_create_request_invalid_title_too_long() -> None:
- with pytest.raises(ValidationError):
- ScheduleItemCreateRequest(
- title="x" * 256,
- start_at=datetime(2026, 2, 28, 16, 0, 0, tzinfo=timezone.utc),
- )
-
-
-def test_create_request_with_metadata() -> None:
- metadata = ScheduleItemMetadata(
- color="#FF6B6B",
- location="Meeting Room A",
- notes="Bring documents",
- attachments=[],
- )
- request = ScheduleItemCreateRequest(
- title="Test Event",
- start_at=datetime(2026, 2, 28, 16, 0, 0, tzinfo=timezone.utc),
- metadata=metadata,
- )
- assert request.metadata is not None
- assert request.metadata.color == "#FF6B6B"
-
-
-def test_update_request_partial() -> None:
- request = ScheduleItemUpdateRequest(title="Updated Title")
- assert request.title == "Updated Title"
- assert request.description is None
-
-
-def test_metadata_attachment_document() -> None:
- attachment = ScheduleItemMetadataAttachment(
- name="document.pdf",
- type=AttachmentType.DOCUMENT,
- url="https://example.com/doc.pdf",
- )
- assert attachment.type == AttachmentType.DOCUMENT
- assert attachment.url == "https://example.com/doc.pdf"
-
-
-def test_metadata_attachment_reminder() -> None:
- attachment = ScheduleItemMetadataAttachment(
- name="reminder",
- type=AttachmentType.REMINDER,
- content="Don't forget!",
- )
- assert attachment.type == AttachmentType.REMINDER
- assert attachment.content == "Don't forget!"
-```
-
-**Step 2: 运行测试验证**
-
-Run: `cd backend && uv run pytest tests/unit/v1/schedule_items/test_schemas.py -v`
-
-Expected: PASS
-
----
-
-## Task 9: 创建 Service 单元测试
-
-**Files:**
-- Create: `backend/tests/unit/v1/schedule_items/test_service.py`
-
-**Step 1: 写入 test_service.py**
-
-```python
-from datetime import datetime, timezone
-from unittest.mock import AsyncMock, MagicMock
-from uuid import UUID, uuid4
-
-import pytest
-from fastapi import HTTPException
-from sqlalchemy.exc import SQLAlchemyError
-
-from core.auth.models import CurrentUser
-from models.schedule_items import ScheduleItem, ScheduleItemSourceType, ScheduleItemStatus
-from v1.schedule_items.repository import ScheduleItemRepository
-from v1.schedule_items.schemas import ScheduleItemCreateRequest, ScheduleItemUpdateRequest
-from v1.schedule_items.service import ScheduleItemService
-
-
-def _create_mock_schedule_item(
- item_id: UUID = uuid4(),
- owner_id: UUID = UUID("00000000-0000-0000-0000-000000000001"),
- title: str = "Test Event",
-) -> ScheduleItem:
- item = MagicMock(spec=ScheduleItem)
- item.id = item_id
- item.owner_id = owner_id
- item.title = title
- item.description = None
- item.start_at = datetime(2026, 2, 28, 16, 0, 0, tzinfo=timezone.utc)
- item.end_at = datetime(2026, 2, 28, 17, 0, 0, tzinfo=timezone.utc)
- item.timezone = "UTC"
- item.metadata = {}
- item.source_type = ScheduleItemSourceType.MANUAL
- item.status = ScheduleItemStatus.ACTIVE
- item.created_at = datetime(2026, 2, 27, 10, 0, 0, tzinfo=timezone.utc)
- item.updated_at = datetime(2026, 2, 27, 10, 0, 0, tzinfo=timezone.utc)
- return item
-
-
-class FakeRepo:
- def __init__(self, item: ScheduleItem | None) -> None:
- self._item = item
-
- async def get_by_id(self, item_id: UUID, owner_id: UUID) -> ScheduleItem | None:
- if self._item and item_id == self._item.id:
- return self._item
- return None
-
- async def create(self, data: dict) -> ScheduleItem:
- return _create_mock_schedule_item(**data)
-
- async def update_by_id(self, item_id: UUID, owner_id: UUID, data: dict) -> ScheduleItem | None:
- if not self._item or item_id != self._item.id:
- return None
- return self._item
-
- async def delete_by_id(self, item_id: UUID, owner_id: UUID) -> ScheduleItem | None:
- if not self._item or item_id != self._item.id:
- return None
- return self._item
-
- async def list_by_date_range(
- self, owner_id: UUID, start_at: datetime, end_at: datetime
- ) -> list[ScheduleItem]:
- return [self._item] if self._item else []
-
-
-@pytest.fixture
-def mock_session() -> AsyncMock:
- session = AsyncMock()
- session.commit = AsyncMock()
- session.rollback = AsyncMock()
- return session
-
-
-@pytest.mark.asyncio
-async def test_create_success(mock_session: AsyncMock) -> None:
- user_id = UUID("00000000-0000-0000-0000-000000000001")
- request = ScheduleItemCreateRequest(
- title="Test Event",
- start_at=datetime(2026, 2, 28, 16, 0, 0, tzinfo=timezone.utc),
- )
- service = ScheduleItemService(
- repository=FakeRepo(None),
- session=mock_session,
- current_user=CurrentUser(id=user_id),
- )
-
- result = await service.create(request)
-
- assert result.title == "Test Event"
- mock_session.commit.assert_awaited_once()
-
-
-@pytest.mark.asyncio
-async def test_create_invalid_end_at(mock_session: AsyncMock) -> None:
- user_id = UUID("00000000-0000-0000-0000-000000000001")
- request = ScheduleItemCreateRequest(
- title="Test Event",
- start_at=datetime(2026, 2, 28, 17, 0, 0, tzinfo=timezone.utc),
- end_at=datetime(2026, 2, 28, 16, 0, 0, tzinfo=timezone.utc),
- )
- service = ScheduleItemService(
- repository=FakeRepo(None),
- session=mock_session,
- current_user=CurrentUser(id=user_id),
- )
-
- with pytest.raises(HTTPException) as exc_info:
- await service.create(request)
-
- assert exc_info.value.status_code == 400
-
-
-@pytest.mark.asyncio
-async def test_get_by_id_success(mock_session: AsyncMock) -> None:
- user_id = UUID("00000000-0000-0000-0000-000000000001")
- item = _create_mock_schedule_item()
- service = ScheduleItemService(
- repository=FakeRepo(item),
- session=mock_session,
- current_user=CurrentUser(id=user_id),
- )
-
- result = await service.get_by_id(item.id)
-
- assert result.id == item.id
-
-
-@pytest.mark.asyncio
-async def test_get_by_id_not_found(mock_session: AsyncMock) -> None:
- user_id = UUID("00000000-0000-0000-0000-000000000001")
- service = ScheduleItemService(
- repository=FakeRepo(None),
- session=mock_session,
- current_user=CurrentUser(id=user_id),
- )
-
- with pytest.raises(HTTPException) as exc_info:
- await service.get_by_id(uuid4())
-
- assert exc_info.value.status_code == 404
-
-
-@pytest.mark.asyncio
-async def test_update_success(mock_session: AsyncMock) -> None:
- user_id = UUID("00000000-0000-0000-0000-000000000001")
- item = _create_mock_schedule_item()
- service = ScheduleItemService(
- repository=FakeRepo(item),
- session=mock_session,
- current_user=CurrentUser(id=user_id),
- )
-
- result = await service.update(item.id, ScheduleItemUpdateRequest(title="Updated"))
-
- assert result.title == "Updated"
-
-
-@pytest.mark.asyncio
-async def test_delete_success(mock_session: AsyncMock) -> None:
- user_id = UUID("00000000-0000-0000-0000-000000000001")
- item = _create_mock_schedule_item()
- service = ScheduleItemService(
- repository=FakeRepo(item),
- session=mock_session,
- current_user=CurrentUser(id=user_id),
- )
-
- await service.delete(item.id)
-
- mock_session.commit.assert_awaited_once()
-```
-
-**Step 2: 运行测试验证**
-
-Run: `cd backend && uv run pytest tests/unit/v1/schedule_items/test_service.py -v`
-
-Expected: PASS
-
----
-
-## Task 10: 创建集成测试
-
-**Files:**
-- Create: `backend/tests/integration/test_schedule_items_routes.py`
-
-**Step 1: 写入 test_schedule_items_routes.py**
-
-```python
-from datetime import datetime, timezone
-from typing import Callable
-from uuid import UUID, uuid4
-
-from fastapi import HTTPException
-from fastapi.testclient import TestClient
-
-from app import app
-from core.auth.models import CurrentUser
-from v1.schedule_items.dependencies import get_schedule_item_service
-from v1.schedule_items.schemas import (
- ScheduleItemCreateRequest,
- ScheduleItemListRequest,
- ScheduleItemResponse,
- ScheduleItemUpdateRequest,
-)
-from v1.schedule_items.service import ScheduleItemService
-
-
-class FakeScheduleItemService:
- def __init__(self, item: ScheduleItemResponse | None) -> None:
- self._item = item
-
- async def create(self, request: ScheduleItemCreateRequest) -> ScheduleItemResponse:
- if not self._item:
- raise HTTPException(status_code=503, detail="Store unavailable")
- return self._item
-
- async def get_by_id(self, item_id: UUID) -> ScheduleItemResponse:
- if not self._item or str(self._item.id) != str(item_id):
- raise HTTPException(status_code=404, detail="Schedule item not found")
- return self._item
-
- async def update(
- self, item_id: UUID, request: ScheduleItemUpdateRequest
- ) -> ScheduleItemResponse:
- if not self._item or str(self._item.id) != str(item_id):
- raise HTTPException(status_code=404, detail="Schedule item not found")
- return self._item
-
- async def delete(self, item_id: UUID) -> None:
- if not self._item or str(self._item.id) != str(item_id):
- raise HTTPException(status_code=404, detail="Schedule item not found")
-
- async def list_by_date_range(
- self, request: ScheduleItemListRequest
- ) -> list[ScheduleItemResponse]:
- return [self._item] if self._item else []
-
-
-def _override_schedule_item_service(
- service: FakeScheduleItemService,
-) -> Callable[[], ScheduleItemService]:
- def _get_service() -> ScheduleItemService:
- return service # type: ignore[return-value]
-
- return _get_service
-
-
-def _override_current_user(user_id: UUID) -> Callable[[], CurrentUser]:
- def _get_user() -> CurrentUser:
- return CurrentUser(id=user_id)
-
- return _get_user
-
-
-def test_create_schedule_item_returns_201() -> None:
- user_id = UUID("00000000-0000-0000-0000-000000000001")
- item = ScheduleItemResponse(
- id=uuid4(),
- title="Test Event",
- start_at=datetime(2026, 2, 28, 16, 0, 0, tzinfo=timezone.utc),
- timezone="UTC",
- status="active",
- source_type="manual",
- created_at=datetime(2026, 2, 27, 10, 0, 0, tzinfo=timezone.utc),
- updated_at=datetime(2026, 2, 27, 10, 0, 0, tzinfo=timezone.utc),
- )
-
- app.dependency_overrides[get_schedule_item_service] = _override_schedule_item_service(
- FakeScheduleItemService(item)
- )
-
- client = TestClient(app)
- try:
- response = client.post(
- "/api/v1/schedule-items",
- json={
- "title": "Test Event",
- "start_at": "2026-02-28T16:00:00Z",
- },
- )
- assert response.status_code == 201
- finally:
- app.dependency_overrides = {}
-
-
-def test_list_schedule_items_returns_200() -> None:
- user_id = UUID("00000000-0000-0000-0000-000000000001")
- item = ScheduleItemResponse(
- id=uuid4(),
- title="Test Event",
- start_at=datetime(2026, 2, 28, 16, 0, 0, tzinfo=timezone.utc),
- timezone="UTC",
- status="active",
- source_type="manual",
- created_at=datetime(2026, 2, 27, 10, 0, 0, tzinfo=timezone.utc),
- updated_at=datetime(2026, 2, 27, 10, 0, 0, tzinfo=timezone.utc),
- )
-
- app.dependency_overrides[get_schedule_item_service] = _override_schedule_item_service(
- FakeScheduleItemService(item)
- )
-
- client = TestClient(app)
- try:
- response = client.get(
- "/api/v1/schedule-items",
- params={
- "start_at": "2026-02-01T00:00:00Z",
- "end_at": "2026-02-28T23:59:59Z",
- },
- )
- assert response.status_code == 200
- assert isinstance(response.json(), list)
- finally:
- app.dependency_overrides = {}
-
-
-def test_get_schedule_item_returns_200() -> None:
- user_id = UUID("00000000-0000-0000-0000-000000000001")
- item_id = uuid4()
- item = ScheduleItemResponse(
- id=item_id,
- title="Test Event",
- start_at=datetime(2026, 2, 28, 16, 0, 0, tzinfo=timezone.utc),
- timezone="UTC",
- status="active",
- source_type="manual",
- created_at=datetime(2026, 2, 27, 10, 0, 0, tzinfo=timezone.utc),
- updated_at=datetime(2026, 2, 27, 10, 0, 0, tzinfo=timezone.utc),
- )
-
- app.dependency_overrides[get_schedule_item_service] = _override_schedule_item_service(
- FakeScheduleItemService(item)
- )
-
- client = TestClient(app)
- try:
- response = client.get(f"/api/v1/schedule-items/{item_id}")
- assert response.status_code == 200
- finally:
- app.dependency_overrides = {}
-
-
-def test_update_schedule_item_returns_200() -> None:
- user_id = UUID("00000000-0000-0000-0000-000000000001")
- item_id = uuid4()
- item = ScheduleItemResponse(
- id=item_id,
- title="Updated Event",
- start_at=datetime(2026, 2, 28, 16, 0, 0, tzinfo=timezone.utc),
- timezone="UTC",
- status="active",
- source_type="manual",
- created_at=datetime(2026, 2, 27, 10, 0, 0, tzinfo=timezone.utc),
- updated_at=datetime(2026, 2, 27, 10, 0, 0, tzinfo=timezone.utc),
- )
-
- app.dependency_overrides[get_schedule_item_service] = _override_schedule_item_service(
- FakeScheduleItemService(item)
- )
-
- client = TestClient(app)
- try:
- response = client.patch(
- f"/api/v1/schedule-items/{item_id}",
- json={"title": "Updated Event"},
- )
- assert response.status_code == 200
- finally:
- app.dependency_overrides = {}
-
-
-def test_delete_schedule_item_returns_204() -> None:
- user_id = UUID("00000000-0000-0000-0000-000000000001")
- item_id = uuid4()
- item = ScheduleItemResponse(
- id=item_id,
- title="Test Event",
- start_at=datetime(2026, 2, 28, 16, 0, 0, tzinfo=timezone.utc),
- timezone="UTC",
- status="active",
- source_type="manual",
- created_at=datetime(2026, 2, 27, 10, 0, 0, tzinfo=timezone.utc),
- updated_at=datetime(2026, 2, 27, 10, 0, 0, tzinfo=timezone.utc),
- )
-
- app.dependency_overrides[get_schedule_item_service] = _override_schedule_item_service(
- FakeScheduleItemService(item)
- )
-
- client = TestClient(app)
- try:
- response = client.delete(f"/api/v1/schedule-items/{item_id}")
- assert response.status_code == 204
- finally:
- app.dependency_overrides = {}
-```
-
-**Step 2: 运行测试验证**
-
-Run: `cd backend && uv run pytest tests/integration/test_schedule_items_routes.py -v`
-
-Expected: PASS
-
----
-
-## Task 11: 运行 Lint 和 TypeCheck
-
-**Step 1: 运行 ruff**
-
-Run: `cd backend && uv run ruff check src/v1/schedule_items/`
-
-Expected: No errors
-
-**Step 2: 运行 typecheck**
-
-Run: `cd backend && uv run basedpyright src/v1/schedule_items/`
-
-Expected: No errors
-
----
-
-## Task 12: 更新 API 文档
-
-**Files:**
-- Modify: `docs/runtime/runtime-route.md`
-
-在 `## Auth` 后添加:
-
-```markdown
-## Schedule Items
-
-### POST /schedule-items
-
-创建日历事项(需要认证)。
-
-**Request:**
-```json
-{
- "title": "string (1-255 chars, required)",
- "description": "string? (max 2000 chars)",
- "start_at": "string (ISO 8601 datetime, required)",
- "end_at": "string? (ISO 8601 datetime)",
- "timezone": "string? (default: UTC)",
- "metadata": {
- "color": "#FF6B6B",
- "location": "会议室A",
- "notes": "记得带身份证",
- "attachments": [],
- "version": 1
- }
-}
-```
-
-**Response:** 201 Created
-```json
-{
- "id": "uuid",
- "title": "string",
- "description": "string?",
- "start_at": "string",
- "end_at": "string?",
- "timezone": "string",
- "metadata": {},
- "status": "active",
- "source_type": "manual",
- "created_at": "string",
- "updated_at": "string"
-}
-```
-
-**Errors:**
-- 400: end_at 早于 start_at
-- 401: 未认证
-- 503: 服务不可用
-
----
-
-### GET /schedule-items
-
-按时间范围查询日历事项列表(需要认证)。
-
-**Query Parameters:**
-- `start_at`: ISO 8601 date/datetime(查询范围起始)
-- `end_at`: ISO 8601 date/datetime(查询范围结束)
-
-**Response:** 200 OK
-```json
-[
- {
- "id": "uuid",
- "title": "string",
- "start_at": "string",
- "end_at": "string?",
- "timezone": "string",
- "status": "active"
- }
-]
-```
-
-**Errors:**
-- 400: end_at 早于 start_at
-- 401: 未认证
-
----
-
-### GET /schedule-items/{id}
-
-获取单个日历事项详情(需要认证)。
-
-**Response:** 200 OK
-
-**Errors:**
-- 401: 未认证
-- 404: 事项不存在
-
----
-
-### PATCH /schedule-items/{id}
-
-更新日历事项(需要认证)。
-
-**Request:** 支持 `title`/`description`/`start_at`/`end_at`/`timezone`/`metadata`/`status` 部分更新
-
-**Response:** 200 OK
-
-**Errors:**
-- 401: 未认证
-- 404: 事项不存在
-
----
-
-### DELETE /schedule-items/{id}
-
-删除日历事项(软删除,需要认证)。
-
-**Response:** 204 No Content
-
-**Errors:**
-- 401: 未认证
-- 404: 事项不存在
-
----
-```
-
----
-
-## Task 13: 提交代码
-
-**Step 1: 提交所有变更**
-
-Run: `git add -A && git commit -m "feat: add schedule items CRUD API
-
-- Add ScheduleItem Pydantic schemas with metadata support
-- Add repository layer with CRUD operations
-- Add service layer with authorization
-- Add FastAPI router with all endpoints
-- Add unit and integration tests
-- Update API documentation"`
-
-Expected: Commit created successfully
diff --git a/docs/plans/2026-02-28-ag-ui-chat-design.md b/docs/plans/2026-02-28-ag-ui-chat-design.md
deleted file mode 100644
index ab40467..0000000
--- a/docs/plans/2026-02-28-ag-ui-chat-design.md
+++ /dev/null
@@ -1,567 +0,0 @@
-# AG-UI 聊天功能设计文档
-
-## 1. 概述
-
-本文档描述如何使用 AG-UI 协议实现 AI 聊天功能,包括:
-- 消息的发送与接收(通过 AG-UI 事件流)
-- AI 工具调用(Tool Call)机制
-- 日历卡片作为 Tool Result 渲染
-- 前端工具注册与执行
-- 本地持久化
-
-## 2. 架构设计
-
-### 2.1 整体流程
-
-```
-用户输入消息
- ↓
-AgUiService.sendMessage()
- ↓
-[Mock Mode] 规则引擎决策 → 事件流模拟
-[Real Mode] POST /api/chat → SSE 监听
- ↓
-┌─────────────────────────────────────────────────────────────┐
-│ AG-UI Event Stream (按序处理) │
-├─────────────────────────────────────────────────────────────┤
-│ TEXT_MESSAGE_START → TEXT_MESSAGE_CONTENT* → TEXT_MESSAGE_END │
-│ TOOL_CALL_START → TOOL_CALL_ARGS* → TOOL_CALL_END │
-│ TOOL_CALL_RESULT │
-│ RUN_STARTED → ... → RUN_FINISHED │
-└─────────────────────────────────────────────────────────────┘
- ↓
-ChatListItem 渲染
-```
-
-### 2.2 核心组件
-
-| 组件 | 职责 |
-|------|------|
-| `AgUiEvent` | AG-UI 事件数据模型 |
-| `AgUiService` | 事件流处理:发送消息、解析事件 |
-| `ToolRegistry` | 前端工具注册表:定义工具 + handler |
-| `AiDecisionEngine` | Mock 模式:规则引擎决定是否调用工具 |
-| `UiSchemaParser` | 解析 tool result 中的 UI Schema |
-| `UiSchemaRenderer` | 根据 schema 渲染对应组件 |
-| `ChatHistoryRepository` | 本地持久化:IndexedDB/localStorage |
-
-### 2.3 状态管理
-
-```
-ChatState {
- messages: ChatListItem[] // 渲染列表
- pendingToolCalls: Map
- isLoading: bool
- runId: string | null
-}
-```
-
-## 3. 数据模型
-
-### 3.1 AG-UI 事件模型
-
-```dart
-// 基类
-abstract class AgUiEvent {
- final String type;
- final String? timestamp;
-}
-
-// 生命周期事件
-class RunStartedEvent extends AgUiEvent {
- final String threadId;
- final String runId;
- final String? parentRunId;
-}
-
-class RunFinishedEvent extends AgUiEvent {
- final String threadId;
- final String runId;
- final dynamic result;
-}
-
-// 文本消息事件
-class TextMessageStartEvent extends AgUiEvent {
- final String messageId;
- final String role; // "user" | "assistant" | "system"
-}
-
-class TextMessageContentEvent extends AgUiEvent {
- final String messageId;
- final String delta;
-}
-
-class TextMessageEndEvent extends AgUiEvent {
- final String messageId;
-}
-
-// 工具调用事件
-class ToolCallStartEvent extends AgUiEvent {
- final String toolCallId;
- final String toolCallName;
- final String? parentMessageId;
-}
-
-class ToolCallArgsEvent extends AgUiEvent {
- final String toolCallId;
- final String delta; // JSON fragment
-}
-
-class ToolCallEndEvent extends AgUiEvent {
- final String toolCallId;
-}
-
-class ToolCallResultEvent extends AgUiEvent {
- final String messageId;
- final String toolCallId;
- final ToolResult result; // 给 AI 的原始结果
- final UiCard? ui; // 给 UI 的渲染数据
-}
-
-class ToolCallErrorEvent extends AgUiEvent {
- final String toolCallId;
- final String error;
- final String? code;
-}
-```
-
-### 3.2 Tool Result Schema(v1)
-
-```json
-{
- "type": "tool_result",
- "version": "v1",
- "call_id": "call_abc123",
- "tool_name": "create_calendar_event",
- "result": {
- "eventId": "evt_xxx",
- "ok": true,
- "message": "日程已创建"
- },
- "ui": {
- "type": "card",
- "cardType": "calendar_card.v1",
- "data": {
- "id": "evt_xxx",
- "title": "产品评审会议",
- "description": "讨论Q2路线图",
- "startAt": "2026-03-01T10:00:00+08:00",
- "endAt": "2026-03-01T11:00:00+08:00",
- "timezone": "Asia/Shanghai",
- "location": "会议室A",
- "color": "#4F46E5",
- "sourceType": "agentGenerated"
- },
- "actions": [
- {"type": "open", "label": "打开", "target": "calendar/evt_xxx"},
- {"type": "edit", "label": "编辑", "action": "edit_event"},
- {"type": "delete", "label": "删除", "action": "delete_event"}
- ]
- }
-}
-```
-
-### 3.3 工具定义(前端 Tool Registry)
-
-```dart
-// 工具定义
-class ToolDefinition {
- final String name;
- final String description;
- final Map parameters;
- final ToolHandler handler;
-}
-
-// create_calendar_event 工具
-{
- "name": "create_calendar_event",
- "description": "创建一个日历事件或待办事项",
- "parameters": {
- "type": "object",
- "properties": {
- "title": {
- "type": "string",
- "description": "事件标题",
- "minLength": 1,
- "maxLength": 100
- },
- "description": {
- "type": "string",
- "description": "事件描述"
- },
- "startAt": {
- "type": "string",
- "format": "date-time",
- "description": "开始时间 (ISO8601)"
- },
- "endAt": {
- "type": "string",
- "format": "date-time",
- "description": "结束时间 (ISO8601)"
- },
- "timezone": {
- "type": "string",
- "default": "Asia/Shanghai"
- },
- "location": {
- "type": "string"
- },
- "notes": {
- "type": "string"
- }
- },
- "required": ["title", "startAt"]
- }
-}
-```
-
-### 3.4 ChatListItem 模型
-
-```dart
-enum ChatItemType {
- message, // 纯文本消息
- toolCall, // 工具调用中
- toolResult, // 工具结果卡片
- schedule // 日历事件(兼容旧数据)
-}
-
-abstract class ChatListItem {
- String get id;
- DateTime get timestamp;
- ChatItemType get type;
- MessageSender get sender;
-}
-
-class TextMessageItem extends ChatListItem {
- final String id;
- final String content;
- final DateTime timestamp;
- final MessageSender sender;
- final bool isStreaming; // 是否正在流式输出
-}
-
-class ToolCallItem extends ChatListItem {
- final String id;
- final String callId;
- final String toolName;
- final Map args; // 解析后的参数
- final ToolCallStatus status; // pending | executing | completed | error
- final ToolResult? result;
- final UiCard? uiCard;
-}
-
-class CalendarCardItem extends ChatListItem {
- final String id;
- final String callId; // 关联的 tool call
- final CalendarCardData data;
- final List actions;
-}
-```
-
-## 4. 核心流程
-
-### 4.1 发送消息
-
-```dart
-Future sendMessage(String content) async {
- // 1. 添加用户消息到列表
- final userMessage = TextMessageItem(
- id: generateId(),
- content: content,
- timestamp: DateTime.now(),
- sender: MessageSender.user,
- );
- _chatItems.add(userMessage);
-
- // 2. 发起请求
- if (Env.isMockApi) {
- await _mockEventStream(content);
- } else {
- await _realEventStream(content);
- }
-}
-```
-
-### 4.2 Mock 事件流(规则引擎)
-
-```dart
-class AiDecisionEngine {
- // 意图关键词映射
- static final Map> _intentPatterns = {
- Intent.createEvent: [
- RegExp(r'提醒|开会|预约|日程|安排'),
- RegExp(r'明天|今天|后天|下周'),
- RegExp(r'\d{1,2}点|\d{1,2}:\d{2}'),
- ],
- Intent.searchEvent: [
- RegExp(r'查看|有什么|今天.*日程|明天.*安排'),
- ],
- };
-
- Intent? matchIntent(String text) {
- for (final entry in _intentPatterns.entries) {
- for (final pattern in entry.value) {
- if (pattern.hasMatch(text)) {
- return entry.key;
- }
- }
- }
- return null;
- }
-
- // 支持强制触发:#tool:create_calendar_event {"title": "test"}
- bool tryForceTrigger(String text) {...}
-}
-```
-
-### 4.3 事件解析与处理
-
-```dart
-Future _processEvent(AgUiEvent event) async {
- switch (event.type) {
- case 'TEXT_MESSAGE_START':
- _handleTextMessageStart(event);
- break;
- case 'TEXT_MESSAGE_CONTENT':
- _handleTextMessageContent(event);
- break;
- case 'TEXT_MESSAGE_END':
- _handleTextMessageEnd(event);
- break;
- case 'TOOL_CALL_START':
- _handleToolCallStart(event);
- break;
- case 'TOOL_CALL_ARGS':
- _handleToolCallArgs(event);
- break;
- case 'TOOL_CALL_END':
- await _handleToolCallEnd(event);
- break;
- case 'TOOL_CALL_RESULT':
- _handleToolCallResult(event);
- break;
- case 'TOOL_CALL_ERROR':
- _handleToolCallError(event);
- break;
- }
-}
-
-void _handleToolCallStart(ToolCallStartEvent event) {
- // 创建 pending 状态的 tool call item
- final item = ToolCallItem(
- id: event.toolCallId,
- callId: event.toolCallId,
- toolName: event.toolCallName,
- args: {},
- status: ToolCallStatus.pending,
- );
- _chatItems.add(item);
-}
-
-Future _handleToolCallEnd(ToolCallEndEvent event) async {
- // 1. 找到对应的 pending tool call
- final toolCall = _findPendingToolCall(event.toolCallId);
- if (toolCall == null) return;
-
- // 2. 校验参数 JSON Schema
- final validation = validateToolArgs(toolCall.toolName, toolCall.args);
- if (!validation.ok) {
- _emitToolCallError(event.toolCallId, validation.error);
- return;
- }
-
- // 3. 执行工具 handler
- toolCall.status = ToolCallStatus.executing;
- final result = await ToolRegistry.execute(
- toolCall.toolName,
- toolCall.args,
- );
-
- // 4. 构建 tool result(包含 result + ui)
- final toolResult = ToolResult(
- eventId: result['eventId'],
- ok: result['ok'] ?? true,
- message: result['message'],
- );
-
- final uiCard = _buildUiCard(toolCall.toolName, result);
-
- // 5. 发送 TOOL_CALL_RESULT 事件
- _emitToolCallResult(event.toolCallId, toolResult, uiCard);
-}
-```
-
-### 4.4 UI Schema 渲染
-
-```dart
-class UiSchemaRenderer {
- static final Map _renderers = {
- 'calendar_card.v1': (card) => CalendarCardWidget(
- data: CalendarCardData.fromJson(card.data),
- actions: card.actions,
- ),
- };
-
- static Widget render(UiCard card) {
- final renderer = _renderers[card.cardType];
- if (renderer != null) {
- return renderer(card);
- }
- // Unknown card type fallback
- return _renderUnknownCard(card);
- }
-
- static Widget _renderUnknownCard(UiCard card) {
- return GenericCardWidget(
- rawJson: jsonEncode(card.toJson()),
- cardType: card.cardType,
- );
- }
-}
-```
-
-### 4.5 日历卡片组件
-
-```dart
-class CalendarCardWidget extends StatelessWidget {
- final CalendarCardData data;
- final List actions;
-
- @override
- Widget build(BuildContext context) {
- final color = ColorExt.parse(data.color ?? '#4F46E5');
-
- return Container(
- decoration: BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.circular(12),
- boxShadow: [...],
- ),
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- // 颜色条
- Container(
- height: 4,
- color: color,
- ),
- // 内容
- Padding(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(data.title, style: ...),
- if (data.description != null) ...,
- _buildTimeRow(),
- if (data.location != null) ...,
- ],
- ),
- ),
- // Actions
- if (actions.isNotEmpty) _buildActions(actions),
- ],
- ),
- );
- }
-}
-```
-
-## 5. 持久化设计
-
-### 5.1 存储结构
-
-```dart
-// localStorage / IndexedDB
-{
- "chat_sessions": {
- "current_thread_id": {
- "messages": [...], // ChatListItem JSON
- "lastRunId": "run_xxx",
- "updatedAt": "2026-02-28T12:00:00Z"
- }
- },
- "calendar_events": {
- "evt_xxx": {...} // 独立存储的日历事件
- }
-}
-```
-
-### 5.2 恢复逻辑
-
-```dart
-Future restoreSession() async {
- final session = await ChatHistoryRepository.load('current_thread_id');
- if (session != null) {
- _chatItems.clear();
- _chatItems.addAll(session.messages);
- _runId = session.lastRunId;
- }
-}
-```
-
-## 6. 错误处理
-
-### 6.1 Tool Call 错误
-
-```dart
-void _emitToolCallError(String callId, String error) {
- // 1. 更新 item 状态
- final item = _findToolCallItem(callId);
- item?.status = ToolCallStatus.error;
- item?.errorMessage = error;
-
- // 2. 渲染错误卡片
- final errorCard = UiCard(
- cardType: 'error_card.v1',
- data: {'message': error},
- );
-
- // 3. 触发 UI 更新
- notifyListeners();
-}
-```
-
-### 6.2 事件流重连
-
-```dart
-// 断线重连时从 snapshot 恢复
-Future reconnect() async {
- final snapshot = await _fetchMessagesSnapshot();
- _chatItems.clear();
- _chatItems.addAll(snapshot.messages);
-
- // 重新订阅事件流
- _subscribeToEvents();
-}
-```
-
-## 7. 实施计划
-
-### Phase 1: 基础框架
-- [ ] 定义 AG-UI 事件模型
-- [ ] 实现 AgUiService 基础结构
-- [ ] 实现 ToolRegistry
-
-### Phase 2: Mock 实现
-- [ ] 实现 AiDecisionEngine 规则引擎
-- [ ] 实现 Mock 事件流
-- [ ] 集成现有 HomeScreen
-
-### Phase 3: UI 渲染
-- [ ] 实现 UiSchemaParser
-- [ ] 实现 CalendarCardWidget
-- [ ] 实现 ToolPending / ToolError 状态卡片
-
-### Phase 4: 持久化
-- [ ] 实现 ChatHistoryRepository
-- [ ] 实现会话恢复
-
-### Phase 5: 真实后端对接
-- [ ] 实现 SSE 客户端
-- [ ] 实现事件流解析器
-
-## 8. 版本历史
-
-| 版本 | 日期 | 变更 |
-|------|------|------|
-| v1.0 | 2026-02-28 | 初始版本 |
diff --git a/docs/plans/2026-02-28-ag-ui-chat-implementation-plan.md b/docs/plans/2026-02-28-ag-ui-chat-implementation-plan.md
deleted file mode 100644
index 6a4a546..0000000
--- a/docs/plans/2026-02-28-ag-ui-chat-implementation-plan.md
+++ /dev/null
@@ -1,2463 +0,0 @@
-# AG-UI 聊天功能实现计划 v1.3
-
-> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
->
-> **Revision History:**
-> - v1.3: 修复 AiDecisionEngine 规则优先级、ChatState.copyWith 空值处理、测试用例对齐
-> - v1.2: 修复 AgUiService.onEvent 可变、ChatBloc 初始化、补充测试覆盖
-> - v1.1: 修复编译错误、事件映射、职责边界、设计 token、测试覆盖等问题
-
-**Goal:** 实现基于 AG-UI 协议的 AI 聊天功能,包括事件流处理、工具调用、日历卡片渲染
-
-**Architecture:**
-- 核心组件:AgUiService 处理事件流、ToolRegistry 管理前端工具
-- 数据流:用户消息 → 事件流 → AI 响应 → ToolCall → 执行 → UI 渲染
-- Mock 模式使用规则引擎模拟 AI 决策,真实模式对接 SSE
-
-**Tech Stack:** Flutter, Dart, shared_preferences
-
-**Scope:** 本次仅实现 Mock 模式,真实 SSE 对接后续迭代
-
----
-
-## 阶段 0: 依赖与脚手架
-
-### Task 0: 添加依赖
-
-**Files:**
-- Modify: `apps/pubspec.yaml`
-
-**Step 1: 添加依赖**
-
-```yaml
-dependencies:
- shared_preferences: ^2.2.2
- json_annotation: ^4.8.1
-
-dev_dependencies:
- json_serializable: ^6.7.1
- build_runner: ^2.4.8
-```
-
-**Step 2: 安装依赖**
-
-Run: `cd apps && flutter pub get`
-
-Expected: 依赖安装成功
-
-**Step 3: 创建目录结构**
-
-Run: `mkdir -p apps/lib/features/chat/{data/{models,tools,services,ai,repositories},ui/widgets}`
-
-**Step 4: Commit**
-
-```bash
-git add apps/pubspec.yaml apps/pubspec.lock
-git commit -m "chore(chat): add json_annotation and shared_preferences deps"
-```
-
----
-
-## 阶段 1: 基础框架
-
-### Task 1: 创建 AG-UI 事件模型
-
-**Files:**
-- Create: `apps/lib/features/chat/data/models/ag_ui_event.dart`
-
-**Step 1: 写入 AG-UI 事件基类和子类型**
-
-```dart
-import 'package:json_annotation/json_annotation.dart';
-import 'tool_result.dart'; // 引入 UiCard 定义
-
-part 'ag_ui_event.g.dart';
-
-/// Wire protocol 事件类型字符串(与服务端协议对齐)
-class AgUiEventTypeWire {
- static const runStarted = 'RUN_STARTED';
- static const runFinished = 'RUN_FINISHED';
- static const runError = 'RUN_ERROR';
- static const textMessageStart = 'TEXT_MESSAGE_START';
- static const textMessageContent = 'TEXT_MESSAGE_CONTENT';
- static const textMessageEnd = 'TEXT_MESSAGE_END';
- static const toolCallStart = 'TOOL_CALL_START';
- static const toolCallArgs = 'TOOL_CALL_ARGS';
- static const toolCallEnd = 'TOOL_CALL_END';
- static const toolCallResult = 'TOOL_CALL_RESULT';
- static const toolCallError = 'TOOL_CALL_ERROR';
-}
-
-/// 内部事件类型枚举
-enum AgUiEventType {
- runStarted,
- runFinished,
- runError,
- textMessageStart,
- textMessageContent,
- textMessageEnd,
- toolCallStart,
- toolCallArgs,
- toolCallEnd,
- toolCallResult,
- toolCallError,
- unknown,
-}
-
-/// 事件类型映射工具
-class AgUiEventTypeMapper {
- static AgUiEventType fromWire(String wireType) {
- switch (wireType) {
- case AgUiEventTypeWire.runStarted:
- return AgUiEventType.runStarted;
- case AgUiEventTypeWire.runFinished:
- return AgUiEventType.runFinished;
- case AgUiEventTypeWire.runError:
- return AgUiEventType.runError;
- case AgUiEventTypeWire.textMessageStart:
- return AgUiEventType.textMessageStart;
- case AgUiEventTypeWire.textMessageContent:
- return AgUiEventType.textMessageContent;
- case AgUiEventTypeWire.textMessageEnd:
- return AgUiEventType.textMessageEnd;
- case AgUiEventTypeWire.toolCallStart:
- return AgUiEventType.toolCallStart;
- case AgUiEventTypeWire.toolCallArgs:
- return AgUiEventType.toolCallArgs;
- case AgUiEventTypeWire.toolCallEnd:
- return AgUiEventType.toolCallEnd;
- case AgUiEventTypeWire.toolCallResult:
- return AgUiEventType.toolCallResult;
- case AgUiEventTypeWire.toolCallError:
- return AgUiEventType.toolCallError;
- default:
- return AgUiEventType.unknown;
- }
- }
-
- static String toWire(AgUiEventType type) {
- switch (type) {
- case AgUiEventType.runStarted:
- return AgUiEventTypeWire.runStarted;
- case AgUiEventType.runFinished:
- return AgUiEventTypeWire.runFinished;
- case AgUiEventType.runError:
- return AgUiEventTypeWire.runError;
- case AgUiEventType.textMessageStart:
- return AgUiEventTypeWire.textMessageStart;
- case AgUiEventType.textMessageContent:
- return AgUiEventTypeWire.textMessageContent;
- case AgUiEventType.textMessageEnd:
- return AgUiEventTypeWire.textMessageEnd;
- case AgUiEventType.toolCallStart:
- return AgUiEventTypeWire.toolCallStart;
- case AgUiEventType.toolCallArgs:
- return AgUiEventTypeWire.toolCallArgs;
- case AgUiEventType.toolCallEnd:
- return AgUiEventTypeWire.toolCallEnd;
- case AgUiEventType.toolCallResult:
- return AgUiEventTypeWire.toolCallResult;
- case AgUiEventType.toolCallError:
- return AgUiEventTypeWire.toolCallError;
- case AgUiEventType.unknown:
- return 'UNKNOWN';
- }
- }
-}
-
-/// 基类事件
-@JsonSerializable()
-class AgUiEvent {
- final AgUiEventType type;
- final String? timestamp;
-
- AgUiEvent({required this.type, this.timestamp});
-
- factory AgUiEvent.fromJson(Map json) {
- final wireType = json['type'] as String? ?? 'UNKNOWN';
- final type = AgUiEventTypeMapper.fromWire(wireType);
-
- switch (type) {
- case AgUiEventType.textMessageStart:
- return TextMessageStartEvent.fromJson(json);
- case AgUiEventType.textMessageContent:
- return TextMessageContentEvent.fromJson(json);
- case AgUiEventType.textMessageEnd:
- return TextMessageEndEvent.fromJson(json);
- case AgUiEventType.toolCallStart:
- return ToolCallStartEvent.fromJson(json);
- case AgUiEventType.toolCallArgs:
- return ToolCallArgsEvent.fromJson(json);
- case AgUiEventType.toolCallEnd:
- return ToolCallEndEvent.fromJson(json);
- case AgUiEventType.toolCallResult:
- return ToolCallResultEvent.fromJson(json);
- case AgUiEventType.toolCallError:
- return ToolCallErrorEvent.fromJson(json);
- case AgUiEventType.runStarted:
- return RunStartedEvent.fromJson(json);
- case AgUiEventType.runFinished:
- return RunFinishedEvent.fromJson(json);
- case AgUiEventType.runError:
- return RunErrorEvent.fromJson(json);
- case AgUiEventType.unknown:
- default:
- return UnknownAgUiEvent(raw: json);
- }
- }
-
- Map toJson() => _$AgUiEventToJson(this);
-}
-
-/// 未知事件(容错处理)
-@JsonSerializable()
-class UnknownAgUiEvent extends AgUiEvent {
- final Map raw;
-
- UnknownAgUiEvent({required this.raw})
- : super(type: AgUiEventType.unknown);
-
- factory UnknownAgUiEvent.fromJson(Map json) =>
- _$UnknownAgUiEventFromJson(json);
-
- @override
- Map toJson() => raw;
-}
-
-@JsonSerializable()
-class RunStartedEvent extends AgUiEvent {
- final String threadId;
- final String runId;
-
- RunStartedEvent({
- required this.threadId,
- required this.runId,
- }) : super(type: AgUiEventType.runStarted);
-
- factory RunStartedEvent.fromJson(Map json) =>
- _$RunStartedEventFromJson(json);
-}
-
-@JsonSerializable()
-class RunFinishedEvent extends AgUiEvent {
- final String threadId;
- final String runId;
-
- RunFinishedEvent({
- required this.threadId,
- required this.runId,
- }) : super(type: AgUiEventType.runFinished);
-
- factory RunFinishedEvent.fromJson(Map json) =>
- _$RunFinishedEventFromJson(json);
-}
-
-@JsonSerializable()
-class RunErrorEvent extends AgUiEvent {
- final String message;
- final String? code;
-
- RunErrorEvent({
- required this.message,
- this.code,
- }) : super(type: AgUiEventType.runError);
-
- factory RunErrorEvent.fromJson(Map json) =>
- _$RunErrorEventFromJson(json);
-}
-
-@JsonSerializable()
-class TextMessageStartEvent extends AgUiEvent {
- final String messageId;
- final String role;
-
- TextMessageStartEvent({
- required this.messageId,
- required this.role,
- }) : super(type: AgUiEventType.textMessageStart);
-
- factory TextMessageStartEvent.fromJson(Map json) =>
- _$TextMessageStartEventFromJson(json);
-}
-
-@JsonSerializable()
-class TextMessageContentEvent extends AgUiEvent {
- final String messageId;
- final String delta;
-
- TextMessageContentEvent({
- required this.messageId,
- required this.delta,
- }) : super(type: AgUiEventType.textMessageContent);
-
- factory TextMessageContentEvent.fromJson(Map json) =>
- _$TextMessageContentEventFromJson(json);
-}
-
-@JsonSerializable()
-class TextMessageEndEvent extends AgUiEvent {
- final String messageId;
-
- TextMessageEndEvent({required this.messageId})
- : super(type: AgUiEventType.textMessageEnd);
-
- factory TextMessageEndEvent.fromJson(Map json) =>
- _$TextMessageEndEventFromJson(json);
-}
-
-@JsonSerializable()
-class ToolCallStartEvent extends AgUiEvent {
- final String toolCallId;
- final String toolCallName;
- final String? parentMessageId;
-
- ToolCallStartEvent({
- required this.toolCallId,
- required this.toolCallName,
- this.parentMessageId,
- }) : super(type: AgUiEventType.toolCallStart);
-
- factory ToolCallStartEvent.fromJson(Map json) =>
- _$ToolCallStartEventFromJson(json);
-}
-
-@JsonSerializable()
-class ToolCallArgsEvent extends AgUiEvent {
- final String toolCallId;
- final String delta;
-
- ToolCallArgsEvent({
- required this.toolCallId,
- required this.delta,
- }) : super(type: AgUiEventType.toolCallArgs);
-
- factory ToolCallArgsEvent.fromJson(Map json) =>
- _$ToolCallArgsEventFromJson(json);
-}
-
-@JsonSerializable()
-class ToolCallEndEvent extends AgUiEvent {
- final String toolCallId;
-
- ToolCallEndEvent({required this.toolCallId})
- : super(type: AgUiEventType.toolCallEnd);
-
- factory ToolCallEndEvent.fromJson(Map json) =>
- _$ToolCallEndEventFromJson(json);
-}
-
-@JsonSerializable()
-class ToolCallResultEvent extends AgUiEvent {
- final String messageId;
- final String toolCallId;
- final Map result;
- final UiCard? ui;
-
- ToolCallResultEvent({
- required this.messageId,
- required this.toolCallId,
- required this.result,
- this.ui,
- }) : super(type: AgUiEventType.toolCallResult);
-
- factory ToolCallResultEvent.fromJson(Map json) =>
- _$ToolCallResultEventFromJson(json);
-}
-
-@JsonSerializable()
-class ToolCallErrorEvent extends AgUiEvent {
- final String toolCallId;
- final String error;
- final String? code;
-
- ToolCallErrorEvent({
- required this.toolCallId,
- required this.error,
- this.code,
- }) : super(type: AgUiEventType.toolCallError);
-
- factory ToolCallErrorEvent.fromJson(Map json) =>
- _$ToolCallErrorEventFromJson(json);
-}
-
-// UiCard 定义在 tool_result.dart,通过 import 引入
-// 此文件顶部需要: import 'tool_result.dart';
-```
-
-**Step 2: 生成代码**
-
-Run: `cd apps && dart run build_runner build --delete-conflicting-outputs`
-
-Expected: 生成 `ag_ui_event.g.dart`
-
-**Step 3: Commit**
-
-```bash
-git add apps/lib/features/chat/data/models/ag_ui_event.dart
-git commit -m "feat(chat): add AG-UI event models with wire protocol mapping"
-```
-
----
-
-### Task 2: 创建 Tool Result Schema 模型
-
-**Files:**
-- Create: `apps/lib/features/chat/data/models/tool_result.dart`
-
-**Step 1: 写入 ToolResult 和 UiCard 模型**
-
-```dart
-import 'package:json_annotation/json_annotation.dart';
-
-part 'tool_result.g.dart';
-
-/// 工具执行结果(给 AI 的原始数据)
-@JsonSerializable()
-class ToolResult {
- final String? eventId;
- final bool ok;
- final String? message;
-
- ToolResult({
- this.eventId,
- this.ok = true,
- this.message,
- });
-
- factory ToolResult.fromJson(Map json) =>
- _$ToolResultFromJson(json);
-
- Map toJson() => _$ToolResultToJson(this);
-}
-
-/// UI 卡片 Schema(给 UI 渲染)
-@JsonSerializable()
-class UiCard {
- @JsonKey(name: 'type')
- final String cardType;
-
- @JsonKey(name: 'version')
- final String? schemaVersion;
-
- final Map data;
- final List? actions;
-
- UiCard({
- required this.cardType,
- this.schemaVersion = 'v1',
- required this.data,
- this.actions,
- });
-
- factory UiCard.fromJson(Map json) =>
- _$UiCardFromJson(json);
-
- Map toJson() => _$UiCardToJson(this);
-}
-
-/// 卡片操作按钮
-@JsonSerializable()
-class CardAction {
- final String type;
- final String label;
- final String? target;
- final String? action;
-
- CardAction({
- required this.type,
- required this.label,
- this.target,
- this.action,
- });
-
- factory CardAction.fromJson(Map json) =>
- _$CardActionFromJson(json);
-
- Map toJson() => _$CardActionToJson(this);
-}
-
-/// 日历卡片数据
-@JsonSerializable()
-class CalendarCardData {
- final String id;
- final String title;
- final String? description;
- final String startAt;
- final String? endAt;
- final String? timezone;
- final String? location;
- final String? color;
- final String? sourceType;
-
- CalendarCardData({
- required this.id,
- required this.title,
- this.description,
- required this.startAt,
- this.endAt,
- this.timezone,
- this.location,
- this.color,
- this.sourceType,
- });
-
- factory CalendarCardData.fromJson(Map json) =>
- _$CalendarCardDataFromJson(json);
-
- Map toJson() => _$CalendarCardDataToJson(this);
-}
-```
-
-**Step 2: 生成代码**
-
-Run: `cd apps && dart run build_runner build --delete-conflicting-outputs`
-
-**Step 3: Commit**
-
-```bash
-git add apps/lib/features/chat/data/models/tool_result.dart
-git commit -m "feat(chat): add ToolResult and UiCard models"
-```
-
----
-
-### Task 3: 创建 ChatListItem 模型(独立于 home)
-
-**Files:**
-- Create: `apps/lib/features/chat/data/models/chat_list_item.dart`
-
-**Step 1: 写入 ChatListItem 模型**
-
-```dart
-import 'tool_result.dart';
-
-enum ChatItemType { message, toolCall, toolResult }
-
-enum MessageSender { user, ai }
-
-enum ToolCallStatus { pending, executing, completed, error }
-
-/// 聊天列表项基类
-abstract class ChatListItem {
- String get id;
- DateTime get timestamp;
- ChatItemType get type;
- MessageSender get sender;
-}
-
-/// 文本消息项
-class TextMessageItem extends ChatListItem {
- @override
- final String id;
- final String content;
- @override
- final DateTime timestamp;
- @override
- final MessageSender sender;
- final bool isStreaming;
-
- TextMessageItem({
- required this.id,
- required this.content,
- required this.timestamp,
- required this.sender,
- this.isStreaming = false,
- });
-
- @override
- ChatItemType get type => ChatItemType.message;
-
- TextMessageItem copyWith({
- String? id,
- String? content,
- DateTime? timestamp,
- MessageSender? sender,
- bool? isStreaming,
- }) {
- return TextMessageItem(
- id: id ?? this.id,
- content: content ?? this.content,
- timestamp: timestamp ?? this.timestamp,
- sender: sender ?? this.sender,
- isStreaming: isStreaming ?? this.isStreaming,
- );
- }
-}
-
-/// 工具调用项(pending 状态)
-class ToolCallItem extends ChatListItem {
- @override
- final String id;
- final String callId;
- final String toolName;
- final Map args;
- final ToolCallStatus status;
- final String? errorMessage;
- @override
- final DateTime timestamp;
- @override
- final MessageSender sender;
-
- ToolCallItem({
- required this.id,
- required this.callId,
- required this.toolName,
- required this.args,
- required this.status,
- this.errorMessage,
- required this.timestamp,
- required this.sender,
- });
-
- @override
- ChatItemType get type => ChatItemType.toolCall;
-
- ToolCallItem copyWith({
- String? id,
- String? callId,
- String? toolName,
- Map? args,
- ToolCallStatus? status,
- String? errorMessage,
- DateTime? timestamp,
- MessageSender? sender,
- }) {
- return ToolCallItem(
- id: id ?? this.id,
- callId: callId ?? this.callId,
- toolName: toolName ?? this.toolName,
- args: args ?? this.args,
- status: status ?? this.status,
- errorMessage: errorMessage ?? this.errorMessage,
- timestamp: timestamp ?? this.timestamp,
- sender: sender ?? this.sender,
- );
- }
-}
-
-/// 工具结果卡片项
-class ToolResultItem extends ChatListItem {
- @override
- final String id;
- final String callId;
- final UiCard uiCard;
- @override
- final DateTime timestamp;
- @override
- final MessageSender sender;
-
- ToolResultItem({
- required this.id,
- required this.callId,
- required this.uiCard,
- required this.timestamp,
- required this.sender,
- });
-
- @override
- ChatItemType get type => ChatItemType.toolResult;
-}
-```
-
-**Step 2: Commit**
-
-```bash
-git add apps/lib/features/chat/data/models/chat_list_item.dart
-git commit -m "feat(chat): add ChatListItem models in chat feature"
-```
-
----
-
-### Task 4: 创建 ToolRegistry
-
-**Files:**
-- Create: `apps/lib/features/chat/data/tools/tool_registry.dart`
-
-**Step 1: 写入 ToolRegistry**
-
-```dart
-import 'dart:convert';
-
-typedef ToolHandler = Future