From 621992153c885972764bfb752795aec55bfa5d4c Mon Sep 17 00:00:00 2001 From: jgarrison929 Date: Fri, 13 Mar 2026 07:19:54 -0700 Subject: [PATCH 1/4] Python: Fix spurious runtime tools warning when using use_latest_version When use_latest_version=True, AzureAIClient fetches the existing agent from the service rather than creating one. In this flow the client never records creation-time tool names, so the subsequent _remove_agent_level_run_options check incorrectly treats an empty runtime tool list as a mismatch and always emits: 'AzureAIClient does not support runtime tools or structured_output overrides after agent creation.' Root cause: the 'tools_changed' flag was set to 'runtime_tools is not None', which evaluates to True even for an empty list (the framework default). When warn_runtime_tools_and_structure_changed is False we have no creation-time baseline to compare against. Fix: when no creation-time baseline exists, only flag 'tools_changed' when runtime_tools is *non-empty* (i.e. the user actually supplied tools). An empty tool list from framework defaults no longer triggers a false-positive warning. The existing behavior for agents created by the client (where we have a proper baseline to compare tool sets) is unchanged. Added a regression test that verifies no warning fires for the use_latest_version + empty tools path. Fixes microsoft/agent-framework#4681 --- .../agent_framework_azure_ai/_client.py | 19 ++++++-- .../azure-ai/tests/test_azure_ai_client.py | 43 +++++++++++++++++++ 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/python/packages/azure-ai/agent_framework_azure_ai/_client.py b/python/packages/azure-ai/agent_framework_azure_ai/_client.py index 1fc6c7c1c9..1e0ec17a41 100644 --- a/python/packages/azure-ai/agent_framework_azure_ai/_client.py +++ b/python/packages/azure-ai/agent_framework_azure_ai/_client.py @@ -486,21 +486,32 @@ def _remove_agent_level_run_options( runtime_structured_output = self._get_structured_output_signature(chat_options) if runtime_tools is not None or runtime_structured_output is not None: - tools_changed = runtime_tools is not None - structured_output_changed = runtime_structured_output is not None + tools_changed = False + structured_output_changed = False if self.warn_runtime_tools_and_structure_changed: + # We created the agent ourselves so we can compare tool sets. if runtime_tools is not None: tools_changed = self._extract_tool_names(runtime_tools) != self._created_agent_tool_names if runtime_structured_output is not None: structured_output_changed = ( runtime_structured_output != self._created_agent_structured_output_signature ) + else: + # Agent was not created by this client (e.g. use_latest_version + # or explicit agent_version). We have no creation-time baseline + # so only warn when non-empty tools or structured_output are + # supplied — an empty tool list is just the framework default + # and should not trigger a false-positive warning. + if runtime_tools: + tools_changed = True + if runtime_structured_output is not None: + structured_output_changed = True if tools_changed or structured_output_changed: logger.warning( - "AzureAIClient does not support runtime tools or structured_output overrides after agent creation. " - "Use AzureOpenAIResponsesClient instead." + "AzureAIClient does not support runtime tools or structured_output overrides " + "after agent creation. Use AzureOpenAIResponsesClient instead." ) agent_level_option_to_run_keys = { diff --git a/python/packages/azure-ai/tests/test_azure_ai_client.py b/python/packages/azure-ai/tests/test_azure_ai_client.py index f0246f40b2..2c0c9f7e8d 100644 --- a/python/packages/azure-ai/tests/test_azure_ai_client.py +++ b/python/packages/azure-ai/tests/test_azure_ai_client.py @@ -914,6 +914,49 @@ async def test_use_latest_version_existing_agent( assert client.agent_version == "2.5" +async def test_use_latest_version_no_spurious_warning_for_empty_tools( + mock_project_client: MagicMock, +) -> None: + """Test that use_latest_version=True does not emit a false-positive tools warning. + + When the agent is fetched via use_latest_version the framework may still + pass an empty runtime tools list (``[]``). The client should not warn + about a tool mismatch in this case because no user-supplied tools are + actually being overridden. Regression test for + https://github.com/microsoft/agent-framework/issues/4681 + """ + client = create_test_azure_ai_client( + mock_project_client, agent_name="existing-agent", use_latest_version=True + ) + + # Mock existing agent + mock_existing_agent = MagicMock() + mock_existing_agent.name = "existing-agent" + mock_existing_agent.versions.latest.version = "2.5" + mock_project_client.agents.get = AsyncMock(return_value=mock_existing_agent) + + messages = [Message(role="user", contents=[Content.from_text(text="Hello")])] + + # First call fetches the latest version + with patch( + "agent_framework.openai._responses_client.RawOpenAIResponsesClient._prepare_options", + return_value={"model": "test-model", "tools": []}, + ): + await client._prepare_options(messages, {}) + + # Subsequent call with empty tools — should NOT warn + with ( + patch( + "agent_framework.openai._responses_client.RawOpenAIResponsesClient._prepare_options", + return_value={"model": "test-model", "tools": []}, + ), + patch("agent_framework_azure_ai._client.logger.warning") as mock_warning, + ): + await client._prepare_options(messages, {}) + + mock_warning.assert_not_called() + + async def test_use_latest_version_agent_not_found( mock_project_client: MagicMock, ) -> None: From b4c8ac45778a44c55283cb7823a14d551216eae8 Mon Sep 17 00:00:00 2001 From: Josh Garrison Date: Mon, 16 Mar 2026 16:24:01 -0700 Subject: [PATCH 2/4] Address Copilot review: assert no warning across both _prepare_options calls Moved the logger.warning patch to wrap both the first and second _prepare_options calls, ensuring neither emits a spurious warning when use_latest_version=True with empty tools. --- .../packages/azure-ai/tests/test_azure_ai_client.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/python/packages/azure-ai/tests/test_azure_ai_client.py b/python/packages/azure-ai/tests/test_azure_ai_client.py index 2c0c9f7e8d..1f9e7d3d8d 100644 --- a/python/packages/azure-ai/tests/test_azure_ai_client.py +++ b/python/packages/azure-ai/tests/test_azure_ai_client.py @@ -937,14 +937,7 @@ async def test_use_latest_version_no_spurious_warning_for_empty_tools( messages = [Message(role="user", contents=[Content.from_text(text="Hello")])] - # First call fetches the latest version - with patch( - "agent_framework.openai._responses_client.RawOpenAIResponsesClient._prepare_options", - return_value={"model": "test-model", "tools": []}, - ): - await client._prepare_options(messages, {}) - - # Subsequent call with empty tools — should NOT warn + # Patch logger.warning across BOTH calls — neither should warn with ( patch( "agent_framework.openai._responses_client.RawOpenAIResponsesClient._prepare_options", @@ -952,6 +945,9 @@ async def test_use_latest_version_no_spurious_warning_for_empty_tools( ), patch("agent_framework_azure_ai._client.logger.warning") as mock_warning, ): + # First call fetches the latest version + await client._prepare_options(messages, {}) + # Subsequent call with empty tools await client._prepare_options(messages, {}) mock_warning.assert_not_called() From 8e52c8fe96462e99165d24610ebdf3b6e4cdad4e Mon Sep 17 00:00:00 2001 From: Josh Garrison Date: Thu, 19 Mar 2026 09:44:31 -0700 Subject: [PATCH 3/4] Add positive test: non-empty tools with use_latest_version emits warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Companion test requested by giles17 — verifies that non-empty runtime tools still correctly trigger the mismatch warning when use_latest_version=True, guarding against regressions that suppress all warnings in the else branch. --- .../azure-ai/tests/test_azure_ai_client.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/python/packages/azure-ai/tests/test_azure_ai_client.py b/python/packages/azure-ai/tests/test_azure_ai_client.py index 1f9e7d3d8d..2ce8d1f82d 100644 --- a/python/packages/azure-ai/tests/test_azure_ai_client.py +++ b/python/packages/azure-ai/tests/test_azure_ai_client.py @@ -953,6 +953,44 @@ async def test_use_latest_version_no_spurious_warning_for_empty_tools( mock_warning.assert_not_called() +async def test_use_latest_version_warns_for_non_empty_tools( + mock_project_client: MagicMock, +) -> None: + """Test that use_latest_version=True with non-empty tools DOES emit a warning. + + Companion to the empty-tools test above. When the user supplies actual + runtime tools while use_latest_version=True, the client should warn that + the tools differ from the agent's creation-time configuration. + """ + client = create_test_azure_ai_client( + mock_project_client, agent_name="existing-agent", use_latest_version=True + ) + + # Mock existing agent + mock_existing_agent = MagicMock() + mock_existing_agent.name = "existing-agent" + mock_existing_agent.versions.latest.version = "2.5" + mock_project_client.agents.get = AsyncMock(return_value=mock_existing_agent) + + messages = [Message(role="user", contents=[Content.from_text(text="Hello")])] + + non_empty_tools = [{"type": "function", "function": {"name": "my_tool"}}] + + with ( + patch( + "agent_framework.openai._responses_client.RawOpenAIResponsesClient._prepare_options", + return_value={"model": "test-model", "tools": non_empty_tools}, + ), + patch("agent_framework_azure_ai._client.logger.warning") as mock_warning, + ): + # First call fetches the latest version + await client._prepare_options(messages, {}) + # Subsequent call with non-empty tools — SHOULD warn + await client._prepare_options(messages, {}) + + mock_warning.assert_called() + + async def test_use_latest_version_agent_not_found( mock_project_client: MagicMock, ) -> None: From 17ad30c4925cd22689ac69344c92ae464bb0e694 Mon Sep 17 00:00:00 2001 From: Josh Garrison Date: Thu, 26 Mar 2026 20:33:45 -0700 Subject: [PATCH 4/4] style: run prek hooks per review feedback --- python/packages/azure-ai/tests/test_azure_ai_client.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/python/packages/azure-ai/tests/test_azure_ai_client.py b/python/packages/azure-ai/tests/test_azure_ai_client.py index 2ce8d1f82d..7900d439a5 100644 --- a/python/packages/azure-ai/tests/test_azure_ai_client.py +++ b/python/packages/azure-ai/tests/test_azure_ai_client.py @@ -925,9 +925,7 @@ async def test_use_latest_version_no_spurious_warning_for_empty_tools( actually being overridden. Regression test for https://github.com/microsoft/agent-framework/issues/4681 """ - client = create_test_azure_ai_client( - mock_project_client, agent_name="existing-agent", use_latest_version=True - ) + client = create_test_azure_ai_client(mock_project_client, agent_name="existing-agent", use_latest_version=True) # Mock existing agent mock_existing_agent = MagicMock() @@ -962,9 +960,7 @@ async def test_use_latest_version_warns_for_non_empty_tools( runtime tools while use_latest_version=True, the client should warn that the tools differ from the agent's creation-time configuration. """ - client = create_test_azure_ai_client( - mock_project_client, agent_name="existing-agent", use_latest_version=True - ) + client = create_test_azure_ai_client(mock_project_client, agent_name="existing-agent", use_latest_version=True) # Mock existing agent mock_existing_agent = MagicMock()