fix: improve READY detection in reasoning handler#6218
Conversation
The reasoning handler only recognized the exact string 'READY: I am ready to execute the task.' which caused it to always detect 'NOT READY' even when the model outputs just 'READY'. Now uses regex to match 'READY' as a standalone keyword while excluding 'NOT READY', handling various LLM output formats. Fixes crewAIInc#6204
📝 WalkthroughWalkthroughA new module-level helper ChangesReadiness Detection Refactor
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@lib/crewai/src/crewai/utilities/reasoning_handler.py`:
- Around line 109-120: The regex pattern in the _is_ready_response function
needs to be fixed to handle both word boundary issues and variable whitespace.
Replace the current regex r"(?<!NOT\s)READY" with a two-pass check approach:
first verify that "NOT READY" does not appear in the text (case-insensitive),
then check for "READY" as a standalone word using proper word boundaries like
r"\bREADY\b". This avoids false positives from matching READY inside words like
ALREADY or UNREADY, and handles any amount of whitespace between NOT and READY
without relying on fixed-width lookbehinds.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: e1a57a5e-00d4-4bb8-93bd-e2da989c285d
📒 Files selected for processing (1)
lib/crewai/src/crewai/utilities/reasoning_handler.py
| def _is_ready_response(text: str) -> bool: | ||
| """Check if the LLM response indicates readiness to execute. | ||
|
|
||
| Matches 'READY' as a standalone keyword while excluding 'NOT READY'. | ||
| This handles various LLM output formats: | ||
| - "READY" | ||
| - "---\nREADY" | ||
| - "READY: I am ready to execute the task." | ||
| But NOT: | ||
| - "NOT READY" | ||
| """ | ||
| return bool(re.search(r"(?<!NOT\s)READY", text)) |
There was a problem hiding this comment.
Regex pattern has false-positive risks that contradict the docstring.
Two issues with r"(?<!NOT\s)READY":
-
No word boundary after READY — will match
READYinside words like"ALREADY"or"UNREADY", which are plausible in plan text (e.g., "I have ALREADY identified the tools"). -
Fixed-width lookbehind can't handle variable whitespace — Python's
remodule requires fixed-width lookbehinds, so"NOT READY"(double space) bypasses the check since the 4 chars beforeREADYare"T ", not"NOT ".
Since downstream code gates task execution on plan.ready (see AgentExecutor which only creates todos when plan_ready is true), false positives would cause premature execution.
🛠️ Proposed fix using two-pass check for robustness
def _is_ready_response(text: str) -> bool:
"""Check if the LLM response indicates readiness to execute.
Matches 'READY' as a standalone keyword while excluding 'NOT READY'.
This handles various LLM output formats:
- "READY"
- "---\nREADY"
- "READY: I am ready to execute the task."
But NOT:
- "NOT READY"
+ - "NOT READY" (variable whitespace)
+ - "ALREADY" (READY within other words)
"""
- return bool(re.search(r"(?<!NOT\s)READY", text))
+ has_ready = bool(re.search(r"\bREADY\b", text))
+ has_not_ready = bool(re.search(r"\bNOT\s+READY\b", text, re.IGNORECASE))
+ return has_ready and not has_not_ready🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@lib/crewai/src/crewai/utilities/reasoning_handler.py` around lines 109 - 120,
The regex pattern in the _is_ready_response function needs to be fixed to handle
both word boundary issues and variable whitespace. Replace the current regex
r"(?<!NOT\s)READY" with a two-pass check approach: first verify that "NOT READY"
does not appear in the text (case-insensitive), then check for "READY" as a
standalone word using proper word boundaries like r"\bREADY\b". This avoids
false positives from matching READY inside words like ALREADY or UNREADY, and
handles any amount of whitespace between NOT and READY without relying on
fixed-width lookbehinds.
Summary
Fixes #6204
The reasoning handler only recognized the exact string
"READY: I am ready to execute the task."when checking if an agent is ready to execute. This caused the handler to always detect "NOT READY" even when the model clearly outputs just"READY".Problem
When using reasoning with models like Ollama GLM5.2, the model outputs
"READY"after the plan content (e.g.,<PLAN CONTENTS>\n---\nREADY), but the handler fails to detect it because it only matches the full sentence"READY: I am ready to execute the task.".This affects 3 code paths:
_call_with_functionfallback when JSON parsing fails_call_with_functionfallback when function calling throws an exception_parse_planning_response(the text-based parsing path)Solution
Replace the exact string match with a regex-based check that:
READYas a standalone keywordNOT READY(negative lookbehind forNOT)READY,---\nREADY, full sentence, etc.)Testing
re.search(r"(?<!\bNOT\s)READY\b", "READY")→ True ✓re.search(r"(?<!\bNOT\s)READY\b", "---\nREADY")→ True ✓re.search(r"(?<!\bNOT\s)READY\b", "READY: I am ready to execute the task.")→ True ✓re.search(r"(?<!\bNOT\s)READY\b", "NOT READY")→ False ✓re.search(r"(?<!\bNOT\s)READY\b", "You indicated you weren't ready.")→ False ✓Summary by CodeRabbit