Compare commits

..

5 Commits

Author SHA1 Message Date
Lucas Gomide
aa4a54f059 Merge branch 'main' into feature-isolated-memory 2025-04-14 16:37:08 -03:00
Lucas Gomide
e346064c36 feat: warn when long-term memory is defined but entity memory is not 2025-04-14 14:15:07 -03:00
Lucas Gomide
4fcca4c486 docs: enhance memory documentation 2025-04-14 14:15:07 -03:00
Lucas Gomide
4e9e190661 feat: add tests to ensure we are able to use contextual memory by set individual memories 2025-04-14 14:15:07 -03:00
Lucas Gomide
9eeed380a8 feat: support defining any memory in an isolated way
This change makes it easier to use a specific memory type without unintentionally enabling all others.

Previously, setting memory=True would implicitly configure all available memories (like LTM and STM), which might not be ideal in all cases. For example, when building a chatbot that only needs an external memory, users were forced to also configure LTM and STM — which rely on default OpenAPI embeddings — even if they weren’t needed.

With this update, users can now define a single memory in isolation, making the configuration process simpler and more flexible.
2025-04-14 14:15:07 -03:00
17 changed files with 51 additions and 166 deletions

View File

@@ -1,33 +0,0 @@
name: Notify Downstream
on:
push:
branches:
- main
permissions:
contents: read
jobs:
notify-downstream:
runs-on: ubuntu-latest
steps:
- name: Generate GitHub App token
id: app-token
uses: tibdex/github-app-token@v2
with:
app_id: ${{ secrets.OSS_SYNC_APP_ID }}
private_key: ${{ secrets.OSS_SYNC_APP_PRIVATE_KEY }}
- name: Notify Repo B
uses: peter-evans/repository-dispatch@v3
with:
token: ${{ steps.app-token.outputs.token }}
repository: ${{ secrets.OSS_SYNC_DOWNSTREAM_REPO }}
event-type: upstream-commit
client-payload: |
{
"commit_sha": "${{ github.sha }}"
}

View File

@@ -257,14 +257,10 @@ reporting_task:
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:

View File

@@ -118,7 +118,7 @@ class LatestAiDevelopmentCrew():
@agent
def researcher(self) -> Agent:
return Agent(
config=self.agents_config['researcher'], # type: ignore[index]
config=self.agents_config['researcher'],
verbose=True,
tools=[SerperDevTool()]
)
@@ -126,7 +126,7 @@ class LatestAiDevelopmentCrew():
@agent
def reporting_analyst(self) -> Agent:
return Agent(
config=self.agents_config['reporting_analyst'], # type: ignore[index]
config=self.agents_config['reporting_analyst'],
verbose=True
)
```

View File

@@ -52,16 +52,12 @@ After creating your CrewAI project as outlined in the [Installation](/installati
```python code
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
@@ -84,27 +80,27 @@ class YourCrewName:
@agent
def agent_one(self) -> Agent:
return Agent(
config=self.agents_config['agent_one'], # type: ignore[index]
config=self.agents_config['agent_one'],
verbose=True
)
@agent
def agent_two(self) -> Agent:
return Agent(
config=self.agents_config['agent_two'], # type: ignore[index]
config=self.agents_config['agent_two'],
verbose=True
)
@task
def task_one(self) -> Task:
return Task(
config=self.tasks_config['task_one'] # type: ignore[index]
config=self.tasks_config['task_one']
)
@task
def task_two(self) -> Task:
return Task(
config=self.tasks_config['task_two'] # type: ignore[index]
config=self.tasks_config['task_two']
)
@crew

View File

@@ -438,7 +438,7 @@ In this section, you'll find detailed examples that help you select, configure,
@agent
def researcher(self) -> Agent:
return Agent(
config=self.agents_config['researcher'], # type: ignore[index]
config=self.agents_config['researcher'],
llm=local_nvidia_nim_llm
)
@@ -535,13 +535,14 @@ In this section, you'll find detailed examples that help you select, configure,
<Accordion title="Hugging Face">
Set the following environment variables in your `.env` file:
```toml Code
HF_TOKEN=<your-api-key>
HUGGINGFACE_API_KEY=<your-api-key>
```
Example usage in your CrewAI project:
```python Code
llm = LLM(
model="huggingface/meta-llama/Meta-Llama-3.1-8B-Instruct"
model="huggingface/meta-llama/Meta-Llama-3.1-8B-Instruct",
base_url="your_api_endpoint"
)
```
</Accordion>

View File

@@ -113,7 +113,7 @@ class LatestAiDevelopmentCrew():
@agent
def researcher(self) -> Agent:
return Agent(
config=self.agents_config['researcher'], # type: ignore[index]
config=self.agents_config['researcher'],
verbose=True,
tools=[SerperDevTool()]
)
@@ -121,20 +121,20 @@ class LatestAiDevelopmentCrew():
@agent
def reporting_analyst(self) -> Agent:
return Agent(
config=self.agents_config['reporting_analyst'], # type: ignore[index]
config=self.agents_config['reporting_analyst'],
verbose=True
)
@task
def research_task(self) -> Task:
return Task(
config=self.tasks_config['research_task'] # type: ignore[index]
config=self.tasks_config['research_task']
)
@task
def reporting_task(self) -> Task:
return Task(
config=self.tasks_config['reporting_task'] # type: ignore[index]
config=self.tasks_config['reporting_task']
)
@crew

View File

@@ -185,20 +185,15 @@ Let's modify the `crew.py` file:
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]
config=self.agents_config['researcher'],
verbose=True,
tools=[SerperDevTool()]
)
@@ -206,20 +201,20 @@ class ResearchCrew():
@agent
def analyst(self) -> Agent:
return Agent(
config=self.agents_config['analyst'], # type: ignore[index]
config=self.agents_config['analyst'],
verbose=True
)
@task
def research_task(self) -> Task:
return Task(
config=self.tasks_config['research_task'] # type: ignore[index]
config=self.tasks_config['research_task']
)
@task
def analysis_task(self) -> Task:
return Task(
config=self.tasks_config['analysis_task'], # type: ignore[index]
config=self.tasks_config['analysis_task'],
output_file='output/report.md'
)
@@ -392,4 +387,4 @@ Now that you've built your first crew, you can:
<Check>
Congratulations! You've successfully built your first CrewAI crew that can research and analyze any topic you provide. This foundational experience has equipped you with the skills to create increasingly sophisticated AI systems that can tackle complex, multi-stage problems through collaborative intelligence.
</Check>
</Check>

View File

@@ -203,40 +203,35 @@ These task definitions provide detailed instructions to our agents, ensuring the
# 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]
config=self.agents_config['content_writer'],
verbose=True
)
@agent
def content_reviewer(self) -> Agent:
return Agent(
config=self.agents_config['content_reviewer'], # type: ignore[index]
config=self.agents_config['content_reviewer'],
verbose=True
)
@task
def write_section_task(self) -> Task:
return Task(
config=self.tasks_config['write_section_task'] # type: ignore[index]
config=self.tasks_config['write_section_task']
)
@task
def review_section_task(self) -> Task:
return Task(
config=self.tasks_config['review_section_task'], # type: ignore[index]
config=self.tasks_config['review_section_task'],
context=[self.write_section_task()]
)

View File

@@ -87,20 +87,15 @@ Follow the steps below to get Crewing! 🚣‍♂️
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]
config=self.agents_config['researcher'],
verbose=True,
tools=[SerperDevTool()]
)
@@ -108,20 +103,20 @@ Follow the steps below to get Crewing! 🚣‍♂️
@agent
def reporting_analyst(self) -> Agent:
return Agent(
config=self.agents_config['reporting_analyst'], # type: ignore[index]
config=self.agents_config['reporting_analyst'],
verbose=True
)
@task
def research_task(self) -> Task:
return Task(
config=self.tasks_config['research_task'], # type: ignore[index]
config=self.tasks_config['research_task'],
)
@task
def reporting_task(self) -> Task:
return Task(
config=self.tasks_config['reporting_task'], # type: ignore[index]
config=self.tasks_config['reporting_task'],
output_file='output/report.md' # This is the file that will be contain the final report.
)

View File

@@ -535,7 +535,6 @@ class Agent(BaseAgent):
verbose=self.verbose,
response_format=response_format,
i18n=self.i18n,
original_agent=self,
)
return await lite_agent.kickoff_async(messages)

View File

@@ -91,12 +91,6 @@ ENV_VARS = {
"key_name": "CEREBRAS_API_KEY",
},
],
"huggingface": [
{
"prompt": "Enter your Huggingface API key (HF_TOKEN) (press Enter to skip)",
"key_name": "HF_TOKEN",
},
],
"sambanova": [
{
"prompt": "Enter your SambaNovaCloud API key (press Enter to skip)",
@@ -112,7 +106,6 @@ PROVIDERS = [
"gemini",
"nvidia_nim",
"groq",
"huggingface",
"ollama",
"watson",
"bedrock",
@@ -277,12 +270,6 @@ MODELS = {
"bedrock/mistral.mistral-7b-instruct-v0:2",
"bedrock/mistral.mixtral-8x7b-instruct-v0:1",
],
"huggingface": [
"huggingface/meta-llama/Meta-Llama-3.1-8B-Instruct",
"huggingface/mistralai/Mixtral-8x7B-Instruct-v0.1",
"huggingface/tiiuae/falcon-180B-chat",
"huggingface/google/gemma-7b-it",
],
"sambanova": [
"sambanova/Meta-Llama-3.3-70B-Instruct",
"sambanova/QwQ-32B-Preview",

View File

@@ -1,7 +1,6 @@
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
# If you want to run a snippet of code before or after the crew starts,
# you can use the @before_kickoff and @after_kickoff decorators
# https://docs.crewai.com/concepts/crews#example-crew-class-with-decorators
@@ -10,26 +9,25 @@ from typing import List
class {{crew_name}}():
"""{{crew_name}} crew"""
agents: List[BaseAgent]
tasks: List[Task]
# Learn more about YAML configuration files here:
# Agents: https://docs.crewai.com/concepts/agents#yaml-configuration-recommended
# Tasks: https://docs.crewai.com/concepts/tasks#yaml-configuration-recommended
agents_config = 'config/agents.yaml'
tasks_config = 'config/tasks.yaml'
# If you would like to add tools to your agents, you can learn more about it here:
# https://docs.crewai.com/concepts/agents#agent-tools
@agent
def researcher(self) -> Agent:
return Agent(
config=self.agents_config['researcher'], # type: ignore[index]
config=self.agents_config['researcher'],
verbose=True
)
@agent
def reporting_analyst(self) -> Agent:
return Agent(
config=self.agents_config['reporting_analyst'], # type: ignore[index]
config=self.agents_config['reporting_analyst'],
verbose=True
)
@@ -39,13 +37,13 @@ class {{crew_name}}():
@task
def research_task(self) -> Task:
return Task(
config=self.tasks_config['research_task'], # type: ignore[index]
config=self.tasks_config['research_task'],
)
@task
def reporting_task(self) -> Task:
return Task(
config=self.tasks_config['reporting_task'], # type: ignore[index]
config=self.tasks_config['reporting_task'],
output_file='report.md'
)

View File

@@ -1,7 +1,5 @@
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
# If you want to run a snippet of code before or after the crew starts,
# you can use the @before_kickoff and @after_kickoff decorators
@@ -12,9 +10,6 @@ from typing import List
class PoemCrew:
"""Poem Crew"""
agents: List[BaseAgent]
tasks: List[Task]
# Learn more about YAML configuration files here:
# Agents: https://docs.crewai.com/concepts/agents#yaml-configuration-recommended
# Tasks: https://docs.crewai.com/concepts/tasks#yaml-configuration-recommended
@@ -26,7 +21,7 @@ class PoemCrew:
@agent
def poem_writer(self) -> Agent:
return Agent(
config=self.agents_config["poem_writer"], # type: ignore[index]
config=self.agents_config["poem_writer"],
)
# To learn more about structured task outputs,
@@ -35,7 +30,7 @@ class PoemCrew:
@task
def write_poem(self) -> Task:
return Task(
config=self.tasks_config["write_poem"], # type: ignore[index]
config=self.tasks_config["write_poem"],
)
@crew

View File

@@ -21,7 +21,7 @@ class SQLiteFlowPersistence(FlowPersistence):
moderate performance requirements.
"""
db_path: str
db_path: str # Type annotation for instance variable
def __init__(self, db_path: Optional[str] = None):
"""Initialize SQLite persistence.

View File

@@ -1,23 +0,0 @@
import pytest
from crewai.cli.constants import ENV_VARS, MODELS, PROVIDERS
def test_huggingface_in_providers():
"""Test that Huggingface is in the PROVIDERS list."""
assert "huggingface" in PROVIDERS
def test_huggingface_env_vars():
"""Test that Huggingface environment variables are properly configured."""
assert "huggingface" in ENV_VARS
assert any(
detail.get("key_name") == "HF_TOKEN"
for detail in ENV_VARS["huggingface"]
)
def test_huggingface_models():
"""Test that Huggingface models are properly configured."""
assert "huggingface" in MODELS
assert len(MODELS["huggingface"]) > 0

View File

@@ -4069,17 +4069,11 @@ def test_crew_guardrail_feedback_in_context():
@pytest.mark.vcr(filter_headers=["authorization"])
def test_before_kickoff_callback():
from crewai.project import CrewBase
from crewai.project import CrewBase, agent, before_kickoff, task
@CrewBase
class TestCrewClass:
from typing import List
from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.project import CrewBase, agent, before_kickoff, crew, task
agents: List[BaseAgent]
tasks: List[Task]
from crewai.project import crew
agents_config = None
tasks_config = None

View File

@@ -1,9 +1,6 @@
from typing import List
import pytest
from crewai.agent import Agent
from crewai.agents.agent_builder.base_agent import BaseAgent
from crewai.crew import Crew
from crewai.llm import LLM
from crewai.project import (
@@ -43,32 +40,28 @@ class InternalCrew:
agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml"
agents: List[BaseAgent]
tasks: List[Task]
@llm
def local_llm(self):
return LLM(
model="openai/model_name",
model='openai/model_name',
api_key="None",
base_url="http://xxx.xxx.xxx.xxx:8000/v1",
)
base_url="http://xxx.xxx.xxx.xxx:8000/v1")
@agent
def researcher(self):
return Agent(config=self.agents_config["researcher"]) # type: ignore[index]
return Agent(config=self.agents_config["researcher"])
@agent
def reporting_analyst(self):
return Agent(config=self.agents_config["reporting_analyst"]) # type: ignore[index]
return Agent(config=self.agents_config["reporting_analyst"])
@task
def research_task(self):
return Task(config=self.tasks_config["research_task"]) # type: ignore[index]
return Task(config=self.tasks_config["research_task"])
@task
def reporting_task(self):
return Task(config=self.tasks_config["reporting_task"]) # type: ignore[index]
return Task(config=self.tasks_config["reporting_task"])
@before_kickoff
def modify_inputs(self, inputs):
@@ -172,27 +165,24 @@ def test_before_kickoff_with_none_input():
def test_multiple_before_after_kickoff():
@CrewBase
class MultipleHooksCrew:
agents: List[BaseAgent]
tasks: List[Task]
agents_config = "config/agents.yaml"
tasks_config = "config/tasks.yaml"
@agent
def researcher(self):
return Agent(config=self.agents_config["researcher"]) # type: ignore[index]
return Agent(config=self.agents_config["researcher"])
@agent
def reporting_analyst(self):
return Agent(config=self.agents_config["reporting_analyst"]) # type: ignore[index]
return Agent(config=self.agents_config["reporting_analyst"])
@task
def research_task(self):
return Task(config=self.tasks_config["research_task"]) # type: ignore[index]
return Task(config=self.tasks_config["research_task"])
@task
def reporting_task(self):
return Task(config=self.tasks_config["reporting_task"]) # type: ignore[index]
return Task(config=self.tasks_config["reporting_task"])
@before_kickoff
def first_before(self, inputs):