Merge branch 'main' into feat/individual-react-agent

This commit is contained in:
Lorenze Jay
2025-04-01 12:08:40 -07:00
committed by GitHub
3 changed files with 19 additions and 14 deletions

View File

@@ -401,11 +401,16 @@ You can test different real life examples of AI crews in the [CrewAI-examples re
### Using Crews and Flows Together ### 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 ```python
from crewai.flow.flow import Flow, listen, start, router from crewai.flow.flow import Flow, listen, start, router, or_
from crewai import Crew, Agent, Task from crewai import Crew, Agent, Task, Process
from pydantic import BaseModel from pydantic import BaseModel
# Define structured state for precise control # Define structured state for precise control
@@ -479,7 +484,7 @@ class AdvancedAnalysisFlow(Flow[MarketState]):
) )
return strategy_crew.kickoff() return strategy_crew.kickoff()
@listen("medium_confidence", "low_confidence") @listen(or_("medium_confidence", "low_confidence"))
def request_additional_analysis(self): def request_additional_analysis(self):
self.state.recommendations.append("Gather more data") self.state.recommendations.append("Gather more data")
return "Additional analysis required" return "Additional analysis required"

View File

@@ -7,29 +7,27 @@ from pydantic import (
BaseModel, BaseModel,
ConfigDict, ConfigDict,
Field, Field,
PydanticDeprecatedSince20,
create_model, create_model,
validator, field_validator,
) )
from pydantic import BaseModel as PydanticBaseModel from pydantic import BaseModel as PydanticBaseModel
from crewai.tools.structured_tool import CrewStructuredTool from crewai.tools.structured_tool import CrewStructuredTool
# Ignore all "PydanticDeprecatedSince20" warnings globally
warnings.filterwarnings("ignore", category=PydanticDeprecatedSince20)
class BaseTool(BaseModel, ABC): class BaseTool(BaseModel, ABC):
class _ArgsSchemaPlaceholder(PydanticBaseModel): class _ArgsSchemaPlaceholder(PydanticBaseModel):
pass pass
model_config = ConfigDict() model_config = ConfigDict(arbitrary_types_allowed=True)
name: str name: str
"""The unique name of the tool that clearly communicates its purpose.""" """The unique name of the tool that clearly communicates its purpose."""
description: str description: str
"""Used to tell the model how/when/why to use the tool.""" """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.""" """The schema for the arguments that the tool accepts."""
description_updated: bool = False description_updated: bool = False
"""Flag to check if the description has been updated.""" """Flag to check if the description has been updated."""
@@ -38,7 +36,8 @@ class BaseTool(BaseModel, ABC):
result_as_answer: bool = False result_as_answer: bool = False
"""Flag to check if the tool should be the final agent answer.""" """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( def _default_args_schema(
cls, v: Type[PydanticBaseModel] cls, v: Type[PydanticBaseModel]
) -> Type[PydanticBaseModel]: ) -> Type[PydanticBaseModel]:

View File

@@ -287,8 +287,9 @@ def generate_model_description(model: Type[BaseModel]) -> str:
else: else:
return str(field_type) return str(field_type)
fields = model.__annotations__ fields = model.model_fields
field_descriptions = [ 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}" return "{\n " + ",\n ".join(field_descriptions) + "\n}"