Skip to content

Commit d879be8

Browse files
chore: fix ruff linting issues in agents module
fix(agents): linting, import paths, cache key alignment, and static method
1 parent 24b84a4 commit d879be8

File tree

16 files changed

+286
-294
lines changed

16 files changed

+286
-294
lines changed

src/crewai/agents/__init__.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
from crewai.agents.cache.cache_handler import CacheHandler
2-
from crewai.agents.parser import parse, AgentAction, AgentFinish, OutputParserException
2+
from crewai.agents.parser import AgentAction, AgentFinish, OutputParserError, parse
33
from crewai.agents.tools_handler import ToolsHandler
44

5-
__all__ = ["CacheHandler", "parse", "AgentAction", "AgentFinish", "OutputParserException", "ToolsHandler"]
5+
__all__ = [
6+
"AgentAction",
7+
"AgentFinish",
8+
"CacheHandler",
9+
"OutputParserError",
10+
"ToolsHandler",
11+
"parse",
12+
]
Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from abc import ABC, abstractmethod
2-
from typing import Any, Dict, List, Optional
2+
from typing import Any
33

4-
from pydantic import PrivateAttr
4+
from pydantic import ConfigDict, PrivateAttr
55

66
from crewai.agent import BaseAgent
77
from crewai.tools import BaseTool
@@ -16,27 +16,25 @@ class BaseAgentAdapter(BaseAgent, ABC):
1616
"""
1717

1818
adapted_structured_output: bool = False
19-
_agent_config: Optional[Dict[str, Any]] = PrivateAttr(default=None)
19+
_agent_config: dict[str, Any] | None = PrivateAttr(default=None)
2020

21-
model_config = {"arbitrary_types_allowed": True}
21+
model_config = ConfigDict(arbitrary_types_allowed=True)
2222

23-
def __init__(self, agent_config: Optional[Dict[str, Any]] = None, **kwargs: Any):
23+
def __init__(self, agent_config: dict[str, Any] | None = None, **kwargs: Any):
2424
super().__init__(adapted_agent=True, **kwargs)
2525
self._agent_config = agent_config
2626

2727
@abstractmethod
28-
def configure_tools(self, tools: Optional[List[BaseTool]] = None) -> None:
28+
def configure_tools(self, tools: list[BaseTool] | None = None) -> None:
2929
"""Configure and adapt tools for the specific agent implementation.
3030
3131
Args:
3232
tools: Optional list of BaseTool instances to be configured
3333
"""
34-
pass
3534

3635
def configure_structured_output(self, structured_output: Any) -> None:
3736
"""Configure the structured output for the specific agent implementation.
3837
3938
Args:
4039
structured_output: The structured output to be configured
4140
"""
42-
pass

src/crewai/agents/agent_adapters/base_tool_adapter.py

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from abc import ABC, abstractmethod
2-
from typing import Any, List, Optional
2+
from typing import Any
33

44
from crewai.tools.base_tool import BaseTool
55

@@ -12,23 +12,22 @@ class BaseToolAdapter(ABC):
1212
different frameworks and platforms.
1313
"""
1414

15-
original_tools: List[BaseTool]
16-
converted_tools: List[Any]
15+
original_tools: list[BaseTool]
16+
converted_tools: list[Any]
1717

18-
def __init__(self, tools: Optional[List[BaseTool]] = None):
18+
def __init__(self, tools: list[BaseTool] | None = None):
1919
self.original_tools = tools or []
2020
self.converted_tools = []
2121

2222
@abstractmethod
23-
def configure_tools(self, tools: List[BaseTool]) -> None:
23+
def configure_tools(self, tools: list[BaseTool]) -> None:
2424
"""Configure and convert tools for the specific implementation.
2525
2626
Args:
2727
tools: List of BaseTool instances to be configured and converted
2828
"""
29-
pass
3029

31-
def tools(self) -> List[Any]:
30+
def tools(self) -> list[Any]:
3231
"""Return all converted tools."""
3332
return self.converted_tools
3433

src/crewai/agents/agent_builder/base_agent.py

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import uuid
22
from abc import ABC, abstractmethod
3+
from collections.abc import Callable
34
from copy import copy as shallow_copy
45
from hashlib import md5
5-
from typing import Any, Callable, Dict, List, Optional, TypeVar
6+
from typing import Any, TypeVar
67

78
from pydantic import (
89
UUID4,
@@ -25,7 +26,6 @@
2526
from crewai.tools.base_tool import BaseTool, Tool
2627
from crewai.utilities import I18N, Logger, RPMController
2728
from crewai.utilities.config import process_config
28-
from crewai.utilities.converter import Converter
2929
from crewai.utilities.string_utils import interpolate_only
3030

3131
T = TypeVar("T", bound="BaseAgent")
@@ -81,17 +81,17 @@ class BaseAgent(ABC, BaseModel):
8181

8282
__hash__ = object.__hash__ # type: ignore
8383
_logger: Logger = PrivateAttr(default_factory=lambda: Logger(verbose=False))
84-
_rpm_controller: Optional[RPMController] = PrivateAttr(default=None)
84+
_rpm_controller: RPMController | None = PrivateAttr(default=None)
8585
_request_within_rpm_limit: Any = PrivateAttr(default=None)
86-
_original_role: Optional[str] = PrivateAttr(default=None)
87-
_original_goal: Optional[str] = PrivateAttr(default=None)
88-
_original_backstory: Optional[str] = PrivateAttr(default=None)
86+
_original_role: str | None = PrivateAttr(default=None)
87+
_original_goal: str | None = PrivateAttr(default=None)
88+
_original_backstory: str | None = PrivateAttr(default=None)
8989
_token_process: TokenProcess = PrivateAttr(default_factory=TokenProcess)
9090
id: UUID4 = Field(default_factory=uuid.uuid4, frozen=True)
9191
role: str = Field(description="Role of the agent")
9292
goal: str = Field(description="Objective of the agent")
9393
backstory: str = Field(description="Backstory of the agent")
94-
config: Optional[Dict[str, Any]] = Field(
94+
config: dict[str, Any] | None = Field(
9595
description="Configuration for the agent", default=None, exclude=True
9696
)
9797
cache: bool = Field(
@@ -100,15 +100,15 @@ class BaseAgent(ABC, BaseModel):
100100
verbose: bool = Field(
101101
default=False, description="Verbose mode for the Agent Execution"
102102
)
103-
max_rpm: Optional[int] = Field(
103+
max_rpm: int | None = Field(
104104
default=None,
105105
description="Maximum number of requests per minute for the agent execution to be respected.",
106106
)
107107
allow_delegation: bool = Field(
108108
default=False,
109109
description="Enable agent to delegate and ask questions among each other.",
110110
)
111-
tools: Optional[List[BaseTool]] = Field(
111+
tools: list[BaseTool] | None = Field(
112112
default_factory=list, description="Tools at agents' disposal"
113113
)
114114
max_iter: int = Field(
@@ -122,41 +122,41 @@ class BaseAgent(ABC, BaseModel):
122122
)
123123
crew: Any = Field(default=None, description="Crew to which the agent belongs.")
124124
i18n: I18N = Field(default=I18N(), description="Internationalization settings.")
125-
cache_handler: Optional[InstanceOf[CacheHandler]] = Field(
125+
cache_handler: InstanceOf[CacheHandler] | None = Field(
126126
default=None, description="An instance of the CacheHandler class."
127127
)
128128
tools_handler: InstanceOf[ToolsHandler] = Field(
129129
default_factory=ToolsHandler,
130130
description="An instance of the ToolsHandler class.",
131131
)
132-
tools_results: List[Dict[str, Any]] = Field(
132+
tools_results: list[dict[str, Any]] = Field(
133133
default=[], description="Results of the tools used by the agent."
134134
)
135-
max_tokens: Optional[int] = Field(
135+
max_tokens: int | None = Field(
136136
default=None, description="Maximum number of tokens for the agent's execution."
137137
)
138-
knowledge: Optional[Knowledge] = Field(
138+
knowledge: Knowledge | None = Field(
139139
default=None, description="Knowledge for the agent."
140140
)
141-
knowledge_sources: Optional[List[BaseKnowledgeSource]] = Field(
141+
knowledge_sources: list[BaseKnowledgeSource] | None = Field(
142142
default=None,
143143
description="Knowledge sources for the agent.",
144144
)
145-
knowledge_storage: Optional[Any] = Field(
145+
knowledge_storage: Any | None = Field(
146146
default=None,
147147
description="Custom knowledge storage for the agent.",
148148
)
149149
security_config: SecurityConfig = Field(
150150
default_factory=SecurityConfig,
151151
description="Security configuration for the agent, including fingerprinting.",
152152
)
153-
callbacks: List[Callable] = Field(
153+
callbacks: list[Callable] = Field(
154154
default=[], description="Callbacks to be used for the agent"
155155
)
156156
adapted_agent: bool = Field(
157157
default=False, description="Whether the agent is adapted"
158158
)
159-
knowledge_config: Optional[KnowledgeConfig] = Field(
159+
knowledge_config: KnowledgeConfig | None = Field(
160160
default=None,
161161
description="Knowledge configuration for the agent such as limits and threshold",
162162
)
@@ -168,7 +168,7 @@ def process_model_config(cls, values):
168168

169169
@field_validator("tools")
170170
@classmethod
171-
def validate_tools(cls, tools: List[Any]) -> List[BaseTool]:
171+
def validate_tools(cls, tools: list[Any]) -> list[BaseTool]:
172172
"""Validate and process the tools provided to the agent.
173173
174174
This method ensures that each tool is either an instance of BaseTool
@@ -221,7 +221,7 @@ def validate_and_set_attributes(self):
221221

222222
@field_validator("id", mode="before")
223223
@classmethod
224-
def _deny_user_set_id(cls, v: Optional[UUID4]) -> None:
224+
def _deny_user_set_id(cls, v: UUID4 | None) -> None:
225225
if v:
226226
raise PydanticCustomError(
227227
"may_not_set_field", "This field is not to be set by the user.", {}
@@ -252,8 +252,8 @@ def key(self):
252252
def execute_task(
253253
self,
254254
task: Any,
255-
context: Optional[str] = None,
256-
tools: Optional[List[BaseTool]] = None,
255+
context: str | None = None,
256+
tools: list[BaseTool] | None = None,
257257
) -> str:
258258
pass
259259

@@ -262,9 +262,8 @@ def create_agent_executor(self, tools=None) -> None:
262262
pass
263263

264264
@abstractmethod
265-
def get_delegation_tools(self, agents: List["BaseAgent"]) -> List[BaseTool]:
265+
def get_delegation_tools(self, agents: list["BaseAgent"]) -> list[BaseTool]:
266266
"""Set the task tools that init BaseAgenTools class."""
267-
pass
268267

269268
def copy(self: T) -> T: # type: ignore # Signature of "copy" incompatible with supertype "BaseModel"
270269
"""Create a deep copy of the Agent."""
@@ -309,7 +308,7 @@ def copy(self: T) -> T: # type: ignore # Signature of "copy" incompatible with
309308

310309
copied_data = self.model_dump(exclude=exclude)
311310
copied_data = {k: v for k, v in copied_data.items() if v is not None}
312-
copied_agent = type(self)(
311+
return type(self)(
313312
**copied_data,
314313
llm=existing_llm,
315314
tools=self.tools,
@@ -318,9 +317,7 @@ def copy(self: T) -> T: # type: ignore # Signature of "copy" incompatible with
318317
knowledge_storage=copied_knowledge_storage,
319318
)
320319

321-
return copied_agent
322-
323-
def interpolate_inputs(self, inputs: Dict[str, Any]) -> None:
320+
def interpolate_inputs(self, inputs: dict[str, Any]) -> None:
324321
"""Interpolate inputs into the agent description and backstory."""
325322
if self._original_role is None:
326323
self._original_role = self.role
@@ -362,5 +359,5 @@ def set_rpm_controller(self, rpm_controller: RPMController) -> None:
362359
self._rpm_controller = rpm_controller
363360
self.create_agent_executor()
364361

365-
def set_knowledge(self, crew_embedder: Optional[Dict[str, Any]] = None):
362+
def set_knowledge(self, crew_embedder: dict[str, Any] | None = None):
366363
pass

src/crewai/agents/agent_builder/base_agent_executor_mixin.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import time
2-
from typing import TYPE_CHECKING, Dict, List
2+
from typing import TYPE_CHECKING
33

4+
from crewai.events.event_listener import event_listener
45
from crewai.memory.entity.entity_memory_item import EntityMemoryItem
56
from crewai.memory.long_term.long_term_memory_item import LongTermMemoryItem
67
from crewai.utilities import I18N
78
from crewai.utilities.converter import ConverterError
89
from crewai.utilities.evaluators.task_evaluator import TaskEvaluator
910
from crewai.utilities.printer import Printer
10-
from crewai.events.event_listener import event_listener
1111

1212
if TYPE_CHECKING:
1313
from crewai.agents.agent_builder.base_agent import BaseAgent
@@ -21,7 +21,7 @@ class CrewAgentExecutorMixin:
2121
task: "Task"
2222
iterations: int
2323
max_iter: int
24-
messages: List[Dict[str, str]]
24+
messages: list[dict[str, str]]
2525
_i18n: I18N
2626
_printer: Printer = Printer()
2727

@@ -46,7 +46,6 @@ def _create_short_term_memory(self, output) -> None:
4646
)
4747
except Exception as e:
4848
print(f"Failed to add to short term memory: {e}")
49-
pass
5049

5150
def _create_external_memory(self, output) -> None:
5251
"""Create and save a external-term memory item if conditions are met."""
@@ -67,7 +66,6 @@ def _create_external_memory(self, output) -> None:
6766
)
6867
except Exception as e:
6968
print(f"Failed to add to external memory: {e}")
70-
pass
7169

7270
def _create_long_term_memory(self, output) -> None:
7371
"""Create and save long-term and entity memory items based on evaluation."""
@@ -113,10 +111,8 @@ def _create_long_term_memory(self, output) -> None:
113111
self.crew._entity_memory.save(entity_memories)
114112
except AttributeError as e:
115113
print(f"Missing attributes for long term memory: {e}")
116-
pass
117114
except Exception as e:
118115
print(f"Failed to add to long term memory: {e}")
119-
pass
120116
elif (
121117
self.crew
122118
and self.crew._long_term_memory

src/crewai/agents/crew_agent_executor.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from crewai.agents.parser import (
1313
AgentAction,
1414
AgentFinish,
15-
OutputParserException,
15+
OutputParserError,
1616
)
1717
from crewai.agents.tools_handler import ToolsHandler
1818
from crewai.events.event_bus import crewai_event_bus
@@ -228,7 +228,7 @@ def _invoke_loop(self) -> AgentFinish:
228228
self._invoke_step_callback(formatted_answer)
229229
self._append_message(formatted_answer.text)
230230

231-
except OutputParserException as e:
231+
except OutputParserError as e: # noqa: PERF203
232232
formatted_answer = handle_output_parser_exception(
233233
e=e,
234234
messages=self.messages,
@@ -251,17 +251,20 @@ def _invoke_loop(self) -> AgentFinish:
251251
i18n=self._i18n,
252252
)
253253
continue
254-
else:
255-
handle_unknown_error(self._printer, e)
256-
raise e
254+
handle_unknown_error(self._printer, e)
255+
raise e
257256
finally:
258257
self.iterations += 1
259258

260259
# During the invoke loop, formatted_answer alternates between AgentAction
261260
# (when the agent is using tools) and eventually becomes AgentFinish
262-
# (when the agent reaches a final answer). This assertion confirms we've
261+
# (when the agent reaches a final answer). This check confirms we've
263262
# reached a final answer and helps type checking understand this transition.
264-
assert isinstance(formatted_answer, AgentFinish)
263+
if not isinstance(formatted_answer, AgentFinish):
264+
raise RuntimeError(
265+
"Agent execution ended without reaching a final answer. "
266+
f"Got {type(formatted_answer).__name__} instead of AgentFinish."
267+
)
265268
self._show_logs(formatted_answer)
266269
return formatted_answer
267270

@@ -324,9 +327,7 @@ def _show_start_logs(self) -> None:
324327
self.agent,
325328
AgentLogsStartedEvent(
326329
agent_role=self.agent.role,
327-
task_description=(
328-
getattr(self.task, "description") if self.task else "Not Found"
329-
),
330+
task_description=(self.task.description if self.task else "Not Found"),
330331
verbose=self.agent.verbose
331332
or (hasattr(self, "crew") and getattr(self.crew, "verbose", False)),
332333
),
@@ -415,8 +416,7 @@ def _format_prompt(prompt: str, inputs: dict[str, str]) -> str:
415416
"""
416417
prompt = prompt.replace("{input}", inputs["input"])
417418
prompt = prompt.replace("{tool_names}", inputs["tool_names"])
418-
prompt = prompt.replace("{tools}", inputs["tools"])
419-
return prompt
419+
return prompt.replace("{tools}", inputs["tools"])
420420

421421
def _handle_human_feedback(self, formatted_answer: AgentFinish) -> AgentFinish:
422422
"""Process human feedback.

0 commit comments

Comments
 (0)