From 407d36227323a669130b8db220475f77870c4faf Mon Sep 17 00:00:00 2001 From: Greyson LaLonde Date: Thu, 2 Apr 2026 06:54:11 +0800 Subject: [PATCH] fix: crew field serializer for circular ref round-trip --- lib/crewai/src/crewai/__init__.py | 7 ++++- .../crewai/agents/agent_builder/base_agent.py | 30 ++++++++++++------- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/lib/crewai/src/crewai/__init__.py b/lib/crewai/src/crewai/__init__.py index 349ebd621..e7a039caa 100644 --- a/lib/crewai/src/crewai/__init__.py +++ b/lib/crewai/src/crewai/__init__.py @@ -145,12 +145,17 @@ try: "ToolResult": _ToolResult, } + _resolve_namespace = { + **_full_namespace, + **sys.modules[_BaseAgent.__module__].__dict__, + } + for _mod_name in ( _BaseAgent.__module__, Agent.__module__, _AgentExecutor.__module__, ): - sys.modules[_mod_name].__dict__.update(_full_namespace) + sys.modules[_mod_name].__dict__.update(_resolve_namespace) _BaseAgent.model_rebuild(force=True, _types_namespace=_full_namespace) _AgentExecutor.model_rebuild(force=True, _types_namespace=_full_namespace) diff --git a/lib/crewai/src/crewai/agents/agent_builder/base_agent.py b/lib/crewai/src/crewai/agents/agent_builder/base_agent.py index f6988ae6b..f487a0d8c 100644 --- a/lib/crewai/src/crewai/agents/agent_builder/base_agent.py +++ b/lib/crewai/src/crewai/agents/agent_builder/base_agent.py @@ -5,19 +5,20 @@ from copy import copy as shallow_copy from hashlib import md5 from pathlib import Path import re -from typing import TYPE_CHECKING, Any, Final, Literal +from typing import TYPE_CHECKING, Annotated, Any, Final, Literal import uuid from pydantic import ( UUID4, BaseModel, + BeforeValidator, Field, InstanceOf, PrivateAttr, - field_serializer, field_validator, model_validator, ) +from pydantic.functional_serializers import PlainSerializer from pydantic_core import PydanticCustomError from typing_extensions import Self @@ -50,6 +51,16 @@ if TYPE_CHECKING: from crewai.crew import Crew +def _validate_crew_ref(value: Any) -> Any: + return value + + +def _serialize_crew_ref(value: Any) -> str | None: + if value is None: + return None + return str(value.id) if hasattr(value, "id") else str(value) + + _SLUG_RE: Final[re.Pattern[str]] = re.compile( r"^(?:crewai-amp:)?[a-zA-Z0-9][a-zA-Z0-9_-]*(?:#[\w-]+)?$" ) @@ -168,9 +179,13 @@ class BaseAgent(BaseModel, ABC, metaclass=AgentMeta): llm: str | BaseLLM | None = Field( default=None, description="Language model that will run the agent." ) - crew: Crew | None = Field( - default=None, description="Crew to which the agent belongs." - ) + crew: Annotated[ + Crew | str | None, + BeforeValidator(_validate_crew_ref), + PlainSerializer( + _serialize_crew_ref, return_type=str | None, when_used="always" + ), + ] = Field(default=None, description="Crew to which the agent belongs.") i18n: I18N = Field( default_factory=get_i18n, description="Internationalization settings." ) @@ -234,11 +249,6 @@ class BaseAgent(BaseModel, ABC, metaclass=AgentMeta): min_length=1, ) - @field_serializer("crew") - @classmethod - def _serialize_crew(cls, v: Crew | None) -> str | None: - return str(v.id) if v else None - @model_validator(mode="before") @classmethod def process_model_config(cls, values: Any) -> dict[str, Any]: