77from uipath_langchain_client .base_client import UiPathBaseChatModel
88from uipath_langchain_client .clients .openai .utils import fix_url_and_api_flavor_header
99from uipath_langchain_client .settings import (
10+ ApiFlavor ,
1011 ApiType ,
1112 RoutingMode ,
1213 UiPathAPIConfig ,
@@ -31,6 +32,7 @@ class UiPathChatOpenAI(UiPathBaseChatModel, ChatOpenAI): # type: ignore[overrid
3132 api_version = "2025-03-01-preview" ,
3233 freeze_base_url = False ,
3334 )
35+ api_flavor : ApiFlavor | str | None = None
3436
3537 # Override fields to avoid errors when instantiating the class
3638 openai_api_key : SecretStr | None | Callable [[], str ] | Callable [[], Awaitable [str ]] = Field (
@@ -39,13 +41,24 @@ class UiPathChatOpenAI(UiPathBaseChatModel, ChatOpenAI): # type: ignore[overrid
3941
4042 @model_validator (mode = "after" )
4143 def setup_uipath_client (self ) -> Self :
44+ if self .api_flavor is not None :
45+ self .api_config .api_flavor = self .api_flavor
46+ # Lock LangChain's use_responses_api to match the discovered flavor.
47+ # Without this, features like reasoning={} or certain model names
48+ # silently switch LangChain to the Responses API, which would fail
49+ # if the model only supports chat-completions (or vice versa).
50+ if self .api_flavor == ApiFlavor .CHAT_COMPLETIONS :
51+ self .use_responses_api = False
52+ elif self .api_flavor == ApiFlavor .RESPONSES :
53+ self .use_responses_api = True
4254 base_url = str (self .uipath_sync_client .base_url ).rstrip ("/" )
55+ locked_flavor = str (self .api_config .api_flavor ) if self .api_config .api_flavor else None
4356
4457 def on_request (request : Request ) -> None :
45- fix_url_and_api_flavor_header (base_url , request )
58+ fix_url_and_api_flavor_header (base_url , request , api_flavor = locked_flavor )
4659
4760 async def on_request_async (request : Request ) -> None :
48- fix_url_and_api_flavor_header (base_url , request )
61+ fix_url_and_api_flavor_header (base_url , request , api_flavor = locked_flavor )
4962
5063 self .uipath_sync_client .event_hooks ["request" ].append (on_request )
5164 self .uipath_async_client .event_hooks ["request" ].append (on_request_async )
@@ -75,6 +88,7 @@ class UiPathAzureChatOpenAI(UiPathBaseChatModel, AzureChatOpenAI): # type: igno
7588 api_version = "2025-03-01-preview" ,
7689 freeze_base_url = False ,
7790 )
91+ api_flavor : ApiFlavor | str | None = None
7892
7993 # Override fields to avoid errors when instantiating the class
8094 azure_endpoint : str | None = Field (default = "PLACEHOLDER" )
@@ -83,13 +97,20 @@ class UiPathAzureChatOpenAI(UiPathBaseChatModel, AzureChatOpenAI): # type: igno
8397
8498 @model_validator (mode = "after" )
8599 def setup_uipath_client (self ) -> Self :
100+ if self .api_flavor is not None :
101+ self .api_config .api_flavor = self .api_flavor
102+ if self .api_flavor == ApiFlavor .CHAT_COMPLETIONS :
103+ self .use_responses_api = False
104+ elif self .api_flavor == ApiFlavor .RESPONSES :
105+ self .use_responses_api = True
86106 base_url = str (self .uipath_sync_client .base_url ).rstrip ("/" )
107+ locked_flavor = str (self .api_config .api_flavor ) if self .api_config .api_flavor else None
87108
88109 def on_request (request : Request ) -> None :
89- fix_url_and_api_flavor_header (base_url , request )
110+ fix_url_and_api_flavor_header (base_url , request , api_flavor = locked_flavor )
90111
91112 async def on_request_async (request : Request ) -> None :
92- fix_url_and_api_flavor_header (base_url , request )
113+ fix_url_and_api_flavor_header (base_url , request , api_flavor = locked_flavor )
93114
94115 self .uipath_sync_client .event_hooks ["request" ].append (on_request )
95116 self .uipath_async_client .event_hooks ["request" ].append (on_request_async )
0 commit comments