Skip to content

feat: adaptive replanning when task results deviate from plan#5392

Closed
Ricardo-M-L wants to merge 2 commits intocrewAIInc:mainfrom
Ricardo-M-L:feat/adaptive-replanning
Closed

feat: adaptive replanning when task results deviate from plan#5392
Ricardo-M-L wants to merge 2 commits intocrewAIInc:mainfrom
Ricardo-M-L:feat/adaptive-replanning

Conversation

@Ricardo-M-L
Copy link
Copy Markdown

@Ricardo-M-L Ricardo-M-L commented Apr 10, 2026

Summary

  • Adds adaptive re-planning capability when planning=True crews encounter task results that deviate from the original plan's assumptions
  • Introduces ReplanningEvaluator that runs a lightweight LLM check after each task to detect deviations (missing data, unexpected results, infeasible approaches)
  • When deviation is detected, CrewPlanner.replan() generates revised plans for remaining tasks only, using actual results as context
  • Fully backwards compatible: replan_on_failure defaults to False, existing crews are completely unaffected

New API

crew = Crew(
    agents=[...],
    tasks=[...],
    planning=True,
    replan_on_failure=True,     # enables adaptive replanning
    max_replans=3,              # prevents infinite loops (default: 3)
    evaluation_criteria=EvaluationCriteria(
        quality_threshold=7.0,  # configurable quality bar
        check_completeness=True,
        check_relevance=True,
        custom_criteria="Must include data sources",
    ),
    replanning_evaluator=custom_evaluator,  # pluggable evaluator
)

Files Changed

File Change
lib/crewai/src/crewai/utilities/replanning_evaluator.py New - ReplanningEvaluator, ReplanDecision, EvaluationCriteria
lib/crewai/src/crewai/utilities/planning_handler.py Added replan() method to CrewPlanner
lib/crewai/src/crewai/crew.py Added fields + _evaluate_and_replan() hook in _execute_tasks()
lib/crewai/tests/utilities/test_replanning_evaluator.py New - 34 test cases

How It Works

  1. After each synchronous task completes, _should_evaluate_for_replan() checks if replanning is enabled and budget remains
  2. ReplanningEvaluator.evaluate() makes a structured LLM call: "Does this result deviate significantly from what the plan assumed?"
  3. If ReplanDecision.should_replan=True, CrewPlanner.replan() generates revised plans for remaining tasks using completed results as context
  4. Revised plans are injected into remaining task descriptions as [REVISED PLAN] sections (old revisions are replaced, not stacked)
  5. _replan_count prevents runaway loops (capped at max_replans)

Test Plan

  • 34 test cases covering all components (all passing)
  • ReplanDecision model validation (bounds, defaults, all fields)
  • EvaluationCriteria model validation (bounds, custom criteria)
  • ReplanningEvaluator (init, no-remaining-tasks, replan/no-replan decisions, parse failure fallback, criteria text building)
  • CrewPlanner.replan() (returns revised plans, raises on failure, remaining tasks summary)
  • Crew integration (field defaults, custom config, should_evaluate guards, replan triggers, error handling, replan count, revision stacking, backwards compatibility)
  • Existing test_planning_handler.py tests still pass (12/12)

Fixes #4983

🤖 Generated with Claude Code


Note

Medium Risk
Adds new LLM-driven evaluation and dynamic replanning into the core sequential execution loop, which can change task descriptions mid-run and affect determinism/cost. Guardrails exist (replan_on_failure default off, max_replans cap), but the behavior is complex and touches planning/execution paths.

Overview
Introduces adaptive replanning for planning=True crews via new Crew options (replan_on_failure, max_replans, evaluation_criteria, and pluggable replanning_evaluator). After each synchronous task, an LLM-based ReplanningEvaluator can decide whether outputs deviate from the original plan and, if so, CrewPlanner.replan() regenerates plans for remaining tasks and injects them into task descriptions as [REVISED PLAN].

Adds CrewPlanner.replan() to produce revised plans using completed TaskOutputs as context, plus a new utilities/replanning_evaluator.py module with structured decision/criteria models and robust fallback behavior. Includes a comprehensive new test suite covering evaluator behavior, replanning generation, and Crew integration/backwards-compatibility.

Reviewed by Cursor Bugbot for commit 782f96a. Bugbot is set up for automated code reviews on this repo. Configure here.

When `planning=True`, the plan is currently static and never updated during
execution, causing compounding errors when early tasks return unexpected
results. This adds an optional `replan_on_failure` flag that enables
adaptive re-planning: after each task, a lightweight ReplanningEvaluator
checks whether the result deviates from the plan's assumptions, and if so,
triggers CrewPlanner.replan() to generate revised plans for remaining tasks.

New API (fully backwards compatible):
- `replan_on_failure=True` on Crew enables the feature
- `max_replans=N` prevents infinite replanning loops
- `replanning_evaluator` allows plugging in a custom evaluator
- `evaluation_criteria` configures quality threshold, completeness, relevance

Fixes crewAIInc#4983

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread lib/crewai/src/crewai/crew.py
Comment thread lib/crewai/src/crewai/crew.py
- Move _replan_count increment after successful replanning so failed
  attempts don't consume the replan budget
- Remove unused ReplanDecision import

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 782f96a. Configure here.

self._logger.log(
"warning",
f"Replanning failed: {e}. Continuing with original plan.",
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Replan count not incremented on replanning failure

High Severity

_replan_count += 1 is only reached on the success path inside the try block (after planner.replan() returns). When planner.replan() raises an exception, the increment is skipped and the except block doesn't increment it either. This means persistent replanning failures never consume the max_replans budget, so _should_evaluate_for_replan() keeps returning True and the system retries on every subsequent task — defeating the runaway-loop protection. The corresponding test also asserts _replan_count == 1 after a failure, which will fail against this code.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 782f96a. Configure here.

@Ricardo-M-L
Copy link
Copy Markdown
Author

Closing — branch has diverged significantly from upstream, and large features should be discussed first. Will resubmit properly if needed.

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.

[FEATURE] Adaptive Re-planning When Task Results Deviate from Plan

1 participant