mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-05-03 00:02:36 +00:00
Add RPM control to both agents and crews (#133)
* moving file into utilities * creating Logger and RPMController * Adding support for RPM to agents and crew
This commit is contained in:
4
src/crewai/utilities/__init__.py
Normal file
4
src/crewai/utilities/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from .i18n import I18N
|
||||
from .logger import Logger
|
||||
from .prompts import Prompts
|
||||
from .rpm_controller import RPMController
|
||||
47
src/crewai/utilities/i18n.py
Normal file
47
src/crewai/utilities/i18n.py
Normal file
@@ -0,0 +1,47 @@
|
||||
import json
|
||||
import os
|
||||
from typing import Dict, Optional
|
||||
|
||||
from pydantic import BaseModel, Field, PrivateAttr, ValidationError, model_validator
|
||||
|
||||
|
||||
class I18N(BaseModel):
|
||||
_translations: Optional[Dict[str, str]] = PrivateAttr()
|
||||
language: Optional[str] = Field(
|
||||
default="en",
|
||||
description="Language used to load translations",
|
||||
)
|
||||
|
||||
@model_validator(mode="after")
|
||||
def load_translation(self) -> "I18N":
|
||||
"""Load translations from a JSON file based on the specified language."""
|
||||
try:
|
||||
dir_path = os.path.dirname(os.path.realpath(__file__))
|
||||
prompts_path = os.path.join(
|
||||
dir_path, f"../translations/{self.language}.json"
|
||||
)
|
||||
|
||||
with open(prompts_path, "r") as f:
|
||||
self._translations = json.load(f)
|
||||
except FileNotFoundError:
|
||||
raise ValidationError(
|
||||
f"Trasnlation file for language '{self.language}' not found."
|
||||
)
|
||||
except json.JSONDecodeError:
|
||||
raise ValidationError(f"Error decoding JSON from the prompts file.")
|
||||
return self
|
||||
|
||||
def slice(self, slice: str) -> str:
|
||||
return self.retrieve("slices", slice)
|
||||
|
||||
def errors(self, error: str) -> str:
|
||||
return self.retrieve("errors", error)
|
||||
|
||||
def tools(self, error: str) -> str:
|
||||
return self.retrieve("tools", error)
|
||||
|
||||
def retrieve(self, kind, key):
|
||||
try:
|
||||
return self._translations[kind].get(key)
|
||||
except:
|
||||
raise ValidationError(f"Translation for '{kind}':'{key}' not found.")
|
||||
11
src/crewai/utilities/logger.py
Normal file
11
src/crewai/utilities/logger.py
Normal file
@@ -0,0 +1,11 @@
|
||||
class Logger:
|
||||
def __init__(self, verbose_level=0):
|
||||
verbose_level = (
|
||||
2 if isinstance(verbose_level, bool) and verbose_level else verbose_level
|
||||
)
|
||||
self.verbose_level = verbose_level
|
||||
|
||||
def log(self, level, message):
|
||||
level_map = {"debug": 1, "info": 2}
|
||||
if self.verbose_level and level_map.get(level, 0) <= self.verbose_level:
|
||||
print(f"\n[{level.upper()}]: {message}")
|
||||
32
src/crewai/utilities/prompts.py
Normal file
32
src/crewai/utilities/prompts.py
Normal file
@@ -0,0 +1,32 @@
|
||||
from typing import ClassVar
|
||||
|
||||
from langchain.prompts import PromptTemplate
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from crewai.utilities import I18N
|
||||
|
||||
|
||||
class Prompts(BaseModel):
|
||||
"""Manages and generates prompts for a generic agent with support for different languages."""
|
||||
|
||||
i18n: I18N = Field(default=I18N())
|
||||
|
||||
SCRATCHPAD_SLICE: ClassVar[str] = "\n{agent_scratchpad}"
|
||||
|
||||
def task_execution_with_memory(self) -> str:
|
||||
"""Generate a prompt for task execution with memory components."""
|
||||
return self._build_prompt(["role_playing", "tools", "memory", "task"])
|
||||
|
||||
def task_execution_without_tools(self) -> str:
|
||||
"""Generate a prompt for task execution without tools components."""
|
||||
return self._build_prompt(["role_playing", "task"])
|
||||
|
||||
def task_execution(self) -> str:
|
||||
"""Generate a standard prompt for task execution."""
|
||||
return self._build_prompt(["role_playing", "tools", "task"])
|
||||
|
||||
def _build_prompt(self, components: [str]) -> str:
|
||||
"""Constructs a prompt string from specified components."""
|
||||
prompt_parts = [self.i18n.slice(component) for component in components]
|
||||
prompt_parts.append(self.SCRATCHPAD_SLICE)
|
||||
return PromptTemplate.from_template("".join(prompt_parts))
|
||||
57
src/crewai/utilities/rpm_controller.py
Normal file
57
src/crewai/utilities/rpm_controller.py
Normal file
@@ -0,0 +1,57 @@
|
||||
import threading
|
||||
import time
|
||||
from typing import Union
|
||||
|
||||
from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, model_validator
|
||||
|
||||
from crewai.utilities.logger import Logger
|
||||
|
||||
|
||||
class RPMController(BaseModel):
|
||||
model_config = ConfigDict(arbitrary_types_allowed=True)
|
||||
max_rpm: Union[int, None] = Field(default=None)
|
||||
logger: Logger = Field(default=None)
|
||||
_current_rpm: int = PrivateAttr(default=0)
|
||||
_timer: threading.Timer = PrivateAttr(default=None)
|
||||
_lock: threading.Lock = PrivateAttr(default=None)
|
||||
|
||||
@model_validator(mode="after")
|
||||
def reset_counter(self):
|
||||
if self.max_rpm:
|
||||
self._lock = threading.Lock()
|
||||
self._reset_request_count()
|
||||
return self
|
||||
|
||||
def check_or_wait(self):
|
||||
if not self.max_rpm:
|
||||
return True
|
||||
|
||||
with self._lock:
|
||||
if self._current_rpm < self.max_rpm:
|
||||
self._current_rpm += 1
|
||||
return True
|
||||
else:
|
||||
self.logger.log(
|
||||
"info", "Max RPM reached, waiting for next minute to start."
|
||||
)
|
||||
self._wait_for_next_minute()
|
||||
self._current_rpm = 1
|
||||
return True
|
||||
|
||||
def stop_rpm_counter(self):
|
||||
if self._timer:
|
||||
self._timer.cancel()
|
||||
self._timer = None
|
||||
|
||||
def _wait_for_next_minute(self):
|
||||
time.sleep(60)
|
||||
with self._lock:
|
||||
self._current_rpm = 0
|
||||
|
||||
def _reset_request_count(self):
|
||||
with self._lock:
|
||||
self._current_rpm = 0
|
||||
if self._timer:
|
||||
self._timer.cancel()
|
||||
self._timer = threading.Timer(60.0, self._reset_request_count)
|
||||
self._timer.start()
|
||||
Reference in New Issue
Block a user