mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-07 15:18:29 +00:00
* fix: Correctly copy memory objects during crew training (#2593)
Co-Authored-By: Joe Moura <joao@crewai.com>
* style: Fix import order in tests/crew_test.py
Co-Authored-By: Joe Moura <joao@crewai.com>
* fix: Rely on validator for memory copy, update test assertions
Removes manual deep copy of memory objects in Crew.copy().
The Pydantic model_validator 'create_crew_memory' handles the
initialization of new memory instances for the copied crew.
Updates test_crew_copy_with_memory assertions to verify that
the private memory attributes (_short_term_memory, etc.) are
correctly initialized as new instances in the copied crew.
Co-Authored-By: Joe Moura <joao@crewai.com>
* Revert "fix: Rely on validator for memory copy, update test assertions"
This reverts commit 8702bf1e34.
* fix: Re-add manual deep copy for all memory types in Crew.copy
Addresses feedback on PR #2594 to ensure all memory objects
(short_term, long_term, entity, external, user) are correctly
deep copied using model_copy(deep=True).
Also simplifies the test case to directly verify the copy behavior
instead of relying on the train method.
Co-Authored-By: Joe Moura <joao@crewai.com>
---------
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Joe Moura <joao@crewai.com>
This commit is contained in:
committed by
GitHub
parent
6a1eb10830
commit
88455cd52c
@@ -1214,6 +1214,17 @@ class Crew(BaseModel):
|
||||
|
||||
copied_data = self.model_dump(exclude=exclude)
|
||||
copied_data = {k: v for k, v in copied_data.items() if v is not None}
|
||||
if self.short_term_memory:
|
||||
copied_data["short_term_memory"] = self.short_term_memory.model_copy(deep=True)
|
||||
if self.long_term_memory:
|
||||
copied_data["long_term_memory"] = self.long_term_memory.model_copy(deep=True)
|
||||
if self.entity_memory:
|
||||
copied_data["entity_memory"] = self.entity_memory.model_copy(deep=True)
|
||||
if self.external_memory:
|
||||
copied_data["external_memory"] = self.external_memory.model_copy(deep=True)
|
||||
if self.user_memory:
|
||||
copied_data["user_memory"] = self.user_memory.model_copy(deep=True)
|
||||
|
||||
|
||||
copied_data.pop("agents", None)
|
||||
copied_data.pop("tasks", None)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
from concurrent.futures import Future
|
||||
from unittest import mock
|
||||
from unittest.mock import MagicMock, patch
|
||||
@@ -19,6 +20,7 @@ from crewai.crews.crew_output import CrewOutput
|
||||
from crewai.knowledge.source.string_knowledge_source import StringKnowledgeSource
|
||||
from crewai.llm import LLM
|
||||
from crewai.memory.contextual.contextual_memory import ContextualMemory
|
||||
from crewai.memory.short_term.short_term_memory import ShortTermMemory
|
||||
from crewai.process import Process
|
||||
from crewai.task import Task
|
||||
from crewai.tasks.conditional_task import ConditionalTask
|
||||
@@ -4116,6 +4118,54 @@ def test_crew_kickoff_for_each_works_with_manager_agent_copy():
|
||||
assert crew_copy.manager_agent.id != crew.manager_agent.id
|
||||
assert crew_copy.manager_agent.role == crew.manager_agent.role
|
||||
assert crew_copy.manager_agent.goal == crew.manager_agent.goal
|
||||
assert crew_copy.manager_agent.backstory == crew.manager_agent.backstory
|
||||
assert isinstance(crew_copy.manager_agent.agent_executor, CrewAgentExecutor)
|
||||
assert isinstance(crew_copy.manager_agent.cache_handler, CacheHandler)
|
||||
|
||||
def test_crew_copy_with_memory():
|
||||
"""Test that copying a crew with memory enabled does not raise validation errors and copies memory correctly."""
|
||||
agent = Agent(role="Test Agent", goal="Test Goal", backstory="Test Backstory")
|
||||
task = Task(description="Test Task", expected_output="Test Output", agent=agent)
|
||||
crew = Crew(agents=[agent], tasks=[task], memory=True)
|
||||
|
||||
original_short_term_id = id(crew._short_term_memory) if crew._short_term_memory else None
|
||||
original_long_term_id = id(crew._long_term_memory) if crew._long_term_memory else None
|
||||
original_entity_id = id(crew._entity_memory) if crew._entity_memory else None
|
||||
original_external_id = id(crew._external_memory) if crew._external_memory else None
|
||||
original_user_id = id(crew._user_memory) if crew._user_memory else None
|
||||
|
||||
|
||||
try:
|
||||
crew_copy = crew.copy()
|
||||
|
||||
assert hasattr(crew_copy, "_short_term_memory"), "Copied crew should have _short_term_memory"
|
||||
assert crew_copy._short_term_memory is not None, "Copied _short_term_memory should not be None"
|
||||
assert id(crew_copy._short_term_memory) != original_short_term_id, "Copied _short_term_memory should be a new object"
|
||||
|
||||
assert hasattr(crew_copy, "_long_term_memory"), "Copied crew should have _long_term_memory"
|
||||
assert crew_copy._long_term_memory is not None, "Copied _long_term_memory should not be None"
|
||||
assert id(crew_copy._long_term_memory) != original_long_term_id, "Copied _long_term_memory should be a new object"
|
||||
|
||||
assert hasattr(crew_copy, "_entity_memory"), "Copied crew should have _entity_memory"
|
||||
assert crew_copy._entity_memory is not None, "Copied _entity_memory should not be None"
|
||||
assert id(crew_copy._entity_memory) != original_entity_id, "Copied _entity_memory should be a new object"
|
||||
|
||||
if original_external_id:
|
||||
assert hasattr(crew_copy, "_external_memory"), "Copied crew should have _external_memory"
|
||||
assert crew_copy._external_memory is not None, "Copied _external_memory should not be None"
|
||||
assert id(crew_copy._external_memory) != original_external_id, "Copied _external_memory should be a new object"
|
||||
else:
|
||||
assert not hasattr(crew_copy, "_external_memory") or crew_copy._external_memory is None, "Copied _external_memory should be None if not originally present"
|
||||
|
||||
if original_user_id:
|
||||
assert hasattr(crew_copy, "_user_memory"), "Copied crew should have _user_memory"
|
||||
assert crew_copy._user_memory is not None, "Copied _user_memory should not be None"
|
||||
assert id(crew_copy._user_memory) != original_user_id, "Copied _user_memory should be a new object"
|
||||
else:
|
||||
assert not hasattr(crew_copy, "_user_memory") or crew_copy._user_memory is None, "Copied _user_memory should be None if not originally present"
|
||||
|
||||
|
||||
except pydantic_core.ValidationError as e:
|
||||
if "Input should be an instance of" in str(e) and ("Memory" in str(e)):
|
||||
pytest.fail(f"Copying with memory raised Pydantic ValidationError, likely due to incorrect memory copy: {e}")
|
||||
else:
|
||||
raise e # Re-raise other validation errors
|
||||
except Exception as e:
|
||||
pytest.fail(f"Copying crew raised an unexpected exception: {e}")
|
||||
|
||||
Reference in New Issue
Block a user