From 625a807d29b1ebf6be4a2c84bffb1bf3ecf9e9a0 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Sun, 29 Dec 2024 15:52:11 +0000 Subject: [PATCH] fix: preserve executor state between iterations (#1815) Co-Authored-By: Joe Moura --- src/crewai/agent.py | 8 +++- .../base_agent_executor_mixin.py | 21 +++++++--- src/crewai/agents/crew_agent_executor.py | 39 +++++++++++++------ 3 files changed, 51 insertions(+), 17 deletions(-) diff --git a/src/crewai/agent.py b/src/crewai/agent.py index 999d1d800..58b7ab68a 100644 --- a/src/crewai/agent.py +++ b/src/crewai/agent.py @@ -322,7 +322,13 @@ class Agent(BaseAgent): task_prompt += crew_knowledge_context tools = tools or self.tools or [] - self.create_agent_executor(tools=tools, task=task) + + # Only create a new executor if it doesn't exist or if tools/task changed + if (not hasattr(self, 'agent_executor') or + self.agent_executor is None or + tools != self.agent_executor.original_tools or + task != self.agent_executor.task): + self.create_agent_executor(tools=tools, task=task) if self.crew and self.crew._train: task_prompt = self._training_handler(task_prompt=task_prompt) 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 a79f6ecf0..8e4b67fcf 100644 --- a/src/crewai/agents/agent_builder/base_agent_executor_mixin.py +++ b/src/crewai/agents/agent_builder/base_agent_executor_mixin.py @@ -23,14 +23,25 @@ class CrewAgentExecutorMixin: max_iter: int _i18n: I18N _printer: Printer = Printer() + _logger = Printer() def _should_force_answer(self) -> bool: """Determine if a forced answer is required based on iteration count. - Also tracks when a forced answer has been triggered.""" - if self.iterations >= self.max_iter: - self.have_forced_answer = True - return True - return False + + This method checks if the maximum iterations have been reached. + The state of forced answers (have_forced_answer) is managed by + the executor's _invoke_loop method. + + Returns: + bool: True if iterations >= max_iter, indicating a forced + answer should be triggered + """ + should_force = self.iterations >= self.max_iter + if should_force: + self._logger.debug( + f"Max iterations ({self.max_iter}) reached." + ) + return should_force def _create_short_term_memory(self, output) -> None: """Create and save a short-term memory item if conditions are met.""" diff --git a/src/crewai/agents/crew_agent_executor.py b/src/crewai/agents/crew_agent_executor.py index ca02ca8c5..3182b4539 100644 --- a/src/crewai/agents/crew_agent_executor.py +++ b/src/crewai/agents/crew_agent_executor.py @@ -75,9 +75,11 @@ class CrewAgentExecutor(CrewAgentExecutorMixin): self.request_within_rpm_limit = request_within_rpm_limit self.ask_for_human_input = False self.messages: List[Dict[str, str]] = [] + # Initialize state tracking variables self.iterations = 0 self.log_error_after = 3 - self.have_forced_answer = False + self.have_forced_answer = False # Track if we've hit max iterations + self._logger = self._printer # Use printer for logging self.tool_name_to_tool_map: Dict[str, BaseTool] = { tool.name: tool for tool in self.tools } @@ -169,19 +171,34 @@ class CrewAgentExecutor(CrewAgentExecutorMixin): if self.step_callback: self.step_callback(formatted_answer) - if self._should_force_answer(): - # have_forced_answer is now set in _should_force_answer - if self.have_forced_answer: - return AgentFinish( - thought="", - output=self._i18n.errors( - "force_final_answer_error" - ).format(formatted_answer.text), - text=formatted_answer.text, - ) + # Check if we should force an answer and update state + should_force = self._should_force_answer() + self._printer.print( + content=f"Current state - iterations: {self.iterations}, max_iter: {self.max_iter}, have_forced_answer: {self.have_forced_answer}", + color="yellow" + ) + + if should_force: + # Set have_forced_answer to True as soon as we hit max iterations + self.have_forced_answer = True + self._printer.print( + content=f"Max iterations reached. Set have_forced_answer=True", + color="yellow" + ) + + # Return final answer with warning formatted_answer.text += ( f'\n{self._i18n.errors("force_final_answer")}' ) + self._printer.print( + content="Forcing final answer", + color="yellow" + ) + return AgentFinish( + thought="", + output=formatted_answer.text, + text=formatted_answer.text, + ) self.messages.append( self._format_msg(formatted_answer.text, role="assistant") )