uipath-langchain-client 1.0.1__tar.gz → 1.0.2__tar.gz

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 (32) hide show
  1. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/CHANGELOG.md +5 -0
  2. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/PKG-INFO +2 -2
  3. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/pyproject.toml +1 -1
  4. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/__version__.py +1 -1
  5. uipath_langchain_client-1.0.2/src/uipath_langchain_client/clients/google/chat_models.py +60 -0
  6. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/vertexai/chat_models.py +4 -0
  7. uipath_langchain_client-1.0.1/src/uipath_langchain_client/clients/google/chat_models.py +0 -203
  8. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/.gitignore +0 -0
  9. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/README.md +0 -0
  10. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/demo.py +0 -0
  11. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/__init__.py +0 -0
  12. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/base_client.py +0 -0
  13. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/anthropic/__init__.py +0 -0
  14. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/anthropic/chat_models.py +0 -0
  15. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/azure/__init__.py +0 -0
  16. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/azure/chat_models.py +0 -0
  17. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/azure/embeddings.py +0 -0
  18. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/bedrock/__init__.py +0 -0
  19. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/bedrock/chat_models.py +0 -0
  20. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/bedrock/embeddings.py +0 -0
  21. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/bedrock/utils.py +0 -0
  22. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/google/__init__.py +0 -0
  23. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/google/embeddings.py +0 -0
  24. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/normalized/__init__.py +0 -0
  25. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/normalized/chat_models.py +0 -0
  26. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/normalized/embeddings.py +0 -0
  27. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/openai/__init__.py +0 -0
  28. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/openai/chat_models.py +0 -0
  29. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/openai/embeddings.py +0 -0
  30. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/clients/vertexai/__init__.py +0 -0
  31. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/factory.py +0 -0
  32. {uipath_langchain_client-1.0.1 → uipath_langchain_client-1.0.2}/src/uipath_langchain_client/settings.py +0 -0
@@ -2,6 +2,11 @@
2
2
 
3
3
  All notable changes to `uipath_langchain_client` will be documented in this file.
4
4
 
5
+ ## [1.0.2] - 2026-02-02
6
+
7
+ ### Buf Fix
8
+ - Removed old fix on Gemini streaming and updated with a new cleaner one
9
+
5
10
  ## [1.0.1] - 2026-02-02
6
11
 
7
12
  ### Bug Fix
@@ -1,10 +1,10 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uipath-langchain-client
3
- Version: 1.0.1
3
+ Version: 1.0.2
4
4
  Summary: LangChain-compatible chat models and embeddings for UiPath's LLM services
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: langchain>=1.2.7
7
- Requires-Dist: uipath-llm-client>=1.0.0
7
+ Requires-Dist: uipath-llm-client>=1.0.2
8
8
  Provides-Extra: all
9
9
  Requires-Dist: langchain-anthropic>=1.3.1; extra == 'all'
10
10
  Requires-Dist: langchain-aws>=1.2.1; extra == 'all'
@@ -6,7 +6,7 @@ readme = "README.md"
6
6
  requires-python = ">=3.11"
7
7
  dependencies = [
8
8
  "langchain>=1.2.7",
9
- "uipath-llm-client>=1.0.0",
9
+ "uipath-llm-client>=1.0.2",
10
10
  ]
11
11
 
12
12
  [project.optional-dependencies]
@@ -1,3 +1,3 @@
1
1
  __title__ = "UiPath LangChain Client"
2
2
  __description__ = "A Python client for interacting with UiPath's LLM services via LangChain."
3
- __version__ = "1.0.1"
3
+ __version__ = "1.0.2"
@@ -0,0 +1,60 @@
1
+ from typing import Self
2
+
3
+ from httpx import URL, Request
4
+ from pydantic import Field, model_validator
5
+ from uipath_langchain_client.base_client import UiPathBaseLLMClient
6
+ from uipath_langchain_client.settings import UiPathAPIConfig
7
+
8
+ try:
9
+ from langchain_google_genai.chat_models import ChatGoogleGenerativeAI
10
+
11
+ from google.genai.client import Client
12
+ from google.genai.types import HttpOptions
13
+ except ImportError as e:
14
+ raise ImportError(
15
+ "The 'google' extra is required to use UiPathChatGoogleGenerativeAI. "
16
+ "Install it with: uv add uipath-langchain-client[google]"
17
+ ) from e
18
+
19
+
20
+ class UiPathChatGoogleGenerativeAI(UiPathBaseLLMClient, ChatGoogleGenerativeAI):
21
+ api_config: UiPathAPIConfig = UiPathAPIConfig(
22
+ api_type="completions",
23
+ client_type="passthrough",
24
+ vendor_type="vertexai",
25
+ api_flavor="generate-content",
26
+ api_version="v1beta1",
27
+ freeze_base_url=True,
28
+ )
29
+
30
+ # Override fields to avoid errors when instantiating the class
31
+ model: str = Field(default="", alias="model_name")
32
+ project: str | None = "PLACEHOLDER"
33
+ location: str | None = "PLACEHOLDER"
34
+
35
+ @model_validator(mode="after")
36
+ def setup_uipath_client(self) -> Self:
37
+ def fix_url_for_streaming(request: Request):
38
+ if request.headers.get("X-UiPath-Streaming-Enabled") == "true":
39
+ request.url = URL(request.url).copy_add_param("alt", "sse")
40
+
41
+ async def fix_url_for_streaming_async(request: Request):
42
+ if request.headers.get("X-UiPath-Streaming-Enabled") == "true":
43
+ request.url = URL(request.url).copy_add_param("alt", "sse")
44
+
45
+ self.uipath_sync_client.event_hooks["request"].append(fix_url_for_streaming)
46
+ self.uipath_async_client.event_hooks["request"].append(fix_url_for_streaming_async)
47
+
48
+ self.client = Client(
49
+ vertexai=True,
50
+ api_key="PLACEHOLDER",
51
+ http_options=HttpOptions(
52
+ base_url=str(self.uipath_sync_client.base_url),
53
+ headers=dict(self.uipath_sync_client.headers),
54
+ timeout=None, # handled by the UiPath client
55
+ retry_options=None, # handled by the UiPath client
56
+ httpx_client=self.uipath_sync_client,
57
+ httpx_async_client=self.uipath_async_client,
58
+ ),
59
+ )
60
+ return self
@@ -23,6 +23,10 @@ class UiPathChatAnthropicVertex(UiPathBaseLLMClient, ChatAnthropicVertex): # ty
23
23
  freeze_base_url=True,
24
24
  )
25
25
 
26
+ # Override fields to avoid errors when instantiating the class
27
+ project: str | None = "PLACEHOLDER"
28
+ location: str = "PLACEHOLDER"
29
+
26
30
  @model_validator(mode="after")
27
31
  def setup_uipath_client(self) -> Self:
28
32
  self.client = AnthropicVertex(
@@ -1,203 +0,0 @@
1
- from collections.abc import AsyncIterator, Iterator
2
- from typing import Self
3
-
4
- from httpx import Response
5
- from pydantic import Field, SecretStr, model_validator
6
- from uipath_langchain_client.base_client import UiPathBaseLLMClient
7
- from uipath_langchain_client.settings import UiPathAPIConfig
8
-
9
- try:
10
- from langchain_google_genai.chat_models import ChatGoogleGenerativeAI
11
-
12
- from google.genai.client import Client
13
- from google.genai.types import HttpOptions
14
- except ImportError as e:
15
- raise ImportError(
16
- "The 'google' extra is required to use UiPathChatGoogleGenerativeAI. "
17
- "Install it with: uv add uipath-langchain-client[google]"
18
- ) from e
19
-
20
-
21
- def _wrap_iter_lines(original: Iterator[str]) -> Iterator[str]:
22
- """Wrap iter_lines to extract individual JSON objects from streaming responses.
23
-
24
- The LLM Gateway wraps streaming JSON responses in an array like [{...}, {...}].
25
- This extracts each complete JSON object and yields them individually.
26
- Handles multiple JSON objects on a single line (e.g., {...},{...}).
27
-
28
- We prefix output with 'data: ' so the SDK's _iter_response_stream bypasses its
29
- broken brace counting (which doesn't handle braces inside strings) and yields
30
- our JSON objects directly.
31
-
32
- Temporal Fix until it's fixed in the main package.
33
- """
34
- buffer = ""
35
- balance = 0
36
- in_string = False
37
- escape_next = False
38
-
39
- for line in original:
40
- # Handle data: prefix (SSE format)
41
- if line.startswith("data:"):
42
- line = line[5:].lstrip()
43
-
44
- for char in line:
45
- # Handle escape sequences in strings
46
- if escape_next:
47
- buffer += char
48
- escape_next = False
49
- continue
50
-
51
- if char == "\\" and in_string:
52
- buffer += char
53
- escape_next = True
54
- continue
55
-
56
- if char == '"':
57
- in_string = not in_string
58
- buffer += char
59
- continue
60
-
61
- # Only track braces outside of strings
62
- if not in_string:
63
- if char == "{":
64
- balance += 1
65
- buffer += char
66
- elif char == "}":
67
- buffer += char
68
- balance -= 1
69
- if balance == 0 and buffer:
70
- # Complete JSON object found - yield with 'data: ' prefix
71
- # so SDK bypasses its broken brace counting
72
- yield "data: " + buffer
73
- buffer = ""
74
- elif balance == 0:
75
- # Skip characters outside JSON objects (array brackets, commas, whitespace)
76
- continue
77
- else:
78
- buffer += char
79
- else:
80
- buffer += char
81
-
82
- # Yield any remaining buffer (handles incomplete streams)
83
- if buffer:
84
- yield "data: " + buffer
85
-
86
-
87
- async def _wrap_aiter_lines(original: AsyncIterator[str]) -> AsyncIterator[str]:
88
- """Async version of _wrap_iter_lines.
89
-
90
- Extracts individual JSON objects from streaming responses.
91
- Handles multiple JSON objects on a single line (e.g., {...},{...}).
92
-
93
- We prefix output with 'data: ' so the SDK's _iter_response_stream bypasses its
94
- broken brace counting (which doesn't handle braces inside strings) and yields
95
- our JSON objects directly.
96
- """
97
- buffer = ""
98
- balance = 0
99
- in_string = False
100
- escape_next = False
101
-
102
- async for line in original:
103
- # Handle data: prefix (SSE format)
104
- if line.startswith("data:"):
105
- line = line[5:].lstrip()
106
-
107
- for char in line:
108
- # Handle escape sequences in strings
109
- if escape_next:
110
- buffer += char
111
- escape_next = False
112
- continue
113
-
114
- if char == "\\" and in_string:
115
- buffer += char
116
- escape_next = True
117
- continue
118
-
119
- if char == '"':
120
- in_string = not in_string
121
- buffer += char
122
- continue
123
-
124
- # Only track braces outside of strings
125
- if not in_string:
126
- if char == "{":
127
- balance += 1
128
- buffer += char
129
- elif char == "}":
130
- buffer += char
131
- balance -= 1
132
- if balance == 0 and buffer:
133
- # Complete JSON object found - yield with 'data: ' prefix
134
- # so SDK bypasses its broken brace counting
135
- yield "data: " + buffer
136
- buffer = ""
137
- elif balance == 0:
138
- # Skip characters outside JSON objects (array brackets, commas, whitespace)
139
- continue
140
- else:
141
- buffer += char
142
- else:
143
- buffer += char
144
-
145
- # Yield any remaining buffer (handles incomplete streams)
146
- if buffer:
147
- yield "data: " + buffer
148
-
149
-
150
- class UiPathChatGoogleGenerativeAI(UiPathBaseLLMClient, ChatGoogleGenerativeAI):
151
- api_config: UiPathAPIConfig = UiPathAPIConfig(
152
- api_type="completions",
153
- client_type="passthrough",
154
- vendor_type="vertexai",
155
- api_flavor="generate-content",
156
- api_version="v1beta1",
157
- freeze_base_url=True,
158
- )
159
-
160
- # Override fields to avoid errors when instantiating the class
161
- model: str = Field(default="", alias="model_name")
162
- google_api_key: SecretStr | None = Field(default=SecretStr("PLACEHOLDER"))
163
-
164
- @model_validator(mode="after")
165
- def setup_uipath_client(self) -> Self:
166
- def fix_streaming_response(response: Response):
167
- """Monkey-patch iter_lines to strip JSON array brackets."""
168
- original_iter_lines = response.iter_lines
169
- response.iter_lines = lambda: _wrap_iter_lines(original_iter_lines())
170
-
171
- async def fix_streaming_response_async(response: Response):
172
- """Monkey-patch aiter_lines to strip JSON array brackets."""
173
- original_aiter_lines = response.aiter_lines
174
- response.aiter_lines = lambda: _wrap_aiter_lines(original_aiter_lines())
175
-
176
- self.uipath_sync_client.event_hooks["response"].append(fix_streaming_response)
177
- self.uipath_async_client.event_hooks["response"].append(fix_streaming_response_async)
178
-
179
- # TODO: in exactly 2 weeks, we need to uncomment this part of the code because it will work, 5 february 2026 is the date.
180
- # def fix_url_for_streaming(request: Request):
181
- # if request.headers.get("X-UiPath-Streaming-Enabled") == "true":
182
- # request.url = URL(request.url).copy_add_param("alt", "sse")
183
-
184
- # async def fix_url_for_streaming_async(request: Request):
185
- # if request.headers.get("X-UiPath-Streaming-Enabled") == "true":
186
- # request.url = URL(request.url).copy_add_param("alt", "sse")
187
-
188
- # self.uipath_sync_client.event_hooks["request"].append(fix_url_for_streaming)
189
- # self.uipath_async_client.event_hooks["request"].append(fix_url_for_streaming_async)
190
-
191
- self.client = Client(
192
- vertexai=True,
193
- api_key="PLACEHOLDER",
194
- http_options=HttpOptions(
195
- base_url=str(self.uipath_sync_client.base_url),
196
- headers=dict(self.uipath_sync_client.headers),
197
- timeout=None, # handled by the UiPath client
198
- retry_options=None, # handled by the UiPath client
199
- httpx_client=self.uipath_sync_client,
200
- httpx_async_client=self.uipath_async_client,
201
- ),
202
- )
203
- return self