diff --git a/crewai/agent.py b/crewai/agent.py index 71d3f8a47..31087bdb5 100644 --- a/crewai/agent.py +++ b/crewai/agent.py @@ -6,13 +6,14 @@ from langchain.chat_models import ChatOpenAI from langchain.memory import ConversationSummaryMemory from langchain.tools.render import render_text_description from langchain_core.runnables.config import RunnableConfig -from pydantic import BaseModel, Field, InstanceOf, model_validator +from pydantic import ConfigDict, Field, InstanceOf, model_validator from crewai.agents import CacheHandler, CrewAgentOutputParser, ToolsHandler +from crewai.base.model import CrewAIBaseModel from crewai.prompts import Prompts -class Agent(BaseModel): +class Agent(CrewAIBaseModel): """Represents an agent in a system. Each agent has a role, a goal, a backstory, and an optional language model (llm). @@ -29,9 +30,7 @@ class Agent(BaseModel): allow_delegation: Whether the agent is allowed to delegate tasks to other agents. """ - class Config: - arbitrary_types_allowed = True - + model_config = ConfigDict(arbitrary_types_allowed=True) role: str = Field(description="Role of the agent") goal: str = Field(description="Objective of the agent") backstory: str = Field(description="Backstory of the agent") diff --git a/crewai/base/__init__.py b/crewai/base/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/crewai/base/model.py b/crewai/base/model.py new file mode 100644 index 000000000..211ae5be7 --- /dev/null +++ b/crewai/base/model.py @@ -0,0 +1,24 @@ +import uuid +from typing import Optional + +from pydantic import UUID4, BaseModel, Field, field_validator +from pydantic_core import PydanticCustomError + + +class CrewAIBaseModel(BaseModel): + """Base model with unique identifier.""" + + __hash__ = object.__hash__ + id: UUID4 = Field( + default_factory=uuid.uuid4, + frozen=True, + description="Unique identifier for the object, not set by user.", + ) + + @field_validator("id", mode="before") + @classmethod + def _deny_user_set_id(cls, v: Optional[UUID4]) -> None: + if v: + raise PydanticCustomError( + "may_not_set_field", "This field is not to be set by the user.", {} + ) diff --git a/crewai/crew.py b/crewai/crew.py index d0b7907eb..77902f40c 100644 --- a/crewai/crew.py +++ b/crewai/crew.py @@ -2,7 +2,7 @@ import json from typing import Any, Dict, List, Optional, Union from pydantic import ( - BaseModel, + ConfigDict, Field, InstanceOf, Json, @@ -13,17 +13,16 @@ from pydantic_core import PydanticCustomError from crewai.agent import Agent from crewai.agents import CacheHandler +from crewai.base.model import CrewAIBaseModel from crewai.process import Process from crewai.task import Task from crewai.tools.agent_tools import AgentTools -class Crew(BaseModel): +class Crew(CrewAIBaseModel): """Class that represents a group of agents, how they should work together and their tasks.""" - class Config: - arbitrary_types_allowed = True - + model_config = ConfigDict(arbitrary_types_allowed=True) tasks: List[Task] = Field(description="List of tasks", default_factory=list) agents: List[Agent] = Field( description="List of agents in this crew.", default_factory=list diff --git a/crewai/task.py b/crewai/task.py index e87caf0a0..f766f8c0b 100644 --- a/crewai/task.py +++ b/crewai/task.py @@ -1,11 +1,12 @@ from typing import Any, List, Optional -from pydantic import BaseModel, Field, model_validator +from pydantic import Field, model_validator from crewai.agent import Agent +from crewai.base.model import CrewAIBaseModel -class Task(BaseModel): +class Task(CrewAIBaseModel): """Class that represent a task to be executed.""" description: str = Field(description="Description of the actual task.")