Compare commits

...

8 Commits

Author SHA1 Message Date
Devin AI
806b780cd6 Fix lint issue: Properly organize imports in test_redis_mem0_storage.py
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-03-20 13:32:50 +00:00
Devin AI
60da4b35d3 Fix lint issue: Sort imports in test_redis_mem0_storage.py
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-03-20 13:31:25 +00:00
Devin AI
ef0b8e6913 Fix security issue: Use environment variables for API keys in examples
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-03-20 13:29:13 +00:00
Devin AI
05c66405cf Fix #2426: Add support for Redis as vector store in mem0 for user_memory
Co-Authored-By: Joe Moura <joao@crewai.com>
2025-03-20 13:28:02 +00:00
Vini Brasil
fe0813e831 Improve MethodExecutionFailedEvent.error typing (#2401) 2025-03-18 12:52:23 -04:00
Brandon Hancock (bhancock_ai)
33cebea15b spelling and tab fix (#2394) 2025-03-17 16:31:23 -04:00
João Moura
e723e5ca3f preparign new version 2025-03-17 09:13:21 -07:00
Jakub Kopecký
24f1a19310 feat: add docs for ApifyActorsTool (#2254)
* add docs for ApifyActorsTool

* improve readme, add link to template

* format

* improve tool docs

* improve readme

* Update apifyactorstool.mdx (#1)

* Update apifyactorstool.mdx

* Update apifyactorstool.mdx

* dans suggestions

* custom apify icon

* update descripton

* Update apifyactorstool.mdx

---------

Co-authored-by: Jan Čurn <jan.curn@gmail.com>
Co-authored-by: Brandon Hancock (bhancock_ai) <109994880+bhancockio@users.noreply.github.com>
2025-03-16 12:29:57 -04:00
14 changed files with 265 additions and 16 deletions

View File

@@ -106,6 +106,7 @@ 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. |

View File

@@ -115,6 +115,7 @@
"concepts/testing",
"concepts/cli",
"concepts/tools",
"concepts/event-listener",
"concepts/langchain-tools",
"concepts/llamaindex-tools"
]
@@ -154,6 +155,7 @@
"group": "Tools",
"pages": [
"tools/aimindtool",
"tools/apifyactorstool",
"tools/bravesearchtool",
"tools/browserbaseloadtool",
"tools/codedocssearchtool",
@@ -220,4 +222,4 @@
"linkedin": "https://www.linkedin.com/company/crewai-inc",
"youtube": "https://youtube.com/@crewAIInc"
}
}
}

View File

@@ -0,0 +1,99 @@
---
title: Apify Actors
description: "`ApifyActorsTool` lets you call Apify Actors to provide your CrewAI workflows with web scraping, crawling, data extraction, and web automation capabilities."
# hack to use custom Apify icon
icon: "); -webkit-mask-image: url('https://upload.wikimedia.org/wikipedia/commons/a/ae/Apify.svg');/*"
---
# `ApifyActorsTool`
Integrate [Apify Actors](https://apify.com/actors) into your CrewAI workflows.
## Description
The `ApifyActorsTool` connects [Apify Actors](https://apify.com/actors), cloud-based programs for web scraping and automation, to your CrewAI workflows.
Use any of the 4,000+ Actors on [Apify Store](https://apify.com/store) for use cases such as extracting data from social media, search engines, online maps, e-commerce sites, travel portals, or general websites.
For details, see the [Apify CrewAI integration](https://docs.apify.com/platform/integrations/crewai) in Apify documentation.
## Steps to get started
<Steps>
<Step title="Install dependencies">
Install `crewai[tools]` and `langchain-apify` using pip: `pip install 'crewai[tools]' langchain-apify`.
</Step>
<Step title="Obtain an Apify API token">
Sign up to [Apify Console](https://console.apify.com/) and get your [Apify API token](https://console.apify.com/settings/integrations)..
</Step>
<Step title="Configure environment">
Set your Apify API token as the `APIFY_API_TOKEN` environment variable to enable the tool's functionality.
</Step>
</Steps>
## Usage example
Use the `ApifyActorsTool` manually to run the [RAG Web Browser Actor](https://apify.com/apify/rag-web-browser) to perform a web search:
```python
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
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
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.

View File

@@ -1,6 +1,6 @@
[project]
name = "crewai"
version = "0.105.0"
version = "0.108.0"
description = "Cutting-edge framework for orchestrating role-playing, autonomous AI agents. By fostering collaborative intelligence, CrewAI empowers agents to work together seamlessly, tackling complex tasks."
readme = "README.md"
requires-python = ">=3.10,<3.13"

View File

@@ -14,7 +14,7 @@ warnings.filterwarnings(
category=UserWarning,
module="pydantic.main",
)
__version__ = "0.105.0"
__version__ = "0.108.0"
__all__ = [
"Agent",
"Crew",

View File

@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
authors = [{ name = "Your Name", email = "you@example.com" }]
requires-python = ">=3.10,<3.13"
dependencies = [
"crewai[tools]>=0.105.0,<1.0.0"
"crewai[tools]>=0.108.0,<1.0.0"
]
[project.scripts]

View File

@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
authors = [{ name = "Your Name", email = "you@example.com" }]
requires-python = ">=3.10,<3.13"
dependencies = [
"crewai[tools]>=0.105.0,<1.0.0",
"crewai[tools]>=0.108.0,<1.0.0",
]
[project.scripts]

View File

@@ -5,7 +5,7 @@ description = "Power up your crews with {{folder_name}}"
readme = "README.md"
requires-python = ">=3.10,<3.13"
dependencies = [
"crewai[tools]>=0.105.0"
"crewai[tools]>=0.108.0"
]
[tool.crewai]

View File

@@ -9,6 +9,29 @@ from crewai.memory.storage.interface import Storage
class Mem0Storage(Storage):
"""
Extends Storage to handle embedding and searching across entities using Mem0.
Supports configuring Redis as a vector store through the memory_config:
```python
crew = Crew(
memory=True,
memory_config={
"provider": "mem0",
"config": {
"user_id": "your-user-id",
"api_key": os.getenv("MEM0_API_KEY"), # Use environment variable
"vector_store": {
"provider": "redis",
"config": {
"collection_name": "collection_name",
"embedding_model_dims": 1536,
"redis_url": "redis://redis-host:6379/0"
}
}
}
}
)
```
"""
def __init__(self, type, crew=None):
@@ -26,19 +49,49 @@ class Mem0Storage(Storage):
if type == "user" and not user_id:
raise ValueError("User ID is required for user memory type")
# API key in memory config overrides the environment variable
# Get configuration from memory_config
config = self.memory_config.get("config", {})
mem0_api_key = config.get("api_key") or os.getenv("MEM0_API_KEY")
mem0_org_id = config.get("org_id")
mem0_project_id = config.get("project_id")
vector_store_config = config.get("vector_store")
# Initialize MemoryClient with available parameters
if mem0_org_id and mem0_project_id:
self.memory = MemoryClient(
api_key=mem0_api_key, org_id=mem0_org_id, project_id=mem0_project_id
)
# If vector store configuration is provided, use Memory.from_config
if vector_store_config:
try:
from mem0.memory.main import Memory
# Prepare memory config with vector store configuration
memory_config = {
"vector_store": vector_store_config
}
# Add API key if provided
if mem0_api_key:
memory_config["api_key"] = mem0_api_key
# Add org_id and project_id if provided
if mem0_org_id:
memory_config["org_id"] = mem0_org_id
if mem0_project_id:
memory_config["project_id"] = mem0_project_id
# Initialize Memory with configuration
self.memory = Memory.from_config(memory_config)
except ImportError:
raise ImportError(
"Mem0 is not installed. Please install it with `pip install mem0ai`."
)
except Exception as e:
raise ValueError(f"Failed to initialize Memory with vector store configuration: {e}")
else:
self.memory = MemoryClient(api_key=mem0_api_key)
# Fall back to default MemoryClient initialization
if mem0_org_id and mem0_project_id:
self.memory = MemoryClient(
api_key=mem0_api_key, org_id=mem0_org_id, project_id=mem0_project_id
)
else:
self.memory = MemoryClient(api_key=mem0_api_key)
def _sanitize_role(self, role: str) -> str:
"""

View File

@@ -1,3 +1,4 @@
import os
from typing import Any, Dict, Optional
from crewai.memory.memory import Memory
@@ -9,6 +10,29 @@ class UserMemory(Memory):
Inherits from the Memory class and utilizes an instance of a class that
adheres to the Storage for data storage, specifically working with
MemoryItem instances.
To configure with Redis as a vector store, provide a memory_config to the Crew:
```python
crew = Crew(
memory=True,
memory_config={
"provider": "mem0",
"config": {
"user_id": "your-user-id",
"api_key": os.getenv("MEM0_API_KEY"), # Use environment variable
"vector_store": {
"provider": "redis",
"config": {
"collection_name": "collection_name",
"embedding_model_dims": 1536,
"redis_url": "redis://redis-host:6379/0"
}
}
}
}
)
```
"""
def __init__(self, crew=None):

View File

@@ -1,6 +1,6 @@
from typing import Any, Dict, Optional, Union
from pydantic import BaseModel
from pydantic import BaseModel, ConfigDict
from .base_events import CrewEvent
@@ -52,9 +52,11 @@ class MethodExecutionFailedEvent(FlowEvent):
flow_name: str
method_name: str
error: Any
error: Exception
type: str = "method_execution_failed"
model_config = ConfigDict(arbitrary_types_allowed=True)
class FlowFinishedEvent(FlowEvent):
"""Event emitted when a flow completes execution"""

View File

@@ -0,0 +1,68 @@
import os
from unittest.mock import MagicMock, patch
import pytest
from crewai.memory.storage.mem0_storage import Mem0Storage
class TestMem0RedisIntegration:
@pytest.fixture
def mock_memory(self):
with patch("mem0.memory.main.Memory") as mock_memory:
mock_memory_instance = MagicMock()
mock_memory.from_config.return_value = mock_memory_instance
yield mock_memory
def test_mem0_with_redis_config(self, mock_memory):
# Create a mock crew with Redis vector store configuration
mock_crew = MagicMock()
mock_crew.memory_config = {
"provider": "mem0",
"config": {
"user_id": "test-user",
"api_key": "test-api-key",
"vector_store": {
"provider": "redis",
"config": {
"collection_name": "test_collection",
"embedding_model_dims": 1536,
"redis_url": "redis://localhost:6379/0"
}
}
}
}
# Create Mem0Storage instance
with patch("crewai.memory.storage.mem0_storage.MemoryClient"):
storage = Mem0Storage(type="user", crew=mock_crew)
# Check that Memory.from_config was called with correct parameters
mock_memory.from_config.assert_called_once()
config_arg = mock_memory.from_config.call_args[0][0]
assert "vector_store" in config_arg
assert config_arg["vector_store"]["provider"] == "redis"
assert config_arg["vector_store"]["config"]["redis_url"] == "redis://localhost:6379/0"
def test_fallback_to_memory_client(self):
# Create a mock crew without vector store configuration
mock_crew = MagicMock()
mock_crew.memory_config = {
"provider": "mem0",
"config": {
"user_id": "test-user",
"api_key": "test-api-key"
}
}
# Mock MemoryClient
with patch("crewai.memory.storage.mem0_storage.MemoryClient") as mock_client:
mock_client_instance = MagicMock()
mock_client.return_value = mock_client_instance
# Create Mem0Storage instance
storage = Mem0Storage(type="user", crew=mock_crew)
# Check that MemoryClient was called (fallback path)
mock_client.assert_called_once()
assert mock_client.call_args[1]["api_key"] == "test-api-key"

2
uv.lock generated
View File

@@ -619,7 +619,7 @@ wheels = [
[[package]]
name = "crewai"
version = "0.105.0"
version = "0.108.0"
source = { editable = "." }
dependencies = [
{ name = "appdirs" },