Skip to content

fix(reasoning): detect a bare READY marker in text plans#6488

Open
HumphreySun98 wants to merge 2 commits into
crewAIInc:mainfrom
HumphreySun98:fix/reasoning-ready-detection
Open

fix(reasoning): detect a bare READY marker in text plans#6488
HumphreySun98 wants to merge 2 commits into
crewAIInc:mainfrom
HumphreySun98:fix/reasoning-ready-detection

Conversation

@HumphreySun98

Copy link
Copy Markdown

Problem

With reasoning enabled, the executor asks the model to conclude its plan with READY or NOT READY and loops "refine plan" until ready. But there's a mismatch between what the prompts request and what the parser accepts:

  • refine_plan_prompt (and one of the create_plan_prompt variants) say: "Conclude with READY or NOT READY" → models emit a bare READY.
  • The text parser only accepted the exact sentence:
    ready = "READY: I am ready to execute the task." in response

So a bare READY is never detected as ready — the agent stays stuck refining until max attempts. This bites text-parsing models (the reporter used Ollama GLM), where the trace clearly shows READY but it's read as not-ready.

Fix

Add a _detect_plan_ready helper and use it at all three text-detection sites:

_READY_MARKER = re.compile(r"NOT\s+READY|READY", re.IGNORECASE)

def _detect_plan_ready(text: str) -> bool:
    markers = _READY_MARKER.findall(text)
    if not markers:
        return False
    return "NOT" not in markers[-1].upper()
  • Matches the last marker, so a "not ready" mentioned mid-plan doesn't override a final READY.
  • NOT READY wins over the bare READY it contains.
  • The old full sentence ("READY: I am ready to execute the task.") still counts as ready — backward compatible.

Only the text-parsing path is affected; the structured/function-calling path already uses a boolean ready field.

Behavior (old → new)

response ends with old new
READY ❌ not ready ✅ ready
NOT READY: … not ready not ready
READY: I am ready to execute the task. ready ready

Tests

Added TestDetectPlanReady (bare/full/none/mid-text/case-insensitive + _parse_planning_response integration). Full test_structured_planning.py (33) green; ruff + mypy clean. Branched off latest main (v1.15.2).

Fixes #6204


This PR was authored with Claude Code. Per CONTRIBUTING.md, AI-generated contributions require the llm-generated label — I don't have triage permission to set it, so could a maintainer please add it? 🤖 Generated with Claude Code

The refine prompt (and one of the create prompts) tells the model to
"Conclude with READY or NOT READY", so models — especially on the
text-parsing path — emit a bare `READY`. But the parser only accepted the
exact sentence "READY: I am ready to execute the task.", so `READY` was never
detected as ready and the agent stayed stuck refining until max attempts.

Add a _detect_plan_ready helper that matches the last READY / NOT READY marker
(NOT READY wins over the bare READY it contains; the full sentence still
counts as ready) and use it at all three text-detection sites.

Fixes crewAIInc#6204

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 8, 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: Pro Plus

Run ID: 368eeadd-7a42-41e5-a5b2-f9f82a08e280

📥 Commits

Reviewing files that changed from the base of the PR and between 4b99651 and 24d34f6.

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

📝 Walkthrough

Walkthrough

Plan readiness detection now uses a regex-based parser that identifies the last READY or NOT READY marker in model output. The helper is used across function-calling, fallback, and planning-response parsing paths, with expanded tests for marker formats and precedence.

Changes

Plan readiness detection fix

Layer / File(s) Summary
Readiness marker regex and detection helper
lib/crewai/src/crewai/utilities/reasoning_handler.py
Adds regex support and _detect_plan_ready(text) to determine readiness from the last valid marker while ignoring word substrings.
Wire detection into planning response paths
lib/crewai/src/crewai/utilities/reasoning_handler.py
Replaces exact-substring checks in function-calling, fallback, and _parse_planning_response paths with _detect_plan_ready.
Unit tests for readiness detection
lib/crewai/tests/utilities/test_structured_planning.py
Tests bare and full-sentence markers, NOT READY, marker precedence, case handling, missing markers, word boundaries, and bare READY integration.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: detecting a bare READY marker in reasoning plans.
Description check ✅ Passed The description is directly about the readiness parsing fix and matches the changeset.
Linked Issues check ✅ Passed The PR addresses #6204 by recognizing READY in text plans so ready responses are detected correctly.
Out of Scope Changes check ✅ Passed The added tests and word-boundary handling are aligned with the readiness-detection fix and not unrelated scope.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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

🧹 Nitpick comments (1)
lib/crewai/tests/utilities/test_structured_planning.py (1)

28-52: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a false-positive guard test.

The suite covers positive/negative/precedence/case scenarios well. Consider adding a test to verify that common English words containing "ready" (e.g., "already", "readiness") do not trigger a false READY — this directly guards the regex word-boundary concern in the source.

✨ Suggested test
+    def test_word_containing_ready_is_not_a_marker(self):
+        assert _detect_plan_ready("I am already prepared to proceed.") is False
+        assert _detect_plan_ready("The readiness check is complete.") is 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/tests/utilities/test_structured_planning.py` around lines 28 - 52,
Add a false-positive guard test in test_structured_planning for
_detect_plan_ready so that ordinary words containing “ready” like “already” or
“readiness” do not match as READY. Update the test suite near the existing
_detect_plan_ready and AgentReasoning._parse_planning_response cases to assert
these inputs return False, protecting the word-boundary behavior.
🤖 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 31-33: The _READY_MARKER regex in reasoning_handler is too broad
because READY matches inside other words like already or readiness. Update the
pattern used by _READY_MARKER to require word boundaries around the READY token
(while keeping the NOT\s+READY alternative) so _detect_plan_ready only returns
true for an actual standalone readiness signal and not embedded substrings.

---

Nitpick comments:
In `@lib/crewai/tests/utilities/test_structured_planning.py`:
- Around line 28-52: Add a false-positive guard test in test_structured_planning
for _detect_plan_ready so that ordinary words containing “ready” like “already”
or “readiness” do not match as READY. Update the test suite near the existing
_detect_plan_ready and AgentReasoning._parse_planning_response cases to assert
these inputs return False, protecting the word-boundary behavior.
🪄 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: 50296fc4-8581-4111-9b4d-106cd2b7863f

📥 Commits

Reviewing files that changed from the base of the PR and between 289686a and 4b99651.

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

Comment thread lib/crewai/src/crewai/utilities/reasoning_handler.py

@ErenAta16 ErenAta16 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.

Checked the regex logic directly: _detect_plan_ready correctly picks up a bare READY where the old exact-substring check ("READY: I am ready to execute the task." in response_str) would not — confirmed this difference standalone (old check returns False on a bare READY, new one returns True). The last-marker-wins design is the right call too: an earlier "not ready yet" mentioned mid-plan (common phrasing while a model reasons through steps) shouldn't override the concluding verdict, and the NOT prefix check correctly makes "NOT READY" win over the bare "READY" substring it contains rather than the regex accidentally matching on "READY" first. Applied consistently across all three text-detection sites per the diff, which matters since a partial fix (only one of the three sites) would have left the bug intermittently reproducible depending on which code path a given model hit.

Without word boundaries the pattern matched "ready" inside words like
"already", so plain prose ("I am already prepared") registered as READY, and a
trailing "already" could even flip a concluding NOT READY to ready. Anchor both
markers with \b and add regression tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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