1111
1212import json
1313import logging
14+ import os
1415import sys
1516from collections .abc import Mapping , Sequence
17+ from contextlib import contextmanager
1618from copy import copy
1719from typing import TYPE_CHECKING , Any , ClassVar , Final , Generic , cast
1820from urllib .parse import urljoin , urlparse
@@ -109,6 +111,39 @@ def _apply_azure_defaults(
109111 settings ["token_endpoint" ] = default_token_endpoint
110112
111113
114+ @contextmanager
115+ def _prefer_single_azure_endpoint_env (* , endpoint : str | None , base_url : str | None ) -> Any :
116+ """Temporarily expose only the Azure endpoint setting that raw OpenAI clients accept.
117+
118+ The deprecated Azure wrappers have historically tolerated both
119+ ``AZURE_OPENAI_BASE_URL`` and ``AZURE_OPENAI_ENDPOINT`` being present and prefer
120+ ``base_url`` when both are available. The raw OpenAI constructors now validate
121+ that exactly one is set, so we temporarily hide the unused env var while
122+ delegating to those constructors.
123+ """
124+ original_base_url = os .environ .get ("AZURE_OPENAI_BASE_URL" )
125+ original_endpoint = os .environ .get ("AZURE_OPENAI_ENDPOINT" )
126+
127+ try :
128+ if base_url :
129+ os .environ ["AZURE_OPENAI_BASE_URL" ] = str (base_url )
130+ os .environ .pop ("AZURE_OPENAI_ENDPOINT" , None )
131+ elif endpoint :
132+ os .environ ["AZURE_OPENAI_ENDPOINT" ] = str (endpoint )
133+ os .environ .pop ("AZURE_OPENAI_BASE_URL" , None )
134+ yield
135+ finally :
136+ if original_base_url is None :
137+ os .environ .pop ("AZURE_OPENAI_BASE_URL" , None )
138+ else :
139+ os .environ ["AZURE_OPENAI_BASE_URL" ] = original_base_url
140+
141+ if original_endpoint is None :
142+ os .environ .pop ("AZURE_OPENAI_ENDPOINT" , None )
143+ else :
144+ os .environ ["AZURE_OPENAI_ENDPOINT" ] = original_endpoint
145+
146+
112147# endregion
113148
114149
@@ -315,6 +350,8 @@ def __init__(
315350 "or 'AZURE_OPENAI_RESPONSES_DEPLOYMENT_NAME' environment variable."
316351 )
317352
353+ endpoint_value = azure_openai_settings .get ("endpoint" )
354+ client_base_url = azure_openai_settings .get ("base_url" )
318355 if not async_client :
319356 # Create the Azure OpenAI client directly
320357 merged_headers = dict (copy (default_headers )) if default_headers else {}
@@ -332,9 +369,7 @@ def __init__(
332369 if not api_key_secret and not ad_token_provider :
333370 raise ValueError ("Please provide either api_key, credential, or a client." )
334371
335- client_endpoint = azure_openai_settings .get ("endpoint" )
336- client_base_url = azure_openai_settings .get ("base_url" )
337- if not client_endpoint and not client_base_url :
372+ if not endpoint_value and not client_base_url :
338373 raise ValueError ("Please provide an endpoint or a base_url" )
339374
340375 client_args : dict [str , Any ] = {"default_headers" : merged_headers }
@@ -346,8 +381,8 @@ def __init__(
346381 client_args ["api_key" ] = api_key_secret .get_secret_value ()
347382 if client_base_url :
348383 client_args ["base_url" ] = str (client_base_url )
349- if client_endpoint and not client_base_url :
350- client_args ["azure_endpoint" ] = str (client_endpoint )
384+ if endpoint_value and not client_base_url :
385+ client_args ["azure_endpoint" ] = str (endpoint_value )
351386 if responses_deployment_name :
352387 client_args ["azure_deployment" ] = responses_deployment_name
353388 if "websocket_base_url" in kwargs :
@@ -360,16 +395,17 @@ def __init__(
360395 self .api_version = azure_openai_settings .get ("api_version" ) or ""
361396 self .deployment_name = responses_deployment_name
362397
363- super ().__init__ (
364- async_client = async_client ,
365- model = responses_deployment_name ,
366- api_version = azure_openai_settings .get ("api_version" ),
367- instruction_role = instruction_role ,
368- default_headers = default_headers ,
369- middleware = middleware , # type: ignore[arg-type]
370- function_invocation_configuration = function_invocation_configuration ,
371- ** kwargs ,
372- )
398+ with _prefer_single_azure_endpoint_env (endpoint = endpoint_value , base_url = client_base_url ):
399+ super ().__init__ (
400+ async_client = async_client ,
401+ model = responses_deployment_name ,
402+ api_version = azure_openai_settings .get ("api_version" ),
403+ instruction_role = instruction_role ,
404+ default_headers = default_headers ,
405+ middleware = middleware , # type: ignore[arg-type]
406+ function_invocation_configuration = function_invocation_configuration ,
407+ ** kwargs ,
408+ )
373409
374410 @staticmethod
375411 def _create_client_from_project (
@@ -530,6 +566,8 @@ def __init__(
530566 "or 'AZURE_OPENAI_CHAT_DEPLOYMENT_NAME' environment variable."
531567 )
532568
569+ endpoint_value = azure_openai_settings .get ("endpoint" )
570+ base_url_value = azure_openai_settings .get ("base_url" )
533571 if not async_client :
534572 # Create the Azure OpenAI client directly
535573 merged_headers = dict (copy (default_headers )) if default_headers else {}
@@ -547,8 +585,6 @@ def __init__(
547585 if not api_key_secret and not ad_token_provider :
548586 raise ValueError ("Please provide either api_key, credential, or a client." )
549587
550- endpoint_value = azure_openai_settings .get ("endpoint" )
551- base_url_value = azure_openai_settings .get ("base_url" )
552588 if not endpoint_value and not base_url_value :
553589 raise ValueError ("Please provide an endpoint or a base_url" )
554590
@@ -573,16 +609,17 @@ def __init__(
573609 self .api_version = azure_openai_settings .get ("api_version" ) or ""
574610 self .deployment_name = chat_deployment_name
575611
576- super ().__init__ (
577- async_client = async_client ,
578- model = chat_deployment_name ,
579- api_version = azure_openai_settings .get ("api_version" ),
580- instruction_role = instruction_role ,
581- default_headers = default_headers ,
582- additional_properties = additional_properties ,
583- middleware = middleware , # type: ignore[arg-type]
584- function_invocation_configuration = function_invocation_configuration ,
585- )
612+ with _prefer_single_azure_endpoint_env (endpoint = endpoint_value , base_url = base_url_value ):
613+ super ().__init__ (
614+ async_client = async_client ,
615+ model = chat_deployment_name ,
616+ api_version = azure_openai_settings .get ("api_version" ),
617+ instruction_role = instruction_role ,
618+ default_headers = default_headers ,
619+ additional_properties = additional_properties ,
620+ middleware = middleware , # type: ignore[arg-type]
621+ function_invocation_configuration = function_invocation_configuration ,
622+ )
586623
587624 @override
588625 def _parse_text_from_openai (self , choice : Choice | ChunkChoice ) -> Content | None :
0 commit comments