diff --git a/lib/crewai/src/crewai/utilities/reasoning_handler.py b/lib/crewai/src/crewai/utilities/reasoning_handler.py index 21c0a1e1d5..a3ef4594c3 100644 --- a/lib/crewai/src/crewai/utilities/reasoning_handler.py +++ b/lib/crewai/src/crewai/utilities/reasoning_handler.py @@ -4,6 +4,7 @@ import json import logging +import re from typing import TYPE_CHECKING, Any, Final, Literal, cast from pydantic import BaseModel, Field @@ -411,7 +412,7 @@ def _create_reasoning_plan( return ( response_str, [], - "READY: I am ready to execute the task." in response_str, + AgentReasoning._is_plan_ready(response_str), ) except HookAborted: @@ -437,7 +438,7 @@ def _create_reasoning_plan( return ( fallback_str, [], - "READY: I am ready to execute the task." in fallback_str, + AgentReasoning._is_plan_ready(fallback_str), ) except HookAborted: raise @@ -585,6 +586,21 @@ def _create_refine_prompt(self, current_plan: str) -> str: current_plan=current_plan, ) + @staticmethod + def _is_plan_ready(response: str) -> bool: + """Check if the agent indicated readiness in the planning response. + + Detects standalone ``READY`` that is not part of ``NOT READY``. + Case-insensitive to handle ``Ready``, ``READY``, ``ready``, etc. + + Args: + response: The LLM response text. + + Returns: + True if the agent declared READY, False otherwise. + """ + return bool(re.search(r"(? tuple[str, bool]: """Parses the planning response to extract the plan and readiness. @@ -599,7 +615,7 @@ def _parse_planning_response(response: str) -> tuple[str, bool]: return "No plan was generated.", False plan = response - ready = "READY: I am ready to execute the task." in response + ready = AgentReasoning._is_plan_ready(response) return plan, ready