eaglelandsonce
commited on
Commit
•
c781bdd
1
Parent(s):
37389a4
Update crewai/crew.py
Browse files- crewai/crew.py +65 -70
crewai/crew.py
CHANGED
@@ -22,116 +22,111 @@ from crewai.tools.agent_tools import AgentTools
|
|
22 |
|
23 |
|
24 |
class Crew(BaseModel):
|
25 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
|
27 |
__hash__ = object.__hash__
|
28 |
model_config = ConfigDict(arbitrary_types_allowed=True)
|
29 |
-
tasks: List[Task] = Field(
|
30 |
-
agents: List[Agent] = Field(
|
31 |
-
|
32 |
-
)
|
33 |
-
|
34 |
-
|
35 |
-
)
|
36 |
-
verbose: Union[int, bool] = Field(
|
37 |
-
description="Verbose mode for the Agent Execution", default=0
|
38 |
-
)
|
39 |
-
config: Optional[Union[Json, Dict[str, Any]]] = Field(
|
40 |
-
description="Configuration of the crew.", default=None
|
41 |
-
)
|
42 |
-
cache_handler: Optional[InstanceOf[CacheHandler]] = Field(
|
43 |
-
default=CacheHandler(), description="An instance of the CacheHandler class."
|
44 |
-
)
|
45 |
-
id: UUID4 = Field(
|
46 |
-
default_factory=uuid.uuid4,
|
47 |
-
frozen=True,
|
48 |
-
description="Unique identifier for the object, not set by user.",
|
49 |
-
)
|
50 |
|
51 |
@field_validator("id", mode="before")
|
52 |
@classmethod
|
53 |
def _deny_user_set_id(cls, v: Optional[UUID4]) -> None:
|
|
|
54 |
if v:
|
55 |
raise PydanticCustomError(
|
56 |
-
"may_not_set_field", "
|
57 |
)
|
58 |
|
59 |
@classmethod
|
60 |
@field_validator("config", mode="before")
|
61 |
def check_config_type(cls, v: Union[Json, Dict[str, Any]]):
|
62 |
-
if isinstance(v, Json)
|
63 |
-
return json.loads(v)
|
64 |
-
return v
|
65 |
|
66 |
@model_validator(mode="after")
|
67 |
def check_config(self):
|
|
|
68 |
if not self.config and not self.tasks and not self.agents:
|
69 |
raise PydanticCustomError(
|
70 |
-
"missing_keys",
|
|
|
|
|
71 |
)
|
72 |
|
73 |
if self.config:
|
74 |
-
|
75 |
-
raise PydanticCustomError(
|
76 |
-
"missing_keys_in_config", "Config should have agents and tasks", {}
|
77 |
-
)
|
78 |
-
|
79 |
-
self.agents = [Agent(**agent) for agent in self.config["agents"]]
|
80 |
-
|
81 |
-
tasks = []
|
82 |
-
for task in self.config["tasks"]:
|
83 |
-
task_agent = [agt for agt in self.agents if agt.role == task["agent"]][
|
84 |
-
0
|
85 |
-
]
|
86 |
-
del task["agent"]
|
87 |
-
tasks.append(Task(**task, agent=task_agent))
|
88 |
-
|
89 |
-
self.tasks = tasks
|
90 |
|
91 |
if self.agents:
|
92 |
for agent in self.agents:
|
93 |
agent.set_cache_handler(self.cache_handler)
|
94 |
return self
|
95 |
|
96 |
-
def
|
97 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
|
99 |
-
|
100 |
-
|
101 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
for agent in self.agents:
|
103 |
agent.cache_handler = self.cache_handler
|
104 |
|
105 |
if self.process == Process.sequential:
|
106 |
-
return self.
|
107 |
-
|
108 |
-
def __sequential_loop(self) -> str:
|
109 |
-
"""Loop that executes the sequential process.
|
110 |
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
task_outcome = None
|
115 |
for task in self.tasks:
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
task.
|
120 |
-
|
121 |
-
|
122 |
-
self.__log("info", f"Starting Task: {task.description} ...")
|
123 |
-
|
124 |
-
task_outcome = task.execute(task_outcome)
|
125 |
|
126 |
-
|
|
|
|
|
|
|
127 |
|
128 |
-
|
|
|
129 |
|
130 |
-
def
|
131 |
-
"""
|
132 |
level_map = {"debug": 1, "info": 2}
|
133 |
verbose_level = (
|
134 |
2 if isinstance(self.verbose, bool) and self.verbose else self.verbose
|
135 |
)
|
136 |
if verbose_level and level_map[level] <= verbose_level:
|
137 |
-
print(message)
|
|
|
22 |
|
23 |
|
24 |
class Crew(BaseModel):
|
25 |
+
"""
|
26 |
+
Represents a group of agents, defining how they should collaborate and the tasks they should perform.
|
27 |
+
|
28 |
+
Attributes:
|
29 |
+
tasks: List of tasks assigned to the crew.
|
30 |
+
agents: List of agents part of this crew.
|
31 |
+
process: The process flow that the crew will follow (e.g., sequential).
|
32 |
+
verbose: Indicates the verbosity level for logging during execution.
|
33 |
+
config: Configuration settings for the crew.
|
34 |
+
cache_handler: Handles caching for the crew's operations.
|
35 |
+
id: A unique identifier for the crew instance.
|
36 |
+
"""
|
37 |
|
38 |
__hash__ = object.__hash__
|
39 |
model_config = ConfigDict(arbitrary_types_allowed=True)
|
40 |
+
tasks: List[Task] = Field(default_factory=list)
|
41 |
+
agents: List[Agent] = Field(default_factory=list)
|
42 |
+
process: Process = Field(default=Process.sequential)
|
43 |
+
verbose: Union[int, bool] = Field(default=0)
|
44 |
+
config: Optional[Union[Json, Dict[str, Any]]] = Field(default=None)
|
45 |
+
cache_handler: Optional[InstanceOf[CacheHandler]] = Field(default=CacheHandler())
|
46 |
+
id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
|
48 |
@field_validator("id", mode="before")
|
49 |
@classmethod
|
50 |
def _deny_user_set_id(cls, v: Optional[UUID4]) -> None:
|
51 |
+
"""Prevent manual setting of the 'id' field by users."""
|
52 |
if v:
|
53 |
raise PydanticCustomError(
|
54 |
+
"may_not_set_field", "The 'id' field cannot be set by the user.", {}
|
55 |
)
|
56 |
|
57 |
@classmethod
|
58 |
@field_validator("config", mode="before")
|
59 |
def check_config_type(cls, v: Union[Json, Dict[str, Any]]):
|
60 |
+
return json.loads(v) if isinstance(v, Json) else v
|
|
|
|
|
61 |
|
62 |
@model_validator(mode="after")
|
63 |
def check_config(self):
|
64 |
+
"""Validates that the crew is properly configured with agents and tasks."""
|
65 |
if not self.config and not self.tasks and not self.agents:
|
66 |
raise PydanticCustomError(
|
67 |
+
"missing_keys",
|
68 |
+
"Either 'agents' and 'tasks' need to be set or 'config'.",
|
69 |
+
{},
|
70 |
)
|
71 |
|
72 |
if self.config:
|
73 |
+
self._setup_from_config()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
|
75 |
if self.agents:
|
76 |
for agent in self.agents:
|
77 |
agent.set_cache_handler(self.cache_handler)
|
78 |
return self
|
79 |
|
80 |
+
def _setup_from_config(self):
|
81 |
+
"""Initializes agents and tasks from the provided config."""
|
82 |
+
if not self.config.get("agents") or not self.config.get("tasks"):
|
83 |
+
raise PydanticCustomError(
|
84 |
+
"missing_keys_in_config", "Config should have 'agents' and 'tasks'.", {}
|
85 |
+
)
|
86 |
+
|
87 |
+
self.agents = [Agent(**agent) for agent in self.config["agents"]]
|
88 |
+
self.tasks = [self._create_task(task) for task in self.config["tasks"]]
|
89 |
|
90 |
+
def _create_task(self, task_config):
|
91 |
+
"""Creates a task instance from its configuration."""
|
92 |
+
task_agent = next(
|
93 |
+
agt for agt in self.agents if agt.role == task_config["agent"]
|
94 |
+
)
|
95 |
+
del task_config["agent"]
|
96 |
+
return Task(**task_config, agent=task_agent)
|
97 |
+
|
98 |
+
def kickoff(self) -> str:
|
99 |
+
"""Starts the crew to work on its assigned tasks."""
|
100 |
for agent in self.agents:
|
101 |
agent.cache_handler = self.cache_handler
|
102 |
|
103 |
if self.process == Process.sequential:
|
104 |
+
return self._sequential_loop()
|
|
|
|
|
|
|
105 |
|
106 |
+
def _sequential_loop(self) -> str:
|
107 |
+
"""Executes tasks sequentially and returns the final output."""
|
108 |
+
task_output = None
|
|
|
109 |
for task in self.tasks:
|
110 |
+
self._prepare_and_execute_task(task)
|
111 |
+
task_output = task.execute(task_output)
|
112 |
+
self._log(
|
113 |
+
"debug", f"\n\n[{task.agent.role}] Task output: {task_output}\n\n"
|
114 |
+
)
|
115 |
+
return task_output
|
|
|
|
|
|
|
116 |
|
117 |
+
def _prepare_and_execute_task(self, task):
|
118 |
+
"""Prepares and logs information about the task being executed."""
|
119 |
+
if task.agent.allow_delegation:
|
120 |
+
task.tools += AgentTools(agents=self.agents).tools()
|
121 |
|
122 |
+
self._log("debug", f"Working Agent: {task.agent.role}")
|
123 |
+
self._log("info", f"Starting Task: {task.description}")
|
124 |
|
125 |
+
def _log(self, level, message):
|
126 |
+
"""Logs a message at the specified verbosity level."""
|
127 |
level_map = {"debug": 1, "info": 2}
|
128 |
verbose_level = (
|
129 |
2 if isinstance(self.verbose, bool) and self.verbose else self.verbose
|
130 |
)
|
131 |
if verbose_level and level_map[level] <= verbose_level:
|
132 |
+
print(message)
|