Skip to content

Commit 275e36f

Browse files
authored
Feat/version 1.3.0 (#38)
1 parent ecad23e commit 275e36f

18 files changed

Lines changed: 760 additions & 671 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
All notable changes to `uipath_llm_client` (core package) will be documented in this file.
44

5+
## [1.3.0] - 2026-03-10
6+
7+
### Version Bump
8+
- Stable release
9+
- Fixes
10+
511
## [1.2.4] - 2026-02-26
612

713
### Refactor

packages/uipath_langchain_client/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
All notable changes to `uipath_langchain_client` will be documented in this file.
44

5+
## [1.3.0] - 2026-03-10
6+
7+
### Version Bump
8+
- Stable release
9+
- Fixes
10+
511
## [1.2.7] - 2026-02-26
612

713
### Fix

packages/uipath_langchain_client/pyproject.toml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,29 @@ dynamic = ["version"]
55
readme = "README.md"
66
requires-python = ">=3.11"
77
dependencies = [
8-
"langchain>=1.2.7",
9-
"uipath-llm-client>=1.2.4",
8+
"langchain>=1.2.10",
9+
"uipath-llm-client>=1.3.0",
1010
]
1111

1212
[project.optional-dependencies]
1313
openai = [
14-
"langchain-openai>=1.1.7",
14+
"langchain-openai>=1.1.11",
1515
]
1616
aws = [
17-
"langchain-aws>=1.2.1",
17+
"langchain-aws>=1.4.0",
1818
]
1919
google = [
20-
"langchain-google-genai>=4.2.0",
20+
"langchain-google-genai>=4.2.1",
2121
]
2222
anthropic = [
23-
"langchain-anthropic>=1.3.1",
24-
"anthropic[bedrock,vertex]>=0.77.0",
23+
"langchain-anthropic>=1.3.4",
24+
"anthropic[bedrock,vertex]>=0.84.0",
2525
]
2626
azure = [
27-
"langchain-azure-ai>=1.0.0",
27+
"langchain-azure-ai>=1.1.0",
2828
]
2929
vertexai = [
30-
"langchain-google-vertexai>=3.2.1",
30+
"langchain-google-vertexai>=3.2.2",
3131
]
3232
fireworks = [
3333
"langchain-fireworks>=1.1.0",
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
__title__ = "UiPath LangChain Client"
22
__description__ = "A Python client for interacting with UiPath's LLM services via LangChain."
3-
__version__ = "1.2.7"
3+
__version__ = "1.3.0"

packages/uipath_langchain_client/src/uipath_langchain_client/base_client.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class UiPathBaseLLMClient(BaseModel, ABC):
102102
)
103103

104104
default_headers: Mapping[str, str] | None = Field(
105-
default={
105+
default_factory=lambda: {
106106
"X-UiPath-LLMGateway-TimeoutSeconds": "295", # server side timeout, default is 10, maximum is 300
107107
"X-UiPath-LLMGateway-AllowFull4xxResponse": "true", # allow full 4xx responses (default is false)
108108
},
@@ -210,7 +210,7 @@ def uipath_request(
210210
async def uipath_arequest(
211211
self,
212212
method: Literal["POST", "GET"] = "POST",
213-
url: str = "/",
213+
url: URL | str = "/",
214214
*,
215215
request_body: dict[str, Any] | None = None,
216216
**kwargs: Any,
Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,70 @@
11
from typing import Self
22

3-
from pydantic import model_validator
3+
from httpx import URL, Request
4+
from pydantic import Field, model_validator
45

56
from uipath_langchain_client.base_client import UiPathBaseChatModel
67
from uipath_langchain_client.settings import UiPathAPIConfig
78

89
try:
9-
from azure.ai.inference import ChatCompletionsClient
10-
from azure.ai.inference.aio import ChatCompletionsClient as ChatCompletionsClientAsync
11-
from azure.core.credentials import AzureKeyCredential
12-
from langchain_azure_ai.chat_models import AzureAIChatCompletionsModel
10+
from azure.core.credentials import AzureKeyCredential, TokenCredential
11+
from azure.core.credentials_async import AsyncTokenCredential
12+
from langchain_azure_ai.chat_models import AzureAIOpenAIApiChatModel
13+
from openai import AsyncOpenAI, OpenAI
1314
except ImportError as e:
1415
raise ImportError(
1516
"The 'azure' extra is required to use UiPathAzureAIChatCompletionsModel. "
1617
"Install it with: uv add uipath-langchain-client[azure]"
1718
) from e
1819

1920

20-
class UiPathAzureAIChatCompletionsModel(UiPathBaseChatModel, AzureAIChatCompletionsModel): # type: ignore[override]
21+
class UiPathAzureAIChatCompletionsModel(UiPathBaseChatModel, AzureAIOpenAIApiChatModel): # type: ignore[override]
2122
api_config: UiPathAPIConfig = UiPathAPIConfig(
2223
api_type="completions",
2324
client_type="passthrough",
2425
vendor_type="azure",
25-
freeze_base_url=True,
26+
freeze_base_url=False,
2627
)
2728

28-
# Override fields to avoid errors when instantiating the class
29-
endpoint: str | None = "PLACEHOLDER"
29+
# Override fields to avoid env var lookup / validation errors at instantiation
30+
endpoint: str | None = Field(default="PLACEHOLDER")
31+
credential: str | AzureKeyCredential | TokenCredential | AsyncTokenCredential | None = Field(
32+
default="PLACEHOLDER"
33+
)
3034

3135
@model_validator(mode="after")
3236
def setup_uipath_client(self) -> Self:
33-
# TODO: finish implementation once we have a proper model in UiPath API
34-
self._client = ChatCompletionsClient(
35-
endpoint="PLACEHOLDER",
36-
credential=AzureKeyCredential("PLACEHOLDER"),
37-
model=self.model_name,
38-
**self.client_kwargs,
37+
base_url = str(self.uipath_sync_client.base_url).rstrip("/")
38+
39+
def fix_url_and_api_flavor_header(request: Request):
40+
url_suffix = str(request.url).split(base_url)[-1]
41+
if "responses" in url_suffix:
42+
request.headers["X-UiPath-LlmGateway-ApiFlavor"] = "responses"
43+
else:
44+
request.headers["X-UiPath-LlmGateway-ApiFlavor"] = "chat-completions"
45+
request.url = URL(base_url)
46+
47+
async def fix_url_and_api_flavor_header_async(request: Request):
48+
url_suffix = str(request.url).split(base_url)[-1]
49+
if "responses" in url_suffix:
50+
request.headers["X-UiPath-LlmGateway-ApiFlavor"] = "responses"
51+
else:
52+
request.headers["X-UiPath-LlmGateway-ApiFlavor"] = "chat-completions"
53+
request.url = URL(base_url)
54+
55+
self.uipath_sync_client.event_hooks["request"].append(fix_url_and_api_flavor_header)
56+
self.uipath_async_client.event_hooks["request"].append(fix_url_and_api_flavor_header_async)
57+
58+
self.root_client = OpenAI(
59+
api_key="PLACEHOLDER",
60+
max_retries=0, # handled by the UiPath client
61+
http_client=self.uipath_sync_client,
3962
)
40-
self._async_client = ChatCompletionsClientAsync(
41-
endpoint="PLACEHOLDER",
42-
credential=AzureKeyCredential("PLACEHOLDER"),
43-
model=self.model_name,
44-
**self.client_kwargs,
63+
self.root_async_client = AsyncOpenAI(
64+
api_key="PLACEHOLDER",
65+
max_retries=0, # handled by the UiPath client
66+
http_client=self.uipath_async_client,
4567
)
68+
self.client = self.root_client.chat.completions
69+
self.async_client = self.root_async_client.chat.completions
4670
return self
Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,47 @@
11
from typing import Self
22

3-
from pydantic import model_validator
3+
from pydantic import Field, model_validator
44

55
from uipath_langchain_client.base_client import UiPathBaseEmbeddings
66
from uipath_langchain_client.settings import UiPathAPIConfig
77

88
try:
9-
from azure.ai.inference import EmbeddingsClient
10-
from azure.ai.inference.aio import EmbeddingsClient as EmbeddingsClientAsync
11-
from langchain_azure_ai.embeddings import AzureAIEmbeddingsModel
9+
from azure.core.credentials import AzureKeyCredential, TokenCredential
10+
from azure.core.credentials_async import AsyncTokenCredential
11+
from langchain_azure_ai.embeddings import AzureAIOpenAIApiEmbeddingsModel
12+
from openai import AsyncOpenAI, OpenAI
1213
except ImportError as e:
1314
raise ImportError(
1415
"The 'azure' extra is required to use UiPathAzureAIEmbeddingsModel. "
1516
"Install it with: uv add uipath-langchain-client[azure]"
1617
) from e
1718

1819

19-
class UiPathAzureAIEmbeddingsModel(UiPathBaseEmbeddings, AzureAIEmbeddingsModel): # type: ignore[override]
20+
class UiPathAzureAIEmbeddingsModel(UiPathBaseEmbeddings, AzureAIOpenAIApiEmbeddingsModel): # type: ignore[override]
2021
api_config: UiPathAPIConfig = UiPathAPIConfig(
2122
api_type="embeddings",
2223
client_type="passthrough",
2324
vendor_type="azure",
2425
freeze_base_url=True,
2526
)
2627

27-
# Override fields to avoid errors when instantiating the class
28-
endpoint: str | None = "PLACEHOLDER"
29-
credentials: str | None = "PLACEHOLDER"
28+
# Override fields to avoid env var lookup / validation errors at instantiation
29+
model: str = Field(default="", alias="model_name")
30+
endpoint: str | None = Field(default="PLACEHOLDER")
31+
credential: str | AzureKeyCredential | TokenCredential | AsyncTokenCredential | None = Field(
32+
default="PLACEHOLDER"
33+
)
3034

3135
@model_validator(mode="after")
3236
def setup_uipath_client(self) -> Self:
33-
# TODO: finish implementation once we have a proper model in UiPath API
34-
self._client = EmbeddingsClient(
35-
endpoint="PLACEHOLDER",
36-
credentials="PLACEHOLDER",
37-
model=self.model_name,
38-
**self.client_kwargs,
39-
)
40-
self._async_client = EmbeddingsClientAsync(
41-
endpoint="PLACEHOLDER",
42-
credentials="PLACEHOLDER",
43-
model=self.model_name,
44-
**self.client_kwargs,
45-
)
37+
self.client = OpenAI(
38+
api_key="PLACEHOLDER",
39+
max_retries=0, # handled by the UiPath client
40+
http_client=self.uipath_sync_client,
41+
).embeddings
42+
self.async_client = AsyncOpenAI(
43+
api_key="PLACEHOLDER",
44+
max_retries=0, # handled by the UiPath client
45+
http_client=self.uipath_async_client,
46+
).embeddings
4647
return self

packages/uipath_langchain_client/src/uipath_langchain_client/clients/normalized/chat_models.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ def _llm_type(self) -> str:
140140

141141
@property
142142
def _default_params(self) -> dict[str, Any]:
143-
"""Get the default parameters for calling OpenAI API."""
143+
"""Get the default parameters for the normalized API request."""
144144
exclude_if_none = {
145145
"frequency_penalty": self.frequency_penalty,
146146
"presence_penalty": self.presence_penalty,
@@ -175,7 +175,7 @@ def _get_usage_metadata(self, json_data: dict[str, Any]) -> UsageMetadata:
175175
cache_creation=json_data.get("cache_creation_input_tokens", 0),
176176
),
177177
output_token_details=OutputTokenDetails(
178-
audio=json_data.get("audio_tokens", 0),
178+
audio=json_data.get("output_audio_tokens", 0),
179179
reasoning=json_data.get("thoughts_tokens", 0),
180180
),
181181
)
@@ -241,7 +241,15 @@ def _preprocess_request(
241241
{
242242
"id": tool_call["id"],
243243
"name": tool_call["function"]["name"],
244-
"arguments": json.loads(tool_call["function"]["arguments"]),
244+
"arguments": (
245+
tool_call["function"]["arguments"]
246+
if isinstance(tool_call["function"]["arguments"], dict)
247+
else (
248+
json.loads(tool_call["function"]["arguments"])
249+
if tool_call["function"]["arguments"]
250+
else {}
251+
)
252+
),
245253
}
246254
for tool_call in converted_message["tool_calls"]
247255
]
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from uipath.llm_client.utils.exceptions import (
2+
UiPathAPIError,
3+
UiPathAuthenticationError,
4+
UiPathBadRequestError,
5+
UiPathConflictError,
6+
UiPathGatewayTimeoutError,
7+
UiPathInternalServerError,
8+
UiPathNotFoundError,
9+
UiPathPermissionDeniedError,
10+
UiPathRateLimitError,
11+
UiPathRequestTooLargeError,
12+
UiPathServiceUnavailableError,
13+
UiPathTooManyRequestsError,
14+
UiPathUnprocessableEntityError,
15+
)
16+
from uipath.llm_client.utils.retry import RetryConfig
17+
18+
__all__ = [
19+
"RetryConfig",
20+
"UiPathAPIError",
21+
"UiPathBadRequestError",
22+
"UiPathAuthenticationError",
23+
"UiPathPermissionDeniedError",
24+
"UiPathNotFoundError",
25+
"UiPathConflictError",
26+
"UiPathRequestTooLargeError",
27+
"UiPathUnprocessableEntityError",
28+
"UiPathRateLimitError",
29+
"UiPathInternalServerError",
30+
"UiPathServiceUnavailableError",
31+
"UiPathGatewayTimeoutError",
32+
"UiPathTooManyRequestsError",
33+
]

pyproject.toml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ readme = "README.md"
66
requires-python = ">=3.11"
77
dependencies = [
88
"httpx>=0.28.1",
9-
"tenacity>=9.1.2",
9+
"tenacity>=9.1.4",
1010
"pydantic>=2.12.5",
11-
"pydantic-settings>=2.12.0",
12-
"uipath>=2.5.17",
11+
"pydantic-settings>=2.13.1",
12+
"uipath>=2.10.11",
1313
]
1414

1515
authors = [
@@ -19,26 +19,26 @@ authors = [
1919

2020
[project.optional-dependencies]
2121
openai = [
22-
"openai>=2.15.0",
22+
"openai>=2.24.0",
2323
]
2424
google = [
25-
"google-genai>=1.59.0",
25+
"google-genai>=1.65.0",
2626
]
2727
anthropic = [
28-
"anthropic>=0.76.0",
28+
"anthropic>=0.84.0",
2929
]
3030
all = [
3131
"uipath-llm-client[openai,google,anthropic]",
3232
]
3333

3434
[dependency-groups]
3535
dev = [
36-
"langchain-tests>=1.1.2",
37-
"pytest>=8.4.2",
36+
"langchain-tests>=1.1.5",
37+
"pytest>=9.0.2",
3838
"pytest-asyncio>=1.3.0",
3939
"pytest-recording>=0.13.4",
40-
"pyright>=1.1.407",
41-
"ruff>=0.14.9",
40+
"pyright>=1.1.408",
41+
"ruff>=0.15.3",
4242
"uipath-llm-client[all]",
4343
"uipath_langchain_client[all]",
4444
]

0 commit comments

Comments
 (0)