From bb1f5b8201975d7675c2dd0e4547f300b094f760 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 27 Jan 2026 06:42:38 +0000 Subject: [PATCH 1/3] Initial plan From 990e8dff0866f88b3650f15a215741e0c44273e2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 27 Jan 2026 06:47:07 +0000 Subject: [PATCH 2/3] Fix send_chat_history_messages to send empty lists to API Co-authored-by: pontemonti <7850950+pontemonti@users.noreply.github.com> --- .../services/mcp_tool_registration_service.py | 14 +++------ .../openai/mcp_tool_registration_service.py | 12 ++----- .../mcp_tool_server_configuration_service.py | 9 ++---- .../services/test_send_chat_history.py | 20 +++++++----- .../openai/test_send_chat_history.py | 21 ++++++++++--- .../services/test_send_chat_history.py | 31 ++++++++++++++----- 6 files changed, 59 insertions(+), 48 deletions(-) diff --git a/libraries/microsoft-agents-a365-tooling-extensions-agentframework/microsoft_agents_a365/tooling/extensions/agentframework/services/mcp_tool_registration_service.py b/libraries/microsoft-agents-a365-tooling-extensions-agentframework/microsoft_agents_a365/tooling/extensions/agentframework/services/mcp_tool_registration_service.py index c4b1ec88..20f4caa7 100644 --- a/libraries/microsoft-agents-a365-tooling-extensions-agentframework/microsoft_agents_a365/tooling/extensions/agentframework/services/mcp_tool_registration_service.py +++ b/libraries/microsoft-agents-a365-tooling-extensions-agentframework/microsoft_agents_a365/tooling/extensions/agentframework/services/mcp_tool_registration_service.py @@ -221,10 +221,12 @@ async def send_chat_history_messages( Send chat history messages to the MCP platform for real-time threat protection. This is the primary implementation method that handles message conversion - and delegation to the core tooling service. + and delegation to the core tooling service. Empty message lists are valid + and will be sent to the API. Args: chat_messages: Sequence of Agent Framework ChatMessage objects to send. + Empty lists are valid and will be sent to the API. turn_context: TurnContext from the Agents SDK containing conversation info. tool_options: Optional configuration for the request. Defaults to AgentFramework-specific options if not provided. @@ -249,11 +251,6 @@ async def send_chat_history_messages( if turn_context is None: raise ValueError("turn_context cannot be None") - # Handle empty messages - return success with warning - if len(chat_messages) == 0: - self._logger.warning("Empty message list provided to send_chat_history_messages") - return OperationResult.success() - self._logger.info(f"Send chat history initiated with {len(chat_messages)} messages") # Use default options if not provided @@ -263,10 +260,7 @@ async def send_chat_history_messages( # Convert messages to ChatHistoryMessage format history_messages = self._convert_chat_messages_to_history(chat_messages) - # Check if all messages were filtered out during conversion - if len(history_messages) == 0: - self._logger.warning("All messages were filtered out during conversion (empty content)") - return OperationResult.success() + self._logger.debug(f"Converted {len(history_messages)} messages to ChatHistoryMessage format") # Delegate to core service result = await self._mcp_server_configuration_service.send_chat_history( diff --git a/libraries/microsoft-agents-a365-tooling-extensions-openai/microsoft_agents_a365/tooling/extensions/openai/mcp_tool_registration_service.py b/libraries/microsoft-agents-a365-tooling-extensions-openai/microsoft_agents_a365/tooling/extensions/openai/mcp_tool_registration_service.py index 7708b4d2..a5f566d8 100644 --- a/libraries/microsoft-agents-a365-tooling-extensions-openai/microsoft_agents_a365/tooling/extensions/openai/mcp_tool_registration_service.py +++ b/libraries/microsoft-agents-a365-tooling-extensions-openai/microsoft_agents_a365/tooling/extensions/openai/mcp_tool_registration_service.py @@ -340,6 +340,7 @@ async def send_chat_history_messages( This method accepts a list of OpenAI TResponseInputItem messages, converts them to ChatHistoryMessage format, and sends them to the MCP platform. + Empty message lists are valid and will be sent to the API. Args: turn_context: TurnContext from the Agents SDK containing conversation info. @@ -347,7 +348,7 @@ async def send_chat_history_messages( and activity.text. messages: List of OpenAI TResponseInputItem messages to send. Supports UserMessage, AssistantMessage, SystemMessage, and other OpenAI - message types. + message types. Empty lists are valid and will be sent to the API. options: Optional ToolOptions for customization. If not provided, uses default options with orchestrator_name="OpenAI". @@ -382,11 +383,6 @@ async def send_chat_history_messages( if messages is None: raise ValueError("messages cannot be None") - # Handle empty list as no-op - if len(messages) == 0: - self._logger.info("Empty message list provided, returning success") - return OperationResult.success() - self._logger.info(f"Sending {len(messages)} OpenAI messages as chat history") # Set default options @@ -399,10 +395,6 @@ async def send_chat_history_messages( # Convert OpenAI messages to ChatHistoryMessage format chat_history_messages = self._convert_openai_messages_to_chat_history(messages) - if len(chat_history_messages) == 0: - self._logger.warning("No messages could be converted to chat history format") - return OperationResult.success() - self._logger.debug( f"Converted {len(chat_history_messages)} messages to ChatHistoryMessage format" ) diff --git a/libraries/microsoft-agents-a365-tooling/microsoft_agents_a365/tooling/services/mcp_tool_server_configuration_service.py b/libraries/microsoft-agents-a365-tooling/microsoft_agents_a365/tooling/services/mcp_tool_server_configuration_service.py index 71d2ee5d..bdce2da9 100644 --- a/libraries/microsoft-agents-a365-tooling/microsoft_agents_a365/tooling/services/mcp_tool_server_configuration_service.py +++ b/libraries/microsoft-agents-a365-tooling/microsoft_agents_a365/tooling/services/mcp_tool_server_configuration_service.py @@ -569,7 +569,7 @@ async def send_chat_history( Must have a valid activity with conversation.id, activity.id, and activity.text. chat_history_messages: List of ChatHistoryMessage objects representing the chat - history. Must be non-empty. + history. Empty lists are valid and will be sent to the API. options: Optional ToolOptions instance containing optional parameters. Returns: @@ -578,7 +578,7 @@ async def send_chat_history( On failure, returns OperationResult.failed() with error details. Raises: - ValueError: If turn_context is None, chat_history_messages is None or empty, + ValueError: If turn_context is None, chat_history_messages is None, turn_context.activity is None, or any of the required fields (conversation.id, activity.id, activity.text) are missing or empty. @@ -602,11 +602,6 @@ async def send_chat_history( if chat_history_messages is None: raise ValueError("chat_history_messages cannot be None") - # Handle empty messages - return success with warning (consistent with extension behavior) - if len(chat_history_messages) == 0: - self._logger.warning("Empty message list provided to send_chat_history") - return OperationResult.success() - # Extract required information from turn context if not turn_context.activity: raise ValueError("turn_context.activity cannot be None") diff --git a/tests/tooling/extensions/agentframework/services/test_send_chat_history.py b/tests/tooling/extensions/agentframework/services/test_send_chat_history.py index f3a780a3..79bbfda2 100644 --- a/tests/tooling/extensions/agentframework/services/test_send_chat_history.py +++ b/tests/tooling/extensions/agentframework/services/test_send_chat_history.py @@ -120,17 +120,19 @@ async def test_send_chat_history_from_store_validates_turn_context_none( @pytest.mark.asyncio @pytest.mark.unit - async def test_send_chat_history_messages_empty_messages_returns_success( + async def test_send_chat_history_messages_empty_messages_calls_api( self, service, mock_turn_context ): - """Test that empty message list returns success with warning log.""" + """Test that empty message list is sent to the API.""" # Act result = await service.send_chat_history_messages([], mock_turn_context) # Assert assert result.succeeded is True - # Core service should not be called for empty messages - service._mcp_server_configuration_service.send_chat_history.assert_not_called() + # Core service should be called with empty list + service._mcp_server_configuration_service.send_chat_history.assert_called_once() + call_args = service._mcp_server_configuration_service.send_chat_history.call_args + assert call_args.kwargs["chat_history_messages"] == [] @pytest.mark.asyncio @pytest.mark.unit @@ -492,10 +494,10 @@ async def test_send_chat_history_messages_skips_messages_with_none_role( @pytest.mark.asyncio @pytest.mark.unit - async def test_send_chat_history_messages_all_filtered_returns_success( + async def test_send_chat_history_messages_all_filtered_calls_api_with_empty_list( self, service, mock_turn_context, mock_role ): - """Test that all messages filtered out returns success without calling core (CRM-006).""" + """Test that all messages filtered out calls API with empty list (CRM-006).""" # Arrange - all messages have empty content msg1 = Mock() msg1.message_id = "msg-1" @@ -517,8 +519,10 @@ async def test_send_chat_history_messages_all_filtered_returns_success( # Assert assert result.succeeded is True - # Core service should not be called when all messages are filtered out - service._mcp_server_configuration_service.send_chat_history.assert_not_called() + # Core service should be called with empty list when all messages are filtered out + service._mcp_server_configuration_service.send_chat_history.assert_called_once() + call_args = service._mcp_server_configuration_service.send_chat_history.call_args + assert call_args.kwargs["chat_history_messages"] == [] @pytest.mark.asyncio @pytest.mark.unit diff --git a/tests/tooling/extensions/openai/test_send_chat_history.py b/tests/tooling/extensions/openai/test_send_chat_history.py index 9d7b9f12..290de9f4 100644 --- a/tests/tooling/extensions/openai/test_send_chat_history.py +++ b/tests/tooling/extensions/openai/test_send_chat_history.py @@ -45,14 +45,25 @@ async def test_send_chat_history_messages_validates_messages_none( # UV-03 @pytest.mark.asyncio @pytest.mark.unit - async def test_send_chat_history_messages_empty_list_returns_success( + async def test_send_chat_history_messages_empty_list_calls_api( self, service, mock_turn_context ): - """Test that empty message list returns success (no-op).""" - result = await service.send_chat_history_messages(mock_turn_context, []) + """Test that empty message list is sent to the API.""" + with patch.object( + service.config_service, + "send_chat_history", + new_callable=AsyncMock, + ) as mock_send: + mock_send.return_value = OperationResult.success() - assert result.succeeded is True - assert len(result.errors) == 0 + result = await service.send_chat_history_messages(mock_turn_context, []) + + assert result.succeeded is True + assert len(result.errors) == 0 + # Verify the API was called with empty list + mock_send.assert_called_once() + call_args = mock_send.call_args + assert call_args.kwargs["chat_history_messages"] == [] # UV-04 @pytest.mark.asyncio diff --git a/tests/tooling/services/test_send_chat_history.py b/tests/tooling/services/test_send_chat_history.py index 60b56c80..21b9cc07 100644 --- a/tests/tooling/services/test_send_chat_history.py +++ b/tests/tooling/services/test_send_chat_history.py @@ -146,14 +146,29 @@ async def test_send_chat_history_validates_chat_history_messages( await service.send_chat_history(mock_turn_context, None) @pytest.mark.asyncio - async def test_send_chat_history_empty_list_returns_success(self, service, mock_turn_context): - """Test that send_chat_history returns success for empty list (CRM-008).""" - # Act - result = await service.send_chat_history(mock_turn_context, []) - - # Assert - empty list should return success, not raise exception - assert result.succeeded is True - assert len(result.errors) == 0 + async def test_send_chat_history_empty_list_calls_api(self, service, mock_turn_context): + """Test that send_chat_history sends empty list to API (CRM-008).""" + # Arrange + mock_response = AsyncMock() + mock_response.status = 200 + mock_response.text = AsyncMock(return_value="OK") + + # Mock aiohttp.ClientSession + with patch("aiohttp.ClientSession") as mock_session: + mock_session_instance = MagicMock() + mock_post = AsyncMock() + mock_post.__aenter__.return_value = mock_response + mock_session_instance.post.return_value = mock_post + mock_session.return_value.__aenter__.return_value = mock_session_instance + + # Act + result = await service.send_chat_history(mock_turn_context, []) + + # Assert - empty list should call API and return success + assert result.succeeded is True + assert len(result.errors) == 0 + # Verify the API was called + assert mock_session_instance.post.called @pytest.mark.asyncio async def test_send_chat_history_validates_activity(self, service, chat_history_messages): From 765c1531bad6a9a1ead40491fcb2ac68b23cb8f1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 27 Jan 2026 06:49:38 +0000 Subject: [PATCH 3/3] Fix minor grammar issues in test comments Co-authored-by: pontemonti <7850950+pontemonti@users.noreply.github.com> --- .../agentframework/services/test_send_chat_history.py | 4 ++-- tests/tooling/extensions/openai/test_send_chat_history.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/tooling/extensions/agentframework/services/test_send_chat_history.py b/tests/tooling/extensions/agentframework/services/test_send_chat_history.py index 79bbfda2..f951376b 100644 --- a/tests/tooling/extensions/agentframework/services/test_send_chat_history.py +++ b/tests/tooling/extensions/agentframework/services/test_send_chat_history.py @@ -129,7 +129,7 @@ async def test_send_chat_history_messages_empty_messages_calls_api( # Assert assert result.succeeded is True - # Core service should be called with empty list + # Core service should be called with an empty list service._mcp_server_configuration_service.send_chat_history.assert_called_once() call_args = service._mcp_server_configuration_service.send_chat_history.call_args assert call_args.kwargs["chat_history_messages"] == [] @@ -519,7 +519,7 @@ async def test_send_chat_history_messages_all_filtered_calls_api_with_empty_list # Assert assert result.succeeded is True - # Core service should be called with empty list when all messages are filtered out + # Core service should be called with an empty list when all messages are filtered out service._mcp_server_configuration_service.send_chat_history.assert_called_once() call_args = service._mcp_server_configuration_service.send_chat_history.call_args assert call_args.kwargs["chat_history_messages"] == [] diff --git a/tests/tooling/extensions/openai/test_send_chat_history.py b/tests/tooling/extensions/openai/test_send_chat_history.py index 290de9f4..e1141ea9 100644 --- a/tests/tooling/extensions/openai/test_send_chat_history.py +++ b/tests/tooling/extensions/openai/test_send_chat_history.py @@ -60,7 +60,7 @@ async def test_send_chat_history_messages_empty_list_calls_api( assert result.succeeded is True assert len(result.errors) == 0 - # Verify the API was called with empty list + # Verify the API was called with an empty list mock_send.assert_called_once() call_args = mock_send.call_args assert call_args.kwargs["chat_history_messages"] == []