Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions lib/crewai/src/crewai/experimental/agent_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -2802,8 +2802,10 @@ def invoke(
)

if self.state.ask_for_human_input:
formatted_answer = self._handle_human_feedback(formatted_answer)
self._force_display_final_answer(formatted_answer)
formatted_answer = self._handle_human_feedback(formatted_answer)

formatted_answer = self._handle_human_feedback(formatted_answer)
Comment on lines 2804 to +2808

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove the duplicate human-feedback invocation in sync flow.

formatted_answer is passed to _handle_human_feedback(...) twice in the ask_for_human_input branch (Line 2806 and Line 2808), which can trigger two prompts/loops instead of one.

Suggested fix
                 if self.state.ask_for_human_input:
-                            self._force_display_final_answer(formatted_answer)
-                            formatted_answer = self._handle_human_feedback(formatted_answer)
-
-                            formatted_answer = self._handle_human_feedback(formatted_answer)
+                    self._force_display_final_answer(formatted_answer)
+                    formatted_answer = self._handle_human_feedback(formatted_answer)
📝 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
if self.state.ask_for_human_input:
formatted_answer = self._handle_human_feedback(formatted_answer)
self._force_display_final_answer(formatted_answer)
formatted_answer = self._handle_human_feedback(formatted_answer)
formatted_answer = self._handle_human_feedback(formatted_answer)
if self.state.ask_for_human_input:
self._force_display_final_answer(formatted_answer)
formatted_answer = self._handle_human_feedback(formatted_answer)
🤖 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 2804 -
2808, Remove the duplicate invocation of the _handle_human_feedback method in
the ask_for_human_input branch. Within the if self.state.ask_for_human_input
block, there are two consecutive calls to
_handle_human_feedback(formatted_answer) on separate lines (lines 2806 and
2808). Delete the second duplicate call on line 2808 so that
_handle_human_feedback is only invoked once after _force_display_final_answer,
ensuring the user is only prompted for human feedback one time instead of two.

self._save_to_memory(formatted_answer)

return {"output": formatted_answer.output}
Expand Down Expand Up @@ -2908,10 +2910,10 @@ async def invoke_async(self, inputs: dict[str, Any]) -> dict[str, Any]:
)

if self.state.ask_for_human_input:
formatted_answer = await self._ahandle_human_feedback(
formatted_answer
)

self._force_display_final_answer(formatted_answer)
formatted_answer = await self._ahandle_human_feedback(
formatted_answer
)
self._save_to_memory(formatted_answer)

return {"output": formatted_answer.output}
Expand All @@ -2930,7 +2932,13 @@ async def invoke_async(self, inputs: dict[str, Any]) -> dict[str, Any]:
raise
finally:
self._is_executing = False

def _force_display_final_answer(self, formatted_answer: Any) -> None:
"""Forces display of the agent's final answer before human feedback loop."""
if formatted_answer and hasattr(formatted_answer, "output"):
try:
self._console.print(f"[bold purple]Final Answer:[/bold purple] {formatted_answer.output}")
except Exception:
print(f"\nFinal Answer: {formatted_answer.output}\n")
async def ainvoke(self, inputs: dict[str, Any]) -> dict[str, Any]:
"""Async version of invoke. Alias for invoke_async."""
return await self.invoke_async(inputs)
Expand Down
23 changes: 23 additions & 0 deletions test_bug.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import sys
# Forcing Python to read the precise source directories for both components
sys.path.insert(0, r"C:\Users\zero\crewAI\lib\crewai\src")
sys.path.insert(0, r"C:\Users\zero\crewAI\lib\crewai-core\src")
Comment on lines +1 to +4

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove machine-specific sys.path injection from committed test code.

Hardcoded local Windows paths are not portable and can cause environment-dependent import behavior. If this is a local repro utility, keep it out of the repository test surface or resolve paths relative to repo root in a dev-only script.

🤖 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 `@test_bug.py` around lines 1 - 4, Remove the two sys.path.insert() calls on
lines 3-4 in test_bug.py that reference hardcoded Windows paths
(C:\Users\zero\crewAI\...). These machine-specific paths make the test
non-portable and environment-dependent. If these paths are necessary for local
development, either move this code to a separate dev-only script outside the
repository, or replace the hardcoded absolute paths with relative paths computed
from the repository root using appropriate path resolution methods that work
cross-platform.


from crewai import Agent, Crew, Task, Process
from crewai.llms.base_llm import BaseLLM

class StubLLM(BaseLLM):
def call(self, messages, tools=None, callbacks=None, available_functions=None,
from_task=None, from_agent=None, response_model=None):
return "Thought: I know it.\nFinal Answer: The sky is blue."

def supports_function_calling(self) -> bool:
return False

agent = Agent(role="Tester", goal="Be a Minimal Reproduction", backstory="bg",
llm=StubLLM(model="stub"), verbose=False)

task = Task(description="Sky colour?", expected_output="a colour",
agent=agent, human_input=True)

Crew(agents=[agent], tasks=[task], process=Process.sequential, verbose=False).kickoff()
Comment on lines +17 to +23

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Avoid import-time interactive execution in a test_*.py file.

This executes kickoff() at module import with human_input=True, which can hang automated test runs during discovery. Move execution behind if __name__ == "__main__": and keep it out of default test collection.

🤖 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 `@test_bug.py` around lines 17 - 23, The Crew instantiation and kickoff()
method call are executing at module import time, which causes the test file to
hang during test discovery when human_input=True is set. Move the entire code
block containing the Task creation and Crew(agents=[agent], tasks=[task],
process=Process.sequential, verbose=False).kickoff() execution inside an if
__name__ == "__main__": guard block so it only runs when the script is executed
directly, not during test collection.