uipath 2.1.40__py3-none-any.whl → 2.1.42__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.
@@ -7,7 +7,7 @@ import threading
7
7
  import time
8
8
  from typing import Optional
9
9
 
10
- from ._oidc_utils import get_auth_config
10
+ from ._oidc_utils import OidcUtils
11
11
 
12
12
  # Server port
13
13
  PORT = 6234
@@ -74,7 +74,7 @@ def make_request_handler_class(state, code_verifier, token_callback, domain):
74
74
  content = f.read()
75
75
 
76
76
  # Get the redirect URI from auth config
77
- auth_config = get_auth_config()
77
+ auth_config = OidcUtils.get_auth_config()
78
78
  redirect_uri = auth_config["redirect_uri"]
79
79
 
80
80
  content = content.replace("__PY_REPLACE_EXPECTED_STATE__", state)
@@ -0,0 +1,151 @@
1
+ import asyncio
2
+ import json
3
+ import os
4
+ import webbrowser
5
+ from socket import AF_INET, SOCK_STREAM, error, socket
6
+ from typing import Optional
7
+ from urllib.parse import urlparse
8
+
9
+ from uipath._cli._auth._auth_server import HTTPServer
10
+ from uipath._cli._auth._client_credentials import ClientCredentialsService
11
+ from uipath._cli._auth._oidc_utils import OidcUtils
12
+ from uipath._cli._auth._portal_service import PortalService, select_tenant
13
+ from uipath._cli._auth._url_utils import set_force_flag
14
+ from uipath._cli._auth._utils import update_auth_file, update_env_file
15
+ from uipath._cli._utils._console import ConsoleLogger
16
+
17
+
18
+ class AuthService:
19
+ def __init__(
20
+ self,
21
+ environment: str,
22
+ *,
23
+ force: bool,
24
+ client_id: Optional[str],
25
+ client_secret: Optional[str],
26
+ base_url: Optional[str],
27
+ scope: Optional[str],
28
+ ):
29
+ self._force = force
30
+ self._console = ConsoleLogger()
31
+ self._domain = self._get_domain(environment)
32
+ self._client_id = client_id
33
+ self._client_secret = client_secret
34
+ self._base_url = base_url
35
+ self._scope = scope
36
+ set_force_flag(self._force)
37
+
38
+ def _get_domain(self, environment: str) -> str:
39
+ # only search env var if not force authentication
40
+ if not self._force:
41
+ uipath_url = os.getenv("UIPATH_URL")
42
+ if uipath_url and environment == "cloud": # "cloud" is the default
43
+ parsed_url = urlparse(uipath_url)
44
+ if parsed_url.scheme and parsed_url.netloc:
45
+ environment = f"{parsed_url.scheme}://{parsed_url.netloc}"
46
+ else:
47
+ self._console.error(
48
+ f"Malformed UIPATH_URL: '{uipath_url}'. Please ensure it includes both scheme and netloc (e.g., 'https://cloud.uipath.com')."
49
+ )
50
+ return environment
51
+
52
+ def authenticate(self) -> None:
53
+ if self._client_id and self._client_secret:
54
+ self._authenticate_client_credentials()
55
+ return
56
+
57
+ self._authenticate_authorization_code()
58
+
59
+ def _authenticate_client_credentials(self) -> None:
60
+ if not self._base_url:
61
+ self._console.error(
62
+ "--base-url is required when using client credentials authentication."
63
+ )
64
+ return
65
+ self._console.hint("Using client credentials authentication.")
66
+ credentials_service = ClientCredentialsService(self._base_url)
67
+ credentials_service.authenticate(
68
+ self._client_id, # type: ignore
69
+ self._client_secret, # type: ignore
70
+ self._scope,
71
+ )
72
+
73
+ def _authenticate_authorization_code(self) -> None:
74
+ with PortalService(self._domain) as portal_service:
75
+ if not self._force:
76
+ # use existing env vars
77
+ if (
78
+ os.getenv("UIPATH_URL")
79
+ and os.getenv("UIPATH_TENANT_ID")
80
+ and os.getenv("UIPATH_ORGANIZATION_ID")
81
+ ):
82
+ try:
83
+ portal_service.ensure_valid_token()
84
+ return
85
+ except Exception:
86
+ self._console.error(
87
+ "Authentication token is invalid. Please reauthenticate using the '--force' flag.",
88
+ )
89
+ auth_url, code_verifier, state = OidcUtils.get_auth_url(self._domain)
90
+ webbrowser.open(auth_url, 1)
91
+ auth_config = OidcUtils.get_auth_config()
92
+
93
+ self._console.link(
94
+ "If a browser window did not open, please open the following URL in your browser:",
95
+ auth_url,
96
+ )
97
+ server = HTTPServer(port=auth_config["port"])
98
+ token_data = asyncio.run(server.start(state, code_verifier, self._domain))
99
+
100
+ if not token_data:
101
+ self._console.error(
102
+ "Authentication failed. Please try again.",
103
+ )
104
+
105
+ portal_service.update_token_data(token_data)
106
+ update_auth_file(token_data)
107
+ access_token = token_data["access_token"]
108
+ update_env_file({"UIPATH_ACCESS_TOKEN": access_token})
109
+
110
+ tenants_and_organizations = portal_service.get_tenants_and_organizations()
111
+ base_url = select_tenant(self._domain, tenants_and_organizations)
112
+ try:
113
+ portal_service.post_auth(base_url)
114
+ except Exception:
115
+ self._console.error(
116
+ "Could not prepare the environment. Please try again.",
117
+ )
118
+
119
+ def set_port(self):
120
+ def is_port_in_use(target_port: int) -> bool:
121
+ with socket(AF_INET, SOCK_STREAM) as s:
122
+ try:
123
+ s.bind(("localhost", target_port))
124
+ s.close()
125
+ return False
126
+ except error:
127
+ return True
128
+
129
+ auth_config = OidcUtils.get_auth_config()
130
+ port = int(auth_config.get("port", 8104))
131
+ port_option_one = int(auth_config.get("portOptionOne", 8104)) # type: ignore
132
+ port_option_two = int(auth_config.get("portOptionTwo", 8055)) # type: ignore
133
+ port_option_three = int(auth_config.get("portOptionThree", 42042)) # type: ignore
134
+ if is_port_in_use(port):
135
+ if is_port_in_use(port_option_one):
136
+ if is_port_in_use(port_option_two):
137
+ if is_port_in_use(port_option_three):
138
+ self._console.error(
139
+ "All configured ports are in use. Please close applications using ports or configure different ports."
140
+ )
141
+ else:
142
+ port = port_option_three
143
+ else:
144
+ port = port_option_two
145
+ else:
146
+ port = port_option_one
147
+ auth_config["port"] = port
148
+ with open(
149
+ os.path.join(os.path.dirname(__file__), "..", "auth_config.json"), "w"
150
+ ) as f:
151
+ json.dump(auth_config, f)
@@ -1,4 +1,4 @@
1
- from typing import Optional
1
+ from typing import Optional, cast
2
2
  from urllib.parse import urlparse
3
3
 
4
4
  import httpx
@@ -14,12 +14,13 @@ console = ConsoleLogger()
14
14
  class ClientCredentialsService:
15
15
  """Service for client credentials authentication flow."""
16
16
 
17
- def __init__(self, domain: str):
18
- self.domain = domain
17
+ def __init__(self, base_url: str):
18
+ self._base_url = base_url
19
+ self._domain = self._extract_domain_from_base_url(base_url)
19
20
 
20
21
  def get_token_url(self) -> str:
21
22
  """Get the token URL for the specified domain."""
22
- match self.domain:
23
+ match self._domain:
23
24
  case "alpha":
24
25
  return "https://alpha.uipath.com/identity_/connect/token"
25
26
  case "staging":
@@ -39,7 +40,7 @@ class ClientCredentialsService:
39
40
  """
40
41
  return hostname == domain or hostname.endswith(f".{domain}")
41
42
 
42
- def extract_domain_from_base_url(self, base_url: str) -> str:
43
+ def _extract_domain_from_base_url(self, base_url: str) -> str:
43
44
  """Extract domain from base URL.
44
45
 
45
46
  Args:
@@ -71,7 +72,7 @@ class ClientCredentialsService:
71
72
 
72
73
  def authenticate(
73
74
  self, client_id: str, client_secret: str, scope: Optional[str] = "OR.Execution"
74
- ) -> Optional[TokenData]:
75
+ ) -> None:
75
76
  """Authenticate using client credentials flow.
76
77
 
77
78
  Args:
@@ -97,37 +98,35 @@ class ClientCredentialsService:
97
98
  match response.status_code:
98
99
  case 200:
99
100
  token_data = response.json()
100
- return {
101
- "access_token": token_data["access_token"],
102
- "token_type": token_data.get("token_type", "Bearer"),
103
- "expires_in": token_data.get("expires_in", 3600),
104
- "scope": token_data.get("scope", scope),
105
- # Client credentials flow doesn't provide these, but we need them for compatibility
106
- "refresh_token": "",
107
- "id_token": "",
108
- }
101
+ token_data = cast(
102
+ TokenData,
103
+ {
104
+ "access_token": token_data["access_token"],
105
+ "token_type": token_data.get("token_type", "Bearer"),
106
+ "expires_in": token_data.get("expires_in", 3600),
107
+ "scope": token_data.get("scope", scope),
108
+ "refresh_token": "",
109
+ "id_token": "",
110
+ },
111
+ )
112
+ self._setup_environment(token_data)
109
113
  case 400:
110
114
  console.error(
111
115
  "Invalid client credentials or request parameters."
112
116
  )
113
- return None
114
117
  case 401:
115
118
  console.error("Unauthorized: Invalid client credentials.")
116
- return None
117
119
  case _:
118
120
  console.error(
119
121
  f"Authentication failed: {response.status_code} - {response.text}"
120
122
  )
121
- return None
122
123
 
123
124
  except httpx.RequestError as e:
124
125
  console.error(f"Network error during authentication: {e}")
125
- return None
126
126
  except Exception as e:
127
127
  console.error(f"Unexpected error during authentication: {e}")
128
- return None
129
128
 
130
- def setup_environment(self, token_data: TokenData, base_url: str):
129
+ def _setup_environment(self, token_data: TokenData):
131
130
  """Setup environment variables for client credentials authentication.
132
131
 
133
132
  Args:
@@ -138,7 +137,7 @@ class ClientCredentialsService:
138
137
 
139
138
  env_vars = {
140
139
  "UIPATH_ACCESS_TOKEN": token_data["access_token"],
141
- "UIPATH_URL": base_url,
140
+ "UIPATH_URL": self._base_url,
142
141
  "UIPATH_ORGANIZATION_ID": parsed_access_token.get("prt_id", ""),
143
142
  "UIPATH_TENANT_ID": "",
144
143
  }
@@ -24,47 +24,52 @@ def get_state_param() -> str:
24
24
  return base64.urlsafe_b64encode(os.urandom(32)).decode("utf-8").rstrip("=")
25
25
 
26
26
 
27
- def get_auth_config() -> AuthConfig:
28
- auth_config = {}
29
- with open(os.path.join(os.path.dirname(__file__), "auth_config.json"), "r") as f:
30
- auth_config = json.load(f)
31
-
32
- port = auth_config.get("port", 8104)
33
-
34
- redirect_uri = auth_config["redirect_uri"].replace("__PY_REPLACE_PORT__", str(port))
35
-
36
- return AuthConfig(
37
- client_id=auth_config["client_id"],
38
- redirect_uri=redirect_uri,
39
- scope=auth_config["scope"],
40
- port=port,
41
- )
42
-
43
-
44
- def get_auth_url(domain: str) -> tuple[str, str, str]:
45
- """Get the authorization URL for OAuth2 PKCE flow.
46
-
47
- Args:
48
- domain (str): The UiPath domain to authenticate against (e.g. 'alpha', 'cloud')
49
-
50
- Returns:
51
- tuple[str, str]: A tuple containing:
52
- - The authorization URL with query parameters
53
- - The code verifier for PKCE flow
54
- """
55
- code_verifier, code_challenge = generate_code_verifier_and_challenge()
56
- auth_config = get_auth_config()
57
- state = get_state_param()
58
- query_params = {
59
- "client_id": auth_config["client_id"],
60
- "redirect_uri": auth_config["redirect_uri"],
61
- "response_type": "code",
62
- "scope": auth_config["scope"],
63
- "state": state,
64
- "code_challenge": code_challenge,
65
- "code_challenge_method": "S256",
66
- }
67
-
68
- query_string = urlencode(query_params)
69
- url = build_service_url(domain, f"/identity_/connect/authorize?{query_string}")
70
- return url, code_verifier, state
27
+ class OidcUtils:
28
+ @classmethod
29
+ def get_auth_config(cls) -> AuthConfig:
30
+ with open(
31
+ os.path.join(os.path.dirname(__file__), "auth_config.json"), "r"
32
+ ) as f:
33
+ auth_config = json.load(f)
34
+
35
+ port = auth_config.get("port", 8104)
36
+
37
+ redirect_uri = auth_config["redirect_uri"].replace(
38
+ "__PY_REPLACE_PORT__", str(port)
39
+ )
40
+
41
+ return AuthConfig(
42
+ client_id=auth_config["client_id"],
43
+ redirect_uri=redirect_uri,
44
+ scope=auth_config["scope"],
45
+ port=port,
46
+ )
47
+
48
+ @classmethod
49
+ def get_auth_url(cls, domain: str) -> tuple[str, str, str]:
50
+ """Get the authorization URL for OAuth2 PKCE flow.
51
+
52
+ Args:
53
+ domain (str): The UiPath domain to authenticate against (e.g. 'alpha', 'cloud')
54
+
55
+ Returns:
56
+ tuple[str, str]: A tuple containing:
57
+ - The authorization URL with query parameters
58
+ - The code verifier for PKCE flow
59
+ """
60
+ code_verifier, code_challenge = generate_code_verifier_and_challenge()
61
+ auth_config = cls.get_auth_config()
62
+ state = get_state_param()
63
+ query_params = {
64
+ "client_id": auth_config["client_id"],
65
+ "redirect_uri": auth_config["redirect_uri"],
66
+ "response_type": "code",
67
+ "scope": auth_config["scope"],
68
+ "state": state,
69
+ "code_challenge": code_challenge,
70
+ "code_challenge_method": "S256",
71
+ }
72
+
73
+ query_string = urlencode(query_params)
74
+ url = build_service_url(domain, f"/identity_/connect/authorize?{query_string}")
75
+ return url, code_verifier, state
@@ -8,7 +8,7 @@ import httpx
8
8
  from ..._utils._ssl_context import get_httpx_client_kwargs
9
9
  from .._utils._console import ConsoleLogger
10
10
  from ._models import TenantsAndOrganizationInfoResponse, TokenData
11
- from ._oidc_utils import get_auth_config
11
+ from ._oidc_utils import OidcUtils
12
12
  from ._url_utils import build_service_url, get_base_url
13
13
  from ._utils import (
14
14
  get_auth_data,
@@ -102,7 +102,7 @@ class PortalService:
102
102
  raise RuntimeError("HTTP client is not initialized")
103
103
 
104
104
  url = build_service_url(self.domain, "/identity_/connect/token")
105
- client_id = get_auth_config().get("client_id")
105
+ client_id = OidcUtils.get_auth_config().get("client_id")
106
106
 
107
107
  data = {
108
108
  "grant_type": "refresh_token",
@@ -136,32 +136,33 @@ class PortalService:
136
136
  auth_data = get_auth_data()
137
137
  claims = get_parsed_token_data(auth_data)
138
138
  exp = claims.get("exp")
139
-
140
139
  if exp is not None and float(exp) > time.time():
141
140
  if not os.getenv("UIPATH_URL"):
142
141
  tenants_and_organizations = self.get_tenants_and_organizations()
143
142
  select_tenant(
144
143
  self.domain if self.domain else "alpha", tenants_and_organizations
145
144
  )
146
- return auth_data.get("access_token")
147
-
148
- refresh_token = auth_data.get("refresh_token")
149
- if refresh_token is None:
150
- raise Exception("Refresh token not found")
151
- token_data = self.post_refresh_token_request(refresh_token)
152
- update_auth_file(token_data)
153
-
154
- self.access_token = token_data["access_token"]
155
- self.prt_id = claims.get("prt_id")
156
-
157
- updated_env_contents = {
158
- "UIPATH_ACCESS_TOKEN": token_data["access_token"],
159
- }
160
- if not os.getenv("UIPATH_URL"):
161
- tenants_and_organizations = self.get_tenants_and_organizations()
162
- select_tenant(
163
- self.domain if self.domain else "alpha", tenants_and_organizations
164
- )
145
+ updated_env_contents = {
146
+ "UIPATH_ACCESS_TOKEN": auth_data["access_token"],
147
+ }
148
+ else:
149
+ refresh_token = auth_data.get("refresh_token")
150
+ if refresh_token is None:
151
+ raise Exception("Refresh token not found")
152
+ token_data = self.post_refresh_token_request(refresh_token)
153
+ update_auth_file(token_data)
154
+
155
+ self.access_token = token_data["access_token"]
156
+ self.prt_id = claims.get("prt_id")
157
+
158
+ updated_env_contents = {
159
+ "UIPATH_ACCESS_TOKEN": token_data["access_token"],
160
+ }
161
+ if not os.getenv("UIPATH_URL"):
162
+ tenants_and_organizations = self.get_tenants_and_organizations()
163
+ select_tenant(
164
+ self.domain if self.domain else "alpha", tenants_and_organizations
165
+ )
165
166
 
166
167
  update_env_file(updated_env_contents)
167
168
 
@@ -1,6 +1,8 @@
1
1
  import os
2
2
  from urllib.parse import urlparse
3
3
 
4
+ ignore_env_var = False
5
+
4
6
 
5
7
  def get_base_url(domain: str) -> str:
6
8
  """Get the base URL for UiPath services.
@@ -11,11 +13,14 @@ def get_base_url(domain: str) -> str:
11
13
  Returns:
12
14
  The base URL to use for UiPath services
13
15
  """
14
- # If UIPATH_URL is set and domain is 'cloud' (default), use the base from UIPATH_URL
15
- uipath_url = os.getenv("UIPATH_URL")
16
- if uipath_url and domain == "cloud":
17
- parsed_url = urlparse(uipath_url)
18
- return f"{parsed_url.scheme}://{parsed_url.netloc}"
16
+ global ignore_env_var
17
+
18
+ if not ignore_env_var:
19
+ # If UIPATH_URL is set and domain is 'cloud' (default), use the base from UIPATH_URL
20
+ uipath_url = os.getenv("UIPATH_URL")
21
+ if uipath_url and domain == "cloud":
22
+ parsed_url = urlparse(uipath_url)
23
+ return f"{parsed_url.scheme}://{parsed_url.netloc}"
19
24
 
20
25
  # If domain is already a full URL, use it directly
21
26
  if domain.startswith("http"):
@@ -25,6 +30,11 @@ def get_base_url(domain: str) -> str:
25
30
  return f"https://{domain if domain else 'cloud'}.uipath.com"
26
31
 
27
32
 
33
+ def set_force_flag(force: bool):
34
+ global ignore_env_var
35
+ ignore_env_var = force
36
+
37
+
28
38
  def build_service_url(domain: str, path: str) -> str:
29
39
  """Build a service URL by combining the base URL with a path.
30
40
 
@@ -4,7 +4,7 @@ import traceback
4
4
  from datetime import datetime
5
5
  from os import environ as env
6
6
  from pathlib import Path
7
- from typing import Any, Dict
7
+ from typing import Any, Dict, cast
8
8
  from uuid import uuid4
9
9
 
10
10
  import pyperclip # type: ignore[import-untyped]
@@ -15,7 +15,12 @@ from textual.binding import Binding
15
15
  from textual.containers import Container, Horizontal
16
16
  from textual.widgets import Button, Footer, Input, ListView, RichLog
17
17
 
18
- from uipath.agent.conversation import UiPathConversationEvent
18
+ from uipath.agent.conversation import (
19
+ UiPathConversationContentPart,
20
+ UiPathConversationEvent,
21
+ UiPathConversationMessage,
22
+ UiPathInlineValue,
23
+ )
19
24
 
20
25
  from ..._runtime._contracts import (
21
26
  UiPathErrorContract,
@@ -116,7 +121,8 @@ class UiPathDevTerminal(App[Any]):
116
121
 
117
122
  details_panel = self.query_one("#details-panel", RunDetailsPanel)
118
123
  if details_panel and details_panel.current_run:
119
- if details_panel.current_run.status != "suspended":
124
+ status = details_panel.current_run.status
125
+ if status == "running":
120
126
  self.app.notify(
121
127
  "Wait for agent response...", timeout=1.5, severity="warning"
122
128
  )
@@ -128,7 +134,22 @@ class UiPathDevTerminal(App[Any]):
128
134
  ),
129
135
  details_panel.current_run.id,
130
136
  )
131
- details_panel.current_run.resume_data = {"value": user_text}
137
+ if details_panel.current_run.status == "suspended":
138
+ details_panel.current_run.resume_data = user_text
139
+ else:
140
+ details_panel.current_run.input_data = UiPathConversationMessage(
141
+ message_id=str(uuid4()),
142
+ created_at=datetime.now().isoformat(),
143
+ updated_at=datetime.now().isoformat(),
144
+ content_parts=[
145
+ UiPathConversationContentPart(
146
+ content_part_id=str(uuid4()),
147
+ mime_type="text/plain",
148
+ data=UiPathInlineValue(inline=user_text),
149
+ )
150
+ ],
151
+ role="user",
152
+ )
132
153
  asyncio.create_task(self._execute_runtime(details_panel.current_run))
133
154
  event.input.clear()
134
155
 
@@ -147,7 +168,7 @@ class UiPathDevTerminal(App[Any]):
147
168
  async def action_execute_run(self) -> None:
148
169
  """Execute a new run with UiPath runtime."""
149
170
  new_run_panel = self.query_one("#new-run-panel", NewRunPanel)
150
- entrypoint, input_data = new_run_panel.get_input_values()
171
+ entrypoint, input_data, conversational = new_run_panel.get_input_values()
151
172
 
152
173
  if not entrypoint:
153
174
  return
@@ -158,7 +179,7 @@ class UiPathDevTerminal(App[Any]):
158
179
  except json.JSONDecodeError:
159
180
  return
160
181
 
161
- run = ExecutionRun(entrypoint, input)
182
+ run = ExecutionRun(entrypoint, input, conversational)
162
183
 
163
184
  self.runs[run.id] = run
164
185
 
@@ -166,7 +187,10 @@ class UiPathDevTerminal(App[Any]):
166
187
 
167
188
  self._show_run_details(run)
168
189
 
169
- asyncio.create_task(self._execute_runtime(run))
190
+ if not run.conversational:
191
+ asyncio.create_task(self._execute_runtime(run))
192
+ else:
193
+ self._focus_chat_input()
170
194
 
171
195
  async def action_clear_history(self) -> None:
172
196
  """Clear run history."""
@@ -191,6 +215,7 @@ class UiPathDevTerminal(App[Any]):
191
215
  entrypoint=run.entrypoint,
192
216
  trace_id=str(uuid4()),
193
217
  execution_id=run.id,
218
+ is_conversational=run.conversational,
194
219
  logs_min_level=env.get("LOG_LEVEL", "INFO"),
195
220
  log_handler=RunContextLogHandler(
196
221
  run_id=run.id, callback=self._handle_log_message
@@ -201,11 +226,16 @@ class UiPathDevTerminal(App[Any]):
201
226
  )
202
227
 
203
228
  if run.status == "suspended":
204
- context.resume = True
205
229
  context.input_json = run.resume_data
230
+ context.resume = True
206
231
  self._add_info_log(run, f"Resuming execution: {run.entrypoint}")
207
232
  else:
208
- context.input_json = run.input_data
233
+ if run.conversational:
234
+ context.input_message = cast(
235
+ UiPathConversationMessage, run.input_data
236
+ )
237
+ else:
238
+ context.input_json = run.input_data
209
239
  self._add_info_log(run, f"Starting execution: {run.entrypoint}")
210
240
 
211
241
  run.status = "running"
@@ -214,7 +244,10 @@ class UiPathDevTerminal(App[Any]):
214
244
  result = await self.runtime_factory.execute_in_root_span(context)
215
245
 
216
246
  if result is not None:
217
- if result.status == UiPathRuntimeStatus.SUSPENDED.value:
247
+ if (
248
+ result.status == UiPathRuntimeStatus.SUSPENDED.value
249
+ and result.resume
250
+ ):
218
251
  run.status = "suspended"
219
252
  else:
220
253
  run.output_data = result.output
@@ -254,6 +287,13 @@ class UiPathDevTerminal(App[Any]):
254
287
  # Populate the details panel with run data
255
288
  details_panel.update_run(run)
256
289
 
290
+ def _focus_chat_input(self):
291
+ """Focus the chat input box."""
292
+ details_panel = self.query_one("#details-panel", RunDetailsPanel)
293
+ details_panel.switch_tab("chat-tab")
294
+ chat_input = details_panel.query_one("#chat-input", Input)
295
+ chat_input.focus()
296
+
257
297
  def _add_run_in_history(self, run: ExecutionRun):
258
298
  """Add run to history panel."""
259
299
  history_panel = self.query_one("#history-panel", RunHistoryPanel)
@@ -1,10 +1,11 @@
1
1
  import time
2
- from typing import Dict, List, Union
2
+ from typing import Dict, List, Optional, Union
3
3
 
4
4
  from textual.app import ComposeResult
5
5
  from textual.containers import Container, Vertical, VerticalScroll
6
6
  from textual.widgets import Input, Markdown
7
7
 
8
+ from uipath._cli._dev._terminal._models._execution import ExecutionRun
8
9
  from uipath.agent.conversation import (
9
10
  UiPathConversationEvent,
10
11
  UiPathConversationMessage,
@@ -44,8 +45,22 @@ class ChatPanel(Container):
44
45
  id="chat-input",
45
46
  )
46
47
 
48
+ def update_messages(self, run: ExecutionRun) -> None:
49
+ """Update the chat panel with messages from the given execution run."""
50
+ chat_view = self.query_one("#chat-view")
51
+ chat_view.remove_children()
52
+ self._chat_widgets.clear()
53
+ self._last_update_time.clear()
54
+
55
+ for chat_msg in run.messages:
56
+ self.add_chat_message(None, chat_msg, auto_scroll=False)
57
+ chat_view.scroll_end(animate=False)
58
+
47
59
  def add_chat_message(
48
- self, event: UiPathConversationEvent, chat_msg: UiPathConversationMessage
60
+ self,
61
+ event: Optional[UiPathConversationEvent],
62
+ chat_msg: UiPathConversationMessage,
63
+ auto_scroll: bool = True,
49
64
  ) -> None:
50
65
  """Add or update a chat message bubble."""
51
66
  chat_view = self.query_one("#chat-view")
@@ -90,17 +105,20 @@ class ChatPanel(Container):
90
105
 
91
106
  if existing:
92
107
  should_update = (
93
- event.exchange
108
+ event
109
+ and event.exchange
94
110
  and event.exchange.message
95
111
  and event.exchange.message.end is not None
96
112
  )
97
113
  if should_update or now - last_update > 0.15:
98
114
  existing.update(content)
99
115
  self._last_update_time[chat_msg.message_id] = now
100
- chat_view.scroll_end(animate=False)
116
+ if auto_scroll:
117
+ chat_view.scroll_end(animate=False)
101
118
  else:
102
119
  widget_instance = widget_cls(content)
103
120
  chat_view.mount(widget_instance)
104
121
  self._chat_widgets[chat_msg.message_id] = widget_instance
105
122
  self._last_update_time[chat_msg.message_id] = now
106
- chat_view.scroll_end(animate=False)
123
+ if auto_scroll:
124
+ chat_view.scroll_end(animate=False)
@@ -155,7 +155,11 @@ class RunDetailsPanel(Container):
155
155
 
156
156
  def _update_chat_tab(self, run: ExecutionRun) -> None:
157
157
  chat_input = self.query_one("#chat-input", Input)
158
- chat_input.disabled = run.status == "completed" or run.status == "failed"
158
+ chat_input.disabled = (
159
+ run.status == "completed" or run.status == "failed"
160
+ ) and not run.conversational
161
+ chat_panel = self.query_one("#chat-panel", ChatPanel)
162
+ chat_panel.update_messages(run)
159
163
 
160
164
  def _flatten_values(self, value: object, prefix: str = "") -> list[str]:
161
165
  """Flatten nested dict/list structures into dot-notation paths."""
@@ -288,7 +292,11 @@ class RunDetailsPanel(Container):
288
292
  def _rebuild_spans_tree(self):
289
293
  """Rebuild the spans tree from current run's traces."""
290
294
  spans_tree = self.query_one("#spans-tree", Tree)
291
- spans_tree.clear()
295
+ if spans_tree is None or spans_tree.root is None:
296
+ return
297
+
298
+ spans_tree.root.remove_children()
299
+
292
300
  # Only clear the node mapping since we're rebuilding the tree structure
293
301
  self.span_tree_nodes.clear()
294
302
 
@@ -5,7 +5,7 @@ from typing import Any, Dict, Tuple, cast
5
5
  from textual.app import ComposeResult
6
6
  from textual.containers import Container, Horizontal, Vertical
7
7
  from textual.reactive import reactive
8
- from textual.widgets import Button, Select, TabbedContent, TabPane, TextArea
8
+ from textual.widgets import Button, Checkbox, Select, TabbedContent, TabPane, TextArea
9
9
 
10
10
  from ._json_input import JsonInput
11
11
 
@@ -76,6 +76,12 @@ class NewRunPanel(Container):
76
76
  allow_blank=False,
77
77
  )
78
78
 
79
+ yield Checkbox(
80
+ "chat mode",
81
+ value=False,
82
+ id="conversational-toggle",
83
+ )
84
+
79
85
  yield JsonInput(
80
86
  text=self.initial_input,
81
87
  language="json",
@@ -108,9 +114,16 @@ class NewRunPanel(Container):
108
114
  mock_json_from_schema(ep.get("input", {})), indent=2
109
115
  )
110
116
 
111
- def get_input_values(self) -> Tuple[str, str]:
117
+ async def on_checkbox_changed(self, event: Checkbox.Changed) -> None:
118
+ """Hide JSON input if conversational is enabled."""
119
+ if event.checkbox.id == "conversational-toggle":
120
+ json_input = self.query_one("#json-input", TextArea)
121
+ json_input.display = not event.value
122
+
123
+ def get_input_values(self) -> Tuple[str, str, bool]:
112
124
  json_input = self.query_one("#json-input", TextArea)
113
- return self.selected_entrypoint, json_input.text.strip()
125
+ conversational = self.query_one("#conversational-toggle", Checkbox).value
126
+ return self.selected_entrypoint, json_input.text.strip(), conversational
114
127
 
115
128
  def reset_form(self):
116
129
  """Reset selection and JSON input to defaults."""
@@ -1,6 +1,6 @@
1
1
  import os
2
2
  from datetime import datetime
3
- from typing import Any, Dict, List, Optional
3
+ from typing import Any, Dict, List, Optional, Union
4
4
  from uuid import uuid4
5
5
 
6
6
  from rich.text import Text
@@ -15,15 +15,21 @@ from ._messages import LogMessage, TraceMessage
15
15
  class ExecutionRun:
16
16
  """Represents a single execution run."""
17
17
 
18
- def __init__(self, entrypoint: str, input_data: Dict[str, Any]):
18
+ def __init__(
19
+ self,
20
+ entrypoint: str,
21
+ input_data: Union[Dict[str, Any], UiPathConversationMessage],
22
+ conversational: bool = False,
23
+ ):
19
24
  self.id = str(uuid4())[:8]
20
25
  self.entrypoint = entrypoint
21
26
  self.input_data = input_data
22
- self.resume_data: Optional[Dict[str, Any]] = None
27
+ self.conversational = conversational
28
+ self.resume_data: Optional[Any] = None
23
29
  self.output_data: Optional[Dict[str, Any]] = None
24
30
  self.start_time = datetime.now()
25
31
  self.end_time: Optional[datetime] = None
26
- self.status = "running" # running, completed, failed, suspended
32
+ self.status = "pending" # pending, running, completed, failed, suspended
27
33
  self.traces: List[TraceMessage] = []
28
34
  self.logs: List[LogMessage] = []
29
35
  self.error: Optional[UiPathErrorContract] = None
@@ -34,13 +40,15 @@ class ExecutionRun:
34
40
  if self.end_time:
35
41
  delta = self.end_time - self.start_time
36
42
  return f"{delta.total_seconds():.1f}s"
37
- else:
43
+ elif self.start_time:
38
44
  delta = datetime.now() - self.start_time
39
45
  return f"{delta.total_seconds():.1f}s"
46
+ return "0.0s"
40
47
 
41
48
  @property
42
49
  def display_name(self) -> Text:
43
50
  status_colors = {
51
+ "pending": "grey50",
44
52
  "running": "yellow",
45
53
  "suspended": "cyan",
46
54
  "completed": "green",
@@ -48,6 +56,7 @@ class ExecutionRun:
48
56
  }
49
57
 
50
58
  status_icon = {
59
+ "pending": "●",
51
60
  "running": "▶",
52
61
  "suspended": "⏸",
53
62
  "completed": "✔",
@@ -27,6 +27,11 @@ Screen {
27
27
  color: #e0e0e0;
28
28
  }
29
29
 
30
+ .run-pending {
31
+ border-left: solid grey;
32
+ color: #e0e0e0;
33
+ }
34
+
30
35
  .run-completed {
31
36
  border-left: solid #00ff88;
32
37
  color: #e0e0e0;
@@ -250,3 +255,7 @@ Response, Tool {
250
255
  dock: bottom;
251
256
  margin: 1;
252
257
  }
258
+
259
+ Checkbox{
260
+ margin-top: 1;
261
+ }
@@ -22,7 +22,7 @@ from opentelemetry.sdk.trace.export import (
22
22
  from opentelemetry.trace import Tracer
23
23
  from pydantic import BaseModel, Field
24
24
 
25
- from uipath.agent.conversation import UiPathConversationEvent
25
+ from uipath.agent.conversation import UiPathConversationEvent, UiPathConversationMessage
26
26
  from uipath.tracing import TracingManager
27
27
 
28
28
  from ._logging import LogsInterceptor
@@ -167,6 +167,7 @@ class UiPathRuntimeContext(BaseModel):
167
167
  entrypoint: Optional[str] = None
168
168
  input: Optional[str] = None
169
169
  input_json: Optional[Any] = None
170
+ input_message: Optional[UiPathConversationMessage] = None
170
171
  job_id: Optional[str] = None
171
172
  execution_id: Optional[str] = None
172
173
  trace_id: Optional[str] = None
@@ -186,6 +187,7 @@ class UiPathRuntimeContext(BaseModel):
186
187
  is_eval_run: bool = False
187
188
  log_handler: Optional[logging.Handler] = None
188
189
  chat_handler: Optional[UiPathConversationHandler] = None
190
+ is_conversational: Optional[bool] = None
189
191
 
190
192
  model_config = {"arbitrary_types_allowed": True}
191
193
 
uipath/_cli/cli_auth.py CHANGED
@@ -1,61 +1,15 @@
1
- import asyncio
2
- import json
3
- import os
4
- import socket
5
- import webbrowser
6
1
  from typing import Optional
7
- from urllib.parse import urlparse
8
2
 
9
3
  import click
10
4
 
11
5
  from ..telemetry import track
12
- from ._auth._auth_server import HTTPServer
13
- from ._auth._client_credentials import ClientCredentialsService
14
- from ._auth._oidc_utils import get_auth_config, get_auth_url
15
- from ._auth._portal_service import PortalService, select_tenant
16
- from ._auth._utils import update_auth_file, update_env_file
6
+ from ._auth._auth_service import AuthService
17
7
  from ._utils._common import environment_options
18
8
  from ._utils._console import ConsoleLogger
19
9
 
20
10
  console = ConsoleLogger()
21
11
 
22
12
 
23
- def is_port_in_use(port: int) -> bool:
24
- with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
25
- try:
26
- s.bind(("localhost", port))
27
- s.close()
28
- return False
29
- except socket.error:
30
- return True
31
-
32
-
33
- def set_port():
34
- auth_config = get_auth_config()
35
- port = int(auth_config.get("port", 8104))
36
- port_option_one = int(auth_config.get("portOptionOne", 8104)) # type: ignore
37
- port_option_two = int(auth_config.get("portOptionTwo", 8055)) # type: ignore
38
- port_option_three = int(auth_config.get("portOptionThree", 42042)) # type: ignore
39
- if is_port_in_use(port):
40
- if is_port_in_use(port_option_one):
41
- if is_port_in_use(port_option_two):
42
- if is_port_in_use(port_option_three):
43
- console.error(
44
- "All configured ports are in use. Please close applications using ports or configure different ports."
45
- )
46
- else:
47
- port = port_option_three
48
- else:
49
- port = port_option_two
50
- else:
51
- port = port_option_one
52
- auth_config["port"] = port
53
- with open(
54
- os.path.join(os.path.dirname(__file__), "..", "auth_config.json"), "w"
55
- ) as f:
56
- json.dump(auth_config, f)
57
-
58
-
59
13
  @click.command()
60
14
  @environment_options
61
15
  @click.option(
@@ -63,6 +17,7 @@ def set_port():
63
17
  "--force",
64
18
  is_flag=True,
65
19
  required=False,
20
+ default=False,
66
21
  help="Force new token",
67
22
  )
68
23
  @click.option(
@@ -89,7 +44,7 @@ def set_port():
89
44
  @track
90
45
  def auth(
91
46
  domain,
92
- force: Optional[bool] = False,
47
+ force: bool = False,
93
48
  client_id: Optional[str] = None,
94
49
  client_secret: Optional[str] = None,
95
50
  base_url: Optional[str] = None,
@@ -108,109 +63,21 @@ def auth(
108
63
  - Set REQUESTS_CA_BUNDLE to specify a custom CA bundle for SSL verification
109
64
  - Set UIPATH_DISABLE_SSL_VERIFY to disable SSL verification (not recommended)
110
65
  """
111
- uipath_url = os.getenv("UIPATH_URL")
112
- if uipath_url and domain == "cloud": # "cloud" is the default
113
- parsed_url = urlparse(uipath_url)
114
- if parsed_url.scheme and parsed_url.netloc:
115
- domain = f"{parsed_url.scheme}://{parsed_url.netloc}"
116
- else:
117
- console.error(
118
- f"Malformed UIPATH_URL: '{uipath_url}'. Please ensure it includes both scheme and netloc (e.g., 'https://cloud.uipath.com')."
66
+ auth_service = AuthService(
67
+ domain,
68
+ force=force,
69
+ client_id=client_id,
70
+ client_secret=client_secret,
71
+ base_url=base_url,
72
+ scope=scope,
73
+ )
74
+ with console.spinner("Authenticating with UiPath ..."):
75
+ try:
76
+ auth_service.authenticate()
77
+ console.success(
78
+ "Authentication successful.",
119
79
  )
120
- return
121
-
122
- # Check if client credentials are provided for unattended authentication
123
- if client_id and client_secret:
124
- if not base_url:
80
+ except KeyboardInterrupt:
125
81
  console.error(
126
- "--base-url is required when using client credentials authentication."
127
- )
128
- return
129
-
130
- with console.spinner("Authenticating with client credentials ..."):
131
- credentials_service = ClientCredentialsService(domain)
132
-
133
- # If base_url is provided, extract domain from it to override the CLI domain parameter
134
- if base_url:
135
- extracted_domain = credentials_service.extract_domain_from_base_url(
136
- base_url
137
- )
138
- credentials_service.domain = extracted_domain
139
-
140
- token_data = credentials_service.authenticate(
141
- client_id, client_secret, scope
142
- )
143
-
144
- if token_data:
145
- credentials_service.setup_environment(token_data, base_url)
146
- console.success(
147
- "Client credentials authentication successful.",
148
- )
149
- else:
150
- console.error(
151
- "Client credentials authentication failed. Please check your credentials.",
152
- )
153
- return
154
-
155
- # Interactive authentication flow (existing logic)
156
- with console.spinner("Authenticating with UiPath ..."):
157
- with PortalService(domain) as portal_service:
158
- if not force:
159
- if (
160
- os.getenv("UIPATH_URL")
161
- and os.getenv("UIPATH_TENANT_ID")
162
- and os.getenv("UIPATH_ORGANIZATION_ID")
163
- ):
164
- try:
165
- portal_service.ensure_valid_token()
166
- console.success(
167
- "Authentication successful.",
168
- )
169
- return
170
- except Exception:
171
- console.info(
172
- "Authentication token is invalid. Please reauthenticate.",
173
- )
174
-
175
- auth_url, code_verifier, state = get_auth_url(domain)
176
-
177
- webbrowser.open(auth_url, 1)
178
- auth_config = get_auth_config()
179
-
180
- console.link(
181
- "If a browser window did not open, please open the following URL in your browser:",
182
- auth_url,
82
+ "Authentication cancelled by user.",
183
83
  )
184
-
185
- try:
186
- server = HTTPServer(port=auth_config["port"])
187
- token_data = asyncio.run(server.start(state, code_verifier, domain))
188
-
189
- if not token_data:
190
- console.error(
191
- "Authentication failed. Please try again.",
192
- )
193
- return
194
-
195
- portal_service.update_token_data(token_data)
196
- update_auth_file(token_data)
197
- access_token = token_data["access_token"]
198
- update_env_file({"UIPATH_ACCESS_TOKEN": access_token})
199
-
200
- tenants_and_organizations = (
201
- portal_service.get_tenants_and_organizations()
202
- )
203
- base_url = select_tenant(domain, tenants_and_organizations)
204
- try:
205
- portal_service.post_auth(base_url)
206
- console.success(
207
- "Authentication successful.",
208
- )
209
- except Exception:
210
- console.error(
211
- "Could not prepare the environment. Please try again.",
212
- )
213
- except KeyboardInterrupt:
214
- console.error(
215
- "Authentication cancelled by user.",
216
- )
uipath/_cli/cli_invoke.py CHANGED
@@ -18,6 +18,7 @@ from ..telemetry import track
18
18
  from ._utils._common import get_env_vars
19
19
  from ._utils._folders import get_personal_workspace_info
20
20
  from ._utils._processes import get_release_info
21
+ from .middlewares import Middlewares
21
22
 
22
23
  logger = logging.getLogger(__name__)
23
24
  console = ConsoleLogger()
@@ -87,6 +88,25 @@ def invoke(
87
88
  "x-uipath-organizationunitid": str(personal_workspace_folder_id),
88
89
  }
89
90
 
91
+ context = {
92
+ "url": url,
93
+ "payload": payload,
94
+ "headers": headers,
95
+ }
96
+
97
+ result = Middlewares.next("invoke", context)
98
+
99
+ if result.error_message:
100
+ console.error(
101
+ result.error_message, include_traceback=result.should_include_stacktrace
102
+ )
103
+
104
+ if result.info_message:
105
+ console.info(result.info_message)
106
+
107
+ if not result.should_continue:
108
+ return
109
+
90
110
  with httpx.Client(**get_httpx_client_kwargs()) as client:
91
111
  response = client.post(url, json=payload, headers=headers)
92
112
 
@@ -29,6 +29,7 @@ class Middlewares:
29
29
  "publish": [],
30
30
  "run": [],
31
31
  "dev": [],
32
+ "invoke": [],
32
33
  }
33
34
  _plugins_loaded = False
34
35
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: uipath
3
- Version: 2.1.40
3
+ Version: 2.1.42
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
@@ -6,40 +6,41 @@ uipath/_uipath.py,sha256=lDsF2rBurqxm24DlRan25z9SU9t9b2RkAGvoI645QSw,4314
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=kf4GINkunFGMZkTk2Z4f1Q3-OsxpNnV6u_9BsBt1i0E,2229
9
- uipath/_cli/cli_auth.py,sha256=SfE3wiQZ00f_iv4NQfRpLqV4KVnkUhq8J-a7reg247A,7773
9
+ uipath/_cli/cli_auth.py,sha256=i3ykLlCg68xgPXHHaa0agHwGFIiLiTLzOiF6Su8XaEo,2436
10
10
  uipath/_cli/cli_deploy.py,sha256=KPCmQ0c_NYD5JofSDao5r6QYxHshVCRxlWDVnQvlp5w,645
11
11
  uipath/_cli/cli_dev.py,sha256=JRzXrAUM_sj6FCVG-VveYADTwR8yQ330SgYs3LgbvJc,2104
12
12
  uipath/_cli/cli_eval.py,sha256=Hze4PwW4smivmSZg_eGDHr3pZ6LHxX5MkTJuXB2xpxs,3598
13
13
  uipath/_cli/cli_init.py,sha256=ls577uNm2zWccknIhtVFS3ah2ds0QSy2_TgMp6z7Wt4,6049
14
- uipath/_cli/cli_invoke.py,sha256=zuy3hCn5wfOcd_qYJDmfMB-5qtYS-GENprYXkQN29No,3836
14
+ uipath/_cli/cli_invoke.py,sha256=4jyhqcy7tPrpxvaUhW-9gut6ddsCGMdJJcpOXXmIe8g,4348
15
15
  uipath/_cli/cli_new.py,sha256=9378NYUBc9j-qKVXV7oja-jahfJhXBg8zKVyaon7ctY,2102
16
16
  uipath/_cli/cli_pack.py,sha256=NmwZTfwZ2fURiHyiX1BM0juAtBOjPB1Jmcpu-rD7p-4,11025
17
17
  uipath/_cli/cli_publish.py,sha256=FmBCdeh4zFaESOLfzTTPxGcOwUtsQ_WkvF_fjHEdU8s,6448
18
18
  uipath/_cli/cli_pull.py,sha256=vwS0KMX6O2L6RaPy8tw_qzXe4dC7kf_G6nbLm0I62eI,6831
19
19
  uipath/_cli/cli_push.py,sha256=-j-gDIbT8GyU2SybLQqFl5L8KI9nu3CDijVtltDgX20,3132
20
20
  uipath/_cli/cli_run.py,sha256=pM4FoR0mbykIK2O68auN_NX1LckNsMLJLBtW8MqgLxo,7777
21
- uipath/_cli/middlewares.py,sha256=MffXgAeafn5AqUsbw4l-FVly9Dm9TOvfvGJ61XOTt2Y,4934
21
+ uipath/_cli/middlewares.py,sha256=vgvzIHHpaDxUxHV8cbBv9_PFbq4E4Gq-iJTLvrlyIfw,4956
22
22
  uipath/_cli/spinner.py,sha256=bS-U_HA5yne11ejUERu7CQoXmWdabUD2bm62EfEdV8M,1107
23
- uipath/_cli/_auth/_auth_server.py,sha256=ICgc-GqfQmI6fMieJrGNTLcg6v7JgbKjZRGSBm6fdkg,7102
24
- uipath/_cli/_auth/_client_credentials.py,sha256=aC_xtEzWBQohRlxt85ZE8Ro0Pv9LmNltXECV8yjjO0U,5422
23
+ uipath/_cli/_auth/_auth_server.py,sha256=22km0F1NFNXgyLbvtAx3ssiQlVGHroLdtDCWEqiCiMg,7106
24
+ uipath/_cli/_auth/_auth_service.py,sha256=tX8YuHlgUn2qUDQ_hrbabs7kMTD3K1u3EgqGYj92KRM,6106
25
+ uipath/_cli/_auth/_client_credentials.py,sha256=VIyzgnGHSZxJXG8kSFIcCH0n2K2zep2SYcb5q1nBFcs,5408
25
26
  uipath/_cli/_auth/_models.py,sha256=sYMCfvmprIqnZxStlD_Dxx2bcxgn0Ri4D7uwemwkcNg,948
26
- uipath/_cli/_auth/_oidc_utils.py,sha256=tsYuueJoAYgS9d_ly0b3RmQ4Yybhr4G7ZkAc6lf8Gck,2169
27
- uipath/_cli/_auth/_portal_service.py,sha256=-985pkS9N9lMelesAz4hJUzgWDyf4L4ie4sv3-iklGE,8128
28
- uipath/_cli/_auth/_url_utils.py,sha256=OmCGMukMfpMGtq3zoqqhD9WR5n0RlkXnH5BTFXOcbQ4,1307
27
+ uipath/_cli/_auth/_oidc_utils.py,sha256=j9VCXai_dM9PF1WtoWEsXETvrWUjuTgU-dCJ3oRudyg,2394
28
+ uipath/_cli/_auth/_portal_service.py,sha256=MwsqEs505kMCiPCfjcelgflzvg1V3MqRNNVaOismaDc,8272
29
+ uipath/_cli/_auth/_url_utils.py,sha256=Vr-eYbwW_ltmwkULNEAbn6LNsMHnT4uT1n_1zlqD4Ss,1503
29
30
  uipath/_cli/_auth/_utils.py,sha256=9nb76xe5XmDZ0TAncp-_1SKqL6FdwRi9eS3C2noN1lY,1591
30
31
  uipath/_cli/_auth/auth_config.json,sha256=UnAhdum8phjuZaZKE5KLp0IcPCbIltDEU1M_G8gVbos,443
31
32
  uipath/_cli/_auth/index.html,sha256=uGK0CDTP8Rys_p4O_Pbd2x4tz0frKNVcumjrXnal5Nc,22814
32
33
  uipath/_cli/_auth/localhost.crt,sha256=oGl9oLLOiouHubAt39B4zEfylFvKEtbtr_43SIliXJc,1226
33
34
  uipath/_cli/_auth/localhost.key,sha256=X31VYXD8scZtmGA837dGX5l6G-LXHLo5ItWJhZXaz3c,1679
34
- uipath/_cli/_dev/_terminal/__init__.py,sha256=NcDVlqq-_h2zhXQJS4oCttDG-JIO5fFVZHKG4LEsANY,11706
35
- uipath/_cli/_dev/_terminal/_components/_chat.py,sha256=ne6a2i67-7ZUDLILApZPVzUY3rHcF-dJ0gWL7hPP5LI,3433
36
- uipath/_cli/_dev/_terminal/_components/_details.py,sha256=f8Wr_iX9tDTBHeOs0i8UepNfh8giNVWtA6k2otOdgTk,17010
35
+ uipath/_cli/_dev/_terminal/__init__.py,sha256=35nz6kTZyWSM9pP-FsXq8VXo6r1iM8rRUtqOqYahFLc,13271
36
+ uipath/_cli/_dev/_terminal/_components/_chat.py,sha256=NLRoy49QScHiI-q0FGykkaU8ajv1d23fx7issSALcFA,4119
37
+ uipath/_cli/_dev/_terminal/_components/_details.py,sha256=FbLYtJ56gqHV6CIrpzO_n9Sk_YNg4nzRKTSsbj-DBPQ,17257
37
38
  uipath/_cli/_dev/_terminal/_components/_history.py,sha256=dcT9tohEwpUaLGi7VWu5d-mDIF45UxFzN2Yvdf5N-eM,2691
38
39
  uipath/_cli/_dev/_terminal/_components/_json_input.py,sha256=MPkaeiA5KfkwJZKuNJ02hQksVtluZlmJv9nLRRAWYQI,592
39
- uipath/_cli/_dev/_terminal/_components/_new.py,sha256=jxDFOQ6NCzTgesgx3srRr45ij1FqdICAB0uo6vXeh4I,4614
40
- uipath/_cli/_dev/_terminal/_models/_execution.py,sha256=jp-0lRtHqNDAuk7KKPVZ5CUqlFLfuKGZT_GTwd0LtQs,2615
40
+ uipath/_cli/_dev/_terminal/_components/_new.py,sha256=paA8oRhP5mphpf3RHV0gx7_CYdN5e6158tv_XVQifdE,5219
41
+ uipath/_cli/_dev/_terminal/_models/_execution.py,sha256=gPcxtwWR9eO929VaieOdI1e77clceKLoKA0FYayuCFQ,2869
41
42
  uipath/_cli/_dev/_terminal/_models/_messages.py,sha256=p66MHUi_SS30CQWXtiwydybMKBQrtZLXNfNUD6TdK1w,1832
42
- uipath/_cli/_dev/_terminal/_styles/terminal.tcss,sha256=J5hYPhf_Sdif6dApMLujrwNTXlY0QBwonOdbmskxHY0,3141
43
+ uipath/_cli/_dev/_terminal/_styles/terminal.tcss,sha256=ktVpKwXIXw2VZp8KIZD6fO9i9NTGvts_icCTxMdzEiY,3240
43
44
  uipath/_cli/_dev/_terminal/_utils/_chat.py,sha256=YUZxYVdmEManwHDuZsczJT1dWIYE1dVBgABlurwMFcE,8493
44
45
  uipath/_cli/_dev/_terminal/_utils/_exporter.py,sha256=oI6D_eMwrh_2aqDYUh4GrJg8VLGrLYhDahR-_o0uJns,4144
45
46
  uipath/_cli/_dev/_terminal/_utils/_logger.py,sha256=jeNShEED27cNIHTe_NNx-2kUiXpSLTmi0onM6tVkqRM,888
@@ -57,7 +58,7 @@ uipath/_cli/_evals/_models/__init__.py,sha256=Ewjp3u2YeTH2MmzY9LWf7EIbAoIf_nW9fM
57
58
  uipath/_cli/_evals/_models/_evaluation_set.py,sha256=tVHykSget-G3sOCs9bSchMYUTpFqzXVlYYbY8L9SI0c,1518
58
59
  uipath/_cli/_evals/_models/_evaluators.py,sha256=l57NEVyYmzSKuoIXuGkE94Br01hAMg35fiS2MlTkaQM,2115
59
60
  uipath/_cli/_push/sw_file_handler.py,sha256=AX4TKM-q6CNGw3JyBW02M8ktPZuFMcAU9LN3Ii0Q2QI,18202
60
- uipath/_cli/_runtime/_contracts.py,sha256=X8lev5v4XN2sOIwKWE7VXpFgfNhQjh9UGGbgogo1llE,21246
61
+ uipath/_cli/_runtime/_contracts.py,sha256=5seaUN5nurtimNiCH3c0PH9IcGiF-v1WNxJR-bQN7fs,21380
61
62
  uipath/_cli/_runtime/_escalation.py,sha256=x3vI98qsfRA-fL_tNkRVTFXioM5Gv2w0GFcXJJ5eQtg,7981
62
63
  uipath/_cli/_runtime/_hitl.py,sha256=VKbM021nVg1HEDnTfucSLJ0LsDn83CKyUtVzofS2qTU,11369
63
64
  uipath/_cli/_runtime/_logging.py,sha256=MGklGKPjYKjs7J5Jy9eplA9zCDsdtEbkZdCbTwgut_4,8311
@@ -139,8 +140,8 @@ uipath/tracing/_traced.py,sha256=qeVDrds2OUnpdUIA0RhtF0kg2dlAZhyC1RRkI-qivTM,185
139
140
  uipath/tracing/_utils.py,sha256=wJRELaPu69iY0AhV432Dk5QYf_N_ViRU4kAUG1BI1ew,10384
140
141
  uipath/utils/__init__.py,sha256=VD-KXFpF_oWexFg6zyiWMkxl2HM4hYJMIUDZ1UEtGx0,105
141
142
  uipath/utils/_endpoints_manager.py,sha256=iRTl5Q0XAm_YgcnMcJOXtj-8052sr6jpWuPNz6CgT0Q,8408
142
- uipath-2.1.40.dist-info/METADATA,sha256=Qzmiy04dDbd6AhRGQUWrk0R6qSTBTxIJtjY5kTB6V64,6482
143
- uipath-2.1.40.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
144
- uipath-2.1.40.dist-info/entry_points.txt,sha256=9C2_29U6Oq1ExFu7usihR-dnfIVNSKc-0EFbh0rskB4,43
145
- uipath-2.1.40.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
146
- uipath-2.1.40.dist-info/RECORD,,
143
+ uipath-2.1.42.dist-info/METADATA,sha256=nv3-hB1EOq2ErNpPkxUUBfjJ5y1BWtpKJ57orbyEXho,6482
144
+ uipath-2.1.42.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
145
+ uipath-2.1.42.dist-info/entry_points.txt,sha256=9C2_29U6Oq1ExFu7usihR-dnfIVNSKc-0EFbh0rskB4,43
146
+ uipath-2.1.42.dist-info/licenses/LICENSE,sha256=-KBavWXepyDjimmzH5fVAsi-6jNVpIKFc2kZs0Ri4ng,1058
147
+ uipath-2.1.42.dist-info/RECORD,,