diff --git a/api/core/callback_handler/workflow_tool_callback_handler.py b/api/core/callback_handler/workflow_tool_callback_handler.py index 23aabd99708..8c48a62d93f 100644 --- a/api/core/callback_handler/workflow_tool_callback_handler.py +++ b/api/core/callback_handler/workflow_tool_callback_handler.py @@ -1,6 +1,7 @@ from collections.abc import Generator, Iterable, Mapping from typing import Any +from configs import dify_config from core.callback_handler.agent_tool_callback_handler import DifyAgentCallbackHandler, print_text from core.ops.ops_trace_manager import TraceQueueManager from core.tools.entities.tool_entities import ToolInvokeMessage @@ -19,8 +20,9 @@ class DifyWorkflowCallbackHandler(DifyAgentCallbackHandler): trace_manager: TraceQueueManager | None = None, ) -> Generator[ToolInvokeMessage, None, None]: for tool_output in tool_outputs: - print_text("\n[on_tool_execution]\n", color=self.color) - print_text("Tool: " + tool_name + "\n", color=self.color) - print_text("Outputs: " + tool_output.model_dump_json()[:1000] + "\n", color=self.color) - print_text("\n") + if dify_config.DEBUG: + print_text("\n[on_tool_execution]\n", color=self.color) + print_text("Tool: " + tool_name + "\n", color=self.color) + print_text("Outputs: " + tool_output.model_dump_json()[:1000] + "\n", color=self.color) + print_text("\n") yield tool_output diff --git a/api/tests/unit_tests/core/callback_handler/test_workflow_tool_callback_handler.py b/api/tests/unit_tests/core/callback_handler/test_workflow_tool_callback_handler.py index 5b53c5965ce..81ac48b2036 100644 --- a/api/tests/unit_tests/core/callback_handler/test_workflow_tool_callback_handler.py +++ b/api/tests/unit_tests/core/callback_handler/test_workflow_tool_callback_handler.py @@ -32,8 +32,16 @@ def mock_print_text(mocker: MockerFixture): return mocker.patch("core.callback_handler.workflow_tool_callback_handler.print_text") +@pytest.fixture +def enable_debug(mocker: MockerFixture): + """Force DEBUG on so the handler emits its verbose stdout traces.""" + mocker.patch("core.callback_handler.workflow_tool_callback_handler.dify_config.DEBUG", True) + + class TestDifyWorkflowCallbackHandler: - def test_on_tool_execution_single_output_success(self, handler: DifyWorkflowCallbackHandler, mock_print_text): + def test_on_tool_execution_single_output_success( + self, handler: DifyWorkflowCallbackHandler, mock_print_text, enable_debug + ): # Arrange tool_name = "test_tool" tool_inputs = {"a": 1} @@ -63,7 +71,9 @@ class TestDifyWorkflowCallbackHandler: ] ) - def test_on_tool_execution_multiple_outputs(self, handler: DifyWorkflowCallbackHandler, mock_print_text): + def test_on_tool_execution_multiple_outputs( + self, handler: DifyWorkflowCallbackHandler, mock_print_text, enable_debug + ): # Arrange tool_name = "multi_tool" outputs = [ @@ -101,6 +111,29 @@ class TestDifyWorkflowCallbackHandler: assert results == [] mock_print_text.assert_not_called() + def test_on_tool_execution_skips_print_when_debug_disabled( + self, handler: DifyWorkflowCallbackHandler, mock_print_text, mocker: MockerFixture + ): + """When DEBUG is off, outputs are still yielded but nothing is printed + and model_dump_json() is never invoked.""" + # Arrange + mocker.patch("core.callback_handler.workflow_tool_callback_handler.dify_config.DEBUG", False) + message = MagicMock() + + # Act + results = list( + handler.on_tool_execution( + tool_name="quiet_tool", + tool_inputs={}, + tool_outputs=[message], + ) + ) + + # Assert + assert results == [message] + mock_print_text.assert_not_called() + message.model_dump_json.assert_not_called() + @pytest.mark.parametrize( ("invalid_outputs", "expected_exception"), [ @@ -110,7 +143,7 @@ class TestDifyWorkflowCallbackHandler: ], ) def test_on_tool_execution_invalid_outputs_type( - self, handler: DifyWorkflowCallbackHandler, invalid_outputs, expected_exception + self, handler: DifyWorkflowCallbackHandler, invalid_outputs, expected_exception, enable_debug ): # Arrange tool_name = "invalid_tool" @@ -125,7 +158,9 @@ class TestDifyWorkflowCallbackHandler: ) ) - def test_on_tool_execution_long_json_truncation(self, handler: DifyWorkflowCallbackHandler, mock_print_text): + def test_on_tool_execution_long_json_truncation( + self, handler: DifyWorkflowCallbackHandler, mock_print_text, enable_debug + ): # Arrange tool_name = "long_json_tool" long_json = "x" * 1500 @@ -147,7 +182,9 @@ class TestDifyWorkflowCallbackHandler: color="blue", ) - def test_on_tool_execution_model_dump_json_exception(self, handler: DifyWorkflowCallbackHandler, mock_print_text): + def test_on_tool_execution_model_dump_json_exception( + self, handler: DifyWorkflowCallbackHandler, mock_print_text, enable_debug + ): # Arrange tool_name = "exception_tool" bad_message = MagicMock() @@ -167,7 +204,7 @@ class TestDifyWorkflowCallbackHandler: assert mock_print_text.call_count >= 2 def test_on_tool_execution_none_message_id_and_trace_manager( - self, handler: DifyWorkflowCallbackHandler, mock_print_text + self, handler: DifyWorkflowCallbackHandler, mock_print_text, enable_debug ): # Arrange tool_name = "optional_params_tool"