1
1
import json
2
- import threading
3
- import time
4
2
import uuid
5
- from typing import Any , ClassVar , Dict , List , Optional , Union
3
+ from typing import Any , Dict , List , Optional , Union
6
4
7
5
from pydantic import (
8
6
UUID4 ,
19
17
20
18
from crewai .agent import Agent
21
19
from crewai .agents .cache import CacheHandler
22
- from crewai .i18n import I18N
23
20
from crewai .process import Process
24
21
from crewai .task import Task
25
22
from crewai .tools .agent_tools import AgentTools
23
+ from crewai .utilities import I18N , Logger , RPMController
26
24
27
25
28
26
class Crew (BaseModel ):
@@ -37,23 +35,26 @@ class Crew(BaseModel):
37
35
config: Configuration settings for the crew.
38
36
cache_handler: Handles caching for the crew's operations.
39
37
max_rpm: Maximum number of requests per minute for the crew execution to be respected.
40
- rpm: Current number of requests per minute for the crew execution.
41
38
id: A unique identifier for the crew instance.
42
39
"""
43
40
44
41
__hash__ = object .__hash__
45
- _timer : Optional [threading .Timer ] = PrivateAttr (default = None )
46
- lock : ClassVar [threading .Lock ] = threading .Lock ()
47
- rpm : ClassVar [int ] = 0
48
- max_rpm : Optional [int ] = Field (default = None )
42
+ _rpm_controller : RPMController = PrivateAttr ()
43
+ _logger : Logger = PrivateAttr ()
44
+ _cache_handler : Optional [InstanceOf [CacheHandler ]] = PrivateAttr (
45
+ default = CacheHandler ()
46
+ )
49
47
model_config = ConfigDict (arbitrary_types_allowed = True )
50
48
tasks : List [Task ] = Field (default_factory = list )
51
49
agents : List [Agent ] = Field (default_factory = list )
52
50
process : Process = Field (default = Process .sequential )
53
51
verbose : Union [int , bool ] = Field (default = 0 )
54
52
config : Optional [Union [Json , Dict [str , Any ]]] = Field (default = None )
55
- cache_handler : Optional [InstanceOf [CacheHandler ]] = Field (default = CacheHandler ())
56
53
id : UUID4 = Field (default_factory = uuid .uuid4 , frozen = True )
54
+ max_rpm : Optional [int ] = Field (
55
+ default = None ,
56
+ description = "Maximum number of requests per minute for the crew execution to be respected." ,
57
+ )
57
58
language : str = Field (
58
59
default = "en" ,
59
60
description = "Language used for the crew, defaults to English." ,
@@ -74,9 +75,10 @@ def check_config_type(cls, v: Union[Json, Dict[str, Any]]):
74
75
return json .loads (v ) if isinstance (v , Json ) else v
75
76
76
77
@model_validator (mode = "after" )
77
- def set_reset_counter (self ):
78
- if self .max_rpm :
79
- self ._reset_request_count ()
78
+ def set_private_attrs (self ):
79
+ self ._cache_handler = CacheHandler ()
80
+ self ._logger = Logger (self .verbose )
81
+ self ._rpm_controller = RPMController (max_rpm = self .max_rpm , logger = self ._logger )
80
82
return self
81
83
82
84
@model_validator (mode = "after" )
@@ -94,8 +96,8 @@ def check_config(self):
94
96
95
97
if self .agents :
96
98
for agent in self .agents :
97
- agent .set_cache_handler (self .cache_handler )
98
- agent .set_request_within_rpm_limit (self .ensure_request_within_rpm_limit )
99
+ agent .set_cache_handler (self ._cache_handler )
100
+ agent .set_rpm_controller (self ._rpm_controller )
99
101
return self
100
102
101
103
def _setup_from_config (self ):
@@ -116,28 +118,9 @@ def _create_task(self, task_config):
116
118
del task_config ["agent" ]
117
119
return Task (** task_config , agent = task_agent )
118
120
119
- def ensure_request_within_rpm_limit (self ):
120
- if not self .max_rpm :
121
- return True
122
-
123
- with Crew .lock :
124
- if Crew .rpm < self .max_rpm :
125
- Crew .rpm += 1
126
- return True
127
- self ._log ("info" , "Max RPM reached, waiting for next minute to start." )
128
-
129
- return self ._wait_for_next_minute ()
130
-
131
- def _wait_for_next_minute (self ):
132
- time .sleep (60 )
133
- with Crew .lock :
134
- Crew .rpm = 0
135
- return True
136
-
137
121
def kickoff (self ) -> str :
138
122
"""Starts the crew to work on its assigned tasks."""
139
123
for agent in self .agents :
140
- agent .cache_handler = self .cache_handler
141
124
agent .i18n = I18N (language = self .language )
142
125
143
126
if self .process == Process .sequential :
@@ -149,33 +132,18 @@ def _sequential_loop(self) -> str:
149
132
for task in self .tasks :
150
133
self ._prepare_and_execute_task (task )
151
134
task_output = task .execute (task_output )
152
- self ._log ("debug" , f"\n [{ task .agent .role } ] Task output: { task_output } \n \n " )
153
- self ._stop_timer ()
135
+ self ._logger .log (
136
+ "debug" , f"[{ task .agent .role } ] Task output: { task_output } \n \n "
137
+ )
138
+
139
+ if self .max_rpm :
140
+ self ._rpm_controller .stop_rpm_counter ()
154
141
return task_output
155
142
156
143
def _prepare_and_execute_task (self , task ):
157
144
"""Prepares and logs information about the task being executed."""
158
145
if task .agent .allow_delegation :
159
146
task .tools += AgentTools (agents = self .agents ).tools ()
160
147
161
- self ._log ("debug" , f"Working Agent: { task .agent .role } " )
162
- self ._log ("info" , f"Starting Task: { task .description } " )
163
-
164
- def _log (self , level , message ):
165
- """Logs a message at the specified verbosity level."""
166
- level_map = {"debug" : 1 , "info" : 2 }
167
- verbose_level = (
168
- 2 if isinstance (self .verbose , bool ) and self .verbose else self .verbose
169
- )
170
- if verbose_level and level_map [level ] <= verbose_level :
171
- print (f"\n { message } " )
172
-
173
- def _stop_timer (self ):
174
- if self ._timer :
175
- self ._timer .cancel ()
176
-
177
- def _reset_request_count (self ):
178
- self ._stop_timer ()
179
- self ._timer = threading .Timer (60.0 , self ._reset_request_count )
180
- self ._timer .start ()
181
- Crew .rpm = 0
148
+ self ._logger .log ("debug" , f"Working Agent: { task .agent .role } " )
149
+ self ._logger .log ("info" , f"Starting Task: { task .description } " )
0 commit comments