Compare commits

...

7 Commits

Author SHA1 Message Date
Devin AI
f4926a9810 Fix lint error and validation error in test_markdown_task.py
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-05-20 05:51:08 +00:00
Devin AI
05e3e9c2ff Enhance markdown feature based on PR feedback
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-05-20 05:44:56 +00:00
Devin AI
2c26ab27c0 Add markdown attribute to Task class for formatting responses in Markdown
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-05-20 05:39:49 +00:00
Vidit Ostwal
bef5971598 Added Stop parameter docs (#2854)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-05-17 17:41:12 -04:00
Vidit Ostwal
aa6e5b703e Fix fail llama test (#2819)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
* Changed test case

* Addd new interaction with llama

* fixed linting issue

* Gemma Flaky test case

* Gemma Flaky test case

* Minor change

* Minor change

* Dropped API key

* Removed falky test case check file
2025-05-16 15:18:11 -04:00
Tony Kipkemboi
0b35e40a24 docs: add StagehandTool documentation and improve MDX structure (#2842)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
2025-05-15 12:24:25 -04:00
Lucas Gomide
49bbf3f234 Docs Updates (#2840)
Some checks failed
Notify Downstream / notify-downstream (push) Has been cancelled
* docs: remove EventHandler reference on docs

* docs: add section explaining how to run a Crew from CrewBase
2025-05-15 09:17:21 -04:00
15 changed files with 451 additions and 6163 deletions

View File

@@ -117,6 +117,12 @@ class YourCrewName:
)
```
How to run the above code:
```python code
YourCrewName().crew().kickoff(inputs={"any": "input here"})
```
<Note>
Tasks will be executed in the order they are defined.
</Note>
@@ -184,6 +190,11 @@ class YourCrewName:
verbose=True
)
```
How to run the above code:
```python code
YourCrewName().crew().kickoff(inputs={})
```
In this example:

View File

@@ -677,18 +677,24 @@ CrewAI supports streaming responses from LLMs, allowing your application to rece
CrewAI emits events for each chunk received during streaming:
```python
from crewai import LLM
from crewai.utilities.events import EventHandler, LLMStreamChunkEvent
from crewai.utilities.events import (
LLMStreamChunkEvent
)
from crewai.utilities.events.base_event_listener import BaseEventListener
class MyEventHandler(EventHandler):
def on_llm_stream_chunk(self, event: LLMStreamChunkEvent):
# Process each chunk as it arrives
print(f"Received chunk: {event.chunk}")
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}")
# Register the event handler
from crewai.utilities.events import crewai_event_bus
crewai_event_bus.register_handler(MyEventHandler())
my_listener = MyCustomListener()
```
<Tip>
[Click here](https://docs.crewai.com/concepts/event-listener#event-listeners) for more details
</Tip>
</Tab>
</Tabs>
@@ -785,6 +791,24 @@ Learn how to get the most out of your LLM configuration:
Remember to regularly monitor your token usage and adjust your configuration as needed to optimize costs and performance.
</Info>
</Accordion>
<Accordion title="Drop Additional Parameters">
CrewAI internally uses Litellm for LLM calls, which allows you to drop additional parameters that are not needed for your specific use case. This can help simplify your code and reduce the complexity of your LLM configuration.
For example, if you don't need to send the <code>stop</code> parameter, you can simply omit it from your LLM call:
```python
from crewai import LLM
import os
os.environ["OPENAI_API_KEY"] = "<api-key>"
o3_llm = LLM(
model="o3",
drop_params=True,
additional_drop_params=["stop"]
)
```
</Accordion>
</AccordionGroup>
## Common Issues and Solutions

View File

@@ -129,6 +129,7 @@
"tools/seleniumscrapingtool",
"tools/snowflakesearchtool",
"tools/spidertool",
"tools/stagehandtool",
"tools/txtsearchtool",
"tools/visiontool",
"tools/weaviatevectorsearchtool",

View File

@@ -4,8 +4,6 @@ description: Dive deeper into low-level prompt customization for CrewAI, enablin
icon: message-pen
---
# Customizing Prompts at a Low Level
## 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. Heres why you might want to take advantage of this deeper control:

View File

@@ -4,8 +4,6 @@ description: Learn how to use CrewAI's fingerprinting system to uniquely identif
icon: fingerprint
---
# Fingerprinting in CrewAI
## 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.

View File

@@ -4,8 +4,6 @@ description: Learn best practices for designing powerful, specialized AI agents
icon: robot
---
# Crafting Effective Agents
## 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.

View File

@@ -4,8 +4,6 @@ description: Learn how to assess your AI application needs and choose the right
icon: scale-balanced
---
# Evaluating Use Cases for CrewAI
## 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.

View File

@@ -4,8 +4,6 @@ description: Step-by-step tutorial to create a collaborative AI team that works
icon: users-gear
---
# Build Your First Crew
## 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.

View File

@@ -4,8 +4,6 @@ description: Learn how to create structured, event-driven workflows with precise
icon: diagram-project
---
# Build Your First Flow
## 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.

View File

@@ -4,8 +4,6 @@ description: A comprehensive guide to managing, persisting, and leveraging state
icon: diagram-project
---
# Mastering Flow State Management
## 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.

View File

@@ -0,0 +1,244 @@
---
title: Stagehand Tool
description: Web automation tool that integrates Stagehand with CrewAI for browser interaction and automation
icon: hand
---
# 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
pip install stagehand-py
```
## Usage
### Basic Implementation
The StagehandTool can be implemented in two ways:
#### 1. Using Context Manager (Recommended)
<Tip>
The context manager approach is recommended as it ensures proper cleanup of resources even if exceptions occur.
</Tip>
```python
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
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
# 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
# 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
# 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
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/)

View File

@@ -135,6 +135,10 @@ class Task(BaseModel):
description="Whether the task should have a human review the final answer of the agent",
default=False,
)
markdown: Optional[bool] = Field(
description="Whether the task should instruct the agent to return the final answer formatted in Markdown",
default=False,
)
converter_cls: Optional[Type[Converter]] = Field(
description="A converter class used to export structured output",
default=None,
@@ -522,10 +526,14 @@ class Task(BaseModel):
return guardrail_result
def prompt(self) -> str:
"""Prompt the task.
"""Generates the task prompt with optional markdown formatting.
When the markdown attribute is True, instructions for formatting the
response in Markdown syntax will be added to the prompt.
Returns:
Prompt of the task.
str: The formatted prompt string containing the task description,
expected output, and optional markdown formatting instructions.
"""
tasks_slices = [self.description]
@@ -533,6 +541,17 @@ class Task(BaseModel):
expected_output=self.expected_output
)
tasks_slices = [self.description, output]
if self.markdown:
markdown_instruction = """Your final answer MUST be formatted in Markdown syntax.
Follow these guidelines:
- Use # for headers
- Use ** for bold text
- Use * for italic text
- Use - or * for bullet points
- Use `code` for inline code
- Use ```language for code blocks"""
tasks_slices.append(markdown_instruction)
return "\n".join(tasks_slices)
def interpolate_inputs_and_add_conversation_history(

View File

@@ -0,0 +1,96 @@
"""Test the markdown attribute in Task class."""
import pytest
from pydantic import BaseModel
from crewai import Agent, Task
@pytest.mark.parametrize(
"markdown_enabled,should_contain_instructions",
[
(True, True),
(False, False),
],
)
def test_markdown_option_in_task_prompt(markdown_enabled, should_contain_instructions):
"""Test that markdown flag correctly controls the inclusion of markdown formatting instructions."""
researcher = Agent(
role="Researcher",
goal="Research a topic",
backstory="You're a researcher specialized in providing well-formatted content.",
allow_delegation=False,
)
task = Task(
description="Research advances in AI in 2023",
expected_output="A summary of key AI advances in 2023",
markdown=markdown_enabled,
agent=researcher,
)
prompt = task.prompt()
assert "Research advances in AI in 2023" in prompt
assert "A summary of key AI advances in 2023" in prompt
if should_contain_instructions:
assert "Your final answer MUST be formatted in Markdown syntax." in prompt
assert "Use # for headers" in prompt
assert "Use ** for bold text" in prompt
else:
assert "Your final answer MUST be formatted in Markdown syntax." not in prompt
def test_markdown_with_empty_description():
"""Test markdown formatting with empty description."""
researcher = Agent(
role="Researcher",
goal="Research a topic",
backstory="You're a researcher.",
allow_delegation=False,
)
task = Task(
description="",
expected_output="A summary",
markdown=True,
agent=researcher,
)
prompt = task.prompt()
assert prompt.strip() != ""
assert "A summary" in prompt
assert "Your final answer MUST be formatted in Markdown syntax." in prompt
def test_markdown_with_complex_output_format():
"""Test markdown with JSON output format to ensure compatibility."""
class ResearchOutput(BaseModel):
title: str
findings: list[str]
researcher = Agent(
role="Researcher",
goal="Research a topic",
backstory="You're a researcher.",
allow_delegation=False,
)
task = Task(
description="Research topic",
expected_output="Research results",
markdown=True,
output_json=ResearchOutput,
agent=researcher,
)
prompt = task.prompt()
assert "Your final answer MUST be formatted in Markdown syntax." in prompt
assert "Research topic" in prompt
assert "Research results" in prompt

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,4 @@
import json
import os
from typing import Dict, List, Optional
from unittest.mock import MagicMock, Mock, patch
@@ -19,6 +18,8 @@ from crewai.utilities.converter import (
validate_model,
)
from crewai.utilities.pydantic_schema_parser import PydanticSchemaParser
# Tests for enums
from enum import Enum
@pytest.fixture(scope="module")
@@ -359,7 +360,7 @@ def test_convert_with_instructions():
@pytest.mark.vcr(filter_headers=["authorization"])
def test_converter_with_llama3_2_model():
llm = LLM(model="ollama/llama3.2:3b", base_url="http://localhost:11434")
llm = LLM(model="openrouter/meta-llama/llama-3.2-3b-instruct")
sample_text = "Name: Alice Llama, Age: 30"
instructions = get_conversion_instructions(SimpleModel, llm)
converter = Converter(
@@ -431,7 +432,7 @@ def test_converter_error_handling():
)
with pytest.raises(ConverterError) as exc_info:
output = converter.to_pydantic()
converter.to_pydantic()
assert "Failed to convert text into a Pydantic model" in str(exc_info.value)
@@ -515,10 +516,6 @@ def test_converter_with_list_field():
assert output.items == [1, 2, 3]
# Tests for enums
from enum import Enum
def test_converter_with_enum():
class Color(Enum):
RED = "red"
@@ -565,7 +562,7 @@ def test_converter_with_ambiguous_input():
)
with pytest.raises(ConverterError) as exc_info:
output = converter.to_pydantic()
converter.to_pydantic()
assert "failed to convert text into a pydantic model" in str(exc_info.value).lower()