mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-01-11 00:58:30 +00:00
Improve EventListener and TraceCollectionListener for improved event… (#4160)
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
Build uv cache / build-cache (3.10) (push) Has been cancelled
Build uv cache / build-cache (3.11) (push) Has been cancelled
Build uv cache / build-cache (3.12) (push) Has been cancelled
Build uv cache / build-cache (3.13) (push) Has been cancelled
Some checks failed
CodeQL Advanced / Analyze (actions) (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Notify Downstream / notify-downstream (push) Has been cancelled
Mark stale issues and pull requests / stale (push) Has been cancelled
Build uv cache / build-cache (3.10) (push) Has been cancelled
Build uv cache / build-cache (3.11) (push) Has been cancelled
Build uv cache / build-cache (3.12) (push) Has been cancelled
Build uv cache / build-cache (3.13) (push) Has been cancelled
* Refactor EventListener and TraceCollectionListener for improved event handling - Removed unused threading and method branches from EventListener to simplify the code. - Updated event handling methods in EventListener to use new formatter methods for better clarity and consistency. - Refactored TraceCollectionListener to eliminate unnecessary parameters in formatter calls, enhancing readability. - Simplified ConsoleFormatter by removing outdated tree management methods and focusing on panel-based output for status updates. - Enhanced ToolUsage to track run attempts for better tool usage metrics. * clearer for knowledge retrieval and dropped some reduancies * Refactor EventListener and ConsoleFormatter for improved clarity and consistency - Removed the MCPToolExecutionCompletedEvent handler from EventListener to streamline event processing. - Updated ConsoleFormatter to enhance output formatting by adding line breaks for better readability in status content. - Renamed status messages for MCP Tool execution to provide clearer context during tool operations. * fix run attempt incrementation * task name consistency * memory events consistency * ensure hitl works * linting
This commit is contained in:
@@ -7,22 +7,19 @@ from crewai.events.event_listener import event_listener
|
||||
class TestFlowHumanInputIntegration:
|
||||
"""Test integration between Flow execution and human input functionality."""
|
||||
|
||||
def test_console_formatter_pause_resume_methods(self):
|
||||
"""Test that ConsoleFormatter pause/resume methods work correctly."""
|
||||
def test_console_formatter_pause_resume_methods_exist(self):
|
||||
"""Test that ConsoleFormatter pause/resume methods exist and are callable."""
|
||||
formatter = event_listener.formatter
|
||||
|
||||
original_paused_state = formatter._live_paused
|
||||
# Methods should exist and be callable
|
||||
assert hasattr(formatter, "pause_live_updates")
|
||||
assert hasattr(formatter, "resume_live_updates")
|
||||
assert callable(formatter.pause_live_updates)
|
||||
assert callable(formatter.resume_live_updates)
|
||||
|
||||
try:
|
||||
formatter._live_paused = False
|
||||
|
||||
formatter.pause_live_updates()
|
||||
assert formatter._live_paused
|
||||
|
||||
formatter.resume_live_updates()
|
||||
assert not formatter._live_paused
|
||||
finally:
|
||||
formatter._live_paused = original_paused_state
|
||||
# Should not raise
|
||||
formatter.pause_live_updates()
|
||||
formatter.resume_live_updates()
|
||||
|
||||
@patch("builtins.input", return_value="")
|
||||
def test_human_input_pauses_flow_updates(self, mock_input):
|
||||
@@ -38,23 +35,16 @@ class TestFlowHumanInputIntegration:
|
||||
|
||||
formatter = event_listener.formatter
|
||||
|
||||
original_paused_state = formatter._live_paused
|
||||
with (
|
||||
patch.object(formatter, "pause_live_updates") as mock_pause,
|
||||
patch.object(formatter, "resume_live_updates") as mock_resume,
|
||||
):
|
||||
result = executor._ask_human_input("Test result")
|
||||
|
||||
try:
|
||||
formatter._live_paused = False
|
||||
|
||||
with (
|
||||
patch.object(formatter, "pause_live_updates") as mock_pause,
|
||||
patch.object(formatter, "resume_live_updates") as mock_resume,
|
||||
):
|
||||
result = executor._ask_human_input("Test result")
|
||||
|
||||
mock_pause.assert_called_once()
|
||||
mock_resume.assert_called_once()
|
||||
mock_input.assert_called_once()
|
||||
assert result == ""
|
||||
finally:
|
||||
formatter._live_paused = original_paused_state
|
||||
mock_pause.assert_called_once()
|
||||
mock_resume.assert_called_once()
|
||||
mock_input.assert_called_once()
|
||||
assert result == ""
|
||||
|
||||
@patch("builtins.input", side_effect=["feedback", ""])
|
||||
def test_multiple_human_input_rounds(self, mock_input):
|
||||
@@ -70,53 +60,46 @@ class TestFlowHumanInputIntegration:
|
||||
|
||||
formatter = event_listener.formatter
|
||||
|
||||
original_paused_state = formatter._live_paused
|
||||
pause_calls = []
|
||||
resume_calls = []
|
||||
|
||||
try:
|
||||
pause_calls = []
|
||||
resume_calls = []
|
||||
def track_pause():
|
||||
pause_calls.append(True)
|
||||
|
||||
def track_pause():
|
||||
pause_calls.append(True)
|
||||
def track_resume():
|
||||
resume_calls.append(True)
|
||||
|
||||
def track_resume():
|
||||
resume_calls.append(True)
|
||||
with (
|
||||
patch.object(formatter, "pause_live_updates", side_effect=track_pause),
|
||||
patch.object(
|
||||
formatter, "resume_live_updates", side_effect=track_resume
|
||||
),
|
||||
):
|
||||
result1 = executor._ask_human_input("Test result 1")
|
||||
assert result1 == "feedback"
|
||||
|
||||
with (
|
||||
patch.object(formatter, "pause_live_updates", side_effect=track_pause),
|
||||
patch.object(
|
||||
formatter, "resume_live_updates", side_effect=track_resume
|
||||
),
|
||||
):
|
||||
result1 = executor._ask_human_input("Test result 1")
|
||||
assert result1 == "feedback"
|
||||
result2 = executor._ask_human_input("Test result 2")
|
||||
assert result2 == ""
|
||||
|
||||
result2 = executor._ask_human_input("Test result 2")
|
||||
assert result2 == ""
|
||||
|
||||
assert len(pause_calls) == 2
|
||||
assert len(resume_calls) == 2
|
||||
finally:
|
||||
formatter._live_paused = original_paused_state
|
||||
assert len(pause_calls) == 2
|
||||
assert len(resume_calls) == 2
|
||||
|
||||
def test_pause_resume_with_no_live_session(self):
|
||||
"""Test pause/resume methods handle case when no Live session exists."""
|
||||
formatter = event_listener.formatter
|
||||
|
||||
original_live = formatter._live
|
||||
original_paused_state = formatter._live_paused
|
||||
original_streaming_live = formatter._streaming_live
|
||||
|
||||
try:
|
||||
formatter._live = None
|
||||
formatter._live_paused = False
|
||||
formatter._streaming_live = None
|
||||
|
||||
# Should not raise when no session exists
|
||||
formatter.pause_live_updates()
|
||||
formatter.resume_live_updates()
|
||||
|
||||
assert not formatter._live_paused
|
||||
assert formatter._streaming_live is None
|
||||
finally:
|
||||
formatter._live = original_live
|
||||
formatter._live_paused = original_paused_state
|
||||
formatter._streaming_live = original_streaming_live
|
||||
|
||||
def test_pause_resume_exception_handling(self):
|
||||
"""Test that resume is called even if exception occurs during human input."""
|
||||
@@ -131,23 +114,18 @@ class TestFlowHumanInputIntegration:
|
||||
|
||||
formatter = event_listener.formatter
|
||||
|
||||
original_paused_state = formatter._live_paused
|
||||
with (
|
||||
patch.object(formatter, "pause_live_updates") as mock_pause,
|
||||
patch.object(formatter, "resume_live_updates") as mock_resume,
|
||||
patch(
|
||||
"builtins.input", side_effect=KeyboardInterrupt("Test exception")
|
||||
),
|
||||
):
|
||||
with pytest.raises(KeyboardInterrupt):
|
||||
executor._ask_human_input("Test result")
|
||||
|
||||
try:
|
||||
with (
|
||||
patch.object(formatter, "pause_live_updates") as mock_pause,
|
||||
patch.object(formatter, "resume_live_updates") as mock_resume,
|
||||
patch(
|
||||
"builtins.input", side_effect=KeyboardInterrupt("Test exception")
|
||||
),
|
||||
):
|
||||
with pytest.raises(KeyboardInterrupt):
|
||||
executor._ask_human_input("Test result")
|
||||
|
||||
mock_pause.assert_called_once()
|
||||
mock_resume.assert_called_once()
|
||||
finally:
|
||||
formatter._live_paused = original_paused_state
|
||||
mock_pause.assert_called_once()
|
||||
mock_resume.assert_called_once()
|
||||
|
||||
def test_training_mode_human_input(self):
|
||||
"""Test human input in training mode."""
|
||||
@@ -162,28 +140,25 @@ class TestFlowHumanInputIntegration:
|
||||
|
||||
formatter = event_listener.formatter
|
||||
|
||||
original_paused_state = formatter._live_paused
|
||||
with (
|
||||
patch.object(formatter, "pause_live_updates") as mock_pause,
|
||||
patch.object(formatter, "resume_live_updates") as mock_resume,
|
||||
patch.object(formatter.console, "print") as mock_console_print,
|
||||
patch("builtins.input", return_value="training feedback"),
|
||||
):
|
||||
result = executor._ask_human_input("Test result")
|
||||
|
||||
try:
|
||||
with (
|
||||
patch.object(formatter, "pause_live_updates") as mock_pause,
|
||||
patch.object(formatter, "resume_live_updates") as mock_resume,
|
||||
patch("builtins.input", return_value="training feedback"),
|
||||
):
|
||||
result = executor._ask_human_input("Test result")
|
||||
mock_pause.assert_called_once()
|
||||
mock_resume.assert_called_once()
|
||||
assert result == "training feedback"
|
||||
|
||||
mock_pause.assert_called_once()
|
||||
mock_resume.assert_called_once()
|
||||
assert result == "training feedback"
|
||||
|
||||
executor._printer.print.assert_called()
|
||||
call_args = [
|
||||
call[1]["content"]
|
||||
for call in executor._printer.print.call_args_list
|
||||
]
|
||||
training_prompt_found = any(
|
||||
"TRAINING MODE" in content for content in call_args
|
||||
)
|
||||
assert training_prompt_found
|
||||
finally:
|
||||
formatter._live_paused = original_paused_state
|
||||
# Verify the training panel was printed via formatter's console
|
||||
mock_console_print.assert_called()
|
||||
# Check that a Panel with training title was printed
|
||||
call_args = mock_console_print.call_args_list
|
||||
training_panel_found = any(
|
||||
hasattr(call[0][0], "title") and "Training" in str(call[0][0].title)
|
||||
for call in call_args
|
||||
if call[0]
|
||||
)
|
||||
assert training_panel_found
|
||||
|
||||
Reference in New Issue
Block a user