Skip to content

Commit a01f0cf

Browse files
committed
init litellm
1 parent 297e4ae commit a01f0cf

8 files changed

Lines changed: 1742 additions & 647 deletions

File tree

packages/uipath_langchain_client/pyproject.toml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,38 @@ dynamic = ["version"]
55
readme = "README.md"
66
requires-python = ">=3.11"
77
dependencies = [
8-
"langchain>=1.2.13",
8+
"langchain>=1.2.14",
99
"uipath-llm-client>=1.5.10",
1010
]
1111

1212
[project.optional-dependencies]
1313
openai = [
14-
"langchain-openai>=1.1.11",
14+
"langchain-openai>=1.1.12",
1515
]
1616
google = [
1717
"langchain-google-genai>=4.2.1",
1818
]
1919
anthropic = [
2020
"langchain-anthropic>=1.4.0",
21-
"anthropic[bedrock,vertex]>=0.86.0",
21+
"anthropic[bedrock,vertex]>=0.87.0",
2222
]
2323
aws = [
24-
"langchain-aws[anthropic]>=1.4.1",
24+
"langchain-aws[anthropic]>=1.4.2",
2525
]
2626
vertexai = [
2727
"langchain-google-vertexai>=3.2.2",
2828
]
2929
azure = [
30-
"langchain-azure-ai>=1.1.1",
30+
"langchain-azure-ai>=1.2.1",
3131
]
3232
fireworks = [
3333
"langchain-fireworks>=1.1.0",
3434
]
3535
all = [
36-
"uipath-langchain-client[openai,aws,google,anthropic,azure,vertexai,fireworks]"
36+
"uipath-langchain-client[openai,aws,google,anthropic,azure,vertexai,fireworks,litellm]"
37+
]
38+
litellm = [
39+
"langchain-litellm>=0.6.3",
3740
]
3841

3942
[build-system]
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from uipath_langchain_client.clients.litellm.chat_models import UiPathChatLiteLLM
2+
from uipath_langchain_client.clients.litellm.embeddings import UiPathLiteLLMEmbeddings
3+
4+
__all__ = [
5+
"UiPathChatLiteLLM",
6+
"UiPathLiteLLMEmbeddings",
7+
]
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
from typing import Any, Optional, Self
2+
3+
from pydantic import Field, model_validator
4+
5+
from uipath_langchain_client.base_client import UiPathBaseChatModel
6+
7+
try:
8+
from langchain_litellm import ChatLiteLLM
9+
from openai import AsyncOpenAI, OpenAI
10+
except ImportError as e:
11+
raise ImportError(
12+
"The 'litellm' extra is required to use UiPathChatLiteLLM. "
13+
"Install it with: uv add uipath-langchain-client[litellm]"
14+
) from e
15+
16+
from langchain_core.callbacks import (
17+
AsyncCallbackManagerForLLMRun,
18+
CallbackManagerForLLMRun,
19+
)
20+
21+
22+
class UiPathChatLiteLLM(UiPathBaseChatModel, ChatLiteLLM): # type: ignore[override]
23+
"""LiteLLM chat model routed through UiPath LLM Gateway.
24+
25+
Combines UiPath's authentication and routing with LiteLLM's
26+
multi-provider chat interface. The api_config must be provided
27+
by the caller — provider routing is not auto-detected from model names.
28+
"""
29+
30+
# Override ChatLiteLLM's model field to align with UiPathBaseLLMClient.model_name (alias="model")
31+
model: str = Field(default="", alias="model_name")
32+
33+
_uipath_openai_client: Optional[OpenAI] = None
34+
_uipath_async_openai_client: Optional[AsyncOpenAI] = None
35+
36+
@model_validator(mode="after")
37+
def setup_uipath_client(self) -> Self:
38+
base_url = str(self.uipath_sync_client.base_url).rstrip("/")
39+
40+
self._uipath_openai_client = OpenAI(
41+
api_key="PLACEHOLDER",
42+
max_retries=0,
43+
http_client=self.uipath_sync_client,
44+
base_url=base_url,
45+
)
46+
self._uipath_async_openai_client = AsyncOpenAI(
47+
api_key="PLACEHOLDER",
48+
max_retries=0,
49+
http_client=self.uipath_async_client,
50+
base_url=base_url,
51+
)
52+
return self
53+
54+
def completion_with_retry(
55+
self, run_manager: CallbackManagerForLLMRun | None = None, **kwargs: Any
56+
) -> Any:
57+
"""Override to inject UiPath OpenAI client into litellm calls."""
58+
from langchain_litellm.chat_models.litellm import _create_retry_decorator
59+
60+
kwargs["client"] = self._uipath_openai_client
61+
retry_decorator = _create_retry_decorator(self, run_manager=run_manager)
62+
63+
@retry_decorator
64+
def _completion_with_retry(**kwargs: Any) -> Any:
65+
return self.client.completion(**kwargs)
66+
67+
return _completion_with_retry(**kwargs)
68+
69+
async def acompletion_with_retry(
70+
self, run_manager: AsyncCallbackManagerForLLMRun | None = None, **kwargs: Any
71+
) -> Any:
72+
"""Override to inject UiPath async OpenAI client into litellm calls."""
73+
from langchain_litellm.chat_models.litellm import _create_retry_decorator
74+
75+
kwargs["client"] = self._uipath_async_openai_client
76+
retry_decorator = _create_retry_decorator(self, run_manager=run_manager)
77+
78+
@retry_decorator
79+
async def _completion_with_retry(**kwargs: Any) -> Any:
80+
return await self.client.acompletion(**kwargs)
81+
82+
return await _completion_with_retry(**kwargs)
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
from typing import Any, Self
2+
3+
from pydantic import Field, model_validator
4+
5+
from uipath_langchain_client.base_client import UiPathBaseEmbeddings
6+
7+
try:
8+
from langchain_litellm import LiteLLMEmbeddings
9+
from openai import AsyncOpenAI, OpenAI
10+
except ImportError as e:
11+
raise ImportError(
12+
"The 'litellm' extra is required to use UiPathLiteLLMEmbeddings. "
13+
"Install it with: uv add uipath-langchain-client[litellm]"
14+
) from e
15+
16+
17+
class UiPathLiteLLMEmbeddings(UiPathBaseEmbeddings, LiteLLMEmbeddings): # type: ignore[override]
18+
"""LiteLLM embeddings routed through UiPath LLM Gateway.
19+
20+
Combines UiPath's authentication and routing with LiteLLM's
21+
multi-provider embeddings interface. The api_config must be provided
22+
by the caller.
23+
"""
24+
25+
# Override LiteLLMEmbeddings' model field to align with UiPathBaseLLMClient.model_name
26+
model: str = Field(default="", alias="model_name")
27+
28+
_uipath_openai_client: OpenAI | None = None
29+
_uipath_async_openai_client: AsyncOpenAI | None = None
30+
31+
@model_validator(mode="after")
32+
def setup_uipath_client(self) -> Self:
33+
base_url = str(self.uipath_sync_client.base_url).rstrip("/")
34+
35+
self._uipath_openai_client = OpenAI(
36+
api_key="PLACEHOLDER",
37+
max_retries=0,
38+
http_client=self.uipath_sync_client,
39+
base_url=base_url,
40+
)
41+
self._uipath_async_openai_client = AsyncOpenAI(
42+
api_key="PLACEHOLDER",
43+
max_retries=0,
44+
http_client=self.uipath_async_client,
45+
base_url=base_url,
46+
)
47+
return self
48+
49+
def _embedding_with_retry(self, **kwargs: Any) -> Any:
50+
"""Override to inject UiPath OpenAI client into litellm embedding calls."""
51+
import litellm
52+
from langchain_litellm.embeddings.litellm import _create_retry_decorator
53+
54+
kwargs["client"] = self._uipath_openai_client
55+
retry_decorator = _create_retry_decorator(self.max_retries)
56+
57+
@retry_decorator
58+
def _embed() -> Any:
59+
return litellm.embedding(**kwargs)
60+
61+
return _embed()
62+
63+
async def _aembedding_with_retry(self, **kwargs: Any) -> Any:
64+
"""Override to inject UiPath async OpenAI client into litellm embedding calls."""
65+
import litellm
66+
from langchain_litellm.embeddings.litellm import _create_retry_decorator
67+
68+
kwargs["client"] = self._uipath_async_openai_client
69+
retry_decorator = _create_retry_decorator(self.max_retries)
70+
71+
@retry_decorator
72+
async def _aembed() -> Any:
73+
return await litellm.aembedding(**kwargs)
74+
75+
return await _aembed()

pyproject.toml

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ dependencies = [
99
"tenacity>=9.1.4",
1010
"pydantic>=2.12.5",
1111
"pydantic-settings>=2.13.1",
12-
"uipath-platform>=0.1.2",
12+
"uipath-platform>=0.1.16",
1313
]
1414

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

2020
[project.optional-dependencies]
2121
openai = [
22-
"openai>=2.29.0",
22+
"openai>=2.30.0",
2323
]
2424
google = [
25-
"google-genai>=1.68.0",
25+
"google-genai>=1.70.0",
2626
]
2727
anthropic = [
28-
"anthropic>=0.86.0",
28+
"anthropic>=0.87.0",
2929
]
3030
all = [
31-
"uipath-llm-client[openai,google,anthropic]",
31+
"uipath-llm-client[openai,google,anthropic,litellm]",
32+
]
33+
litellm = [
34+
"litellm>=1.83.0",
3235
]
3336

3437
[dependency-groups]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from uipath.llm_client.clients.litellm.client import UiPathLiteLLM
2+
3+
__all__ = [
4+
"UiPathLiteLLM",
5+
]

0 commit comments

Comments
 (0)