From d4e352343f1d68fa725b2bdc0dbb19281b229f9d Mon Sep 17 00:00:00 2001 From: matdev83 <211248003+matdev83@users.noreply.github.com> Date: Mon, 13 Oct 2025 00:34:29 +0200 Subject: [PATCH] Fix tool call reactor handling of empty replacement responses --- .../services/tool_call_reactor_middleware.py | 2 +- .../test_tool_call_reactor_middleware.py | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/core/services/tool_call_reactor_middleware.py b/src/core/services/tool_call_reactor_middleware.py index 55bb898f..7e0a20c3 100644 --- a/src/core/services/tool_call_reactor_middleware.py +++ b/src/core/services/tool_call_reactor_middleware.py @@ -195,7 +195,7 @@ async def process( ) # Create a new response with the replacement content - if result.replacement_response: + if result.replacement_response is not None: replacement_response = self._create_replacement_response( response, result.replacement_response, diff --git a/tests/unit/core/services/test_tool_call_reactor_middleware.py b/tests/unit/core/services/test_tool_call_reactor_middleware.py index 2f27553e..cfbb3fe3 100644 --- a/tests/unit/core/services/test_tool_call_reactor_middleware.py +++ b/tests/unit/core/services/test_tool_call_reactor_middleware.py @@ -403,6 +403,52 @@ async def test_process_with_tool_calls_swallowed_no_replacement( # Should return original response if no replacement provided assert result == response + @pytest.mark.asyncio + async def test_process_with_tool_calls_swallowed_empty_string( + self, middleware, mock_reactor + ): + """Handlers should be able to swallow with an empty replacement payload.""" + + tool_call_response = { + "choices": [ + { + "message": { + "tool_calls": [ + { + "id": "call_124", + "type": "function", + "function": { + "name": "test_tool", + "arguments": '{"arg": "value"}', + }, + } + ] + } + } + ] + } + + response = ProcessedResponse(content=json.dumps(tool_call_response)) + + swallow_result = ToolCallReactionResult( + should_swallow=True, + replacement_response="", + metadata={"handler": "test_handler"}, + ) + + mock_reactor.process_tool_call.return_value = swallow_result + + result = await middleware.process( + response=response, + session_id="test_session", + context={"backend_name": "test", "model_name": "test"}, + ) + + assert isinstance(result, ProcessedResponse) + assert result.content == "" + assert result.metadata["tool_call_swallowed"] is True + assert result.metadata["tool_call_reactor"]["handler"] == "test_handler" + @pytest.mark.asyncio async def test_process_multiple_tool_calls(self, middleware, mock_reactor): """Test processing response with multiple tool calls."""