uipath 2.0.73__py3-none-any.whl → 2.0.75__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.
Potentially problematic release.
This version of uipath might be problematic. Click here for more details.
- uipath/_cli/_auth/_client_credentials.py +2 -3
- uipath/_cli/_auth/_portal_service.py +31 -4
- uipath/_cli/_utils/_folders.py +18 -11
- uipath/_cli/_utils/_processes.py +27 -22
- uipath/_cli/cli_auth.py +51 -46
- uipath/_cli/cli_invoke.py +19 -18
- uipath/_cli/cli_publish.py +44 -38
- uipath/_services/_base_service.py +10 -10
- uipath/_services/attachments_service.py +6 -5
- uipath/_services/buckets_service.py +4 -8
- uipath/_services/llm_gateway_service.py +18 -85
- uipath/_utils/_ssl_context.py +54 -0
- uipath/models/llm_gateway.py +0 -5
- uipath/utils/__init__.py +5 -0
- uipath/utils/_endpoints_manager.py +88 -0
- {uipath-2.0.73.dist-info → uipath-2.0.75.dist-info}/METADATA +2 -1
- {uipath-2.0.73.dist-info → uipath-2.0.75.dist-info}/RECORD +20 -17
- {uipath-2.0.73.dist-info → uipath-2.0.75.dist-info}/WHEEL +0 -0
- {uipath-2.0.73.dist-info → uipath-2.0.75.dist-info}/entry_points.txt +0 -0
- {uipath-2.0.73.dist-info → uipath-2.0.75.dist-info}/licenses/LICENSE +0 -0
|
@@ -3,6 +3,7 @@ from urllib.parse import urlparse
|
|
|
3
3
|
|
|
4
4
|
import httpx
|
|
5
5
|
|
|
6
|
+
from ..._utils._ssl_context import get_httpx_client_kwargs
|
|
6
7
|
from .._utils._console import ConsoleLogger
|
|
7
8
|
from ._models import TokenData
|
|
8
9
|
from ._utils import parse_access_token, update_env_file
|
|
@@ -91,13 +92,11 @@ class ClientCredentialsService:
|
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
try:
|
|
94
|
-
with httpx.Client(
|
|
95
|
+
with httpx.Client(**get_httpx_client_kwargs()) as client:
|
|
95
96
|
response = client.post(token_url, data=data)
|
|
96
|
-
|
|
97
97
|
match response.status_code:
|
|
98
98
|
case 200:
|
|
99
99
|
token_data = response.json()
|
|
100
|
-
# Convert to our TokenData format
|
|
101
100
|
return {
|
|
102
101
|
"access_token": token_data["access_token"],
|
|
103
102
|
"token_type": token_data.get("token_type", "Bearer"),
|
|
@@ -5,6 +5,7 @@ from typing import Optional
|
|
|
5
5
|
import click
|
|
6
6
|
import httpx
|
|
7
7
|
|
|
8
|
+
from ..._utils._ssl_context import get_httpx_client_kwargs
|
|
8
9
|
from .._utils._console import ConsoleLogger
|
|
9
10
|
from ._models import TenantsAndOrganizationInfoResponse, TokenData
|
|
10
11
|
from ._oidc_utils import get_auth_config
|
|
@@ -16,7 +17,6 @@ from ._utils import (
|
|
|
16
17
|
)
|
|
17
18
|
|
|
18
19
|
console = ConsoleLogger()
|
|
19
|
-
client = httpx.Client(follow_redirects=True, timeout=30.0)
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
class PortalService:
|
|
@@ -27,6 +27,8 @@ class PortalService:
|
|
|
27
27
|
domain: Optional[str] = None
|
|
28
28
|
selected_tenant: Optional[str] = None
|
|
29
29
|
|
|
30
|
+
_client: Optional[httpx.Client] = None
|
|
31
|
+
|
|
30
32
|
_tenants_and_organizations: Optional[TenantsAndOrganizationInfoResponse] = None
|
|
31
33
|
|
|
32
34
|
def __init__(
|
|
@@ -39,13 +41,32 @@ class PortalService:
|
|
|
39
41
|
self.access_token = access_token
|
|
40
42
|
self.prt_id = prt_id
|
|
41
43
|
|
|
44
|
+
self._client = httpx.Client(**get_httpx_client_kwargs())
|
|
45
|
+
|
|
46
|
+
def close(self):
|
|
47
|
+
"""Explicitly close the HTTP client."""
|
|
48
|
+
if self._client:
|
|
49
|
+
self._client.close()
|
|
50
|
+
self._client = None
|
|
51
|
+
|
|
52
|
+
def __enter__(self):
|
|
53
|
+
"""Enter the runtime context related to this object."""
|
|
54
|
+
return self
|
|
55
|
+
|
|
56
|
+
def __exit__(self, exc_type, exc_value, traceback):
|
|
57
|
+
"""Exit the runtime context and close the HTTP client."""
|
|
58
|
+
self.close()
|
|
59
|
+
|
|
42
60
|
def update_token_data(self, token_data: TokenData):
|
|
43
61
|
self.access_token = token_data["access_token"]
|
|
44
62
|
self.prt_id = get_parsed_token_data(token_data).get("prt_id")
|
|
45
63
|
|
|
46
64
|
def get_tenants_and_organizations(self) -> TenantsAndOrganizationInfoResponse:
|
|
65
|
+
if self._client is None:
|
|
66
|
+
raise RuntimeError("HTTP client is not initialized")
|
|
67
|
+
|
|
47
68
|
url = f"https://{self.domain}.uipath.com/{self.prt_id}/portal_/api/filtering/leftnav/tenantsAndOrganizationInfo"
|
|
48
|
-
response =
|
|
69
|
+
response = self._client.get(
|
|
49
70
|
url, headers={"Authorization": f"Bearer {self.access_token}"}
|
|
50
71
|
)
|
|
51
72
|
if response.status_code < 400:
|
|
@@ -72,6 +93,9 @@ class PortalService:
|
|
|
72
93
|
return f"https://{self.domain}.uipath.com/{account_name}/{self.selected_tenant}/orchestrator_"
|
|
73
94
|
|
|
74
95
|
def post_refresh_token_request(self, refresh_token: str) -> TokenData:
|
|
96
|
+
if self._client is None:
|
|
97
|
+
raise RuntimeError("HTTP client is not initialized")
|
|
98
|
+
|
|
75
99
|
url = f"https://{self.domain}.uipath.com/identity_/connect/token"
|
|
76
100
|
client_id = get_auth_config().get("client_id")
|
|
77
101
|
|
|
@@ -83,7 +107,7 @@ class PortalService:
|
|
|
83
107
|
|
|
84
108
|
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
|
85
109
|
|
|
86
|
-
response =
|
|
110
|
+
response = self._client.post(url, data=data, headers=headers)
|
|
87
111
|
if response.status_code < 400:
|
|
88
112
|
return response.json()
|
|
89
113
|
elif response.status_code == 401:
|
|
@@ -137,6 +161,9 @@ class PortalService:
|
|
|
137
161
|
update_env_file(updated_env_contents)
|
|
138
162
|
|
|
139
163
|
def post_auth(self, base_url: str) -> None:
|
|
164
|
+
if self._client is None:
|
|
165
|
+
raise RuntimeError("HTTP client is not initialized")
|
|
166
|
+
|
|
140
167
|
or_base_url = (
|
|
141
168
|
f"{base_url}/orchestrator_"
|
|
142
169
|
if base_url
|
|
@@ -148,7 +175,7 @@ class PortalService:
|
|
|
148
175
|
|
|
149
176
|
try:
|
|
150
177
|
[try_enable_first_run_response, acquire_license_response] = [
|
|
151
|
-
|
|
178
|
+
self._client.post(
|
|
152
179
|
url,
|
|
153
180
|
headers={"Authorization": f"Bearer {self.access_token}"},
|
|
154
181
|
)
|
uipath/_cli/_utils/_folders.py
CHANGED
|
@@ -2,27 +2,34 @@ from typing import Optional, Tuple
|
|
|
2
2
|
|
|
3
3
|
import httpx
|
|
4
4
|
|
|
5
|
+
from ..._utils._ssl_context import get_httpx_client_kwargs
|
|
5
6
|
from ._console import ConsoleLogger
|
|
6
7
|
|
|
7
8
|
console = ConsoleLogger()
|
|
8
|
-
client = httpx.Client(follow_redirects=True, timeout=30.0)
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def get_personal_workspace_info(
|
|
12
12
|
base_url: str, token: str
|
|
13
13
|
) -> Tuple[Optional[str], Optional[str]]:
|
|
14
14
|
user_url = f"{base_url}/orchestrator_/odata/Users/UiPath.Server.Configuration.OData.GetCurrentUserExtended?$expand=PersonalWorkspace"
|
|
15
|
-
user_response = client.get(user_url, headers={"Authorization": f"Bearer {token}"})
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
with httpx.Client(**get_httpx_client_kwargs()) as client:
|
|
17
|
+
user_response = client.get(
|
|
18
|
+
user_url, headers={"Authorization": f"Bearer {token}"}
|
|
19
|
+
)
|
|
19
20
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
if user_response.status_code != 200:
|
|
22
|
+
console.error(
|
|
23
|
+
"Error: Failed to fetch user info. Please try reauthenticating."
|
|
24
|
+
)
|
|
25
|
+
return None, None
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|
|
27
|
+
user_data = user_response.json()
|
|
28
|
+
feed_id = user_data.get("PersonalWorskpaceFeedId")
|
|
29
|
+
personal_workspace = user_data.get("PersonalWorkspace")
|
|
26
30
|
|
|
27
|
-
|
|
28
|
-
|
|
31
|
+
if not personal_workspace or not feed_id or "Id" not in personal_workspace:
|
|
32
|
+
return None, None
|
|
33
|
+
|
|
34
|
+
folder_id = personal_workspace.get("Id")
|
|
35
|
+
return feed_id, folder_id
|
uipath/_cli/_utils/_processes.py
CHANGED
|
@@ -4,10 +4,10 @@ from typing import Any
|
|
|
4
4
|
|
|
5
5
|
import httpx
|
|
6
6
|
|
|
7
|
+
from ..._utils._ssl_context import get_httpx_client_kwargs
|
|
7
8
|
from ._console import ConsoleLogger
|
|
8
9
|
|
|
9
10
|
console = ConsoleLogger()
|
|
10
|
-
client = httpx.Client(follow_redirects=True, timeout=30.0)
|
|
11
11
|
odata_top_filter = 25
|
|
12
12
|
|
|
13
13
|
|
|
@@ -24,26 +24,31 @@ def get_release_info(
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
release_url = f"{base_url}/orchestrator_/odata/Releases/UiPath.Server.Configuration.OData.ListReleases?$select=Id,Key,ProcessVersion&$top={odata_top_filter}&$filter=ProcessKey%20eq%20%27{urllib.parse.quote(package_name)}%27"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
27
|
+
|
|
28
|
+
with httpx.Client(**get_httpx_client_kwargs()) as client:
|
|
29
|
+
response = client.get(release_url, headers=headers)
|
|
30
|
+
|
|
31
|
+
if response.status_code == 200:
|
|
32
|
+
try:
|
|
33
|
+
data = json.loads(response.text)
|
|
34
|
+
process = next(
|
|
35
|
+
process
|
|
36
|
+
for process in data["value"]
|
|
37
|
+
if process["ProcessVersion"] == package_version
|
|
38
|
+
)
|
|
39
|
+
release_id = process["Id"]
|
|
40
|
+
release_key = process["Key"]
|
|
41
|
+
return release_id, release_key
|
|
42
|
+
except KeyError:
|
|
43
|
+
console.warning("Warning: Failed to deserialize release data")
|
|
44
|
+
return None, None
|
|
45
|
+
except StopIteration:
|
|
46
|
+
console.error(
|
|
47
|
+
f"Error: No process with name '{package_name}' found in your workspace. Please publish the process first."
|
|
48
|
+
)
|
|
49
|
+
return None, None
|
|
50
|
+
else:
|
|
51
|
+
console.warning(
|
|
52
|
+
f"Warning: Failed to fetch release info {response.status_code}"
|
|
45
53
|
)
|
|
46
54
|
return None, None
|
|
47
|
-
else:
|
|
48
|
-
console.warning(f"Warning: Failed to fetch release info {response.status_code}")
|
|
49
|
-
return None, None
|
uipath/_cli/cli_auth.py
CHANGED
|
@@ -92,6 +92,11 @@ def auth(
|
|
|
92
92
|
|
|
93
93
|
Interactive mode (default): Opens browser for OAuth authentication.
|
|
94
94
|
Unattended mode: Use --client-id, --client-secret and --base-url for client credentials flow.
|
|
95
|
+
|
|
96
|
+
Network options:
|
|
97
|
+
- Set HTTP_PROXY/HTTPS_PROXY/NO_PROXY environment variables for proxy configuration
|
|
98
|
+
- Set REQUESTS_CA_BUNDLE to specify a custom CA bundle for SSL verification
|
|
99
|
+
- Set UIPATH_DISABLE_SSL_VERIFY to disable SSL verification (not recommended)
|
|
95
100
|
"""
|
|
96
101
|
# Check if client credentials are provided for unattended authentication
|
|
97
102
|
if client_id and client_secret:
|
|
@@ -102,7 +107,6 @@ def auth(
|
|
|
102
107
|
return
|
|
103
108
|
|
|
104
109
|
with console.spinner("Authenticating with client credentials ..."):
|
|
105
|
-
# Create service instance
|
|
106
110
|
credentials_service = ClientCredentialsService(domain)
|
|
107
111
|
|
|
108
112
|
# If base_url is provided, extract domain from it to override the CLI domain parameter
|
|
@@ -127,56 +131,57 @@ def auth(
|
|
|
127
131
|
|
|
128
132
|
# Interactive authentication flow (existing logic)
|
|
129
133
|
with console.spinner("Authenticating with UiPath ..."):
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
134
|
+
with PortalService(domain) as portal_service:
|
|
135
|
+
if not force:
|
|
136
|
+
if (
|
|
137
|
+
os.getenv("UIPATH_URL")
|
|
138
|
+
and os.getenv("UIPATH_TENANT_ID")
|
|
139
|
+
and os.getenv("UIPATH_ORGANIZATION_ID")
|
|
140
|
+
):
|
|
141
|
+
try:
|
|
142
|
+
portal_service.ensure_valid_token()
|
|
143
|
+
console.success(
|
|
144
|
+
"Authentication successful.",
|
|
145
|
+
)
|
|
146
|
+
return
|
|
147
|
+
except Exception:
|
|
148
|
+
console.info(
|
|
149
|
+
"Authentication token is invalid. Please reauthenticate.",
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
auth_url, code_verifier, state = get_auth_url(domain)
|
|
153
|
+
|
|
154
|
+
webbrowser.open(auth_url, 1)
|
|
155
|
+
auth_config = get_auth_config()
|
|
156
|
+
|
|
157
|
+
console.link(
|
|
158
|
+
"If a browser window did not open, please open the following URL in your browser:",
|
|
159
|
+
auth_url,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
server = HTTPServer(port=auth_config["port"])
|
|
163
|
+
token_data = server.start(state, code_verifier, domain)
|
|
164
|
+
|
|
165
|
+
if token_data:
|
|
166
|
+
portal_service.update_token_data(token_data)
|
|
167
|
+
update_auth_file(token_data)
|
|
168
|
+
access_token = token_data["access_token"]
|
|
169
|
+
update_env_file({"UIPATH_ACCESS_TOKEN": access_token})
|
|
170
|
+
|
|
171
|
+
tenants_and_organizations = (
|
|
172
|
+
portal_service.get_tenants_and_organizations()
|
|
173
|
+
)
|
|
174
|
+
base_url = select_tenant(domain, tenants_and_organizations)
|
|
138
175
|
try:
|
|
139
|
-
portal_service.
|
|
176
|
+
portal_service.post_auth(base_url)
|
|
140
177
|
console.success(
|
|
141
178
|
"Authentication successful.",
|
|
142
179
|
)
|
|
143
|
-
return
|
|
144
180
|
except Exception:
|
|
145
|
-
console.
|
|
146
|
-
"
|
|
181
|
+
console.error(
|
|
182
|
+
"Could not prepare the environment. Please try again.",
|
|
147
183
|
)
|
|
148
|
-
|
|
149
|
-
auth_url, code_verifier, state = get_auth_url(domain)
|
|
150
|
-
|
|
151
|
-
webbrowser.open(auth_url, 1)
|
|
152
|
-
auth_config = get_auth_config()
|
|
153
|
-
|
|
154
|
-
console.link(
|
|
155
|
-
"If a browser window did not open, please open the following URL in your browser:",
|
|
156
|
-
auth_url,
|
|
157
|
-
)
|
|
158
|
-
|
|
159
|
-
server = HTTPServer(port=auth_config["port"])
|
|
160
|
-
token_data = server.start(state, code_verifier, domain)
|
|
161
|
-
|
|
162
|
-
if token_data:
|
|
163
|
-
portal_service.update_token_data(token_data)
|
|
164
|
-
update_auth_file(token_data)
|
|
165
|
-
access_token = token_data["access_token"]
|
|
166
|
-
update_env_file({"UIPATH_ACCESS_TOKEN": access_token})
|
|
167
|
-
|
|
168
|
-
tenants_and_organizations = portal_service.get_tenants_and_organizations()
|
|
169
|
-
base_url = select_tenant(domain, tenants_and_organizations)
|
|
170
|
-
try:
|
|
171
|
-
portal_service.post_auth(base_url)
|
|
172
|
-
console.success(
|
|
173
|
-
"Authentication successful.",
|
|
174
|
-
)
|
|
175
|
-
except Exception:
|
|
184
|
+
else:
|
|
176
185
|
console.error(
|
|
177
|
-
"
|
|
186
|
+
"Authentication failed. Please try again.",
|
|
178
187
|
)
|
|
179
|
-
else:
|
|
180
|
-
console.error(
|
|
181
|
-
"Authentication failed. Please try again.",
|
|
182
|
-
)
|
uipath/_cli/cli_invoke.py
CHANGED
|
@@ -14,6 +14,7 @@ try:
|
|
|
14
14
|
except ImportError:
|
|
15
15
|
import tomli as tomllib
|
|
16
16
|
|
|
17
|
+
from .._utils._ssl_context import get_httpx_client_kwargs
|
|
17
18
|
from ..telemetry import track
|
|
18
19
|
from ._utils._common import get_env_vars
|
|
19
20
|
from ._utils._folders import get_personal_workspace_info
|
|
@@ -22,7 +23,6 @@ from ._utils._processes import get_release_info
|
|
|
22
23
|
logger = logging.getLogger(__name__)
|
|
23
24
|
load_dotenv(override=True)
|
|
24
25
|
console = ConsoleLogger()
|
|
25
|
-
client = httpx.Client(follow_redirects=True, timeout=30.0)
|
|
26
26
|
|
|
27
27
|
|
|
28
28
|
def _read_project_details() -> [str, str]:
|
|
@@ -92,23 +92,24 @@ def invoke(
|
|
|
92
92
|
"x-uipath-organizationunitid": str(personal_workspace_folder_id),
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
95
|
+
with httpx.Client(**get_httpx_client_kwargs()) as client:
|
|
96
|
+
response = client.post(url, json=payload, headers=headers)
|
|
97
|
+
|
|
98
|
+
if response.status_code == 201:
|
|
99
|
+
job_key = None
|
|
100
|
+
try:
|
|
101
|
+
job_key = response.json()["value"][0]["Key"]
|
|
102
|
+
except KeyError:
|
|
103
|
+
console.error("Error: Failed to get job key from response")
|
|
104
|
+
if job_key:
|
|
105
|
+
with console.spinner("Starting job ..."):
|
|
106
|
+
job_url = f"{base_url}/orchestrator_/jobs(sidepanel:sidepanel/jobs/{job_key}/details)?fid={personal_workspace_folder_id}"
|
|
107
|
+
console.magic("Job started successfully!")
|
|
108
|
+
console.link("Monitor your job here: ", job_url)
|
|
109
|
+
else:
|
|
110
|
+
console.error(
|
|
111
|
+
f"Error: Failed to start job. Status code: {response.status_code} {response.text}"
|
|
112
|
+
)
|
|
112
113
|
|
|
113
114
|
|
|
114
115
|
if __name__ == "__main__":
|
uipath/_cli/cli_publish.py
CHANGED
|
@@ -6,6 +6,7 @@ import click
|
|
|
6
6
|
import httpx
|
|
7
7
|
from dotenv import load_dotenv
|
|
8
8
|
|
|
9
|
+
from .._utils._ssl_context import get_httpx_client_kwargs
|
|
9
10
|
from ..telemetry import track
|
|
10
11
|
from ._utils._common import get_env_vars
|
|
11
12
|
from ._utils._console import ConsoleLogger
|
|
@@ -13,7 +14,6 @@ from ._utils._folders import get_personal_workspace_info
|
|
|
13
14
|
from ._utils._processes import get_release_info
|
|
14
15
|
|
|
15
16
|
console = ConsoleLogger()
|
|
16
|
-
client = httpx.Client(follow_redirects=True, timeout=30.0)
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def get_most_recent_package():
|
|
@@ -35,7 +35,10 @@ def get_available_feeds(
|
|
|
35
35
|
base_url: str, headers: dict[str, str]
|
|
36
36
|
) -> list[tuple[str, str]]:
|
|
37
37
|
url = f"{base_url}/orchestrator_/api/PackageFeeds/GetFeeds"
|
|
38
|
-
|
|
38
|
+
|
|
39
|
+
with httpx.Client(**get_httpx_client_kwargs()) as client:
|
|
40
|
+
response = client.get(url, headers=headers)
|
|
41
|
+
|
|
39
42
|
if response.status_code != 200:
|
|
40
43
|
console.error(
|
|
41
44
|
f"Failed to fetch available feeds. Please check your connection. Status code: {response.status_code} {response.text}"
|
|
@@ -123,40 +126,43 @@ def publish(feed):
|
|
|
123
126
|
else:
|
|
124
127
|
url = url + "?feedId=" + feed
|
|
125
128
|
|
|
126
|
-
with
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
129
|
+
with httpx.Client(**get_httpx_client_kwargs()) as client:
|
|
130
|
+
with open(package_to_publish_path, "rb") as f:
|
|
131
|
+
files = {
|
|
132
|
+
"file": (package_to_publish_path, f, "application/octet-stream")
|
|
133
|
+
}
|
|
134
|
+
response = client.post(url, headers=headers, files=files)
|
|
135
|
+
|
|
136
|
+
if response.status_code == 200:
|
|
137
|
+
console.success("Package published successfully!")
|
|
138
|
+
|
|
139
|
+
if is_personal_workspace:
|
|
140
|
+
package_name = None
|
|
141
|
+
package_version = None
|
|
142
|
+
try:
|
|
143
|
+
data = json.loads(response.text)["value"][0]["Body"]
|
|
144
|
+
package_name = json.loads(data)["Id"]
|
|
145
|
+
package_version = json.loads(data)["Version"]
|
|
146
|
+
except json.decoder.JSONDecodeError:
|
|
147
|
+
console.warning("Failed to deserialize package name")
|
|
148
|
+
if package_name is not None:
|
|
149
|
+
with console.spinner("Getting process information ..."):
|
|
150
|
+
release_id, _ = get_release_info(
|
|
151
|
+
base_url,
|
|
152
|
+
token,
|
|
153
|
+
package_name,
|
|
154
|
+
package_version,
|
|
155
|
+
personal_workspace_feed_id,
|
|
156
|
+
)
|
|
157
|
+
if release_id:
|
|
158
|
+
process_url = f"{base_url}/orchestrator_/processes/{release_id}/edit?fid={personal_workspace_folder_id}"
|
|
159
|
+
console.link("Process configuration link:", process_url)
|
|
160
|
+
console.hint(
|
|
161
|
+
"Use the link above to configure any environment variables"
|
|
162
|
+
)
|
|
163
|
+
else:
|
|
164
|
+
console.warning("Failed to compose process url")
|
|
157
165
|
else:
|
|
158
|
-
console.
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
f"Failed to publish package. Status code: {response.status_code} {response.text}"
|
|
162
|
-
)
|
|
166
|
+
console.error(
|
|
167
|
+
f"Failed to publish package. Status code: {response.status_code} {response.text}"
|
|
168
|
+
)
|
|
@@ -23,6 +23,7 @@ from uipath._utils._read_overwrites import OverwritesManager
|
|
|
23
23
|
from .._config import Config
|
|
24
24
|
from .._execution_context import ExecutionContext
|
|
25
25
|
from .._utils import UiPathUrl, user_agent_value
|
|
26
|
+
from .._utils._ssl_context import get_httpx_client_kwargs
|
|
26
27
|
from .._utils.constants import HEADER_USER_AGENT
|
|
27
28
|
|
|
28
29
|
|
|
@@ -42,17 +43,16 @@ class BaseService:
|
|
|
42
43
|
|
|
43
44
|
self._url = UiPathUrl(self._config.base_url)
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
base_url=self._url.base_url,
|
|
47
|
-
headers=Headers(self.default_headers),
|
|
48
|
-
timeout=30.0,
|
|
49
|
-
)
|
|
46
|
+
default_client_kwargs = get_httpx_client_kwargs()
|
|
50
47
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
48
|
+
client_kwargs = {
|
|
49
|
+
**default_client_kwargs, # SSL, proxy, timeout, redirects
|
|
50
|
+
"base_url": self._url.base_url,
|
|
51
|
+
"headers": Headers(self.default_headers),
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
self._client = Client(**client_kwargs)
|
|
55
|
+
self._client_async = AsyncClient(**client_kwargs)
|
|
56
56
|
|
|
57
57
|
self._overwrites_manager = OverwritesManager()
|
|
58
58
|
self._logger.debug(f"HEADERS: {self.default_headers}")
|
|
@@ -11,6 +11,7 @@ from .._config import Config
|
|
|
11
11
|
from .._execution_context import ExecutionContext
|
|
12
12
|
from .._folder_context import FolderContext
|
|
13
13
|
from .._utils import Endpoint, RequestSpec, header_folder
|
|
14
|
+
from .._utils._ssl_context import get_httpx_client_kwargs
|
|
14
15
|
from .._utils.constants import TEMP_ATTACHMENTS_FOLDER
|
|
15
16
|
from ..tracing._traced import traced
|
|
16
17
|
from ._base_service import BaseService
|
|
@@ -121,7 +122,7 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
121
122
|
for chunk in response.iter_bytes(chunk_size=8192):
|
|
122
123
|
file.write(chunk)
|
|
123
124
|
else:
|
|
124
|
-
with httpx.Client() as client:
|
|
125
|
+
with httpx.Client(**get_httpx_client_kwargs()) as client:
|
|
125
126
|
with client.stream(
|
|
126
127
|
"GET", download_uri, headers=headers
|
|
127
128
|
) as response:
|
|
@@ -390,7 +391,7 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
390
391
|
"PUT", upload_uri, headers=headers, content=file_content
|
|
391
392
|
)
|
|
392
393
|
else:
|
|
393
|
-
with httpx.Client() as client:
|
|
394
|
+
with httpx.Client(**get_httpx_client_kwargs()) as client:
|
|
394
395
|
client.put(upload_uri, headers=headers, content=file_content)
|
|
395
396
|
else:
|
|
396
397
|
# Upload from memory
|
|
@@ -401,7 +402,7 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
401
402
|
if result["BlobFileAccess"]["RequiresAuth"]:
|
|
402
403
|
self.request("PUT", upload_uri, headers=headers, content=content)
|
|
403
404
|
else:
|
|
404
|
-
with httpx.Client() as client:
|
|
405
|
+
with httpx.Client(**get_httpx_client_kwargs()) as client:
|
|
405
406
|
client.put(upload_uri, headers=headers, content=content)
|
|
406
407
|
|
|
407
408
|
return attachment_key
|
|
@@ -526,7 +527,7 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
526
527
|
"PUT", upload_uri, headers=headers, content=file_content
|
|
527
528
|
)
|
|
528
529
|
else:
|
|
529
|
-
with httpx.Client() as client:
|
|
530
|
+
with httpx.Client(**get_httpx_client_kwargs()) as client:
|
|
530
531
|
client.put(upload_uri, headers=headers, content=file_content)
|
|
531
532
|
else:
|
|
532
533
|
# Upload from memory
|
|
@@ -539,7 +540,7 @@ class AttachmentsService(FolderContext, BaseService):
|
|
|
539
540
|
"PUT", upload_uri, headers=headers, content=content
|
|
540
541
|
)
|
|
541
542
|
else:
|
|
542
|
-
with httpx.Client() as client:
|
|
543
|
+
with httpx.Client(**get_httpx_client_kwargs()) as client:
|
|
543
544
|
client.put(upload_uri, headers=headers, content=content)
|
|
544
545
|
|
|
545
546
|
return attachment_key
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import mimetypes
|
|
2
|
-
from typing import
|
|
2
|
+
from typing import Dict, Optional, Union
|
|
3
3
|
|
|
4
4
|
import httpx
|
|
5
5
|
|
|
@@ -7,16 +7,12 @@ from .._config import Config
|
|
|
7
7
|
from .._execution_context import ExecutionContext
|
|
8
8
|
from .._folder_context import FolderContext
|
|
9
9
|
from .._utils import Endpoint, RequestSpec, header_folder, infer_bindings
|
|
10
|
+
from .._utils._ssl_context import get_httpx_client_kwargs
|
|
10
11
|
from ..models import Bucket
|
|
11
12
|
from ..tracing._traced import traced
|
|
12
13
|
from ._base_service import BaseService
|
|
13
14
|
|
|
14
15
|
|
|
15
|
-
def _upload_from_memory_input_processor(inputs: Dict[str, Any]) -> Dict[str, Any]:
|
|
16
|
-
inputs["content"] = "<Redacted>"
|
|
17
|
-
return inputs
|
|
18
|
-
|
|
19
|
-
|
|
20
16
|
class BucketsService(FolderContext, BaseService):
|
|
21
17
|
"""Service for managing UiPath storage buckets.
|
|
22
18
|
|
|
@@ -26,8 +22,8 @@ class BucketsService(FolderContext, BaseService):
|
|
|
26
22
|
|
|
27
23
|
def __init__(self, config: Config, execution_context: ExecutionContext) -> None:
|
|
28
24
|
super().__init__(config=config, execution_context=execution_context)
|
|
29
|
-
self.custom_client = httpx.Client()
|
|
30
|
-
self.custom_client_async = httpx.AsyncClient()
|
|
25
|
+
self.custom_client = httpx.Client(**get_httpx_client_kwargs())
|
|
26
|
+
self.custom_client_async = httpx.AsyncClient(**get_httpx_client_kwargs())
|
|
31
27
|
|
|
32
28
|
@traced(name="buckets_download", run_type="uipath")
|
|
33
29
|
@infer_bindings(resource_type="bucket")
|
|
@@ -10,9 +10,9 @@ from ..models.llm_gateway import (
|
|
|
10
10
|
TextEmbedding,
|
|
11
11
|
ToolChoice,
|
|
12
12
|
ToolDefinition,
|
|
13
|
-
UsageInfo,
|
|
14
13
|
)
|
|
15
14
|
from ..tracing._traced import traced
|
|
15
|
+
from ..utils import EndpointManager
|
|
16
16
|
from ._base_service import BaseService
|
|
17
17
|
|
|
18
18
|
# Common constants
|
|
@@ -54,36 +54,12 @@ class UiPathOpenAIService(BaseService):
|
|
|
54
54
|
def __init__(self, config: Config, execution_context: ExecutionContext) -> None:
|
|
55
55
|
super().__init__(config=config, execution_context=execution_context)
|
|
56
56
|
|
|
57
|
-
@traced(name="llm_embeddings_usage", run_type="uipath")
|
|
58
|
-
async def embeddings_usage(
|
|
59
|
-
self, input: str, embedding_model: str = EmbeddingModels.text_embedding_ada_002
|
|
60
|
-
):
|
|
61
|
-
"""Embedd the input text using llm gateway service.
|
|
62
|
-
|
|
63
|
-
Args:
|
|
64
|
-
input (str): The input text to embedd.
|
|
65
|
-
embedding_model (str, optional): The embedding model to use. Defaults to text-embedding-ada-002.
|
|
66
|
-
|
|
67
|
-
Returns:
|
|
68
|
-
EmbeddingUsageInfo: The embedding usage information.
|
|
69
|
-
"""
|
|
70
|
-
endpoint = Endpoint(
|
|
71
|
-
f"/llmgateway_/openai/deployments/{embedding_model}/embeddings/usage"
|
|
72
|
-
)
|
|
73
|
-
|
|
74
|
-
response = await self.request_async(
|
|
75
|
-
"POST",
|
|
76
|
-
endpoint,
|
|
77
|
-
content=json.dumps({"input": input}),
|
|
78
|
-
params={"api-version": API_VERSION},
|
|
79
|
-
headers=DEFAULT_LLM_HEADERS,
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
return UsageInfo.model_validate(response.json())
|
|
83
|
-
|
|
84
57
|
@traced(name="llm_embeddings", run_type="uipath")
|
|
85
58
|
async def embeddings(
|
|
86
|
-
self,
|
|
59
|
+
self,
|
|
60
|
+
input: str,
|
|
61
|
+
embedding_model: str = EmbeddingModels.text_embedding_ada_002,
|
|
62
|
+
openai_api_version: str = API_VERSION,
|
|
87
63
|
):
|
|
88
64
|
"""Embed the input text using llm gateway service.
|
|
89
65
|
|
|
@@ -93,9 +69,10 @@ class UiPathOpenAIService(BaseService):
|
|
|
93
69
|
Returns:
|
|
94
70
|
TextEmbedding: The embedding response.
|
|
95
71
|
"""
|
|
96
|
-
endpoint =
|
|
97
|
-
|
|
72
|
+
endpoint = EndpointManager.get_embeddings_endpoint().format(
|
|
73
|
+
model=embedding_model, api_version=openai_api_version
|
|
98
74
|
)
|
|
75
|
+
endpoint = Endpoint("/" + endpoint)
|
|
99
76
|
|
|
100
77
|
response = await self.request_async(
|
|
101
78
|
"POST",
|
|
@@ -114,6 +91,7 @@ class UiPathOpenAIService(BaseService):
|
|
|
114
91
|
model: str = ChatModels.gpt_4o_mini_2024_07_18,
|
|
115
92
|
max_tokens: int = 50,
|
|
116
93
|
temperature: float = 0,
|
|
94
|
+
api_version: str = API_VERSION,
|
|
117
95
|
):
|
|
118
96
|
"""Get chat completions using llm gateway service.
|
|
119
97
|
|
|
@@ -139,59 +117,10 @@ class UiPathOpenAIService(BaseService):
|
|
|
139
117
|
Returns:
|
|
140
118
|
ChatCompletion: The chat completion response.
|
|
141
119
|
"""
|
|
142
|
-
endpoint =
|
|
143
|
-
|
|
144
|
-
request_body = {
|
|
145
|
-
"messages": messages,
|
|
146
|
-
"max_tokens": max_tokens,
|
|
147
|
-
"temperature": temperature,
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
response = await self.request_async(
|
|
151
|
-
"POST",
|
|
152
|
-
endpoint,
|
|
153
|
-
content=json.dumps(request_body),
|
|
154
|
-
params={"api-version": API_VERSION},
|
|
155
|
-
headers=DEFAULT_LLM_HEADERS,
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
return ChatCompletion.model_validate(response.json())
|
|
159
|
-
|
|
160
|
-
@traced(name="llm_chat_completions_usage", run_type="uipath")
|
|
161
|
-
async def chat_completions_usage(
|
|
162
|
-
self,
|
|
163
|
-
messages: List[Dict[str, str]],
|
|
164
|
-
model: str = ChatModels.gpt_4o_mini_2024_07_18,
|
|
165
|
-
max_tokens: int = 50,
|
|
166
|
-
temperature: float = 0,
|
|
167
|
-
):
|
|
168
|
-
"""Get chat completions usage using llm gateway service.
|
|
169
|
-
|
|
170
|
-
Args:
|
|
171
|
-
messages (List[Dict[str, str]]): List of message dictionaries with 'role' and 'content' keys.
|
|
172
|
-
The supported roles are 'system', 'user', and 'assistant'.
|
|
173
|
-
|
|
174
|
-
Example:
|
|
175
|
-
```
|
|
176
|
-
[
|
|
177
|
-
{"role": "system", "content": "You are a helpful Python programming assistant."},
|
|
178
|
-
{"role": "user", "content": "How do I read a file in Python?"},
|
|
179
|
-
{"role": "assistant", "content": "You can use the built-in open() function."},
|
|
180
|
-
{"role": "user", "content": "Can you show an example?"}
|
|
181
|
-
]
|
|
182
|
-
```
|
|
183
|
-
The conversation history can be included to provide context to the model.
|
|
184
|
-
model (str, optional): The model to use for chat completion. Defaults to ChatModels.gpt_4o_mini_2024_07_18.
|
|
185
|
-
max_tokens (int, optional): Maximum number of tokens to generate. Defaults to 50.
|
|
186
|
-
temperature (float, optional): Temperature for sampling, between 0 and 1.
|
|
187
|
-
Lower values make output more deterministic. Defaults to 0.
|
|
188
|
-
|
|
189
|
-
Returns:
|
|
190
|
-
ChatCompletion: The chat completion usage response.
|
|
191
|
-
"""
|
|
192
|
-
endpoint = Endpoint(
|
|
193
|
-
f"/llmgateway_/openai/deployments/{model}/chat/completions/usage"
|
|
120
|
+
endpoint = EndpointManager.get_passthrough_endpoint().format(
|
|
121
|
+
model=model, api_version=api_version
|
|
194
122
|
)
|
|
123
|
+
endpoint = Endpoint("/" + endpoint)
|
|
195
124
|
|
|
196
125
|
request_body = {
|
|
197
126
|
"messages": messages,
|
|
@@ -207,7 +136,7 @@ class UiPathOpenAIService(BaseService):
|
|
|
207
136
|
headers=DEFAULT_LLM_HEADERS,
|
|
208
137
|
)
|
|
209
138
|
|
|
210
|
-
return
|
|
139
|
+
return ChatCompletion.model_validate(response.json())
|
|
211
140
|
|
|
212
141
|
|
|
213
142
|
class UiPathLlmChatService(BaseService):
|
|
@@ -229,6 +158,7 @@ class UiPathLlmChatService(BaseService):
|
|
|
229
158
|
top_p: float = 1,
|
|
230
159
|
tools: Optional[List[ToolDefinition]] = None,
|
|
231
160
|
tool_choice: Optional[ToolChoice] = None,
|
|
161
|
+
api_version: str = NORMALIZED_API_VERSION,
|
|
232
162
|
):
|
|
233
163
|
"""Get chat completions using UiPath's normalized LLM Gateway API.
|
|
234
164
|
|
|
@@ -250,7 +180,10 @@ class UiPathLlmChatService(BaseService):
|
|
|
250
180
|
Returns:
|
|
251
181
|
ChatCompletion: The chat completion response.
|
|
252
182
|
"""
|
|
253
|
-
endpoint =
|
|
183
|
+
endpoint = EndpointManager.get_normalized_endpoint().format(
|
|
184
|
+
model=model, api_version=api_version
|
|
185
|
+
)
|
|
186
|
+
endpoint = Endpoint("/" + endpoint)
|
|
254
187
|
|
|
255
188
|
request_body = {
|
|
256
189
|
"messages": messages,
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import ssl
|
|
3
|
+
from typing import Any, Dict
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def expand_path(path):
|
|
7
|
+
"""Expand environment variables and user home directory in path."""
|
|
8
|
+
if not path:
|
|
9
|
+
return path
|
|
10
|
+
# Expand environment variables like $HOME
|
|
11
|
+
path = os.path.expandvars(path)
|
|
12
|
+
# Expand user home directory ~
|
|
13
|
+
path = os.path.expanduser(path)
|
|
14
|
+
return path
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def create_ssl_context():
|
|
18
|
+
# Try truststore first (system certificates)
|
|
19
|
+
try:
|
|
20
|
+
import truststore
|
|
21
|
+
|
|
22
|
+
return truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
|
|
23
|
+
except ImportError:
|
|
24
|
+
# Fallback to manual certificate configuration
|
|
25
|
+
import certifi
|
|
26
|
+
|
|
27
|
+
ssl_cert_file = expand_path(os.environ.get("SSL_CERT_FILE"))
|
|
28
|
+
requests_ca_bundle = expand_path(os.environ.get("REQUESTS_CA_BUNDLE"))
|
|
29
|
+
ssl_cert_dir = expand_path(os.environ.get("SSL_CERT_DIR"))
|
|
30
|
+
|
|
31
|
+
return ssl.create_default_context(
|
|
32
|
+
cafile=ssl_cert_file or requests_ca_bundle or certifi.where(),
|
|
33
|
+
capath=ssl_cert_dir,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_httpx_client_kwargs() -> Dict[str, Any]:
|
|
38
|
+
"""Get standardized httpx client configuration."""
|
|
39
|
+
client_kwargs: Dict[str, Any] = {"follow_redirects": True, "timeout": 30.0}
|
|
40
|
+
|
|
41
|
+
# Check environment variable to disable SSL verification
|
|
42
|
+
disable_ssl_env = os.environ.get("UIPATH_DISABLE_SSL_VERIFY", "").lower()
|
|
43
|
+
disable_ssl_from_env = disable_ssl_env in ("1", "true", "yes", "on")
|
|
44
|
+
|
|
45
|
+
if disable_ssl_from_env:
|
|
46
|
+
client_kwargs["verify"] = False
|
|
47
|
+
else:
|
|
48
|
+
# Use system certificates with truststore fallback
|
|
49
|
+
client_kwargs["verify"] = create_ssl_context()
|
|
50
|
+
|
|
51
|
+
# Auto-detect proxy from environment variables (httpx handles this automatically)
|
|
52
|
+
# HTTP_PROXY, HTTPS_PROXY, NO_PROXY are read by httpx by default
|
|
53
|
+
|
|
54
|
+
return client_kwargs
|
uipath/models/llm_gateway.py
CHANGED
uipath/utils/__init__.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
import httpx
|
|
7
|
+
|
|
8
|
+
loggger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class UiPathEndpoints(Enum):
|
|
12
|
+
AH_NORMALIZED_COMPLETION_ENDPOINT = "agenthub_/llm/api/chat/completions"
|
|
13
|
+
AH_PASSTHROUGH_COMPLETION_ENDPOINT = "agenthub_/llm/openai/deployments/{model}/chat/completions?api-version={api_version}"
|
|
14
|
+
AH_EMBEDDING_ENDPOINT = (
|
|
15
|
+
"agenthub_/llm/openai/deployments/{model}/embeddings?api-version={api_version}"
|
|
16
|
+
)
|
|
17
|
+
AH_CAPABILITIES_ENDPOINT = "agenthub_/llm/api/capabilities"
|
|
18
|
+
|
|
19
|
+
NORMALIZED_COMPLETION_ENDPOINT = "llmgateway_/api/chat/completions"
|
|
20
|
+
PASSTHROUGH_COMPLETION_ENDPOINT = "llmgateway_/openai/deployments/{model}/chat/completions?api-version={api_version}"
|
|
21
|
+
EMBEDDING_ENDPOINT = (
|
|
22
|
+
"llmgateway_/openai/deployments/{model}/embeddings?api-version={api_version}"
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class EndpointManager:
|
|
27
|
+
"""Manages and caches the UiPath endpoints.
|
|
28
|
+
This class provides functionality to determine which UiPath endpoints to use based on
|
|
29
|
+
the availability of AgentHub. It checks for AgentHub capabilities and caches the result
|
|
30
|
+
to avoid repeated network calls.
|
|
31
|
+
Class Attributes:
|
|
32
|
+
_base_url (str): The base URL for UiPath services, retrieved from the UIPATH_URL
|
|
33
|
+
environment variable.
|
|
34
|
+
_agenthub_available (Optional[bool]): Cached result of AgentHub availability check.
|
|
35
|
+
|
|
36
|
+
Methods:
|
|
37
|
+
is_agenthub_available(): Checks if AgentHub is available, caching the result.
|
|
38
|
+
get_passthrough_endpoint(): Returns the appropriate passthrough completion endpoint.
|
|
39
|
+
get_normalized_endpoint(): Returns the appropriate normalized completion endpoint.
|
|
40
|
+
get_embeddings_endpoint(): Returns the appropriate embeddings endpoint.
|
|
41
|
+
All endpoint methods automatically select between AgentHub and standard endpoints
|
|
42
|
+
based on availability.
|
|
43
|
+
""" # noqa: D205
|
|
44
|
+
|
|
45
|
+
_base_url = os.getenv("UIPATH_URL", "")
|
|
46
|
+
_agenthub_available: Optional[bool] = None
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def is_agenthub_available(cls) -> bool:
|
|
50
|
+
"""Check if AgentHub is available and cache the result."""
|
|
51
|
+
if cls._agenthub_available is None:
|
|
52
|
+
cls._agenthub_available = cls._check_agenthub()
|
|
53
|
+
return cls._agenthub_available
|
|
54
|
+
|
|
55
|
+
@classmethod
|
|
56
|
+
def _check_agenthub(cls) -> bool:
|
|
57
|
+
"""Perform the actual check for AgentHub capabilities."""
|
|
58
|
+
try:
|
|
59
|
+
with httpx.Client() as http_client:
|
|
60
|
+
base_url = os.getenv("UIPATH_URL", "")
|
|
61
|
+
capabilities_url = f"{base_url.rstrip('/')}/{UiPathEndpoints.AH_CAPABILITIES_ENDPOINT.value}"
|
|
62
|
+
loggger.debug(f"Checking AgentHub capabilities at {capabilities_url}")
|
|
63
|
+
response = http_client.get(capabilities_url)
|
|
64
|
+
return response.status_code == 200
|
|
65
|
+
except Exception as e:
|
|
66
|
+
loggger.error(f"Error checking AgentHub capabilities: {e}", exc_info=True)
|
|
67
|
+
return False
|
|
68
|
+
|
|
69
|
+
@classmethod
|
|
70
|
+
def get_passthrough_endpoint(cls) -> str:
|
|
71
|
+
if cls.is_agenthub_available():
|
|
72
|
+
return UiPathEndpoints.AH_PASSTHROUGH_COMPLETION_ENDPOINT.value
|
|
73
|
+
|
|
74
|
+
return UiPathEndpoints.PASSTHROUGH_COMPLETION_ENDPOINT.value
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def get_normalized_endpoint(cls) -> str:
|
|
78
|
+
if cls.is_agenthub_available():
|
|
79
|
+
return UiPathEndpoints.AH_NORMALIZED_COMPLETION_ENDPOINT.value
|
|
80
|
+
|
|
81
|
+
return UiPathEndpoints.NORMALIZED_COMPLETION_ENDPOINT.value
|
|
82
|
+
|
|
83
|
+
@classmethod
|
|
84
|
+
def get_embeddings_endpoint(cls) -> str:
|
|
85
|
+
if cls.is_agenthub_available():
|
|
86
|
+
return UiPathEndpoints.AH_EMBEDDING_ENDPOINT.value
|
|
87
|
+
|
|
88
|
+
return UiPathEndpoints.EMBEDDING_ENDPOINT.value
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: uipath
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.75
|
|
4
4
|
Summary: Python SDK and CLI for UiPath Platform, enabling programmatic interaction with automation services, process management, and deployment tools.
|
|
5
5
|
Project-URL: Homepage, https://uipath.com
|
|
6
6
|
Project-URL: Repository, https://github.com/UiPath/uipath-python
|
|
@@ -24,6 +24,7 @@ Requires-Dist: python-dotenv>=1.0.1
|
|
|
24
24
|
Requires-Dist: rich>=13.0.0
|
|
25
25
|
Requires-Dist: tenacity>=9.0.0
|
|
26
26
|
Requires-Dist: tomli>=2.2.1
|
|
27
|
+
Requires-Dist: truststore>=0.10.1
|
|
27
28
|
Provides-Extra: langchain
|
|
28
29
|
Requires-Dist: uipath-langchain<0.1.0,>=0.0.88; extra == 'langchain'
|
|
29
30
|
Description-Content-Type: text/markdown
|
|
@@ -6,21 +6,21 @@ uipath/_uipath.py,sha256=54u-aPF29DE3fOn8yM1pjVTqSZxSSaIsifiZG9Mt_YM,3824
|
|
|
6
6
|
uipath/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
7
7
|
uipath/_cli/README.md,sha256=GLtCfbeIKZKNnGTCsfSVqRQ27V1btT1i2bSAyW_xZl4,474
|
|
8
8
|
uipath/_cli/__init__.py,sha256=vGz3vJHkUvgK9_lKdzqiwwHkge1TCALRiOzGGwyr-8E,1885
|
|
9
|
-
uipath/_cli/cli_auth.py,sha256=
|
|
9
|
+
uipath/_cli/cli_auth.py,sha256=kWk0tznOxmU6xwhJgUAMipTevH2iTIotcNiIwmPlpYI,6507
|
|
10
10
|
uipath/_cli/cli_deploy.py,sha256=KPCmQ0c_NYD5JofSDao5r6QYxHshVCRxlWDVnQvlp5w,645
|
|
11
11
|
uipath/_cli/cli_init.py,sha256=SmB7VplpXRSa5sgqgzojNsZDw0zfsEi2TfkMx3eQpTo,5132
|
|
12
|
-
uipath/_cli/cli_invoke.py,sha256=
|
|
12
|
+
uipath/_cli/cli_invoke.py,sha256=FurosrZNGlmANIrplKWhw3EQ1b46ph5Z2rPwVaYJgmc,4001
|
|
13
13
|
uipath/_cli/cli_new.py,sha256=9378NYUBc9j-qKVXV7oja-jahfJhXBg8zKVyaon7ctY,2102
|
|
14
14
|
uipath/_cli/cli_pack.py,sha256=qqmh7v0j4_vA4Xko5PgKFEbJIOXlmJBGd9IRnDi-wtA,17285
|
|
15
|
-
uipath/_cli/cli_publish.py,sha256=
|
|
15
|
+
uipath/_cli/cli_publish.py,sha256=QT17JTClAyLve6ZjB-WvQaJ-j4DdmNneV_eDRyXjeeQ,6578
|
|
16
16
|
uipath/_cli/cli_run.py,sha256=zYg-9U6mkofdGsE0IGjYi1dOMlG8CdBxiVGxfFiLq5Y,5882
|
|
17
17
|
uipath/_cli/middlewares.py,sha256=f7bVODO9tgdtWNepG5L58-B-VgBSU6Ek2tIU6wLz0xA,4905
|
|
18
18
|
uipath/_cli/spinner.py,sha256=bS-U_HA5yne11ejUERu7CQoXmWdabUD2bm62EfEdV8M,1107
|
|
19
19
|
uipath/_cli/_auth/_auth_server.py,sha256=p93_EvJpdoLLkiVmLygHRKo9ru1-PZOEAaEhNFN3j6c,6424
|
|
20
|
-
uipath/_cli/_auth/_client_credentials.py,sha256=
|
|
20
|
+
uipath/_cli/_auth/_client_credentials.py,sha256=eENVb54-uzEqi7bC5VNjsiULW4fSfs-sK0kgUjRKorA,5412
|
|
21
21
|
uipath/_cli/_auth/_models.py,sha256=sYMCfvmprIqnZxStlD_Dxx2bcxgn0Ri4D7uwemwkcNg,948
|
|
22
22
|
uipath/_cli/_auth/_oidc_utils.py,sha256=WaX9jDlXrlX6yD8i8gsocV8ngjaT72Xd1tvsZMmSbco,2127
|
|
23
|
-
uipath/_cli/_auth/_portal_service.py,sha256=
|
|
23
|
+
uipath/_cli/_auth/_portal_service.py,sha256=iAxEDEY7OcEbIUSKNZnURAuNsimNmU90NLHkkTLqREY,8079
|
|
24
24
|
uipath/_cli/_auth/_utils.py,sha256=9nb76xe5XmDZ0TAncp-_1SKqL6FdwRi9eS3C2noN1lY,1591
|
|
25
25
|
uipath/_cli/_auth/auth_config.json,sha256=ib1qYxU6Totvl2pxFkqqmjVe3tOYR98mFFsUska9lOA,359
|
|
26
26
|
uipath/_cli/_auth/index.html,sha256=ML_xDOcKs0ETYucufJskiYfWSvdrD_E26C0Qd3qpGj8,6280
|
|
@@ -40,23 +40,23 @@ uipath/_cli/_utils/_common.py,sha256=wQ0a_lGj0bsuNvwxUfnLwg6T3IdatdfkrPcZMoufJNU
|
|
|
40
40
|
uipath/_cli/_utils/_console.py,sha256=rj4V3yeR1wnJzFTHnaE6wcY9OoJV-PiIQnLg_p62ClQ,6664
|
|
41
41
|
uipath/_cli/_utils/_constants.py,sha256=mCeSWLURgw_dOMXjzyYBAvxKN3Vcd1vf7XKHgbdrOds,25
|
|
42
42
|
uipath/_cli/_utils/_debug.py,sha256=XlMkjtXT6hqyn7huioLDaVSYqo9fyWCvTkqEJh_ZEGw,1598
|
|
43
|
-
uipath/_cli/_utils/_folders.py,sha256=
|
|
43
|
+
uipath/_cli/_utils/_folders.py,sha256=UVJcKPfPAVR5HF4AP6EXdlNVcfEF1v5pwGCpoAgBY34,1155
|
|
44
44
|
uipath/_cli/_utils/_input_args.py,sha256=pyQhEcQXHdFHYTVNzvfWp439aii5StojoptnmCv5lfs,4094
|
|
45
45
|
uipath/_cli/_utils/_parse_ast.py,sha256=A-QToBIf-oP7yP2DQTHO6blkk6ik5z_IeaIwtEWO4e0,19516
|
|
46
|
-
uipath/_cli/_utils/_processes.py,sha256=
|
|
46
|
+
uipath/_cli/_utils/_processes.py,sha256=q7DfEKHISDWf3pngci5za_z0Pbnf_shWiYEcTOTCiyk,1855
|
|
47
47
|
uipath/_cli/_utils/_tracing.py,sha256=2igb03j3EHjF_A406UhtCKkPfudVfFPjUq5tXUEG4oo,1541
|
|
48
48
|
uipath/_services/__init__.py,sha256=10xtw3ENC30yR9CCq_b94RMZ3YrUeyfHV33yWYUd8tU,896
|
|
49
|
-
uipath/_services/_base_service.py,sha256=
|
|
49
|
+
uipath/_services/_base_service.py,sha256=7ZZDMC1TQkVk7pp-1T4a4sJOBI6O98_y9QrHN5yc8gA,5436
|
|
50
50
|
uipath/_services/actions_service.py,sha256=LYKvG4VxNGQgZ46AzGK9kI1Txb-YmVvZj5ScPOue8Ls,15989
|
|
51
51
|
uipath/_services/api_client.py,sha256=hcof0EMa4-phEHD1WlO7Tdfzq6aL18Sbi2aBE7lJm1w,1821
|
|
52
52
|
uipath/_services/assets_service.py,sha256=acqWogfhZiSO1eeVYqFxmqWGSTmrW46QxI1J0bJe3jo,11918
|
|
53
|
-
uipath/_services/attachments_service.py,sha256=
|
|
54
|
-
uipath/_services/buckets_service.py,sha256=
|
|
53
|
+
uipath/_services/attachments_service.py,sha256=Y0xJlK6UOtbG6oPLT9bW8XbfuGQPK9MEaZdMRdGA3zs,26651
|
|
54
|
+
uipath/_services/buckets_service.py,sha256=5s8tuivd7GUZYj774DDUYTa0axxlUuesc4EBY1V5sdk,18496
|
|
55
55
|
uipath/_services/connections_service.py,sha256=qh-HNL_GJsyPUD0wSJZRF8ZdrTE9l4HrIilmXGK6dDk,4581
|
|
56
56
|
uipath/_services/context_grounding_service.py,sha256=EBf7lIIYz_s1ubf_07OAZXQHjS8kpZ2vqxo4mI3VL-A,25009
|
|
57
57
|
uipath/_services/folder_service.py,sha256=9JqgjKhWD-G_KUnfUTP2BADxL6OK9QNZsBsWZHAULdE,2749
|
|
58
58
|
uipath/_services/jobs_service.py,sha256=CnDd7BM4AMqcMIR1qqu5ohhxf9m0AF4dnGoF4EX38kw,30872
|
|
59
|
-
uipath/_services/llm_gateway_service.py,sha256=
|
|
59
|
+
uipath/_services/llm_gateway_service.py,sha256=ZdKRLdEVL8Zkcl9NDT5AKADxnjqeMIuOe5H2Oy7hYKw,9421
|
|
60
60
|
uipath/_services/processes_service.py,sha256=b-c4ynjcgS0ymp130r0lI93z7DF989u8HWOmWCux754,5727
|
|
61
61
|
uipath/_services/queues_service.py,sha256=VaG3dWL2QK6AJBOLoW2NQTpkPfZjsqsYPl9-kfXPFzA,13534
|
|
62
62
|
uipath/_utils/__init__.py,sha256=VdcpnENJIa0R6Y26NoxY64-wUVyvb4pKfTh1wXDQeMk,526
|
|
@@ -66,6 +66,7 @@ uipath/_utils/_logs.py,sha256=adfX_0UAn3YBeKJ8DQDeZs94rJyHGQO00uDfkaTpNWQ,510
|
|
|
66
66
|
uipath/_utils/_read_overwrites.py,sha256=OQgG9ycPpFnLub5ELQdX9V2Fyh6F9_zDR3xoYagJaMI,5287
|
|
67
67
|
uipath/_utils/_request_override.py,sha256=fIVHzgHVXITUlWcp8osNBwIafM1qm4_ejx0ng5UzfJ4,573
|
|
68
68
|
uipath/_utils/_request_spec.py,sha256=iCtBLqtbWUpFG5g1wtIZBzSupKsfaRLiQFoFc_4B70Q,747
|
|
69
|
+
uipath/_utils/_ssl_context.py,sha256=xSYitos0eJc9cPHzNtHISX9PBvL6D2vas5G_GiBdLp8,1783
|
|
69
70
|
uipath/_utils/_url.py,sha256=-4eluSrIZCUlnQ3qU17WPJkgaC2KwF9W5NeqGnTNGGo,2512
|
|
70
71
|
uipath/_utils/_user_agent.py,sha256=pVJkFYacGwaQBomfwWVAvBQgdBUo62e4n3-fLIajWUU,563
|
|
71
72
|
uipath/_utils/constants.py,sha256=yf4Xd0gmdisrIrsdy3zuiOgboK-XYAcrd4ekb3ZjZeE,878
|
|
@@ -82,7 +83,7 @@ uipath/models/errors.py,sha256=gPyU4sKYn57v03aOVqm97mnU9Do2e7bwMQwiSQVp9qc,461
|
|
|
82
83
|
uipath/models/exceptions.py,sha256=jav4egsVRfC1jN_FLnV7FVgWZapSepSKZQCxMe94Pac,590
|
|
83
84
|
uipath/models/interrupt_models.py,sha256=UzuVTMVesI204YQ4qFQFaN-gN3kksddkrujofcaC7zQ,881
|
|
84
85
|
uipath/models/job.py,sha256=f9L6_kg_VP0dAYvdcz1DWEWzy4NZPdlpHREod0uNK1E,3099
|
|
85
|
-
uipath/models/llm_gateway.py,sha256=
|
|
86
|
+
uipath/models/llm_gateway.py,sha256=rUIus7BrUuuRriXqSJUE9FnjOyQ7pYpaX6hWEYvA6AA,1923
|
|
86
87
|
uipath/models/processes.py,sha256=Atvfrt6X4TYST3iA62jpS_Uxc3hg6uah11p-RaKZ6dk,2029
|
|
87
88
|
uipath/models/queues.py,sha256=N_s0GKucbyjh0RnO8SxPk6wlRgvq8KIIYsfaoIY46tM,6446
|
|
88
89
|
uipath/telemetry/__init__.py,sha256=Wna32UFzZR66D-RzTKlPWlvji9i2HJb82NhHjCCXRjY,61
|
|
@@ -92,8 +93,10 @@ uipath/tracing/__init__.py,sha256=GKRINyWdHVrDsI-8mrZDLdf0oey6GHGlNZTOADK-kgc,22
|
|
|
92
93
|
uipath/tracing/_otel_exporters.py,sha256=x0PDPmDKJcxashsuehVsSsqBCzRr6WsNFaq_3_HS5F0,3014
|
|
93
94
|
uipath/tracing/_traced.py,sha256=qeVDrds2OUnpdUIA0RhtF0kg2dlAZhyC1RRkI-qivTM,18528
|
|
94
95
|
uipath/tracing/_utils.py,sha256=ZeensQexnw69jVcsVrGyED7mPlAU-L1agDGm6_1A3oc,10388
|
|
95
|
-
uipath
|
|
96
|
-
uipath
|
|
97
|
-
uipath-2.0.
|
|
98
|
-
uipath-2.0.
|
|
99
|
-
uipath-2.0.
|
|
96
|
+
uipath/utils/__init__.py,sha256=VD-KXFpF_oWexFg6zyiWMkxl2HM4hYJMIUDZ1UEtGx0,105
|
|
97
|
+
uipath/utils/_endpoints_manager.py,sha256=zcOsYwyoRzDuvdhdHwNabrqXRqC6e5J_GdEOriT7Dek,3768
|
|
98
|
+
uipath-2.0.75.dist-info/METADATA,sha256=uAREv1kvwTRpAZSOumymODhJBi_oIWm8uR1Krr1UMM0,6462
|
|
99
|
+
uipath-2.0.75.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
100
|
+
uipath-2.0.75.dist-info/entry_points.txt,sha256=9C2_29U6Oq1ExFu7usihR-dnfIVNSKc-0EFbh0rskB4,43
|
|
101
|
+
uipath-2.0.75.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
|
|
102
|
+
uipath-2.0.75.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|