fix: crew field serializer for circular ref round-trip

This commit is contained in:
Greyson LaLonde
2026-04-02 06:54:11 +08:00
parent 79535d3d05
commit 407d362273
2 changed files with 26 additions and 11 deletions

View File

@@ -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)

View File

@@ -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]: