Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions lib/crewai/src/crewai/crew.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from copy import copy as shallow_copy
from hashlib import md5
import json
import logging
from pathlib import Path
import re
from typing import (
Expand Down Expand Up @@ -296,8 +297,8 @@ class Crew(FlowTrackable, BaseModel):
max_rpm: int | None = Field(
default=None,
description=(
"Maximum number of requests per minute for the crew execution "
"to be respected."
"Maximum number of requests per minute for the crew execution. "
"Set to None to disable rate limiting (not recommended for production)."
Comment on lines +300 to +301

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

max_rpm=0 still disables throttling without triggering this warning.

Line 767 and Line 2102 both gate RPM behavior on truthiness, so max_rpm=0 skips controller hookup/cleanup just like None. As written, the new description and validator only cover None, so this PR still misses one uncapped configuration path.

Also applies to: 617-630

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/crewai/src/crewai/crew.py` around lines 300 - 301, `max_rpm=0` is still
treated as “disabled” in the `Crew` RPM flow, but the new docs/validation only
mention `None`. Update the `Crew`-related `max_rpm` handling so zero is covered
the same way as `None` in the truthiness checks that control controller hookup
and cleanup, and align the warning/description accordingly. Make sure the
validator and any explanatory text near `Crew`’s `max_rpm` parameter reflect
both uncapped values, not just `None`.

),
)
prompt_file: str | None = Field(
Expand Down Expand Up @@ -613,6 +614,22 @@ def check_config_type(
# TODO: Improve typing
return json.loads(v) if isinstance(v, Json) else v # type: ignore

@model_validator(mode="after")
def _warn_rate_limit_disabled(self) -> Crew:
"""Warn operators when no client-side rate limit is configured.

With ``max_rpm=None`` the only safeguard against rapid-fire requests is
the upstream API provider's own rate limits, which can lead to 429s and
unexpected spend. This warning surfaces the risk at runtime without
changing behavior.
"""
if self.max_rpm is None:
logging.warning(
"max_rpm is None: rate limiting is disabled. "
"Set a positive integer in Crew() to limit API requests and avoid 429 errors."
)
return self

@model_validator(mode="after")
def set_private_attrs(self) -> Crew:
"""set private attributes."""
Expand Down
15 changes: 15 additions & 0 deletions lib/crewai/src/crewai/llm.py
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,21 @@ def _validate_llm_fields(cls, data: Any) -> Any:
data["is_anthropic"] = cls._is_anthropic_model(model)
return data

@model_validator(mode="after")
def _warn_tokens_uncapped(self) -> LLM:
"""Warn when neither ``max_tokens`` nor ``max_completion_tokens`` is set.

Without an explicit cap, a single prompt can produce very large outputs
(e.g. 128k+ tokens on modern models), leading to runaway spend. This
warning surfaces the risk at runtime without changing behavior.
"""
if self.max_tokens is None and self.max_completion_tokens is None:
logging.warning(
"max_tokens/max_completion_tokens not set; LLM responses are uncapped. "
"Set a limit (e.g., max_tokens=4096) to control token costs and avoid runaway generation."
)
Comment on lines +686 to +698

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Zero-valued caps bypass this warning but are still treated as uncapped.

Line 755 and Line 2168 both collapse 0 to “no cap” via self.max_tokens or self.max_completion_tokens. That means LLM(max_tokens=0) still sends an uncapped request without hitting this validator, so the warning does not cover the actual runtime behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/crewai/src/crewai/llm.py` around lines 686 - 698, The uncapped-token
warning in LLM._warn_tokens_uncapped only checks for None, but runtime logic
treats 0 the same as no cap via the max_tokens/max_completion_tokens fallback.
Update the validator and any related cap-handling in LLM so zero-valued caps are
normalized or rejected consistently, and make the warning trigger for both None
and 0 when the effective request will be uncapped.

return self

@model_validator(mode="after")
def _init_litellm(self) -> LLM:
self.is_litellm = True
Expand Down