diff --git a/README.md b/README.md index b44ff6f4f..a1bf63645 100644 --- a/README.md +++ b/README.md @@ -401,11 +401,16 @@ You can test different real life examples of AI crews in the [CrewAI-examples re ### Using Crews and Flows Together -CrewAI's power truly shines when combining Crews with Flows to create sophisticated automation pipelines. Here's how you can orchestrate multiple Crews within a Flow: +CrewAI's power truly shines when combining Crews with Flows to create sophisticated automation pipelines. +CrewAI flows support logical operators like `or_` and `and_` to combine multiple conditions. This can be used with `@start`, `@listen`, or `@router` decorators to create complex triggering conditions. +- `or_`: Triggers when any of the specified conditions are met. +- `and_`Triggers when all of the specified conditions are met. + +Here's how you can orchestrate multiple Crews within a Flow: ```python -from crewai.flow.flow import Flow, listen, start, router -from crewai import Crew, Agent, Task +from crewai.flow.flow import Flow, listen, start, router, or_ +from crewai import Crew, Agent, Task, Process from pydantic import BaseModel # Define structured state for precise control @@ -479,7 +484,7 @@ class AdvancedAnalysisFlow(Flow[MarketState]): ) return strategy_crew.kickoff() - @listen("medium_confidence", "low_confidence") + @listen(or_("medium_confidence", "low_confidence")) def request_additional_analysis(self): self.state.recommendations.append("Gather more data") return "Additional analysis required" diff --git a/src/crewai/tools/base_tool.py b/src/crewai/tools/base_tool.py index b3c0f997c..dc69b02a2 100644 --- a/src/crewai/tools/base_tool.py +++ b/src/crewai/tools/base_tool.py @@ -7,29 +7,27 @@ from pydantic import ( BaseModel, ConfigDict, Field, - PydanticDeprecatedSince20, create_model, - validator, + field_validator, ) from pydantic import BaseModel as PydanticBaseModel from crewai.tools.structured_tool import CrewStructuredTool -# Ignore all "PydanticDeprecatedSince20" warnings globally -warnings.filterwarnings("ignore", category=PydanticDeprecatedSince20) - class BaseTool(BaseModel, ABC): class _ArgsSchemaPlaceholder(PydanticBaseModel): pass - model_config = ConfigDict() + model_config = ConfigDict(arbitrary_types_allowed=True) name: str """The unique name of the tool that clearly communicates its purpose.""" description: str """Used to tell the model how/when/why to use the tool.""" - args_schema: Type[PydanticBaseModel] = Field(default_factory=_ArgsSchemaPlaceholder) + args_schema: Type[PydanticBaseModel] = Field( + default_factory=_ArgsSchemaPlaceholder, validate_default=True + ) """The schema for the arguments that the tool accepts.""" description_updated: bool = False """Flag to check if the description has been updated.""" @@ -38,7 +36,8 @@ class BaseTool(BaseModel, ABC): result_as_answer: bool = False """Flag to check if the tool should be the final agent answer.""" - @validator("args_schema", always=True, pre=True) + @field_validator("args_schema", mode="before") + @classmethod def _default_args_schema( cls, v: Type[PydanticBaseModel] ) -> Type[PydanticBaseModel]: diff --git a/src/crewai/utilities/converter.py b/src/crewai/utilities/converter.py index 991185f4a..b16677ace 100644 --- a/src/crewai/utilities/converter.py +++ b/src/crewai/utilities/converter.py @@ -287,8 +287,9 @@ def generate_model_description(model: Type[BaseModel]) -> str: else: return str(field_type) - fields = model.__annotations__ + fields = model.model_fields field_descriptions = [ - f'"{name}": {describe_field(type_)}' for name, type_ in fields.items() + f'"{name}": {describe_field(field.annotation)}' + for name, field in fields.items() ] return "{\n " + ",\n ".join(field_descriptions) + "\n}"