mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-06-15 05:08:11 +00:00
Compare commits
1 Commits
flow-itera
...
devin/1780
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5878627ca6 |
@@ -179,7 +179,8 @@ class SyncHumanInputProvider(HumanInputProvider):
|
||||
Returns:
|
||||
The final answer after feedback processing.
|
||||
"""
|
||||
feedback = self._prompt_input(context.crew)
|
||||
output_str = self._get_output_string(formatted_answer)
|
||||
feedback = self._prompt_input(context.crew, output_str)
|
||||
|
||||
if context._is_training_mode():
|
||||
return self._handle_training_feedback(formatted_answer, feedback, context)
|
||||
@@ -200,7 +201,8 @@ class SyncHumanInputProvider(HumanInputProvider):
|
||||
Returns:
|
||||
The final answer after feedback processing.
|
||||
"""
|
||||
feedback = await self._prompt_input_async(context.crew)
|
||||
output_str = self._get_output_string(formatted_answer)
|
||||
feedback = await self._prompt_input_async(context.crew, output_str)
|
||||
|
||||
if context._is_training_mode():
|
||||
return await self._handle_training_feedback_async(
|
||||
@@ -259,7 +261,9 @@ class SyncHumanInputProvider(HumanInputProvider):
|
||||
else:
|
||||
context.messages.append(context._format_feedback_message(feedback))
|
||||
answer = context._invoke_loop()
|
||||
feedback = self._prompt_input(context.crew)
|
||||
feedback = self._prompt_input(
|
||||
context.crew, self._get_output_string(answer)
|
||||
)
|
||||
|
||||
return answer
|
||||
|
||||
@@ -311,16 +315,19 @@ class SyncHumanInputProvider(HumanInputProvider):
|
||||
else:
|
||||
context.messages.append(context._format_feedback_message(feedback))
|
||||
answer = await context._ainvoke_loop()
|
||||
feedback = await self._prompt_input_async(context.crew)
|
||||
feedback = await self._prompt_input_async(
|
||||
context.crew, self._get_output_string(answer)
|
||||
)
|
||||
|
||||
return answer
|
||||
|
||||
@staticmethod
|
||||
def _prompt_input(crew: Crew | None) -> str:
|
||||
def _prompt_input(crew: Crew | None, agent_output: str | None = None) -> str:
|
||||
"""Show rich panel and prompt for input.
|
||||
|
||||
Args:
|
||||
crew: The crew instance for context.
|
||||
agent_output: The agent's final output to display for review.
|
||||
|
||||
Returns:
|
||||
User input string from terminal.
|
||||
@@ -334,6 +341,17 @@ class SyncHumanInputProvider(HumanInputProvider):
|
||||
formatter.pause_live_updates()
|
||||
|
||||
try:
|
||||
if agent_output is not None:
|
||||
result_content = Text()
|
||||
result_content.append(agent_output, style="bright_green")
|
||||
result_panel = Panel(
|
||||
result_content,
|
||||
title="Agent Final Answer",
|
||||
border_style="green",
|
||||
padding=(1, 2),
|
||||
)
|
||||
formatter.console.print(result_panel)
|
||||
|
||||
if crew and getattr(crew, "_train", False):
|
||||
prompt_text = (
|
||||
"TRAINING MODE: Provide feedback to improve the agent's performance.\n\n"
|
||||
@@ -369,11 +387,14 @@ class SyncHumanInputProvider(HumanInputProvider):
|
||||
formatter.resume_live_updates()
|
||||
|
||||
@staticmethod
|
||||
async def _prompt_input_async(crew: Crew | None) -> str:
|
||||
async def _prompt_input_async(
|
||||
crew: Crew | None, agent_output: str | None = None
|
||||
) -> str:
|
||||
"""Show rich panel and prompt for input without blocking the event loop.
|
||||
|
||||
Args:
|
||||
crew: The crew instance for context.
|
||||
agent_output: The agent's final output to display for review.
|
||||
|
||||
Returns:
|
||||
User input string from terminal.
|
||||
@@ -387,6 +408,17 @@ class SyncHumanInputProvider(HumanInputProvider):
|
||||
formatter.pause_live_updates()
|
||||
|
||||
try:
|
||||
if agent_output is not None:
|
||||
result_content = Text()
|
||||
result_content.append(agent_output, style="bright_green")
|
||||
result_panel = Panel(
|
||||
result_content,
|
||||
title="Agent Final Answer",
|
||||
border_style="green",
|
||||
padding=(1, 2),
|
||||
)
|
||||
formatter.console.print(result_panel)
|
||||
|
||||
if crew and getattr(crew, "_train", False):
|
||||
prompt_text = (
|
||||
"TRAINING MODE: Provide feedback to improve the agent's performance.\n\n"
|
||||
|
||||
@@ -138,4 +138,136 @@ class TestFlowHumanInputIntegration:
|
||||
for call in call_args
|
||||
if call[0]
|
||||
)
|
||||
assert training_panel_found
|
||||
assert training_panel_found
|
||||
|
||||
@patch("builtins.input", return_value="")
|
||||
def test_prompt_input_displays_agent_output(self, mock_input):
|
||||
"""Test that _prompt_input displays the agent output in a panel when provided."""
|
||||
provider = SyncHumanInputProvider()
|
||||
crew = MagicMock()
|
||||
crew._train = False
|
||||
|
||||
formatter = event_listener.formatter
|
||||
|
||||
with (
|
||||
patch.object(formatter, "pause_live_updates"),
|
||||
patch.object(formatter, "resume_live_updates"),
|
||||
patch.object(formatter.console, "print") as mock_console_print,
|
||||
):
|
||||
provider._prompt_input(crew, agent_output="The sky is blue.")
|
||||
|
||||
mock_console_print.assert_called()
|
||||
call_args = mock_console_print.call_args_list
|
||||
result_panel_found = any(
|
||||
hasattr(call[0][0], "title")
|
||||
and "Agent Final Answer" in str(call[0][0].title)
|
||||
for call in call_args
|
||||
if call[0]
|
||||
)
|
||||
assert result_panel_found, (
|
||||
"Agent output panel should be displayed when agent_output is provided"
|
||||
)
|
||||
|
||||
@patch("builtins.input", return_value="")
|
||||
def test_prompt_input_no_output_panel_when_none(self, mock_input):
|
||||
"""Test that _prompt_input does not display the output panel when agent_output is None."""
|
||||
provider = SyncHumanInputProvider()
|
||||
crew = MagicMock()
|
||||
crew._train = False
|
||||
|
||||
formatter = event_listener.formatter
|
||||
|
||||
with (
|
||||
patch.object(formatter, "pause_live_updates"),
|
||||
patch.object(formatter, "resume_live_updates"),
|
||||
patch.object(formatter.console, "print") as mock_console_print,
|
||||
):
|
||||
provider._prompt_input(crew, agent_output=None)
|
||||
|
||||
call_args = mock_console_print.call_args_list
|
||||
result_panel_found = any(
|
||||
hasattr(call[0][0], "title")
|
||||
and "Agent Final Answer" in str(call[0][0].title)
|
||||
for call in call_args
|
||||
if call[0]
|
||||
)
|
||||
assert not result_panel_found, (
|
||||
"Agent output panel should NOT be displayed when agent_output is None"
|
||||
)
|
||||
|
||||
@patch("builtins.input", return_value="looks good")
|
||||
def test_handle_feedback_passes_output_to_prompt(self, mock_input):
|
||||
"""Test that handle_feedback passes the agent output to _prompt_input.
|
||||
|
||||
This is the core fix for issue #6072: the feedback prompt should always
|
||||
display the result being reviewed, regardless of verbose setting.
|
||||
"""
|
||||
from crewai.agents.parser import AgentFinish
|
||||
|
||||
provider = SyncHumanInputProvider()
|
||||
|
||||
formatted_answer = AgentFinish(
|
||||
thought="I know the answer",
|
||||
output="The sky is blue.",
|
||||
text="Final Answer: The sky is blue.",
|
||||
)
|
||||
|
||||
context = MagicMock()
|
||||
context.crew = MagicMock()
|
||||
context.crew._train = False
|
||||
context._is_training_mode.return_value = False
|
||||
context.ask_for_human_input = False
|
||||
|
||||
formatter = event_listener.formatter
|
||||
|
||||
with (
|
||||
patch.object(formatter, "pause_live_updates"),
|
||||
patch.object(formatter, "resume_live_updates"),
|
||||
patch.object(formatter.console, "print") as mock_console_print,
|
||||
):
|
||||
provider.handle_feedback(formatted_answer, context)
|
||||
|
||||
call_args = mock_console_print.call_args_list
|
||||
result_panel_found = any(
|
||||
hasattr(call[0][0], "title")
|
||||
and "Agent Final Answer" in str(call[0][0].title)
|
||||
for call in call_args
|
||||
if call[0]
|
||||
)
|
||||
assert result_panel_found, (
|
||||
"handle_feedback must display the agent result panel "
|
||||
"so the user can see what they are reviewing (issue #6072)"
|
||||
)
|
||||
|
||||
@patch("builtins.input", return_value="")
|
||||
def test_prompt_input_displays_output_before_feedback_panel(self, mock_input):
|
||||
"""Test that the agent output panel appears before the feedback panel."""
|
||||
provider = SyncHumanInputProvider()
|
||||
crew = MagicMock()
|
||||
crew._train = False
|
||||
|
||||
formatter = event_listener.formatter
|
||||
|
||||
with (
|
||||
patch.object(formatter, "pause_live_updates"),
|
||||
patch.object(formatter, "resume_live_updates"),
|
||||
patch.object(formatter.console, "print") as mock_console_print,
|
||||
):
|
||||
provider._prompt_input(crew, agent_output="Test output")
|
||||
|
||||
call_args = mock_console_print.call_args_list
|
||||
result_panel_idx = None
|
||||
feedback_panel_idx = None
|
||||
for i, call in enumerate(call_args):
|
||||
if call[0] and hasattr(call[0][0], "title"):
|
||||
title = str(call[0][0].title)
|
||||
if "Agent Final Answer" in title:
|
||||
result_panel_idx = i
|
||||
elif "Human Feedback" in title:
|
||||
feedback_panel_idx = i
|
||||
|
||||
assert result_panel_idx is not None, "Agent output panel should be present"
|
||||
assert feedback_panel_idx is not None, "Feedback panel should be present"
|
||||
assert result_panel_idx < feedback_panel_idx, (
|
||||
"Agent output panel should appear before the feedback panel"
|
||||
)
|
||||
Reference in New Issue
Block a user