diff --git a/src/crewai/agent.py b/src/crewai/agent.py index f0e890983..825880315 100644 --- a/src/crewai/agent.py +++ b/src/crewai/agent.py @@ -152,7 +152,7 @@ class Agent(BaseAgent): self._logger = Logger(verbose=self.verbose) if self.max_rpm: self._rpm_controller = RPMController(max_rpm=self.max_rpm, logger=self._logger) - self._token_process = TokenProcess() + self._token_process = TokenProcess() # type: ignore # Known type mismatch between utilities and agent_builder _times_executed: int = PrivateAttr(default=0) max_execution_time: Optional[int] = Field( diff --git a/src/crewai/agents/agent_builder/base_agent_executor_mixin.py b/src/crewai/agents/agent_builder/base_agent_executor_mixin.py index 19d5401a3..63add11f2 100644 --- a/src/crewai/agents/agent_builder/base_agent_executor_mixin.py +++ b/src/crewai/agents/agent_builder/base_agent_executor_mixin.py @@ -82,16 +82,17 @@ class CrewAgentExecutorMixin: ) self.crew._long_term_memory.save(long_term_memory) - for entity in evaluation.entities: - entity_memory = EntityMemoryItem( - name=entity.name, - type=entity.type, - description=entity.description, - relationships="\n".join( - [f"- {r}" for r in entity.relationships] - ), - ) - self.crew._entity_memory.save(entity_memory) + if hasattr(evaluation, 'entities') and evaluation.entities: + for entity in evaluation.entities: + entity_memory = EntityMemoryItem( + name=entity.name, + type=entity.type, + description=entity.description, + relationships="\n".join( + [f"- {r}" for r in entity.relationships] + ), + ) + self.crew._entity_memory.save(entity_memory) except AttributeError as e: print(f"Missing attributes for long term memory: {e}") pass diff --git a/src/crewai/agents/crew_agent_executor.py b/src/crewai/agents/crew_agent_executor.py index 209aaac5f..0becb11e2 100644 --- a/src/crewai/agents/crew_agent_executor.py +++ b/src/crewai/agents/crew_agent_executor.py @@ -147,7 +147,8 @@ class CrewAgentExecutor(CrewAgentExecutorMixin): # Directly append the result to the messages if the # tool is "Add image to content" in case of multimodal # agents - if formatted_answer.tool == self._i18n.tools("add_image")["name"]: + add_image_tool_name = self._i18n.tools("add_image") + if add_image_tool_name and formatted_answer.tool == add_image_tool_name: self.messages.append(tool_result.result) continue @@ -214,13 +215,14 @@ class CrewAgentExecutor(CrewAgentExecutorMixin): if self.agent.verbose or ( hasattr(self, "crew") and getattr(self.crew, "verbose", False) ): - agent_role = self.agent.role.split("\n")[0] + agent_role = self.agent.role.split("\n")[0] if self.agent and self.agent.role else "" self._printer.print( content=f"\033[1m\033[95m# Agent:\033[00m \033[1m\033[92m{agent_role}\033[00m" ) - self._printer.print( - content=f"\033[95m## Task:\033[00m \033[92m{self.task.description}\033[00m" - ) + if self.task and self.task.description: + self._printer.print( + content=f"\033[95m## Task:\033[00m \033[92m{self.task.description}\033[00m" + ) def _show_logs(self, formatted_answer: Union[AgentAction, AgentFinish]): if self.agent is None: @@ -228,7 +230,7 @@ class CrewAgentExecutor(CrewAgentExecutorMixin): if self.agent.verbose or ( hasattr(self, "crew") and getattr(self.crew, "verbose", False) ): - agent_role = self.agent.role.split("\n")[0] + agent_role = self.agent.role.split("\n")[0] if self.agent and self.agent.role else "" if isinstance(formatted_answer, AgentAction): thought = re.sub(r"\n+", "\n", formatted_answer.thought) formatted_json = json.dumps( diff --git a/src/crewai/crew.py b/src/crewai/crew.py index c01a89280..f9ae9f43c 100644 --- a/src/crewai/crew.py +++ b/src/crewai/crew.py @@ -6,6 +6,8 @@ from concurrent.futures import Future from hashlib import md5 from typing import Any, Callable, Dict, List, Optional, Tuple, Union +from crewai.tools.base_tool import BaseTool + from pydantic import ( UUID4, BaseModel, @@ -728,7 +730,7 @@ class Crew(BaseModel): tools_for_task = task.tools or agent_to_use.tools or [] tools_for_task = self._prepare_tools(agent_to_use, task, tools_for_task) - self._log_task_start(task, agent_to_use.role) + self._log_task_start(task, agent_to_use.role if agent_to_use and agent_to_use.role else "") if isinstance(task, ConditionalTask): skipped_task_output = self._handle_conditional_task( @@ -794,8 +796,8 @@ class Crew(BaseModel): return None def _prepare_tools( - self, agent: BaseAgent, task: Task, tools: List[Tool] - ) -> List[Tool]: + self, agent: BaseAgent, task: Task, tools: List[Union[Tool, BaseTool]] + ) -> List[Union[Tool, BaseTool]]: # Add delegation tools if agent allows delegation if agent.allow_delegation: if self.process == Process.hierarchical: @@ -824,8 +826,8 @@ class Crew(BaseModel): return task.agent def _merge_tools( - self, existing_tools: List[Tool], new_tools: List[Tool] - ) -> List[Tool]: + self, existing_tools: List[Union[Tool, BaseTool]], new_tools: List[Union[Tool, BaseTool]] + ) -> List[Union[Tool, BaseTool]]: """Merge new tools into existing tools list, avoiding duplicates by tool name.""" if not new_tools: return existing_tools diff --git a/src/crewai/task.py b/src/crewai/task.py index a63bde57d..9a891c23b 100644 --- a/src/crewai/task.py +++ b/src/crewai/task.py @@ -269,7 +269,9 @@ class Task(BaseModel): @model_validator(mode="after") def check_tools(self): """Check if the tools are set.""" - if not self.tools and self.agent and self.agent.tools: + if self.agent and self.agent.tools: + if self.tools is None: + self.tools = [] self.tools.extend(self.agent.tools) return self @@ -348,7 +350,8 @@ class Task(BaseModel): self.prompt_context = context tools = tools or self.tools or [] - self.processed_by_agents.add(agent.role) + if agent and agent.role: + self.processed_by_agents.add(agent.role) result = agent.execute_task( task=self, diff --git a/src/crewai/tools/agent_tools/base_agent_tools.py b/src/crewai/tools/agent_tools/base_agent_tools.py index e67dce72a..438455f46 100644 --- a/src/crewai/tools/agent_tools/base_agent_tools.py +++ b/src/crewai/tools/agent_tools/base_agent_tools.py @@ -19,13 +19,13 @@ class BaseAgentTool(BaseTool): default_factory=I18N, description="Internationalization settings" ) - def sanitize_agent_name(self, name: str) -> str: + def sanitize_agent_name(self, name: Optional[str]) -> str: """ Sanitize agent role name by normalizing whitespace and setting to lowercase. Converts all whitespace (including newlines) to single spaces and removes quotes. Args: - name (str): The agent role name to sanitize + name (Optional[str]): The agent role name to sanitize Returns: str: The sanitized agent role name, with whitespace normalized,