22
33import sys
44from collections .abc import Mapping , MutableSequence
5- from typing import Any , ClassVar , TypeVar
5+ from typing import Any , ClassVar , TypeVar , cast
66
77from agent_framework import (
88 AGENT_FRAMEWORK_USER_AGENT ,
@@ -379,6 +379,15 @@ async def _prepare_options(
379379 """Take ChatOptions and create the specific options for Azure AI."""
380380 prepared_messages , instructions = self ._prepare_messages_for_azure_ai (messages )
381381 run_options = await super ()._prepare_options (prepared_messages , chat_options , ** kwargs )
382+
383+ # WORKAROUND: Azure AI Projects 'create responses' API has schema divergence from OpenAI's
384+ # Responses API. Azure requires 'type' at item level and 'annotations' in content items.
385+ # See: https://github.com/Azure/azure-sdk-for-python/issues/44493
386+ # See: https://github.com/microsoft/agent-framework/issues/2926
387+ # TODO(agent-framework#2926): Remove this workaround when Azure SDK aligns with OpenAI schema.
388+ if "input" in run_options and isinstance (run_options ["input" ], list ):
389+ run_options ["input" ] = self ._transform_input_for_azure_ai (cast (list [dict [str , Any ]], run_options ["input" ]))
390+
382391 if not self ._is_application_endpoint :
383392 # Application-scoped response APIs do not support "agent" property.
384393 agent_reference = await self ._get_agent_reference_or_create (run_options , instructions )
@@ -393,6 +402,44 @@ async def _prepare_options(
393402
394403 return run_options
395404
405+ def _transform_input_for_azure_ai (self , input_items : list [dict [str , Any ]]) -> list [dict [str , Any ]]:
406+ """Transform input items to match Azure AI Projects expected schema.
407+
408+ WORKAROUND: Azure AI Projects 'create responses' API expects a different schema than OpenAI's
409+ Responses API. Azure requires 'type' at the item level, and requires 'annotations'
410+ only for output_text content items (assistant messages), not for input_text content items
411+ (user messages). This helper adapts the OpenAI-style input to the Azure schema.
412+
413+ See: https://github.com/Azure/azure-sdk-for-python/issues/44493
414+ TODO(agent-framework#2926): Remove when Azure SDK aligns with OpenAI schema.
415+ """
416+ transformed : list [dict [str , Any ]] = []
417+ for item in input_items :
418+ new_item : dict [str , Any ] = dict (item )
419+
420+ # Add 'type': 'message' at item level for role-based items
421+ if "role" in new_item and "type" not in new_item :
422+ new_item ["type" ] = "message"
423+
424+ # Add 'annotations' only to output_text content items (assistant messages)
425+ # User messages (input_text) do NOT support annotations in Azure AI
426+ if "content" in new_item and isinstance (new_item ["content" ], list ):
427+ new_content : list [dict [str , Any ] | Any ] = []
428+ for content_item in new_item ["content" ]:
429+ if isinstance (content_item , dict ):
430+ new_content_item : dict [str , Any ] = dict (content_item )
431+ # Only add annotations to output_text (assistant content)
432+ if new_content_item .get ("type" ) == "output_text" and "annotations" not in new_content_item :
433+ new_content_item ["annotations" ] = []
434+ new_content .append (new_content_item )
435+ else :
436+ new_content .append (content_item )
437+ new_item ["content" ] = new_content
438+
439+ transformed .append (new_item )
440+
441+ return transformed
442+
396443 @override
397444 def _get_current_conversation_id (self , chat_options : ChatOptions , ** kwargs : Any ) -> str | None :
398445 """Get the current conversation ID from chat options or kwargs."""
0 commit comments