Skip to content

fix(reasoning): use regex for plan readiness detection (closes #6204) - #6655

Open
Diwak4r wants to merge 1 commit into
crewAIInc:mainfrom
Diwak4r:fix/reasoning-ready-detection-regex
Open

fix(reasoning): use regex for plan readiness detection (closes #6204)#6655
Diwak4r wants to merge 1 commit into
crewAIInc:mainfrom
Diwak4r:fix/reasoning-ready-detection-regex

Conversation

@Diwak4r

@Diwak4r Diwak4r commented Jul 26, 2026

Copy link
Copy Markdown

Description

The reasoning plan readiness detection was matching only the exact phrase "READY: I am ready to execute the task." in three places within reasoning_handler.py. However, the refine plan prompt instructs the model to "Conclude with READY or NOT READY" — a much shorter format. Models responding with standalone READY were falsely detected as NOT READY, causing the system to loop through unnecessary refinement attempts.

This affected:

  • The JSON parsing fallback path (when function calling result parsing fails)
  • The fallback text-only LLM call path
  • The pure text parsing path for LLMs that don't support function calling

Fix

Replace all three rigid substring checks with a case-insensitive regex that detects standalone READY while excluding NOT READY via a negative lookbehind:

re.search(r"(?<!\bnot\s)\bready\b", response, re.IGNORECASE)

This correctly handles:

  • READY — standalone ✅
  • READY: I am ready to execute the task. — long form ✅
  • Ready / ready — case variants ✅
  • NOT READY — correctly rejected ❌
  • I'm ready! — in-context usage ✅
  • NOTREADY (no space) — correctly rejected ❌

Related Issue

Closes #6204

Copilot AI review requested due to automatic review settings July 26, 2026 07:56
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: 5d08df14-280e-4c61-8f49-55b23ae54bc3

📥 Commits

Reviewing files that changed from the base of the PR and between 1b855b4 and 1b06e11.

📒 Files selected for processing (1)
  • lib/crewai/src/crewai/utilities/reasoning_handler.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • lib/crewai/src/crewai/utilities/reasoning_handler.py

Included review availability: Your plan provides up to 10 included reviews per hour; 8 remain after this review.


📝 Walkthrough

Walkthrough

Planning readiness detection now uses a shared, case-insensitive regex helper that recognizes standalone READY while excluding NOT READY. All planning response paths use this helper.

Changes

Plan readiness detection

Layer / File(s) Summary
Shared readiness matcher
lib/crewai/src/crewai/utilities/reasoning_handler.py
Adds regex support and introduces _is_plan_ready for standalone READY detection that excludes NOT READY.
Planning response integration
lib/crewai/src/crewai/utilities/reasoning_handler.py
Updates function-calling, fallback text, and planning response parsing paths to use _is_plan_ready.

Merge Risk: ⚪ Minimal · up to 1b06e

Planning readiness detection now accepts standalone READY responses case-insensitively while excluding NOT READY, avoiding unnecessary refinement attempts. No current merge-blocking risk remains.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the primary change: using regex for plan readiness detection.
Description check ✅ Passed The description explains the defect, affected code paths, fix, expected behavior, and linked issue. It omits the template's Verification and Additional context sections, but the required technical inf…
Linked Issues check ✅ Passed The change addresses issue #6204 by detecting standalone READY responses case-insensitively while excluding NOT READY across all three readiness-check paths.
Out of Scope Changes check ✅ Passed The changes are limited to the readiness detection logic in reasoning_handler.py and align with issue #6204.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 1 files.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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`:
- Line 413: Update AgentReasoning._is_plan_ready and its fallback callers to
recognize readiness declarations without treating JSON field names as readiness:
preserve structured parsed ready booleans, exclude matches for the "ready" JSON
key, and require one-or-more whitespace after "not" so both NOT READY and NOT 
READY are negative. Add regression coverage for READY, I'm ready!, NOT READY,
NOT  READY, and {"ready": false}.
🪄 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: df5f32be-656a-4247-9186-3174f8a95ecf

📥 Commits

Reviewing files that changed from the base of the PR and between 728183e and a20a2b8.

📒 Files selected for processing (1)
  • lib/crewai/src/crewai/utilities/reasoning_handler.py

response_str,
[],
"READY: I am ready to execute the task." in response_str,
AgentReasoning._is_plan_ready(response_str),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="lib/crewai/src/crewai/utilities/reasoning_handler.py"

echo "== file exists and line count =="
wc -l "$file"

echo "== outline around relevant symbols =="
ast-grep outline "$file" --match 'AgentReasoning' --view expanded || true

echo "== relevant line slices =="
for range in "90-140" "380-445" "550-625"; do
  echo "--- ${file}:${range} ---"
  sed -n "${range}p" "$file" | nl -ba -v "${range#*-}"
done

echo "== searches for _is_plan_ready and ready regex =="
rg -n "_is_plan_ready|ready|NOT\s+READY|NOT\ \+READY|ready\b" "$file"

Repository: crewAIInc/crewAI

Length of output: 1632


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="lib/crewai/src/crewai/utilities/reasoning_handler.py"

python3 - <<'PY'
from pathlib import Path
file = Path("lib/crewai/src/crewai/utilities/reasoning_handler.py")
text = file.read_text()
for start, end in [(90,140), (240,320), (380,450), (550,630)]:
    print(f"--- {file}:{start}-{end} ---")
    for i, line in enumerate(text.splitlines(), 1):
        if start <= i <= end:
            print(f"{i:4d}\t{line}")
print("--- searches ---")
for pat in ["_is_plan_ready", "ready", "NOT", "\\bnot", "parse_planning_response"]:
    print(f"-- {pat} --")
    for i, line in enumerate(text.splitlines(), 1):
        if pat.lower() in line.lower() or pat in line:
            print(f"{i:4d}\t{line}")
PY

echo "== behavioral probe from source regex =="
python3 - <<'PY'
import ast
from pathlib import Path

file = Path("lib/crewai/src/crewai/utilities/reasoning_handler.py")
source = file.read_text()
tree = ast.parse(source, filename=str(file))

compiled_re = None
for node in ast.walk(tree):
    if isinstance(node, ast.AnnAssign):
        annot = node.target.id if isinstance(node.target, ast.Name) else None
        if annot == "plan_ready_regex":
            compiled_re = ast.literal_eval(node.value)
            break

print("compiled_regex_string:", repr(compiled_re))

import re
if compiled_re is not None:
    pattern = re.compile(compiled_re, re.IGNORECASE)
    cases = [
        "READY",
        "I'm ready!",
        "NOT READY",
        "NOT  READY",
        '{"ready": false}',
        '{"ready": true}',
        "not ready",
    ]
    for case in cases:
        m = pattern.search(case)
        print(repr(case), "=>", m.group() if m else None)
PY

Repository: crewAIInc/crewAI

Length of output: 16209


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import re

pattern = re.compile(r"(?<!\bnot\s)\bready\b", re.IGNORECASE)
cases = [
    "READY",
    "I'm ready!",
    "NOT READY",
    "NOT  READY",
    '{"ready": false}',
    '{"ready": true}',
    "not ready",
    "not  ready",
    "ready",
]
for case in cases:
    m = pattern.search(case)
    print(f"{case!r} => {m.group()!r if m else None}")
PY

Repository: crewAIInc/crewAI

Length of output: 327


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import re

pattern = re.compile(r"(?<!\bnot\s)\bready\b", re.IGNORECASE)
cases = [
    "READY",
    "I'm ready!",
    "NOT READY",
    "NOT  READY",
    '{"ready": false}',
    '{"ready": true}',
    "not ready",
    "not  ready",
    "ready",
]
for case in cases:
    m = pattern.search(case)
    print(repr(case), "=>", m.group() if m else None)
PY

Repository: crewAIInc/crewAI

Length of output: 349


Avoid treating every ready token as a readiness declaration.

The fallback paths pass the response text directly into _is_plan_ready, where "{"ready": false}" matches the JSON field name and NOT READY/not ready matches because the lookbehind only handles one whitespace. This can skip refinement for non-ready plans. Preserve parsed structured ready booleans, exclude JSON field names, match one-or-more whitespace after not, and add regression tests for READY, I'm ready!, NOT READY, NOT READY, and {"ready": false}.

🤖 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` at line 413, Update
AgentReasoning._is_plan_ready and its fallback callers to recognize readiness
declarations without treating JSON field names as readiness: preserve structured
parsed ready booleans, exclude matches for the "ready" JSON key, and require
one-or-more whitespace after "not" so both NOT READY and NOT  READY are
negative. Add regression coverage for READY, I'm ready!, NOT READY, NOT  READY,
and {"ready": false}.

Copilot AI review requested due to automatic review settings August 3, 2026 03:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Diwak4r
Diwak4r force-pushed the fix/reasoning-ready-detection-regex branch from a1a3b61 to d126614 Compare August 22, 2026 19:01
@coderabbitai

coderabbitai Bot commented Aug 22, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

…ct string match

The readiness check was matching only the exact phrase
'READY: I am ready to execute the task.' but the refine
plan prompt instructs the model to conclude with just
'READY' or 'NOT READY'. Models responding with standalone
'READY' were falsely detected as NOT READY.

Replace the three rigid substring checks with a case-
insensitive regex that matches standalone READY while
excluding NOT READY via negative lookbehind.

Closes crewAIInc#6204
@Diwak4r
Diwak4r force-pushed the fix/reasoning-ready-detection-regex branch from d126614 to 1b06e11 Compare September 7, 2026 17:01
@coderabbitai

coderabbitai Bot commented Sep 7, 2026

Copy link
Copy Markdown

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Reasoning plan always detects "NOT READY" even though the model indicates "READY"

2 participants