uipath-langchain 0.1.24__py3-none-any.whl → 0.1.34__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. uipath_langchain/_utils/_request_mixin.py +8 -0
  2. uipath_langchain/_utils/_settings.py +3 -2
  3. uipath_langchain/agent/guardrails/__init__.py +0 -16
  4. uipath_langchain/agent/guardrails/actions/__init__.py +2 -0
  5. uipath_langchain/agent/guardrails/actions/base_action.py +1 -0
  6. uipath_langchain/agent/guardrails/actions/block_action.py +2 -1
  7. uipath_langchain/agent/guardrails/actions/escalate_action.py +243 -35
  8. uipath_langchain/agent/guardrails/actions/filter_action.py +55 -0
  9. uipath_langchain/agent/guardrails/actions/log_action.py +2 -1
  10. uipath_langchain/agent/guardrails/guardrail_nodes.py +186 -22
  11. uipath_langchain/agent/guardrails/guardrails_factory.py +200 -4
  12. uipath_langchain/agent/guardrails/types.py +0 -12
  13. uipath_langchain/agent/guardrails/utils.py +146 -0
  14. uipath_langchain/agent/react/agent.py +25 -8
  15. uipath_langchain/agent/react/constants.py +1 -2
  16. uipath_langchain/agent/{guardrails → react/guardrails}/guardrails_subgraph.py +94 -19
  17. uipath_langchain/agent/react/llm_node.py +41 -10
  18. uipath_langchain/agent/react/router.py +48 -37
  19. uipath_langchain/agent/react/types.py +15 -1
  20. uipath_langchain/agent/react/utils.py +1 -1
  21. uipath_langchain/agent/tools/__init__.py +2 -0
  22. uipath_langchain/agent/tools/mcp_tool.py +86 -0
  23. uipath_langchain/chat/__init__.py +4 -0
  24. uipath_langchain/chat/bedrock.py +16 -0
  25. uipath_langchain/chat/openai.py +57 -26
  26. uipath_langchain/chat/supported_models.py +9 -0
  27. uipath_langchain/chat/vertex.py +271 -0
  28. uipath_langchain/embeddings/embeddings.py +18 -12
  29. uipath_langchain/runtime/schema.py +116 -23
  30. {uipath_langchain-0.1.24.dist-info → uipath_langchain-0.1.34.dist-info}/METADATA +9 -6
  31. {uipath_langchain-0.1.24.dist-info → uipath_langchain-0.1.34.dist-info}/RECORD +34 -31
  32. uipath_langchain/chat/gemini.py +0 -330
  33. {uipath_langchain-0.1.24.dist-info → uipath_langchain-0.1.34.dist-info}/WHEEL +0 -0
  34. {uipath_langchain-0.1.24.dist-info → uipath_langchain-0.1.34.dist-info}/entry_points.txt +0 -0
  35. {uipath_langchain-0.1.24.dist-info → uipath_langchain-0.1.34.dist-info}/licenses/LICENSE +0 -0
@@ -48,10 +48,14 @@ class AwsBedrockCompletionsPassthroughClient:
48
48
  model: str,
49
49
  token: str,
50
50
  api_flavor: str,
51
+ agenthub_config: Optional[str] = None,
52
+ byo_connection_id: Optional[str] = None,
51
53
  ):
52
54
  self.model = model
53
55
  self.token = token
54
56
  self.api_flavor = api_flavor
57
+ self.agenthub_config = agenthub_config
58
+ self.byo_connection_id = byo_connection_id
55
59
  self._vendor = "awsbedrock"
56
60
  self._url: Optional[str] = None
57
61
 
@@ -101,6 +105,10 @@ class AwsBedrockCompletionsPassthroughClient:
101
105
  "X-UiPath-Streaming-Enabled": streaming,
102
106
  }
103
107
 
108
+ if self.agenthub_config:
109
+ headers["X-UiPath-AgentHub-Config"] = self.agenthub_config
110
+ if self.byo_connection_id:
111
+ headers["X-UiPath-LlmGateway-ByoIsConnectionId"] = self.byo_connection_id
104
112
  job_key = os.getenv("UIPATH_JOB_KEY")
105
113
  process_key = os.getenv("UIPATH_PROCESS_KEY")
106
114
  if job_key:
@@ -118,6 +126,8 @@ class UiPathChatBedrockConverse(ChatBedrockConverse):
118
126
  tenant_id: Optional[str] = None,
119
127
  token: Optional[str] = None,
120
128
  model_name: str = BedrockModels.anthropic_claude_haiku_4_5,
129
+ agenthub_config: Optional[str] = None,
130
+ byo_connection_id: Optional[str] = None,
121
131
  **kwargs,
122
132
  ):
123
133
  org_id = org_id or os.getenv("UIPATH_ORGANIZATION_ID")
@@ -141,6 +151,8 @@ class UiPathChatBedrockConverse(ChatBedrockConverse):
141
151
  model=model_name,
142
152
  token=token,
143
153
  api_flavor="converse",
154
+ agenthub_config=agenthub_config,
155
+ byo_connection_id=byo_connection_id,
144
156
  )
145
157
 
146
158
  client = passthrough_client.get_client()
@@ -156,6 +168,8 @@ class UiPathChatBedrock(ChatBedrock):
156
168
  tenant_id: Optional[str] = None,
157
169
  token: Optional[str] = None,
158
170
  model_name: str = BedrockModels.anthropic_claude_haiku_4_5,
171
+ agenthub_config: Optional[str] = None,
172
+ byo_connection_id: Optional[str] = None,
159
173
  **kwargs,
160
174
  ):
161
175
  org_id = org_id or os.getenv("UIPATH_ORGANIZATION_ID")
@@ -179,6 +193,8 @@ class UiPathChatBedrock(ChatBedrock):
179
193
  model=model_name,
180
194
  token=token,
181
195
  api_flavor="invoke",
196
+ agenthub_config=agenthub_config,
197
+ byo_connection_id=byo_connection_id,
182
198
  )
183
199
 
184
200
  client = passthrough_client.get_client()
@@ -4,6 +4,7 @@ from typing import Optional
4
4
 
5
5
  import httpx
6
6
  from langchain_openai import AzureChatOpenAI
7
+ from uipath._utils._ssl_context import get_httpx_client_kwargs
7
8
  from uipath.utils import EndpointManager
8
9
 
9
10
  from .supported_models import OpenAIModels
@@ -11,21 +12,41 @@ from .supported_models import OpenAIModels
11
12
  logger = logging.getLogger(__name__)
12
13
 
13
14
 
15
+ def _rewrite_openai_url(
16
+ original_url: str, params: httpx.QueryParams
17
+ ) -> httpx.URL | None:
18
+ """Rewrite OpenAI URLs to UiPath gateway completions endpoint.
19
+
20
+ Handles three URL patterns:
21
+ - responses: false -> .../openai/deployments/.../chat/completions?api-version=...
22
+ - responses: true -> .../openai/responses?api-version=...
23
+ - responses API base -> .../{model}?api-version=... (no /openai/ path)
24
+
25
+ All are rewritten to .../completions
26
+ """
27
+ if "/openai/deployments/" in original_url:
28
+ base_url = original_url.split("/openai/deployments/")[0]
29
+ elif "/openai/responses" in original_url:
30
+ base_url = original_url.split("/openai/responses")[0]
31
+ else:
32
+ # Handle base URL case (no /openai/ path appended yet)
33
+ # Strip query string to get base URL
34
+ base_url = original_url.split("?")[0]
35
+
36
+ new_url_str = f"{base_url}/completions"
37
+ if params:
38
+ return httpx.URL(new_url_str, params=params)
39
+ return httpx.URL(new_url_str)
40
+
41
+
14
42
  class UiPathURLRewriteTransport(httpx.AsyncHTTPTransport):
15
43
  def __init__(self, verify: bool = True, **kwargs):
16
44
  super().__init__(verify=verify, **kwargs)
17
45
 
18
46
  async def handle_async_request(self, request: httpx.Request) -> httpx.Response:
19
- original_url = str(request.url)
20
-
21
- if "/openai/deployments/" in original_url:
22
- base_url = original_url.split("/openai/deployments/")[0]
23
- query_string = request.url.params
24
- new_url_str = f"{base_url}/completions"
25
- if query_string:
26
- request.url = httpx.URL(new_url_str, params=query_string)
27
- else:
28
- request.url = httpx.URL(new_url_str)
47
+ new_url = _rewrite_openai_url(str(request.url), request.url.params)
48
+ if new_url:
49
+ request.url = new_url
29
50
 
30
51
  return await super().handle_async_request(request)
31
52
 
@@ -35,16 +56,9 @@ class UiPathSyncURLRewriteTransport(httpx.HTTPTransport):
35
56
  super().__init__(verify=verify, **kwargs)
36
57
 
37
58
  def handle_request(self, request: httpx.Request) -> httpx.Response:
38
- original_url = str(request.url)
39
-
40
- if "/openai/deployments/" in original_url:
41
- base_url = original_url.split("/openai/deployments/")[0]
42
- query_string = request.url.params
43
- new_url_str = f"{base_url}/completions"
44
- if query_string:
45
- request.url = httpx.URL(new_url_str, params=query_string)
46
- else:
47
- request.url = httpx.URL(new_url_str)
59
+ new_url = _rewrite_openai_url(str(request.url), request.url.params)
60
+ if new_url:
61
+ request.url = new_url
48
62
 
49
63
  return super().handle_request(request)
50
64
 
@@ -57,6 +71,9 @@ class UiPathChatOpenAI(AzureChatOpenAI):
57
71
  api_version: str = "2024-12-01-preview",
58
72
  org_id: Optional[str] = None,
59
73
  tenant_id: Optional[str] = None,
74
+ agenthub_config: Optional[str] = None,
75
+ extra_headers: Optional[dict[str, str]] = None,
76
+ byo_connection_id: Optional[str] = None,
60
77
  **kwargs,
61
78
  ):
62
79
  org_id = org_id or os.getenv("UIPATH_ORGANIZATION_ID")
@@ -80,18 +97,24 @@ class UiPathChatOpenAI(AzureChatOpenAI):
80
97
  self._vendor = "openai"
81
98
  self._model_name = model_name
82
99
  self._url: Optional[str] = None
100
+ self._agenthub_config = agenthub_config
101
+ self._byo_connection_id = byo_connection_id
102
+ self._extra_headers = extra_headers or {}
103
+
104
+ client_kwargs = get_httpx_client_kwargs()
105
+ verify = client_kwargs.get("verify", True)
83
106
 
84
107
  super().__init__(
85
108
  azure_endpoint=self._build_base_url(),
86
109
  model_name=model_name,
87
110
  default_headers=self._build_headers(token),
88
111
  http_async_client=httpx.AsyncClient(
89
- transport=UiPathURLRewriteTransport(verify=True),
90
- verify=True,
112
+ transport=UiPathURLRewriteTransport(verify=verify),
113
+ **client_kwargs,
91
114
  ),
92
115
  http_client=httpx.Client(
93
- transport=UiPathSyncURLRewriteTransport(verify=True),
94
- verify=True,
116
+ transport=UiPathSyncURLRewriteTransport(verify=verify),
117
+ **client_kwargs,
95
118
  ),
96
119
  api_key=token,
97
120
  api_version=api_version,
@@ -104,10 +127,18 @@ class UiPathChatOpenAI(AzureChatOpenAI):
104
127
  "X-UiPath-LlmGateway-ApiFlavor": "auto",
105
128
  "Authorization": f"Bearer {token}",
106
129
  }
130
+
131
+ if self._agenthub_config:
132
+ headers["X-UiPath-AgentHub-Config"] = self._agenthub_config
133
+ if self._byo_connection_id:
134
+ headers["X-UiPath-LlmGateway-ByoIsConnectionId"] = self._byo_connection_id
107
135
  if job_key := os.getenv("UIPATH_JOB_KEY"):
108
136
  headers["X-UiPath-JobKey"] = job_key
109
137
  if process_key := os.getenv("UIPATH_PROCESS_KEY"):
110
138
  headers["X-UiPath-ProcessKey"] = process_key
139
+
140
+ # Allow extra_headers to override defaults
141
+ headers.update(self._extra_headers)
111
142
  return headers
112
143
 
113
144
  @property
@@ -116,9 +147,9 @@ class UiPathChatOpenAI(AzureChatOpenAI):
116
147
  formatted_endpoint = vendor_endpoint.format(
117
148
  vendor=self._vendor,
118
149
  model=self._model_name,
119
- api_version=self._openai_api_version,
120
150
  )
121
- return formatted_endpoint.replace("/completions", "")
151
+ base_endpoint = formatted_endpoint.replace("/completions", "")
152
+ return f"{base_endpoint}?api-version={self._openai_api_version}"
122
153
 
123
154
  def _build_base_url(self) -> str:
124
155
  if not self._url:
@@ -21,14 +21,21 @@ class OpenAIModels:
21
21
  # GPT-5.1 models
22
22
  gpt_5_1_2025_11_13 = "gpt-5.1-2025-11-13"
23
23
 
24
+ # GPT-5.2 models
25
+ gpt_5_2_2025_12_11 = "gpt-5.2-2025-12-11"
26
+
24
27
 
25
28
  class GeminiModels:
26
29
  """Supported Google Gemini model identifiers."""
27
30
 
31
+ # Gemini 2 models
28
32
  gemini_2_5_pro = "gemini-2.5-pro"
29
33
  gemini_2_5_flash = "gemini-2.5-flash"
30
34
  gemini_2_0_flash_001 = "gemini-2.0-flash-001"
31
35
 
36
+ # Gemini 3 models
37
+ gemini_3_pro_preview = "gemini-3-pro-preview"
38
+
32
39
 
33
40
  class BedrockModels:
34
41
  """Supported AWS Bedrock model identifiers."""
@@ -38,5 +45,7 @@ class BedrockModels:
38
45
 
39
46
  # Claude 4 models
40
47
  anthropic_claude_sonnet_4 = "anthropic.claude-sonnet-4-20250514-v1:0"
48
+
49
+ # Claude 4.5 models
41
50
  anthropic_claude_sonnet_4_5 = "anthropic.claude-sonnet-4-5-20250929-v1:0"
42
51
  anthropic_claude_haiku_4_5 = "anthropic.claude-haiku-4-5-20251001-v1:0"
@@ -0,0 +1,271 @@
1
+ import os
2
+ from typing import Any, Optional
3
+
4
+ import httpx
5
+ from uipath._utils._ssl_context import get_httpx_client_kwargs
6
+ from uipath.utils import EndpointManager
7
+
8
+ from .supported_models import GeminiModels
9
+
10
+
11
+ def _check_genai_dependencies() -> None:
12
+ """Check if required dependencies for UiPathChatVertex are installed."""
13
+ import importlib.util
14
+
15
+ missing_packages = []
16
+
17
+ if importlib.util.find_spec("langchain_google_genai") is None:
18
+ missing_packages.append("langchain-google-genai")
19
+
20
+ if importlib.util.find_spec("google.genai") is None:
21
+ missing_packages.append("google-genai")
22
+
23
+ if missing_packages:
24
+ packages_str = ", ".join(missing_packages)
25
+ raise ImportError(
26
+ f"The following packages are required to use UiPathChatVertex: {packages_str}\n"
27
+ "Please install them using one of the following methods:\n\n"
28
+ " # Using pip:\n"
29
+ f" pip install uipath-langchain[vertex]\n\n"
30
+ " # Using uv:\n"
31
+ f" uv add 'uipath-langchain[vertex]'\n\n"
32
+ )
33
+
34
+
35
+ _check_genai_dependencies()
36
+
37
+ import google.genai
38
+ from google.genai import types as genai_types
39
+ from langchain_google_genai import ChatGoogleGenerativeAI
40
+ from pydantic import PrivateAttr
41
+
42
+
43
+ def _rewrite_vertex_url(original_url: str, gateway_url: str) -> httpx.URL | None:
44
+ """Rewrite Google GenAI URLs to UiPath gateway endpoint.
45
+
46
+ Handles URL patterns containing generateContent or streamGenerateContent.
47
+ Returns the gateway URL, or None if no rewrite needed.
48
+ """
49
+ if "generateContent" in original_url or "streamGenerateContent" in original_url:
50
+ return httpx.URL(gateway_url)
51
+ return None
52
+
53
+
54
+ class _UrlRewriteTransport(httpx.HTTPTransport):
55
+ """Transport that rewrites URLs to redirect to UiPath gateway."""
56
+
57
+ def __init__(self, gateway_url: str, verify: bool = True):
58
+ super().__init__(verify=verify)
59
+ self.gateway_url = gateway_url
60
+
61
+ def handle_request(self, request: httpx.Request) -> httpx.Response:
62
+ original_url = str(request.url)
63
+ new_url = _rewrite_vertex_url(original_url, self.gateway_url)
64
+ if new_url:
65
+ # Set streaming header based on original URL before modifying
66
+ is_streaming = "alt=sse" in original_url
67
+ request.headers["X-UiPath-Streaming-Enabled"] = (
68
+ "true" if is_streaming else "false"
69
+ )
70
+ # Update host header to match the new URL
71
+ request.headers["host"] = new_url.host
72
+ request.url = new_url
73
+ return super().handle_request(request)
74
+
75
+
76
+ class _AsyncUrlRewriteTransport(httpx.AsyncHTTPTransport):
77
+ """Async transport that rewrites URLs to redirect to UiPath gateway."""
78
+
79
+ def __init__(self, gateway_url: str, verify: bool = True):
80
+ super().__init__(verify=verify)
81
+ self.gateway_url = gateway_url
82
+
83
+ async def handle_async_request(self, request: httpx.Request) -> httpx.Response:
84
+ original_url = str(request.url)
85
+ new_url = _rewrite_vertex_url(original_url, self.gateway_url)
86
+ if new_url:
87
+ # Set streaming header based on original URL before modifying
88
+ is_streaming = "alt=sse" in original_url
89
+ request.headers["X-UiPath-Streaming-Enabled"] = (
90
+ "true" if is_streaming else "false"
91
+ )
92
+ # Update host header to match the new URL
93
+ request.headers["host"] = new_url.host
94
+ request.url = new_url
95
+ return await super().handle_async_request(request)
96
+
97
+
98
+ class UiPathChatVertex(ChatGoogleGenerativeAI):
99
+ """UiPath Vertex AI Chat model that routes requests through UiPath's LLM Gateway."""
100
+
101
+ _vendor: str = PrivateAttr(default="vertexai")
102
+ _model_name: str = PrivateAttr()
103
+ _uipath_token: str = PrivateAttr()
104
+ _uipath_llmgw_url: Optional[str] = PrivateAttr(default=None)
105
+ _agenthub_config: Optional[str] = PrivateAttr(default=None)
106
+ _byo_connection_id: Optional[str] = PrivateAttr(default=None)
107
+
108
+ def __init__(
109
+ self,
110
+ org_id: Optional[str] = None,
111
+ tenant_id: Optional[str] = None,
112
+ token: Optional[str] = None,
113
+ model_name: str = GeminiModels.gemini_2_5_flash,
114
+ temperature: Optional[float] = None,
115
+ agenthub_config: Optional[str] = None,
116
+ byo_connection_id: Optional[str] = None,
117
+ **kwargs: Any,
118
+ ):
119
+ org_id = org_id or os.getenv("UIPATH_ORGANIZATION_ID")
120
+ tenant_id = tenant_id or os.getenv("UIPATH_TENANT_ID")
121
+ token = token or os.getenv("UIPATH_ACCESS_TOKEN")
122
+
123
+ if not org_id:
124
+ raise ValueError(
125
+ "UIPATH_ORGANIZATION_ID environment variable or org_id parameter is required"
126
+ )
127
+ if not tenant_id:
128
+ raise ValueError(
129
+ "UIPATH_TENANT_ID environment variable or tenant_id parameter is required"
130
+ )
131
+ if not token:
132
+ raise ValueError(
133
+ "UIPATH_ACCESS_TOKEN environment variable or token parameter is required"
134
+ )
135
+
136
+ uipath_url = self._build_base_url(model_name)
137
+ headers = self._build_headers(token, agenthub_config, byo_connection_id)
138
+
139
+ client_kwargs = get_httpx_client_kwargs()
140
+ verify = client_kwargs.get("verify", True)
141
+
142
+ http_options = genai_types.HttpOptions(
143
+ httpx_client=httpx.Client(
144
+ transport=_UrlRewriteTransport(uipath_url, verify=verify),
145
+ headers=headers,
146
+ **client_kwargs,
147
+ ),
148
+ httpx_async_client=httpx.AsyncClient(
149
+ transport=_AsyncUrlRewriteTransport(uipath_url, verify=verify),
150
+ headers=headers,
151
+ **client_kwargs,
152
+ ),
153
+ )
154
+
155
+ if temperature is None and (
156
+ "gemini-3" in model_name or "gemini-2" in model_name
157
+ ):
158
+ temperature = 1.0
159
+
160
+ super().__init__(
161
+ model=model_name,
162
+ google_api_key="uipath-gateway",
163
+ temperature=temperature,
164
+ **kwargs,
165
+ )
166
+
167
+ custom_client = google.genai.Client(
168
+ api_key="uipath-gateway",
169
+ http_options=http_options,
170
+ )
171
+
172
+ object.__setattr__(self, "client", custom_client)
173
+
174
+ self._model_name = model_name
175
+ self._uipath_token = token
176
+ self._uipath_llmgw_url = uipath_url
177
+ self._agenthub_config = agenthub_config
178
+ self._byo_connection_id = byo_connection_id
179
+
180
+ if self.temperature is not None and not 0 <= self.temperature <= 2.0:
181
+ raise ValueError("temperature must be in the range [0.0, 2.0]")
182
+
183
+ if self.top_p is not None and not 0 <= self.top_p <= 1:
184
+ raise ValueError("top_p must be in the range [0.0, 1.0]")
185
+
186
+ if self.top_k is not None and self.top_k <= 0:
187
+ raise ValueError("top_k must be positive")
188
+
189
+ additional_headers = self.additional_headers or {}
190
+ self.default_metadata = tuple(additional_headers.items())
191
+
192
+ @staticmethod
193
+ def _build_headers(
194
+ token: str,
195
+ agenthub_config: Optional[str] = None,
196
+ byo_connection_id: Optional[str] = None,
197
+ ) -> dict[str, str]:
198
+ """Build HTTP headers for UiPath Gateway requests."""
199
+ headers = {
200
+ "Authorization": f"Bearer {token}",
201
+ }
202
+ if agenthub_config:
203
+ headers["X-UiPath-AgentHub-Config"] = agenthub_config
204
+ if byo_connection_id:
205
+ headers["X-UiPath-LlmGateway-ByoIsConnectionId"] = byo_connection_id
206
+ if job_key := os.getenv("UIPATH_JOB_KEY"):
207
+ headers["X-UiPath-JobKey"] = job_key
208
+ if process_key := os.getenv("UIPATH_PROCESS_KEY"):
209
+ headers["X-UiPath-ProcessKey"] = process_key
210
+ return headers
211
+
212
+ @staticmethod
213
+ def _build_base_url(model_name: str) -> str:
214
+ """Build the full URL for the UiPath LLM Gateway."""
215
+ env_uipath_url = os.getenv("UIPATH_URL")
216
+
217
+ if not env_uipath_url:
218
+ raise ValueError("UIPATH_URL environment variable is required")
219
+
220
+ vendor_endpoint = EndpointManager.get_vendor_endpoint()
221
+ formatted_endpoint = vendor_endpoint.format(
222
+ vendor="vertexai",
223
+ model=model_name,
224
+ )
225
+ return f"{env_uipath_url.rstrip('/')}/{formatted_endpoint}"
226
+
227
+ def _stream(self, messages, stop=None, run_manager=None, **kwargs):
228
+ """Streaming fallback - calls _generate and yields single response."""
229
+ from langchain_core.messages import AIMessageChunk
230
+ from langchain_core.outputs import ChatGenerationChunk
231
+
232
+ result = self._generate(messages, stop=stop, run_manager=run_manager, **kwargs)
233
+
234
+ if result.generations:
235
+ message = result.generations[0].message
236
+ chunk = AIMessageChunk(
237
+ content=message.content,
238
+ additional_kwargs=message.additional_kwargs,
239
+ response_metadata=getattr(message, "response_metadata", {}),
240
+ id=message.id,
241
+ tool_calls=getattr(message, "tool_calls", []),
242
+ tool_call_chunks=getattr(message, "tool_call_chunks", []),
243
+ )
244
+ if hasattr(message, "usage_metadata") and message.usage_metadata:
245
+ chunk.usage_metadata = message.usage_metadata
246
+
247
+ yield ChatGenerationChunk(message=chunk)
248
+
249
+ async def _astream(self, messages, stop=None, run_manager=None, **kwargs):
250
+ """Async streaming fallback - calls _agenerate and yields single response."""
251
+ from langchain_core.messages import AIMessageChunk
252
+ from langchain_core.outputs import ChatGenerationChunk
253
+
254
+ result = await self._agenerate(
255
+ messages, stop=stop, run_manager=run_manager, **kwargs
256
+ )
257
+
258
+ if result.generations:
259
+ message = result.generations[0].message
260
+ chunk = AIMessageChunk(
261
+ content=message.content,
262
+ additional_kwargs=message.additional_kwargs,
263
+ response_metadata=getattr(message, "response_metadata", {}),
264
+ id=message.id,
265
+ tool_calls=getattr(message, "tool_calls", []),
266
+ tool_call_chunks=getattr(message, "tool_call_chunks", []),
267
+ )
268
+ if hasattr(message, "usage_metadata") and message.usage_metadata:
269
+ chunk.usage_metadata = message.usage_metadata
270
+
271
+ yield ChatGenerationChunk(message=chunk)
@@ -4,6 +4,7 @@ from typing import Any
4
4
  import httpx
5
5
  from langchain_openai.embeddings import AzureOpenAIEmbeddings, OpenAIEmbeddings
6
6
  from pydantic import Field
7
+ from uipath._utils._ssl_context import get_httpx_client_kwargs
7
8
  from uipath.utils import EndpointManager
8
9
 
9
10
  from uipath_langchain._utils._request_mixin import UiPathRequestMixin
@@ -26,19 +27,24 @@ class UiPathAzureOpenAIEmbeddings(UiPathRequestMixin, AzureOpenAIEmbeddings):
26
27
  )
27
28
 
28
29
  def __init__(self, **kwargs):
30
+ default_client_kwargs = get_httpx_client_kwargs()
31
+ client_kwargs = {
32
+ **default_client_kwargs,
33
+ "event_hooks": {
34
+ "request": [self._log_request_duration],
35
+ "response": [self._log_response_duration],
36
+ },
37
+ }
38
+ aclient_kwargs = {
39
+ **default_client_kwargs,
40
+ "event_hooks": {
41
+ "request": [self._alog_request_duration],
42
+ "response": [self._alog_response_duration],
43
+ },
44
+ }
29
45
  super().__init__(
30
- http_client=httpx.Client(
31
- event_hooks={
32
- "request": [self._log_request_duration],
33
- "response": [self._log_response_duration],
34
- }
35
- ),
36
- http_async_client=httpx.AsyncClient(
37
- event_hooks={
38
- "request": [self._alog_request_duration],
39
- "response": [self._alog_response_duration],
40
- }
41
- ),
46
+ http_client=httpx.Client(**client_kwargs),
47
+ http_async_client=httpx.AsyncClient(**aclient_kwargs),
42
48
  **kwargs,
43
49
  )
44
50
  # Monkey-patch the OpenAI client to use your custom methods