eaglelandsonce commited on
Commit
c781bdd
1 Parent(s): 37389a4

Update crewai/crew.py

Browse files
Files changed (1) hide show
  1. 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
- """Class that represents a group of agents, how they should work together and their tasks."""
 
 
 
 
 
 
 
 
 
 
 
26
 
27
  __hash__ = object.__hash__
28
  model_config = ConfigDict(arbitrary_types_allowed=True)
29
- tasks: List[Task] = Field(description="List of tasks", default_factory=list)
30
- agents: List[Agent] = Field(
31
- description="List of agents in this crew.", default_factory=list
32
- )
33
- process: Process = Field(
34
- description="Process that the crew will follow.", default=Process.sequential
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", "This field is not to be set by the user.", {}
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", "Either agents and task need to be set or config.", {}
 
 
71
  )
72
 
73
  if self.config:
74
- if not self.config.get("agents") or not self.config.get("tasks"):
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 kickoff(self) -> str:
97
- """Kickoff the crew to work on its tasks.
 
 
 
 
 
 
 
98
 
99
- Returns:
100
- Output of the crew for each task.
101
- """
 
 
 
 
 
 
 
102
  for agent in self.agents:
103
  agent.cache_handler = self.cache_handler
104
 
105
  if self.process == Process.sequential:
106
- return self.__sequential_loop()
107
-
108
- def __sequential_loop(self) -> str:
109
- """Loop that executes the sequential process.
110
 
111
- Returns:
112
- Output of the crew.
113
- """
114
- task_outcome = None
115
  for task in self.tasks:
116
- # Add delegation tools to the task if the agent allows it
117
- if task.agent.allow_delegation:
118
- tools = AgentTools(agents=self.agents).tools()
119
- task.tools += tools
120
-
121
- self.__log("debug", f"Working Agent: {task.agent.role}")
122
- self.__log("info", f"Starting Task: {task.description} ...")
123
-
124
- task_outcome = task.execute(task_outcome)
125
 
126
- self.__log("debug", f"Task output: {task_outcome}")
 
 
 
127
 
128
- return task_outcome
 
129
 
130
- def __log(self, level, message):
131
- """Log a message"""
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)