From 8d2928e49af10add10b2142af795ad6756e229c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Moura?= Date: Tue, 20 May 2025 08:39:16 -0700 Subject: [PATCH] fixing handler --- src/crewai/utilities/reasoning_handler.py | 117 +++++++++++----------- 1 file changed, 60 insertions(+), 57 deletions(-) diff --git a/src/crewai/utilities/reasoning_handler.py b/src/crewai/utilities/reasoning_handler.py index 5aeb9716f..2fa5dba3c 100644 --- a/src/crewai/utilities/reasoning_handler.py +++ b/src/crewai/utilities/reasoning_handler.py @@ -45,35 +45,35 @@ class AgentReasoning: """ Public method for the reasoning process that creates and refines a plan for the task until the agent is ready to execute it. - + Returns: AgentReasoningOutput: The output of the agent reasoning process. """ return self.__handle_agent_reasoning() - + def __handle_agent_reasoning(self) -> AgentReasoningOutput: """ Private method that handles the agent reasoning process. - + Returns: AgentReasoningOutput: The output of the agent reasoning process. """ plan, ready = self.__create_initial_plan() - + plan, ready = self.__refine_plan_if_needed(plan, ready) - + reasoning_plan = ReasoningPlan(plan=plan, ready=ready) return AgentReasoningOutput(plan=reasoning_plan) def __create_initial_plan(self) -> Tuple[str, bool]: """ Creates the initial reasoning plan for the task. - + Returns: Tuple[str, bool]: The initial plan and whether the agent is ready to execute the task. """ reasoning_prompt = self.__create_reasoning_prompt() - + if self.llm.supports_function_calling(): plan, ready = self.__call_with_function(reasoning_prompt, "initial_plan") return plan, ready @@ -83,33 +83,33 @@ class AgentReasoning: goal=self.agent.goal, backstory=self.__get_agent_backstory() ) - + response = self.llm.call( [ {"role": "system", "content": system_prompt}, {"role": "user", "content": reasoning_prompt} ] ) - + return self.__parse_reasoning_response(str(response)) - + def __refine_plan_if_needed(self, plan: str, ready: bool) -> Tuple[str, bool]: """ Refines the reasoning plan if the agent is not ready to execute the task. - + Args: plan: The current reasoning plan. ready: Whether the agent is ready to execute the task. - + Returns: Tuple[str, bool]: The refined plan and whether the agent is ready to execute the task. """ attempt = 1 max_attempts = self.agent.max_reasoning_attempts - + while not ready and (max_attempts is None or attempt < max_attempts): refine_prompt = self.__create_refine_prompt(plan) - + if self.llm.supports_function_calling(): plan, ready = self.__call_with_function(refine_prompt, "refine_plan") else: @@ -118,7 +118,7 @@ class AgentReasoning: goal=self.agent.goal, backstory=self.__get_agent_backstory() ) - + response = self.llm.call( [ {"role": "system", "content": system_prompt}, @@ -126,56 +126,59 @@ class AgentReasoning: ] ) plan, ready = self.__parse_reasoning_response(str(response)) - + attempt += 1 - + if max_attempts is not None and attempt >= max_attempts: self.logger.warning( f"Agent reasoning reached maximum attempts ({max_attempts}) without being ready. Proceeding with current plan." ) break - + return plan, ready def __call_with_function(self, prompt: str, prompt_type: str) -> Tuple[str, bool]: """ Calls the LLM with function calling to get a reasoning plan. - + Args: prompt: The prompt to send to the LLM. prompt_type: The type of prompt (initial_plan or refine_plan). - + Returns: Tuple[str, bool]: A tuple containing the plan and whether the agent is ready. """ self.logger.debug(f"Using function calling for {prompt_type} reasoning") - + function_schema = { - "name": "create_reasoning_plan", - "description": "Create or refine a reasoning plan for a task", - "parameters": { - "type": "object", - "properties": { - "plan": { - "type": "string", - "description": "The detailed reasoning plan for the task." + "type": "function", + "function": { + "name": "create_reasoning_plan", + "description": "Create or refine a reasoning plan for a task", + "parameters": { + "type": "object", + "properties": { + "plan": { + "type": "string", + "description": "The detailed reasoning plan for the task." + }, + "ready": { + "type": "boolean", + "description": "Whether the agent is ready to execute the task." + } }, - "ready": { - "type": "boolean", - "description": "Whether the agent is ready to execute the task." - } - }, - "required": ["plan", "ready"] + "required": ["plan", "ready"] + } } } - + try: system_prompt = self.i18n.retrieve("reasoning", prompt_type).format( role=self.agent.role, goal=self.agent.goal, backstory=self.__get_agent_backstory() ) - + response = self.llm.call( [ {"role": "system", "content": system_prompt}, @@ -183,36 +186,36 @@ class AgentReasoning: ], tools=[function_schema] ) - + self.logger.debug(f"Function calling response: {response[:100]}...") - + try: result = json.loads(response) if "plan" in result and "ready" in result: return result["plan"], result["ready"] except (json.JSONDecodeError, KeyError): pass - + response_str = str(response) return response_str, "READY: I am ready to execute the task." in response_str - + except Exception as e: self.logger.warning(f"Error during function calling: {str(e)}. Falling back to text parsing.") - + try: system_prompt = self.i18n.retrieve("reasoning", prompt_type).format( role=self.agent.role, goal=self.agent.goal, backstory=self.__get_agent_backstory() ) - + fallback_response = self.llm.call( [ {"role": "system", "content": system_prompt}, {"role": "user", "content": prompt} ] ) - + fallback_str = str(fallback_response) return fallback_str, "READY: I am ready to execute the task." in fallback_str except Exception as inner_e: @@ -222,7 +225,7 @@ class AgentReasoning: def __get_agent_backstory(self) -> str: """ Safely gets the agent's backstory, providing a default if not available. - + Returns: str: The agent's backstory or a default value. """ @@ -231,12 +234,12 @@ class AgentReasoning: def __create_reasoning_prompt(self) -> str: """ Creates a prompt for the agent to reason about the task. - + Returns: str: The reasoning prompt. """ available_tools = self.__format_available_tools() - + return self.i18n.retrieve("reasoning", "create_plan_prompt").format( role=self.agent.role, goal=self.agent.goal, @@ -249,7 +252,7 @@ class AgentReasoning: def __format_available_tools(self) -> str: """ Formats the available tools for inclusion in the prompt. - + Returns: str: Comma-separated list of tool names. """ @@ -261,10 +264,10 @@ class AgentReasoning: def __create_refine_prompt(self, current_plan: str) -> str: """ Creates a prompt for the agent to refine its reasoning plan. - + Args: current_plan: The current reasoning plan. - + Returns: str: The refine prompt. """ @@ -279,29 +282,29 @@ class AgentReasoning: """ Parses the reasoning response to extract the plan and whether the agent is ready to execute the task. - + Args: response: The LLM response. - + Returns: Tuple[str, bool]: The plan and whether the agent is ready to execute the task. """ if not response: return "No plan was generated.", False - + plan = response ready = False - + if "READY: I am ready to execute the task." in response: ready = True - + return plan, ready - + def _handle_agent_reasoning(self) -> AgentReasoningOutput: """ Deprecated method for backward compatibility. Use handle_agent_reasoning() instead. - + Returns: AgentReasoningOutput: The output of the agent reasoning process. """