Skip to content

fix: add missing ExecutorContext methods to AgentExecutor for human_input support. #6348

Open
VIVEK-311810 wants to merge 1 commit into
crewAIInc:mainfrom
VIVEK-311810:main
Open

fix: add missing ExecutorContext methods to AgentExecutor for human_input support. #6348
VIVEK-311810 wants to merge 1 commit into
crewAIInc:mainfrom
VIVEK-311810:main

Conversation

@VIVEK-311810

@VIVEK-311810 VIVEK-311810 commented Jun 26, 2026

Copy link
Copy Markdown

Summary

Adds three methods to AgentExecutor that are required by the ExecutorContext protocol
but were never implemented when AgentExecutor was promoted to the default executor in 1.15.0.
This caused Task(human_input=True) to crash with an AttributeError for all users who did
not explicitly set executor_class.

Problem

In 1.15.0 Agent.executor_class was silently changed from CrewAgentExecutor to AgentExecutor
as the default (agent/core.py line 342). However AgentExecutor does not fully implement the
ExecutorContext protocol that SyncHumanInputProvider.handle_feedback() calls back on the
executor after receiving user input.

Three methods required by the protocol were missing:

Method Protocol Present in CrewAgentExecutor Present in AgentExecutor before this fix
_format_feedback_message ExecutorContext line 46
_invoke_loop ExecutorContext line 30
_ainvoke_loop AsyncExecutorContext line 54

The intent to support human_input=True was clearly there — ask_for_human_input state,
property, _handle_human_feedback, and _ahandle_human_feedback were all implemented.
These three callback methods were simply missed during the transition.

Error before this fix

Processing your feedback...
An unknown error occurred. Please check the details below.
Error details: 'AgentExecutor' object has no attribute '_format_feedback_message'

Changes

  • src/crewai/experimental/agent_executor.py: added _invoke_loop, _ainvoke_loop,
    _format_feedback_message — all using existing imports (format_message_for_llm,
    I18N_DEFAULT) already present in the file

Testing

  • Task(human_input=True) with default AgentExecutor no longer crashes
  • Sync and async feedback loops both work
  • Behaviour matches CrewAgentExecutor in 1.14.3

Linked Issue

Closes #6347

Summary by CodeRabbit

  • New Features

    • Improved human-feedback handling so the app can rerun an execution step after feedback and continue until a final answer is produced.
    • Added better formatting of feedback messages for clearer interaction during review loops.
  • Bug Fixes

    • Added safeguards to ensure a completed result is returned before finishing, helping prevent incomplete outcomes after feedback-driven reruns.

…nput support

Add _invoke_loop, _ainvoke_loop, and _format_feedback_message to AgentExecutor
so that the ExecutorContext / AsyncExecutorContext protocol is fully implemented,
enabling human_input=True feedback cycles to work without AttributeError.


Claude-Session: https://claude.ai/code/session_01PNsL23nAUz3bUy99Usc2Lz

Co-authored-by: Claude <noreply@anthropic.com>

@corridor-security corridor-security 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.

Summary: This PR adds missing feedback-loop methods to AgentExecutor for synchronous and asynchronous human input handling. No exploitable security vulnerabilities were identified in the added code.

Risk: Low risk. The changes do not introduce new public endpoints, authentication or authorization logic, filesystem access, subprocess execution, SQL, or external network calls.

@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

AgentExecutor now formats human feedback messages and reruns the execution loop in synchronous and asynchronous paths. The rerun helpers clear completion state, invoke the executor again, and require the rerun to produce an AgentFinish.

Changes

Human-feedback executor loop

Layer / File(s) Summary
Feedback message formatting
lib/crewai/src/crewai/experimental/agent_executor.py
_format_feedback_message(feedback) builds an LLMMessage from I18N_DEFAULT.feedback_instructions using format_message_for_llm.
Sync and async reruns
lib/crewai/src/crewai/experimental/agent_executor.py
_invoke_loop() and _ainvoke_loop() reset _finalize_called and state.is_finished, rerun kickoff() or kickoff_async(), and require state.current_answer to be an AgentFinish.

Suggested reviewers

  • greysonlalonde
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main fix: adding missing AgentExecutor support for human_input feedback flow.
Linked Issues check ✅ Passed The change adds the missing feedback formatting and loop methods needed to restore the default AgentExecutor human_input flow.
Out of Scope Changes check ✅ Passed The only described changes are directly tied to the human_input regression fix and do not introduce unrelated scope.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ 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/experimental/agent_executor.py`:
- Around line 3191-3209: Reset the iteration counter before rerunning the
feedback loop, since _invoke_loop and _ainvoke_loop currently only clear
finalize/finished state and then call kickoff/kickoff_async, which leaves
self.state.iterations carrying over from the previous attempt. Update both
methods to mirror the per-run reset used by invoke() and invoke_async() by
resetting self.state.iterations before the rerun so check_max_iterations() and
force_final_answer don’t trigger immediately.
🪄 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: 068598bb-4e36-4306-a0e9-49ea1f31df43

📥 Commits

Reviewing files that changed from the base of the PR and between f364a7d and 97fd309.

📒 Files selected for processing (1)
  • lib/crewai/src/crewai/experimental/agent_executor.py

Comment on lines +3191 to +3209
def _invoke_loop(self) -> AgentFinish:
"""Re-run the agent flow loop for a feedback iteration (sync)."""
self._finalize_called = False
self.state.is_finished = False
self.kickoff()
result = self.state.current_answer
if not isinstance(result, AgentFinish):
raise RuntimeError("Agent execution ended without reaching a final answer.")
return result

async def _ainvoke_loop(self) -> AgentFinish:
"""Re-run the agent flow loop for a feedback iteration (async)."""
self._finalize_called = False
self.state.is_finished = False
await self.kickoff_async()
result = self.state.current_answer
if not isinstance(result, AgentFinish):
raise RuntimeError("Agent execution ended without reaching a final answer.")
return result

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

Reset the iteration counter before rerunning after feedback.

kickoff()/kickoff_async() only clear Flow bookkeeping. They do not reset self.state.iterations, so a feedback rerun inherits the previous attempt's turn count and can immediately hit check_max_iterations()/force_final_answer without consuming the newly appended feedback. Mirror the per-run reset that invoke() and invoke_async() already do here.

Suggested fix
 def _invoke_loop(self) -> AgentFinish:
     """Re-run the agent flow loop for a feedback iteration (sync)."""
     self._finalize_called = False
     self.state.is_finished = False
+    self.state.iterations = 0
+    self.state.current_answer = None
     self.kickoff()
     result = self.state.current_answer
     if not isinstance(result, AgentFinish):
         raise RuntimeError("Agent execution ended without reaching a final answer.")
     return result

 async def _ainvoke_loop(self) -> AgentFinish:
     """Re-run the agent flow loop for a feedback iteration (async)."""
     self._finalize_called = False
     self.state.is_finished = False
+    self.state.iterations = 0
+    self.state.current_answer = None
     await self.kickoff_async()
     result = self.state.current_answer
     if not isinstance(result, AgentFinish):
         raise RuntimeError("Agent execution ended without reaching a final answer.")
     return result
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _invoke_loop(self) -> AgentFinish:
"""Re-run the agent flow loop for a feedback iteration (sync)."""
self._finalize_called = False
self.state.is_finished = False
self.kickoff()
result = self.state.current_answer
if not isinstance(result, AgentFinish):
raise RuntimeError("Agent execution ended without reaching a final answer.")
return result
async def _ainvoke_loop(self) -> AgentFinish:
"""Re-run the agent flow loop for a feedback iteration (async)."""
self._finalize_called = False
self.state.is_finished = False
await self.kickoff_async()
result = self.state.current_answer
if not isinstance(result, AgentFinish):
raise RuntimeError("Agent execution ended without reaching a final answer.")
return result
def _invoke_loop(self) -> AgentFinish:
"""Re-run the agent flow loop for a feedback iteration (sync)."""
self._finalize_called = False
self.state.is_finished = False
self.state.iterations = 0
self.state.current_answer = None
self.kickoff()
result = self.state.current_answer
if not isinstance(result, AgentFinish):
raise RuntimeError("Agent execution ended without reaching a final answer.")
return result
async def _ainvoke_loop(self) -> AgentFinish:
"""Re-run the agent flow loop for a feedback iteration (async)."""
self._finalize_called = False
self.state.is_finished = False
self.state.iterations = 0
self.state.current_answer = None
await self.kickoff_async()
result = self.state.current_answer
if not isinstance(result, AgentFinish):
raise RuntimeError("Agent execution ended without reaching a final answer.")
return result
🤖 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/experimental/agent_executor.py` around lines 3191 -
3209, Reset the iteration counter before rerunning the feedback loop, since
_invoke_loop and _ainvoke_loop currently only clear finalize/finished state and
then call kickoff/kickoff_async, which leaves self.state.iterations carrying
over from the previous attempt. Update both methods to mirror the per-run reset
used by invoke() and invoke_async() by resetting self.state.iterations before
the rerun so check_max_iterations() and force_final_answer don’t trigger
immediately.

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] Task(human_input=True) crashes with AttributeError after default executor swap from CrewAgentExecutor to AgentExecutor in 1.15.0

1 participant