Skip to content

feat: deprecate CrewAgentExecutor, default Crew agents to AgentExecutor#5745

Merged
lorenzejay merged 11 commits into
mainfrom
deprecate-crew-agent-executor
May 12, 2026
Merged

feat: deprecate CrewAgentExecutor, default Crew agents to AgentExecutor#5745
lorenzejay merged 11 commits into
mainfrom
deprecate-crew-agent-executor

Conversation

@iris-clawd
Copy link
Copy Markdown
Contributor

@iris-clawd iris-clawd commented May 7, 2026

Summary

Agents used inside Crew() now default to the experimental AgentExecutor (Flow-based) instead of CrewAgentExecutor. This is the first step toward fully removing CrewAgentExecutor in a future release.

Changes

agent/core.py

  • executor_class field default changed from CrewAgentExecutorAgentExecutor
  • _validate_executor_class validator now emits a DeprecationWarning when CrewAgentExecutor is passed explicitly

agents/crew_agent_executor.py

  • model_post_init (or __init__) emits a DeprecationWarning on instantiation, directing users to crewai.experimental.AgentExecutor

agents/__init__.py

  • Added lazy __getattr__ export for CrewAgentExecutor so existing from crewai.agents import CrewAgentExecutor imports continue to work without breaking circular-import chains

Backward compatibility

  • Passing executor_class=CrewAgentExecutor explicitly still works — it just emits a DeprecationWarning
  • from crewai.agents import CrewAgentExecutor still resolves correctly
  • No public API removed in this PR

Smoke test

from crewai import Agent
from crewai.experimental import AgentExecutor

a = Agent(role="test", goal="test", backstory="test")
assert a.executor_class is AgentExecutor  # ✅

Next steps (follow-on PRs)

  • Remove CrewAgentExecutor from _EXECUTOR_CLASS_MAP and the string-alias map
  • Hard-remove CrewAgentExecutor after one minor version deprecation window
  • Update docs + migration guide

Requested by: Lorenze Jay lorenze@crewai.com

Summary by CodeRabbit

  • Refactor

    • Changed the default agent executor to a newer implementation for more robust synchronous behavior.
  • Deprecation

    • The legacy CrewAgentExecutor emits a deprecation warning; migrate to the new default executor.
  • Bug Fixes

    • Prevents redundant final-answer rounds to avoid duplicate assistant outputs.
  • Tests

    • Updated and re-recorded interaction cassettes; test adjustments include skips/xfails and patched executor targets to align with executor changes.

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Slack user <@U0773HGAUSJ> — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Slack user <@U0773HGAUSJ> — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

2 similar comments
@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Slack user <@U0773HGAUSJ> — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Slack user <@U0773HGAUSJ> — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

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: 0102cdaf-2b09-4346-b71c-d4df11b8d117

📥 Commits

Reviewing files that changed from the base of the PR and between c74b822 and 89bb838.

📒 Files selected for processing (5)
  • lib/crewai/src/crewai/agent/core.py
  • lib/crewai/src/crewai/experimental/agent_executor.py
  • lib/crewai/tests/agents/test_agent.py
  • lib/crewai/tests/cassettes/agents/test_agent_custom_max_iterations.yaml
  • lib/crewai/tests/test_crew.py

📝 Walkthrough

Walkthrough

This PR deprecates CrewAgentExecutor and makes AgentExecutor the default. It removes executor-gated reasoning, adds a sync-path guard for awaitable invoke results, lazy-exports CrewAgentExecutor, updates tests to target the new executor, and re-records VCR cassettes to reflect changed LLM responses.

Changes

Executor Deprecation & Migration

Layer / File(s) Summary
Executor Class Defaults & Sync Exec
lib/crewai/src/crewai/agent/core.py
Agent.executor_class now defaults to AgentExecutor; validation emits DeprecationWarning when CrewAgentExecutor is chosen. _prepare_task_execution no longer conditions reasoning on executor class; synchronous _execute_without_timeout detects awaitable invoke results and errors if run inside an event loop.
CrewAgentExecutor Deprecation
lib/crewai/src/crewai/agents/crew_agent_executor.py
CrewAgentExecutor.__init__ emits a DeprecationWarning recommending crewai.experimental.AgentExecutor.
Backward-Compatible Export
lib/crewai/src/crewai/agents/__init__.py
CrewAgentExecutor removed from static __all__ and provided via module-level __getattr__(); TYPE_CHECKING import retained for typing.
AgentExecutor Guard
lib/crewai/src/crewai/experimental/agent_executor.py
ensure_force_final_answer returns early if self.state.is_finished, preventing duplicate forced-final-answer rounds.

Test Updates

Layer / File(s) Summary
Executor Mock Updates
lib/crewai/tests/agents/test_agent.py, lib/crewai/tests/utilities/test_events.py
Tests updated to patch AgentExecutor.invoke or _format_prompt from crewai.experimental.agent_executor instead of CrewAgentExecutor.
Test Assertions Removed
lib/crewai/tests/agents/test_agent_reasoning.py
Removed assertions that relied on planning text being appended to task.description.
Tests Marked / Adjusted
various test files
Some tests now suppress DeprecationWarning, set explicit executor_class: CrewAgentExecutor in test fixtures, or are marked xfail/skip due to missing training-feedback formatting or async/await behavior differences.

VCR Cassette Updates

Layer / File(s) Summary
Anthropic Multimodal Cassettes
lib/crewai/tests/cassettes/TestCrewMultimodalAnthropic.*.yaml
Request prompts reworded; prior tool-use flows replaced with direct assistant responses; request/response headers and metadata refreshed.
OpenAI Agent Iterations Cassette
lib/crewai/tests/cassettes/agents/test_agent_custom_max_iterations.yaml
Tool schema tightened (strict: true, additionalProperties: false); message sequences reordered to inline assistant/tool exchanges; request/response metadata refreshed.

🎯 3 (Moderate) | ⏱️ ~20 minutes

🐰 The crew default now hops to AgentExecutor bright,
CrewAgentExecutor fades to deprecated light,
Tests rebound with mocks for the new executor way,
Cassettes replay interactions, all up to date today! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 44.44% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the primary change: deprecating CrewAgentExecutor and making AgentExecutor the default for Crew agents.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch deprecate-crew-agent-executor

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
lib/crewai/src/crewai/agent/core.py (2)

1041-1068: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Honor executor_class when creating the executor.

Line 1045 hard-codes AgentExecutor, so executor_class=CrewAgentExecutor no longer has any effect even though the validator, alias map, and deprecation contract say that path still works. That silently changes behavior for existing callers and breaks the intended compatibility window.

Possible fix
-            self.agent_executor = AgentExecutor(
-                llm=self.llm,
-                task=task,
-                agent=self,
-                crew=self.crew,
-                tools=parsed_tools,
-                prompt=prompt,
-                original_tools=raw_tools,
-                stop_words=stop_words,
-                max_iter=self.max_iter,
-                tools_handler=self.tools_handler,
-                tools_names=get_tool_names(parsed_tools),
-                tools_description=render_text_description_and_args(parsed_tools),
-                step_callback=self.step_callback,
-                function_calling_llm=self.function_calling_llm,
-                respect_context_window=self.respect_context_window,
-                request_within_rpm_limit=rpm_limit_fn,
-                callbacks=[TokenCalcHandler(self._token_process)],
-                response_model=(
-                    task.response_model or task.output_pydantic or task.output_json
-                )
-                if task
-                else None,
-            )
+            executor_cls = self.executor_class
+            executor_kwargs = {
+                "llm": self.llm,
+                "task": task,
+                "agent": self,
+                "crew": self.crew,
+                "tools": parsed_tools,
+                "prompt": prompt,
+                "original_tools": raw_tools,
+                "max_iter": self.max_iter,
+                "tools_handler": self.tools_handler,
+                "tools_names": get_tool_names(parsed_tools),
+                "tools_description": render_text_description_and_args(parsed_tools),
+                "step_callback": self.step_callback,
+                "function_calling_llm": self.function_calling_llm,
+                "respect_context_window": self.respect_context_window,
+                "request_within_rpm_limit": rpm_limit_fn,
+                "callbacks": [TokenCalcHandler(self._token_process)],
+                "response_model": (
+                    task.response_model or task.output_pydantic or task.output_json
+                )
+                if task
+                else None,
+            }
+            if executor_cls is AgentExecutor:
+                executor_kwargs["stop_words"] = stop_words
+            else:
+                executor_kwargs["stop"] = stop_words
+
+            self.agent_executor = executor_cls(**executor_kwargs)
🤖 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/agent/core.py` around lines 1041 - 1068, The code
currently hard-codes AgentExecutor when setting self.agent_executor; change it
to use the configured executor_class (e.g., self.executor_class or
executor_class) so executor_class=CrewAgentExecutor is honored: locate the
assignment to self.agent_executor in create agent executor code (the block that
builds AgentExecutor with llm=self.llm, task=task, agent=self, crew=self.crew,
tools=parsed_tools, prompt=prompt, ...), instantiate executor_class(...) with
the exact same keyword args (and the fallback to AgentExecutor if executor_class
is None) so all existing parameters (tools_handler, step_callback,
function_calling_llm, request_within_rpm_limit, callbacks, response_model, etc.)
are forwarded unchanged.

850-864: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Fix the sync task path for AgentExecutor under an active event loop.

With AgentExecutor now the default, this branch can receive a coroutine from invoke() inside async flows, but Line 853 still treats the return value as a dict. That makes crew.kickoff() from async flow methods regress at runtime; the skipped telemetry test is just hiding it.

Either keep this path fully async end-to-end (aexecute_task/kickoff_async) or explicitly handle/reject awaitables here instead of indexing into them as result["output"].

🤖 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/agent/core.py` around lines 850 - 864, The sync path
treats self.agent_executor.invoke(...) as a dict but invoke can return an
awaitable when running under an active event loop (AgentExecutor default);
update the sync branch to detect awaitables (use inspect.isawaitable on the
value returned by agent_executor.invoke) and if it is awaitable, raise a clear
RuntimeError instructing callers to use the async variants (e.g.
AgentExecutor.aexecute_task or kickoff_async) instead of indexing into the
coroutine; otherwise, cast to dict and return result["output"] as before.
🤖 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/tests/agents/test_agent.py`:
- Around line 704-708: Tests were skipped because human-input support wasn't
migrated to the new default AgentExecutor, causing Task(human_input=True) to
break; either preserve routing of human-input tasks to CrewAgentExecutor or
finish wiring the human_input provider to the new state proxy. To fix: update
the human_input provider and any callsites (search for ask_for_human_input,
_invoke_loop, and Task(human_input=True)) to read/write the flag from the new
state proxy used by AgentExecutor (e.g., state.ask_for_human_input) and ensure
AgentExecutor._invoke_loop honours that state, or revert human-input task
handling so CrewAgentExecutor remains the codepath for human_input tasks until
the provider migration is complete. Ensure tests reference the same executor
that supports human input.
- Around line 393-396: The test reveals AgentExecutor (flow-based) is making an
extra LLM provider call on the forced-final-answer path; update the executor so
that when max_iter triggers a forced final answer it emits exactly one provider
request. In practice modify the AgentExecutor loop/dispatch logic (the code that
handles the loop termination / force-final-answer routing) to either (a)
short-circuit the routing step and directly call the final-answer generator
once, or (b) detect that the routing call would send the same
forced-final-answer prompt as the final-answer call and skip/merge the duplicate
provider invocation; locate the flow-based path inside AgentExecutor and its
loop/route-to-final-answer handling and ensure only one provider call is made
when force-final-answer is set.

In
`@lib/crewai/tests/cassettes/TestCrewMultimodalAnthropic.test_pdf_file`[anthropic-claude-sonnet-4-20250514].yaml:
- Around line 4-8: The test cassette
TestCrewMultimodalAnthropic.test_pdf_file[anthropic-claude-sonnet-4-20250514].yaml
is recording a full-PDF dump instead of the required one-sentence description;
update the prompt template used by the flow that produces "Describe the file(s)
you see..." to explicitly constrain responses to a single sentence and to
include an instruction like "return only the complete content: one sentence" and
a hard stop token, and then strengthen the test assertions (or add a validation
step in the test harness) to fail if response contains multiple paragraphs,
exceeds a short token/character limit, or records stop_reason: "max_tokens" so
the cassette cannot accept full-document outputs; apply the same prompt
fix/validation to the related cases (e.g., entries referenced by lines 52-326)
to prevent regressions.

In `@lib/crewai/tests/test_crew.py`:
- Around line 2993-2996: The test currently uses pytest.mark.skip which hides
regressions in Crew.train(); change the decorator so CI fails when behavior
regresses by replacing the skip with pytest.mark.xfail(strict=True) or modify
the test setup to force the compatibility executor path (instantiate or inject
CrewAgentExecutor or set the executor creation to return CrewAgentExecutor) so
Crew.train() still exercises CrewAgentExecutor._format_feedback_message rather
than the new AgentExecutor; update the test decorator or setup accordingly to
ensure the test runs as an expected-failure (strict) or uses CrewAgentExecutor
explicitly.

---

Outside diff comments:
In `@lib/crewai/src/crewai/agent/core.py`:
- Around line 1041-1068: The code currently hard-codes AgentExecutor when
setting self.agent_executor; change it to use the configured executor_class
(e.g., self.executor_class or executor_class) so
executor_class=CrewAgentExecutor is honored: locate the assignment to
self.agent_executor in create agent executor code (the block that builds
AgentExecutor with llm=self.llm, task=task, agent=self, crew=self.crew,
tools=parsed_tools, prompt=prompt, ...), instantiate executor_class(...) with
the exact same keyword args (and the fallback to AgentExecutor if executor_class
is None) so all existing parameters (tools_handler, step_callback,
function_calling_llm, request_within_rpm_limit, callbacks, response_model, etc.)
are forwarded unchanged.
- Around line 850-864: The sync path treats self.agent_executor.invoke(...) as a
dict but invoke can return an awaitable when running under an active event loop
(AgentExecutor default); update the sync branch to detect awaitables (use
inspect.isawaitable on the value returned by agent_executor.invoke) and if it is
awaitable, raise a clear RuntimeError instructing callers to use the async
variants (e.g. AgentExecutor.aexecute_task or kickoff_async) instead of indexing
into the coroutine; otherwise, cast to dict and return result["output"] as
before.
🪄 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: 77ba7f73-9bb2-4c60-8281-2fce6496a7be

📥 Commits

Reviewing files that changed from the base of the PR and between e4a91cd and c74b822.

📒 Files selected for processing (13)
  • lib/crewai/src/crewai/agent/core.py
  • lib/crewai/src/crewai/agents/__init__.py
  • lib/crewai/src/crewai/agents/crew_agent_executor.py
  • lib/crewai/tests/agents/test_agent.py
  • lib/crewai/tests/agents/test_agent_reasoning.py
  • lib/crewai/tests/cassettes/TestCrewMultimodalAnthropic.test_image_file[anthropic-claude-sonnet-4-20250514].yaml
  • lib/crewai/tests/cassettes/TestCrewMultimodalAnthropic.test_mixed_files[anthropic-claude-sonnet-4-20250514].yaml
  • lib/crewai/tests/cassettes/TestCrewMultimodalAnthropic.test_pdf_file[anthropic-claude-sonnet-4-20250514].yaml
  • lib/crewai/tests/cassettes/agents/test_agent_custom_max_iterations.yaml
  • lib/crewai/tests/cassettes/utilities/test_tools_emits_error_events.yaml
  • lib/crewai/tests/telemetry/test_flow_crew_span_integration.py
  • lib/crewai/tests/test_crew.py
  • lib/crewai/tests/utilities/test_events.py
💤 Files with no reviewable changes (1)
  • lib/crewai/tests/agents/test_agent_reasoning.py

Comment thread lib/crewai/tests/agents/test_agent.py Outdated
Comment thread lib/crewai/tests/agents/test_agent.py Outdated
Comment thread lib/crewai/tests/test_crew.py Outdated
@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Slack user <@U0773HGAUSJ> — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

4 similar comments
@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Slack user <@U0773HGAUSJ> — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Slack user <@U0773HGAUSJ> — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Slack user <@U0773HGAUSJ> — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Slack user <@U0773HGAUSJ> — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

5 similar comments
@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@github-actions github-actions Bot added size/M and removed size/S labels May 11, 2026
@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

2 similar comments
@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@iris-clawd
Copy link
Copy Markdown
Contributor Author

requested by Lorenze Jay — friendly nudge from Iris: this PR is still open. Want to take a look or close it out?

@lorenzejay lorenzejay merged commit 3322634 into main May 12, 2026
53 checks passed
@lorenzejay lorenzejay deleted the deprecate-crew-agent-executor branch May 12, 2026 18:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants