From 84c20ce87d926430403ae8d560c99dedc78ed710 Mon Sep 17 00:00:00 2001 From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Date: Fri, 16 Jan 2026 15:03:41 -0800 Subject: [PATCH 1/2] Fixed Azure chat client for asynchronous filtering --- .../agent_framework/azure/_chat_client.py | 3 ++ .../tests/azure/test_azure_chat_client.py | 38 +++++++++++++++++++ 2 files changed, 41 insertions(+) diff --git a/python/packages/core/agent_framework/azure/_chat_client.py b/python/packages/core/agent_framework/azure/_chat_client.py index 248e79ee47..82d16f8f15 100644 --- a/python/packages/core/agent_framework/azure/_chat_client.py +++ b/python/packages/core/agent_framework/azure/_chat_client.py @@ -275,6 +275,9 @@ def _parse_text_from_openai(self, choice: Choice | ChunkChoice) -> TextContent | https://learn.microsoft.com/en-us/azure/ai-foundry/openai/references/on-your-data?tabs=python#context """ message = choice.message if isinstance(choice, Choice) else choice.delta + # When you enable asynchronous content filtering in Azure OpenAI, you may receive empty deltas + if message is None: + return None if hasattr(message, "refusal") and message.refusal: return TextContent(text=message.refusal, raw_representation=choice) if not message.content: diff --git a/python/packages/core/tests/azure/test_azure_chat_client.py b/python/packages/core/tests/azure/test_azure_chat_client.py index 483b13f14f..391b05f8b8 100644 --- a/python/packages/core/tests/azure/test_azure_chat_client.py +++ b/python/packages/core/tests/azure/test_azure_chat_client.py @@ -592,6 +592,44 @@ async def test_get_streaming( ) +@patch.object(AsyncChatCompletions, "create", new_callable=AsyncMock) +async def test_streaming_with_none_delta( + mock_create: AsyncMock, + azure_openai_unit_test_env: dict[str, str], + chat_history: list[ChatMessage], +) -> None: + """Test streaming handles None delta from async content filtering.""" + # First chunk has None delta (simulates async filtering) + chunk_choice_with_none = ChunkChoice.model_construct(index=0, delta=None, finish_reason=None) + chunk_with_none_delta = ChatCompletionChunk.model_construct( + id="test_id", + choices=[chunk_choice_with_none], + created=0, + model="test", + object="chat.completion.chunk", + ) + # Second chunk has actual content + chunk_with_content = ChatCompletionChunk( + id="test_id", + choices=[ChunkChoice(index=0, delta=ChunkChoiceDelta(content="test", role="assistant"), finish_reason="stop")], + created=0, + model="test", + object="chat.completion.chunk", + ) + stream = MagicMock(spec=AsyncStream) + stream.__aiter__.return_value = [chunk_with_none_delta, chunk_with_content] + mock_create.return_value = stream + + chat_history.append(ChatMessage(text="hello world", role="user")) + azure_chat_client = AzureOpenAIChatClient() + + results: list[ChatResponseUpdate] = [] + async for msg in azure_chat_client.get_streaming_response(messages=chat_history): + results.append(msg) + + assert len(results) > 0 + + @ai_function def get_story_text() -> str: """Returns a story about Emily and David.""" From 5210d3a64c6f3c1d888b404c4796ead12c2d1467 Mon Sep 17 00:00:00 2001 From: Dmytro Struk <13853051+dmytrostruk@users.noreply.github.com> Date: Fri, 16 Jan 2026 16:18:28 -0800 Subject: [PATCH 2/2] Updated test --- python/packages/core/agent_framework/azure/_chat_client.py | 2 +- python/packages/core/tests/azure/test_azure_chat_client.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/python/packages/core/agent_framework/azure/_chat_client.py b/python/packages/core/agent_framework/azure/_chat_client.py index 82d16f8f15..164ae9040c 100644 --- a/python/packages/core/agent_framework/azure/_chat_client.py +++ b/python/packages/core/agent_framework/azure/_chat_client.py @@ -276,7 +276,7 @@ def _parse_text_from_openai(self, choice: Choice | ChunkChoice) -> TextContent | """ message = choice.message if isinstance(choice, Choice) else choice.delta # When you enable asynchronous content filtering in Azure OpenAI, you may receive empty deltas - if message is None: + if message is None: # type: ignore return None if hasattr(message, "refusal") and message.refusal: return TextContent(text=message.refusal, raw_representation=choice) diff --git a/python/packages/core/tests/azure/test_azure_chat_client.py b/python/packages/core/tests/azure/test_azure_chat_client.py index 391b05f8b8..3e9a3a5042 100644 --- a/python/packages/core/tests/azure/test_azure_chat_client.py +++ b/python/packages/core/tests/azure/test_azure_chat_client.py @@ -628,6 +628,10 @@ async def test_streaming_with_none_delta( results.append(msg) assert len(results) > 0 + assert any( + isinstance(content, TextContent) and content.text == "test" for msg in results for content in msg.contents + ) + assert any(msg.contents for msg in results) @ai_function