intuned-runtime 1.3.2__py3-none-any.whl → 1.3.4__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 intuned-runtime might be problematic. Click here for more details.

Files changed (51) hide show
  1. intuned_cli/commands/__init__.py +1 -1
  2. intuned_cli/commands/attempt_api_command.py +0 -2
  3. intuned_cli/commands/attempt_authsession_check_command.py +0 -2
  4. intuned_cli/commands/attempt_authsession_command.py +0 -3
  5. intuned_cli/commands/attempt_authsession_create_command.py +0 -2
  6. intuned_cli/commands/attempt_command.py +0 -3
  7. intuned_cli/commands/authsession_command.py +0 -3
  8. intuned_cli/commands/authsession_record_command.py +0 -2
  9. intuned_cli/commands/command.py +0 -3
  10. intuned_cli/commands/deploy_command.py +0 -3
  11. intuned_cli/commands/init_command.py +0 -3
  12. intuned_cli/commands/run_api_command.py +0 -2
  13. intuned_cli/commands/run_authsession_command.py +0 -3
  14. intuned_cli/commands/run_authsession_create_command.py +2 -5
  15. intuned_cli/commands/run_authsession_update_command.py +3 -6
  16. intuned_cli/commands/run_authsession_validate_command.py +2 -5
  17. intuned_cli/commands/run_command.py +0 -3
  18. intuned_cli/commands/save_command.py +0 -3
  19. intuned_cli/controller/deploy.py +0 -2
  20. intuned_cli/controller/save.py +0 -18
  21. intuned_cli/utils/wrapper.py +13 -3
  22. intuned_internal_cli/commands/__init__.py +8 -16
  23. intuned_internal_cli/commands/browser/__init__.py +1 -1
  24. intuned_internal_cli/commands/browser/save_state.py +2 -3
  25. intuned_internal_cli/commands/project/__init__.py +7 -9
  26. intuned_internal_cli/commands/project/auth_session/__init__.py +3 -3
  27. intuned_internal_cli/commands/project/auth_session/check.py +2 -2
  28. intuned_internal_cli/commands/project/auth_session/create.py +2 -3
  29. intuned_internal_cli/commands/project/auth_session/load.py +2 -3
  30. intuned_internal_cli/commands/project/project.py +2 -2
  31. intuned_internal_cli/commands/project/run.py +2 -2
  32. intuned_internal_cli/commands/project/run_interface.py +75 -8
  33. intuned_internal_cli/commands/project/type_check.py +5 -5
  34. intuned_internal_cli/commands/root.py +2 -1
  35. intuned_internal_cli/utils/wrapper.py +15 -0
  36. {intuned_runtime-1.3.2.dist-info → intuned_runtime-1.3.4.dist-info}/METADATA +1 -1
  37. {intuned_runtime-1.3.2.dist-info → intuned_runtime-1.3.4.dist-info}/RECORD +45 -49
  38. runtime/browser/launch_browser.py +15 -0
  39. runtime/browser/launch_chromium.py +10 -1
  40. runtime/run/types.py +0 -5
  41. runtime/types/settings_types.py +12 -4
  42. runtime/utils/anyio.py +26 -0
  43. intuned_internal_cli/commands/ai_source/__init__.py +0 -4
  44. intuned_internal_cli/commands/ai_source/ai_source.py +0 -10
  45. intuned_internal_cli/commands/ai_source/deploy.py +0 -64
  46. intuned_internal_cli/commands/init.py +0 -127
  47. intuned_internal_cli/commands/project/upgrade.py +0 -92
  48. intuned_internal_cli/commands/publish_packages.py +0 -264
  49. {intuned_runtime-1.3.2.dist-info → intuned_runtime-1.3.4.dist-info}/WHEEL +0 -0
  50. {intuned_runtime-1.3.2.dist-info → intuned_runtime-1.3.4.dist-info}/entry_points.txt +0 -0
  51. {intuned_runtime-1.3.2.dist-info → intuned_runtime-1.3.4.dist-info}/licenses/LICENSE +0 -0
@@ -2,18 +2,21 @@ import asyncio
2
2
  import os
3
3
  import signal
4
4
  import socket
5
+ import sys
5
6
  import time
6
7
  from collections.abc import AsyncGenerator
8
+ from pathlib import Path
7
9
  from typing import Any
8
10
  from typing import cast
9
11
  from typing import Literal
10
12
 
11
- import arguably
12
13
  from pydantic import Field
13
14
  from pydantic import ValidationError
14
15
 
16
+ from intuned_internal_cli.utils.wrapper import internal_cli_command
15
17
  from runtime.backend_functions import get_auth_session_parameters
16
18
  from runtime.context import IntunedContext
19
+ from runtime.errors.run_api_errors import ApiNotFoundError
17
20
  from runtime.errors.run_api_errors import InternalInvalidInputError
18
21
  from runtime.errors.run_api_errors import RunApiError
19
22
  from runtime.run.run_api import import_function_from_api_dir
@@ -69,15 +72,18 @@ class MessageWrapper(CamelBaseModel):
69
72
  )
70
73
 
71
74
 
72
- @arguably.command # type: ignore
75
+ @internal_cli_command
73
76
  async def project__run_interface(
74
77
  socket_path: str,
78
+ *,
79
+ jsonl: bool = False,
75
80
  ):
76
81
  """
77
82
  Runs the current project. Project must contain an "api" directory with API functions.
78
83
 
79
84
  Args:
80
85
  socket_path (str): Path to the socket file.
86
+ jsonl (bool, optional): Use a JSONL client instead of socket. Defaults to False.
81
87
 
82
88
  """
83
89
 
@@ -86,7 +92,7 @@ async def project__run_interface(
86
92
  raise Exception("socket_path is required")
87
93
 
88
94
  timeout_timestamp = time.time()
89
- client = UDASClient(socket_path)
95
+ client = SocketClient(socket_path) if not jsonl else JSONLFileClient(socket_path)
90
96
  connected = await client.connect()
91
97
  if not connected:
92
98
  raise Exception("Failed to connect to UDAS")
@@ -97,7 +103,9 @@ async def project__run_interface(
97
103
 
98
104
  def done(exitCode: int = 0):
99
105
  client.close()
100
- exit(exitCode)
106
+ loop.remove_signal_handler(signal.SIGTERM)
107
+ loop.remove_signal_handler(signal.SIGINT)
108
+ sys.exit(exitCode)
101
109
 
102
110
  def interrupt_signal_handler():
103
111
  async def _impl():
@@ -133,6 +141,11 @@ async def project__run_interface(
133
141
  asyncio.Task[RunAutomationSuccessResult] | None, None
134
142
  )
135
143
 
144
+ def import_function(file_path: str, automation_name: str | None = None):
145
+ return import_function_from_api_dir(
146
+ automation_function_name=automation_name, file_path=file_path, base_dir=os.getcwd()
147
+ )
148
+
136
149
  async def handle_message(message: Message):
137
150
  nonlocal run_api_task
138
151
  if message.type == "start":
@@ -151,9 +164,7 @@ async def project__run_interface(
151
164
  run_api_task = asyncio.create_task(
152
165
  run_api(
153
166
  message.parameters,
154
- import_function=lambda file_path, automation_name=None: import_function_from_api_dir(
155
- automation_function_name=automation_name, file_path=file_path, base_dir=os.getcwd()
156
- ),
167
+ import_function=import_function,
157
168
  ),
158
169
  )
159
170
  return
@@ -191,6 +202,14 @@ async def project__run_interface(
191
202
  await client.send_message({"type": "done", "success": False, "result": message.json})
192
203
  break
193
204
  if message.type == "ping":
205
+ api_files = await get_python_files_from_dir(Path() / "api")
206
+ apis = [f'api/{str(p.with_suffix("").as_posix())}' for p in api_files]
207
+
208
+ for api in [*apis, "auth-sessions/create", "auth-sessions/check"]:
209
+ try:
210
+ import_function(api)
211
+ except ApiNotFoundError:
212
+ pass
194
213
  await client.send_message({"type": "pong"})
195
214
  break
196
215
  await handle_message(message)
@@ -231,7 +250,7 @@ async def project__run_interface(
231
250
  done()
232
251
 
233
252
 
234
- class UDASClient:
253
+ class SocketClient:
235
254
  def __init__(self, socket_path: str):
236
255
  self.socket_path = socket_path
237
256
  self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
@@ -263,3 +282,51 @@ class UDASClient:
263
282
  return
264
283
  self.sock.shutdown(socket.SHUT_RDWR)
265
284
  self.sock.close()
285
+
286
+
287
+ class JSONLFileClient(SocketClient):
288
+ def __init__(self, socket_path: str):
289
+ self.socket_path = socket_path
290
+ self.fp = None
291
+
292
+ async def connect(self):
293
+ if not os.path.exists(self.socket_path):
294
+ return False
295
+ self.fp = open(self.socket_path, "r+b", buffering=0)
296
+ return True
297
+
298
+ def receive_messages(self) -> AsyncGenerator[dict[str, Any], None]:
299
+ import json
300
+
301
+ async def generator():
302
+ if self.fp is None:
303
+ raise Exception("Socket not connected")
304
+ while True:
305
+ line = self.fp.readline()
306
+ if not line:
307
+ break
308
+ yield json.loads(line.decode("utf-8"))
309
+
310
+ return generator()
311
+
312
+ async def send_message(self, message: dict[str, Any]):
313
+ print("Sending message", message)
314
+
315
+ def close(self):
316
+ if not self.fp:
317
+ return
318
+ self.fp.close()
319
+
320
+
321
+ async def get_python_files_from_dir(dir: Path) -> list[Path]:
322
+ """Get all Python files under a directory, returning relative paths."""
323
+ python_files: list[Path] = []
324
+
325
+ file_tree = await asyncio.to_thread(os.walk, dir)
326
+ for root, _, files in file_tree:
327
+ for file in files:
328
+ if file.endswith(".py"):
329
+ full_path = Path(root) / file
330
+ relative_path = full_path.relative_to(dir)
331
+ python_files.append(relative_path)
332
+ return python_files
@@ -2,15 +2,15 @@ import json
2
2
  import os
3
3
  import subprocess
4
4
  import sys
5
+ from typing import Any
5
6
 
6
- import arguably
7
+ from intuned_internal_cli.utils.wrapper import internal_cli_command
7
8
 
8
9
  current_dir = os.path.dirname(os.path.abspath(__file__))
9
- PYRIGHT_CONFIG_PATH = os.path.join(current_dir, "..", "..", "pyright_type_check.json")
10
- PYRIGHT_CONFIG_PATH = os.path.abspath(PYRIGHT_CONFIG_PATH)
10
+ PYRIGHT_CONFIG_PATH = os.path.abspath(os.path.join(current_dir, "..", "..", "pyright_type_check.json"))
11
11
 
12
12
 
13
- @arguably.command # type: ignore
13
+ @internal_cli_command
14
14
  async def project__type_check():
15
15
  """
16
16
  Run type checking on the API directory using pyright.
@@ -39,7 +39,7 @@ async def project__type_check():
39
39
  print("📦 Checking Types...")
40
40
 
41
41
  try:
42
- pyright_issues = []
42
+ pyright_issues: list[dict[str, Any]] = []
43
43
  pyright_result = subprocess.run(
44
44
  ["pyright", "--outputjson", project_dir, "--project", PYRIGHT_CONFIG_PATH],
45
45
  capture_output=True,
@@ -1,7 +1,8 @@
1
1
  import arguably
2
2
 
3
3
 
4
- @arguably.command # type: ignore
4
+ # @arguably.command # type: ignore
5
+ # @run_sync
5
6
  async def __root__():
6
7
  """Internal Intuned CLI.
7
8
 
@@ -0,0 +1,15 @@
1
+ from collections.abc import Awaitable
2
+ from collections.abc import Callable
3
+ from typing import ParamSpec
4
+ from typing import TypeVar
5
+
6
+ import arguably
7
+
8
+ from runtime.utils.anyio import run_sync
9
+
10
+ P = ParamSpec("P")
11
+ R = TypeVar("R")
12
+
13
+
14
+ def internal_cli_command(fn: Callable[P, R | Awaitable[R]]) -> Callable[P, R]:
15
+ return arguably.command(run_sync(fn)) # type: ignore
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: intuned-runtime
3
- Version: 1.3.2
3
+ Version: 1.3.4
4
4
  Summary: Runtime SDK that powers browser automation projects running on Intuned
5
5
  License: Elastic-2.0
6
6
  License-File: LICENSE
@@ -1,29 +1,29 @@
1
1
  intuned_cli/__init__.py,sha256=00r4AkrKFEzybNb4LWRZGSi3evyX9adVC6LoFItP5Ls,1208
2
- intuned_cli/commands/__init__.py,sha256=AiCFfIDmlliLvz-eebZ-oh-PgCMF3jA8dH4n9t4BgUE,1779
3
- intuned_cli/commands/attempt_api_command.py,sha256=oBPxiqsc8_J5YSXpuG4bj_HBzHhHehGiP2P-J9ZSvMA,2401
4
- intuned_cli/commands/attempt_authsession_check_command.py,sha256=L4oB7wl6ntAH2PMzWNNMqso6Zit7ts2HjXzqmdC8vzI,1781
5
- intuned_cli/commands/attempt_authsession_command.py,sha256=Qo9sj2mE27ha_XSGCfHhfqLybQzOaP0TjABagBkJkzs,282
6
- intuned_cli/commands/attempt_authsession_create_command.py,sha256=QT1-apHhDaxI3FMNUWApctpN6K694SsOkAwqS9vPRVg,2170
7
- intuned_cli/commands/attempt_command.py,sha256=HEic_NyrDFoTENtiF3UpJpxoxXHNXTd5yMCJjMNPyaI,258
8
- intuned_cli/commands/authsession_command.py,sha256=coHm9k23_aucxYnW08uSdMe0e_WXRwthbdQBXEUkmic,254
9
- intuned_cli/commands/authsession_record_command.py,sha256=B__J9T8qFQ-YFTuQPijdA41iq6-eZC-JpTQGoCuZLu0,2423
10
- intuned_cli/commands/command.py,sha256=cZLdhtdLXakhZ8Qbv6joqpD4AGgf30FYl9dc1KR3x6M,815
11
- intuned_cli/commands/deploy_command.py,sha256=D_CkGH0e1-vNEFd0y-0KFiquxviTYIAs_3Ba6DNj_Vo,1612
12
- intuned_cli/commands/init_command.py,sha256=XDf2ilNzqT43u0nn3GoM_L4VU9lfyxKpx2eTXtig_jI,555
13
- intuned_cli/commands/run_api_command.py,sha256=vcd4xLh0tEfBnk_qE5rg2LY8T2szASLMNzU7HsUI1BE,3451
14
- intuned_cli/commands/run_authsession_command.py,sha256=e_u4WWSDVZKCbK4wcuqqhWTdNrsjcLXaeUx8sIYjhkQ,274
15
- intuned_cli/commands/run_authsession_create_command.py,sha256=5VXDQRnShZhF89drZi6f3Ynb6i-b127IByDMf3mmIoU,3449
16
- intuned_cli/commands/run_authsession_update_command.py,sha256=1MBJ5-Z6TeLXgGX5pnVo2AYzRjTs7hFNADdzb0fuXPc,3501
17
- intuned_cli/commands/run_authsession_validate_command.py,sha256=zoLoyEMVUFsORDB9pf0HnvcMrnGZVgoO3OT75UQCae4,3355
18
- intuned_cli/commands/run_command.py,sha256=Q4-r_IIvGjuXoo-OSOq23aGDiJVoyfhtIMsp7XI11jU,250
19
- intuned_cli/commands/save_command.py,sha256=xm4132hSxAKdA7IGKUSpaDw3A7Dn9Lim5eBb-Vz69I0,1606
2
+ intuned_cli/commands/__init__.py,sha256=Z-a4JJmc67fqHW9bVML15MO1X8YPeHn-SIC_YBSsAP0,1781
3
+ intuned_cli/commands/attempt_api_command.py,sha256=bs_Sgyo1AxX-y3q-hWXD8lhXxdaAW8mPF8s0GfUK2oQ,2351
4
+ intuned_cli/commands/attempt_authsession_check_command.py,sha256=SZ_PvTi_Tsiyz_UPHhsPelH2oiAdwvIA90YNIotLZfw,1731
5
+ intuned_cli/commands/attempt_authsession_command.py,sha256=SqzeaTRz6d2Z2uantxnNaxlr9fAJNlSDTzkfKuAgzMQ,231
6
+ intuned_cli/commands/attempt_authsession_create_command.py,sha256=U8xBdkfkMzma_KKR7-m9p2klqg-BJul1RVei88h82Xo,2120
7
+ intuned_cli/commands/attempt_command.py,sha256=yLL9qxaPQJ9PjzNg95NUkghtf7Z6-EHujhcU8jyJY3I,207
8
+ intuned_cli/commands/authsession_command.py,sha256=0XMkiKfNIzwudVw99S5JhiJOYKiQ6CcQRpSHWGpj2GM,203
9
+ intuned_cli/commands/authsession_record_command.py,sha256=UR_sVTl6AgkTgXedasLa3RrQU189OfuwkA7dK-E1d8k,2373
10
+ intuned_cli/commands/command.py,sha256=IYvFDCxA-ioLrZNQVh7t-7Zi_9bNELQs-J2m9onyNFY,764
11
+ intuned_cli/commands/deploy_command.py,sha256=IJLxvmXuR0R0aBiYDRCZUK1XTWM0U0rIYRqfaetvX9k,1561
12
+ intuned_cli/commands/init_command.py,sha256=HHjwC20LshW1frbUncC4bH3GPh5cL6nzLQq7LThs9LY,504
13
+ intuned_cli/commands/run_api_command.py,sha256=CbXALVcsqI4HP-gcjR--6szrQdqhfw7Dc43QPLPjL00,3401
14
+ intuned_cli/commands/run_authsession_command.py,sha256=5-1a3q_0PuzAoEUEmnr9HBf5HTqkaUzzrssJG4vIa9g,223
15
+ intuned_cli/commands/run_authsession_create_command.py,sha256=YyzNJquHc9wsng1Pa7csmjmilRdgMP57gi_yjAPcQ4c,3158
16
+ intuned_cli/commands/run_authsession_update_command.py,sha256=GpRu3MvTOp-U5nl9oCYNuLvk9G3KvPORIBSfBHtVAFc,3211
17
+ intuned_cli/commands/run_authsession_validate_command.py,sha256=6bUl2FRR19b7_jAKuAENuO-ih_ygbBU_hg7fyM3Dgc8,3064
18
+ intuned_cli/commands/run_command.py,sha256=-ayHF-noiDsnIobbszAz4JEpIEZh-lf8fAWK0CoxiIU,199
19
+ intuned_cli/commands/save_command.py,sha256=H1X3SrRTBHCWiVr7PG94n-MIbW_bPtQWJaWrVvTk-5Y,1555
20
20
  intuned_cli/controller/__test__/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
21
21
  intuned_cli/controller/__test__/test_api.py,sha256=CgPUTsdQZ6r4it8yU1JG96TiN1WKyeUMh__7UICg36k,24489
22
22
  intuned_cli/controller/__test__/test_authsession.py,sha256=fvkqm1B39kAxgb1iLXs4WlcVNzn3P6hvlvNS4IrdBgQ,52491
23
23
  intuned_cli/controller/api.py,sha256=GDBSn7J0567ziBLNEk6tiguUDLwUTvDU6kmMqifYKMQ,7511
24
24
  intuned_cli/controller/authsession.py,sha256=rx5qRaKp4ED3OArD8_qCDGjKqgy1Pc5s9YYfm6bxe-I,18688
25
- intuned_cli/controller/deploy.py,sha256=CFQ3MBEEsJ39JzINiOBgcxGGGQnuARz2TiRL1wsDRKo,5490
26
- intuned_cli/controller/save.py,sha256=xdo8d_bZ_CBTm0nleZXoyTSbl6Xee_acQgstoSYlArI,9526
25
+ intuned_cli/controller/deploy.py,sha256=nmXIWTunPMqx_fcuFhbstWVQiIhCnI3bkJ4oMVBZQH8,5436
26
+ intuned_cli/controller/save.py,sha256=LxIu6IznmTvAC5OpEQcnq1TnxYG6aCNBBdvmyVYs_Zg,8850
27
27
  intuned_cli/types.py,sha256=1BKCukVvn2i37-onpZ9rFLrcVh4kWW_ui0DzOIKugtI,704
28
28
  intuned_cli/utils/__test__/test_browser.py,sha256=NCv7OplirDxAjBpnfZharOa5O0fVNWA9xU3I1GVWB5M,4474
29
29
  intuned_cli/utils/__test__/test_traces.py,sha256=4EfzwizBt7VT9-dANMdBYFKQTPzPWMDnodSVyT5F4dY,901
@@ -40,33 +40,28 @@ intuned_cli/utils/help.py,sha256=NKTQCzaIINQsGHljJH68HemAVThbkKU3IQfxyRyVaD0,223
40
40
  intuned_cli/utils/import_function.py,sha256=UmE2yw5std1ENMFdBU-TUBuQ01qsv7Qr5ElnAhqE6Yc,453
41
41
  intuned_cli/utils/timeout.py,sha256=DkoeoU9XvKKKSQ06CpwqcNvxWqLPAOVuAMw6kSr4Tuo,886
42
42
  intuned_cli/utils/traces.py,sha256=Du_FnvSq-StLsAIQKSNyNSwkoMS-J93Tb6Ln4QgXVTE,793
43
- intuned_cli/utils/wrapper.py,sha256=A_WgbzHYSZYNCoubjR7HNJUfv5--B2QfVW0XOCiO5r0,2045
43
+ intuned_cli/utils/wrapper.py,sha256=MRLtDhZLxQlOd0C44JrGV_WZJ3xbtZFaSsBTZGtd-oY,2269
44
44
  intuned_internal_cli/__init__.py,sha256=bcL7-SPWCE0SmszoBoEvcyf-wAGRHAzIRe7vlCq3NPA,1760
45
- intuned_internal_cli/commands/__init__.py,sha256=gZ-r8UIXvRakeCfvmOZCNWr8CJHBcYzRzbMjyKYPXV0,1003
46
- intuned_internal_cli/commands/ai_source/__init__.py,sha256=lg7owgcK8owNn2a4VBUP9RKxzFsLruhtnnQV0F_z6pc,149
47
- intuned_internal_cli/commands/ai_source/ai_source.py,sha256=2woQtCmhxKvLfEz832eUoCT9gMsuSvEE6rMnHSYXC7w,138
48
- intuned_internal_cli/commands/ai_source/deploy.py,sha256=NpomuP_2mo5SLKe7BZoY5H0Pp36aDtkYU_CyihqOvdI,2457
49
- intuned_internal_cli/commands/browser/__init__.py,sha256=AuVbvh7aSBTFKYvewXZyPoIvfBTe2uHiPcnaAkzapas,95
50
- intuned_internal_cli/commands/browser/save_state.py,sha256=_gfspwLkk6j1zBzqY1Qr7KnEMjGP6x10Q2IvKdfjyuI,839
51
- intuned_internal_cli/commands/init.py,sha256=8rWBenWZfwNtLxOBqhEMbOATyQNEnmDUmrFJ1xBGyxI,4384
52
- intuned_internal_cli/commands/project/__init__.py,sha256=t97wvhSenerYRdbSeCKXqHASA6EWA3lc1hnRhF9baOE,734
53
- intuned_internal_cli/commands/project/auth_session/__init__.py,sha256=gt7mlaW6xmqAc_4-pfF_FiecsR51C6fqCaq_NFbcbwA,300
54
- intuned_internal_cli/commands/project/auth_session/check.py,sha256=UDG2iF6ULmYH6_WdUTVRTAZq3fBHuVSzhWB1tGkkGb0,4524
55
- intuned_internal_cli/commands/project/auth_session/create.py,sha256=r-eYu3uLUo2mzF836CbVgu4oBzcIIDekzzFwwekxmg0,3374
56
- intuned_internal_cli/commands/project/auth_session/load.py,sha256=Y0V6bFZQeHq_lTtR-rQvM9SSbExWhVVMFu-Uykl-9k4,1199
57
- intuned_internal_cli/commands/project/project.py,sha256=_MSh6Xor2Cbh-ItifwgOPq_BP8UDuKB7S6w796FULKQ,137
58
- intuned_internal_cli/commands/project/run.py,sha256=7lqrFrTOaW0W5UF6WTVwwDauAoGbABNv6RVQ6_DEIfQ,12209
59
- intuned_internal_cli/commands/project/run_interface.py,sha256=4RyR8WZriIF7Va4z1wt-q6zZDQOI31n62Ho2dyimzUY,8717
60
- intuned_internal_cli/commands/project/type_check.py,sha256=QFnXL93Y-z250EQRln5sRqwkVqjGJ-eP_p1jGrXB7NA,3522
61
- intuned_internal_cli/commands/project/upgrade.py,sha256=XmkZLflM4O-mwvhwcswlZpazRotwi3xesLgE0Zz8fTI,3061
62
- intuned_internal_cli/commands/publish_packages.py,sha256=sijkaG7_s0I1EWgLekGy1qm8Aqi_gYY8poXbMX0B6Yw,10505
63
- intuned_internal_cli/commands/root.py,sha256=o75rSb5WYa5JMD8HLN3eiNu4fM0mar3y15A63-Qm4s4,426
45
+ intuned_internal_cli/commands/__init__.py,sha256=WUC40iBg5ONoVFjhpLXMrNwgVVbmooUCT0Bm9tl8GAg,589
46
+ intuned_internal_cli/commands/browser/__init__.py,sha256=lFuoW-OysNTN8Toe4sy1rEZmnnfQSKPKtoFRFEmBMKc,79
47
+ intuned_internal_cli/commands/browser/save_state.py,sha256=sKVQ5558IYLNlNVokMvVrJcy7zlL5YZ9HvM9D6K4yZ4,878
48
+ intuned_internal_cli/commands/project/__init__.py,sha256=KJANCr-wxgCd0Fu4NQC0IYzApdU5hl3dVYIDekGhiKg,544
49
+ intuned_internal_cli/commands/project/auth_session/__init__.py,sha256=pjBR6l3NOhSByXG2xM6FpdveWzPj0Lg8-rfJ28VD2KM,252
50
+ intuned_internal_cli/commands/project/auth_session/check.py,sha256=TbEwndBRn04dc2dZsLLqO6hBXbCYfa6V9Hxn9Ia8MBo,4564
51
+ intuned_internal_cli/commands/project/auth_session/create.py,sha256=MG0JVJvEm0pFiQbMogqveOv1bs4STZKGhVt_rmHNB4Q,3413
52
+ intuned_internal_cli/commands/project/auth_session/load.py,sha256=lnW0CDODe9Bvo05zuTZQVqYUbANDNMYhyQBIkI2g_aQ,1238
53
+ intuned_internal_cli/commands/project/project.py,sha256=69XKffH5K4Y2xhWhUdSmYG9CR9E_qp_-3RZXG-v7fdE,177
54
+ intuned_internal_cli/commands/project/run.py,sha256=rJHY9lTKnk2tr7rWjLaCFdeHniM3YsDRF7n1fk4TOf8,12249
55
+ intuned_internal_cli/commands/project/run_interface.py,sha256=sMm74YpqufBThxOxT9RDd2zJjFfkuR6UXG7rDcR3_ZE,11011
56
+ intuned_internal_cli/commands/project/type_check.py,sha256=VYqbtnvD9UpiyP8qCW5fLx52PKIj66Rw_ZD7Xe9HWtw,3565
57
+ intuned_internal_cli/commands/root.py,sha256=HLW2JWAt_5y9rGB8iaciAY4w94krF2v1AwxS_n4y1h0,440
64
58
  intuned_internal_cli/logger.py,sha256=bZK3q-KUdGxk_qzDb6pn-n0LOhKJvi6a9p8oSwZtq3s,594
65
59
  intuned_internal_cli/utils/ai_source_project.py,sha256=xUCM6p3i1XN4bJbuQz8LCzeI4BwqAdSvCl_vwDAEi0k,831
66
60
  intuned_internal_cli/utils/code_tree.py,sha256=1wfxZoQ5kRCfqs2SEPAicbAIPTiD6P1LxSuwYu_eeaI,2790
67
61
  intuned_internal_cli/utils/run_apis.py,sha256=Zee4zkgt9R8XY1XCGzj2Nc4zJ3jlRz1xnO493wotuWw,4690
68
62
  intuned_internal_cli/utils/setup_ide_functions_token.py,sha256=72-hf5HOPO9hj_eo3MTSVEPIwtkaIma_NRepsw_FHQM,304
69
63
  intuned_internal_cli/utils/unix_socket.py,sha256=UISmkJMHrir5iBLUm6vxC3uzTGIFyOk_wa0C9LUw4Cc,1889
64
+ intuned_internal_cli/utils/wrapper.py,sha256=Y0yAs2XrDHChUMUsEYcRT0AbSkZCfdgAvZs0Sdrbirg,366
70
65
  intuned_runtime/__init__.py,sha256=1BPzEc-qC2WAYiCWDOJChpgnFyO3ZNYRKHEZqdHUGwM,322
71
66
  runtime/__init__.py,sha256=87gDXuxUv_kGzQfuB1mh6DF-dDysJN8r684c7jGnHxc,144
72
67
  runtime/backend_functions/__init__.py,sha256=j2EaK4FK8bmdFtqc5FxtFwx1KhIn_7qKPChrrAhJI3s,119
@@ -77,9 +72,9 @@ runtime/browser/extensions/__init__.py,sha256=VGUFvkYUwuYc9UlYy1TD79veXuDhnLDcmb
77
72
  runtime/browser/extensions/helpers.py,sha256=W3XiOf66J_xWpa4-U7hQjW0CfAucCYz12pBcIRnzLTQ,387
78
73
  runtime/browser/extensions/intuned_extension.py,sha256=_La0ikQX2isdiBgZXkZt2iQ6eyW7Fe-9yjePFzpj0rk,2804
79
74
  runtime/browser/helpers.py,sha256=CwgiBToawPgwAY9nIGkGHW544N7Db_OgKmS-SHkN2pU,1255
80
- runtime/browser/launch_browser.py,sha256=ym97J4RffOGUwhi9iNjAR5Ek2f8pKiAtAcDQFSqMJw0,1899
75
+ runtime/browser/launch_browser.py,sha256=MFo9Nb9eQgGO3w3ngRp9epzolcTBvekDQudZwIE6_74,2516
81
76
  runtime/browser/launch_camoufox.py,sha256=TBOAwwipNGlbtMdFYnGkVM0ppLU44vWNkMGZA5uPZCE,1787
82
- runtime/browser/launch_chromium.py,sha256=CetUfwod8JFrpsbePwQqyifw8ofx3jDXR6u9KMxJzJo,8305
77
+ runtime/browser/launch_chromium.py,sha256=p3mpUwVGTOeKBjiaNJMlkW0a5ipQU-sFO2H2J0cTaW0,8832
83
78
  runtime/browser/storage_state.py,sha256=fwLg8sP-H-vgt_6AJKNl03CpgyMVCQWWcN2cqswTQMs,3603
84
79
  runtime/constants.py,sha256=YMYQgCWZdJXUpxz_IN2TvZO5rFye9k_Lk9CS8m-shLg,34
85
80
  runtime/context/__init__.py,sha256=hg8ejm4bJy4tNkwmZ9lKgYJx6bU7OgOdBS684Uv5XGg,73
@@ -103,17 +98,18 @@ runtime/run/pydantic_encoder.py,sha256=wJCljwwINSICvCJ0i2izp2RLkQ15nYglUQCyyjM40
103
98
  runtime/run/run_api.py,sha256=AFhZerLTyHGznGCJl0fLbiTqhZ_WRmphaJK-RqrupTQ,8981
104
99
  runtime/run/setup_context_hook.py,sha256=KTX4mRmeUEmYS9zrmobR1V09GakOk6uz81Uo_xXTJZk,1156
105
100
  runtime/run/traces.py,sha256=fKzh11LqV47ujgq_9I2tdp-dgld566wffWaHwU_4gis,1123
106
- runtime/run/types.py,sha256=RR4RGiYVBIK6f2qXvzfLhQMZ8kmrziu265k5eqoIh98,346
101
+ runtime/run/types.py,sha256=-7ACaxa5vg2qHw14JunvUWt-AchanTQU4FRF57DxJWo,287
107
102
  runtime/types/__init__.py,sha256=LWf5iOMgbve_BrpVP-LWWzDD3v2K4Y2sLxthOnVEqyY,539
108
103
  runtime/types/payload.py,sha256=sty8HgDEn3nJbZrwEOMCXyuG7_ICGDwlBIIWSON5ABY,124
109
104
  runtime/types/run_types.py,sha256=GcYLkL2BHxOjT4O3KvBP6xjBKsmJbjltMt_5bCVnfCI,4554
110
- runtime/types/settings_types.py,sha256=lgu3O-LXSa1Gbv1j6Uzd5udpSFBl2KR9T4vRVWITVfk,2832
105
+ runtime/types/settings_types.py,sha256=pVVh67lv7iHAUUbovGHvbswEFtx_N-b7jTwFvk968Hg,3118
111
106
  runtime/utils/__init__.py,sha256=v0qHjnc54YCkY1yPbXuihgymVZau_15xaEVyaFQj9ts,78
107
+ runtime/utils/anyio.py,sha256=KNemAQmmS425YKbVH_7DAE5lcDG_UziJHHTt9YJKS4o,697
112
108
  runtime/utils/config_loader.py,sha256=yqk2eDGbgyw0Xslgd3dJbB28NjUe02L9LyCxzCmH9r4,482
113
109
  runtime_helpers/__init__.py,sha256=1BPzEc-qC2WAYiCWDOJChpgnFyO3ZNYRKHEZqdHUGwM,322
114
110
  runtime_helpers/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
115
- intuned_runtime-1.3.2.dist-info/METADATA,sha256=octnZbDG6RfYfHhnElBIZxL_v4b1ZaASmPgETnPHDyo,5473
116
- intuned_runtime-1.3.2.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
117
- intuned_runtime-1.3.2.dist-info/entry_points.txt,sha256=ToMS2cqDeRmF1FGkflwoeD-Xz6jJV5p1zIbw9G7IxMg,85
118
- intuned_runtime-1.3.2.dist-info/licenses/LICENSE,sha256=9LIjQdgyU_ptzNIfItNCR7VmEHqYnrY1f1XwOreKFI0,3714
119
- intuned_runtime-1.3.2.dist-info/RECORD,,
111
+ intuned_runtime-1.3.4.dist-info/METADATA,sha256=evPlfZys9C-YXh_s5UsQnqCSBtB4MX0szxNm_hkIcx4,5473
112
+ intuned_runtime-1.3.4.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
113
+ intuned_runtime-1.3.4.dist-info/entry_points.txt,sha256=ToMS2cqDeRmF1FGkflwoeD-Xz6jJV5p1zIbw9G7IxMg,85
114
+ intuned_runtime-1.3.4.dist-info/licenses/LICENSE,sha256=9LIjQdgyU_ptzNIfItNCR7VmEHqYnrY1f1XwOreKFI0,3714
115
+ intuned_runtime-1.3.4.dist-info/RECORD,,
@@ -1,3 +1,5 @@
1
+ import asyncio
2
+ import shutil
1
3
  from contextlib import asynccontextmanager
2
4
  from contextlib import AsyncExitStack
3
5
  from typing import AsyncContextManager
@@ -49,6 +51,19 @@ async def launch_browser(
49
51
  if cdp_port:
50
52
  raise AutomationError(ValueError("CDP port is not supported with Camoufox"))
51
53
  context, page = await stack.enter_async_context(launch_camoufox(headless=headless, proxy=proxy))
54
+ case "brave":
55
+ brave_path = await asyncio.to_thread(shutil.which, "brave-browser-stable")
56
+ if brave_path is None:
57
+ raise RuntimeError("Brave browser not found")
58
+ context, page = await stack.enter_async_context(
59
+ launch_chromium(
60
+ headless=headless,
61
+ cdp_address=cdp_address,
62
+ cdp_port=cdp_port,
63
+ proxy=proxy,
64
+ executable_path=brave_path,
65
+ )
66
+ )
52
67
  case "chromium" | _:
53
68
  context, page = await stack.enter_async_context(
54
69
  launch_chromium(headless=headless, cdp_address=cdp_address, cdp_port=cdp_port, proxy=proxy)
@@ -20,6 +20,7 @@ from .helpers import wait_on_cdp_address
20
20
  logger = logging.getLogger(__name__)
21
21
 
22
22
  if TYPE_CHECKING:
23
+ from playwright.async_api import Page
23
24
  from playwright.async_api import ProxySettings
24
25
  from playwright.async_api import ViewportSize
25
26
 
@@ -57,6 +58,7 @@ async def launch_chromium(
57
58
  proxy: "ProxySettings | None" = None,
58
59
  viewport: "ViewportSize | None" = None,
59
60
  app_mode_initial_url: str | None = None,
61
+ executable_path: os.PathLike[str] | str | None = None,
60
62
  **kwargs: Any,
61
63
  ):
62
64
  from playwright.async_api import async_playwright
@@ -101,8 +103,15 @@ async def launch_chromium(
101
103
  if headless:
102
104
  args_to_ignore.append("--headless=old")
103
105
  extra_args.append("--headless=new")
106
+
107
+ if executable_path is not None:
108
+ executable_path = await anyio.Path(executable_path).resolve()
109
+ if not await executable_path.exists():
110
+ logger.warning(f"Executable path {executable_path} does not exist. Falling back to default.")
111
+ executable_path = None
104
112
  context = await playwright.chromium.launch_persistent_context(
105
113
  os.fspath(user_preferences_dir),
114
+ executable_path=str(executable_path) if executable_path else None,
106
115
  headless=headless,
107
116
  viewport=viewport,
108
117
  proxy=proxy,
@@ -171,7 +180,7 @@ async def dangerous_launch_chromium(
171
180
  for page in context.pages:
172
181
  await page.set_viewport_size(kwargs.get("viewport", {"width": 1280, "height": 800}))
173
182
 
174
- async def set_viewport_size(page):
183
+ async def set_viewport_size(page: "Page"):
175
184
  # check if the page is already closed
176
185
  if page.is_closed():
177
186
  return
runtime/run/types.py CHANGED
@@ -4,11 +4,6 @@ from typing import Awaitable
4
4
  from typing import Optional
5
5
  from typing import Protocol
6
6
 
7
- from git import TYPE_CHECKING
8
-
9
- if TYPE_CHECKING:
10
- pass
11
-
12
7
 
13
8
  class ImportFunction(Protocol):
14
9
  def __call__(self, file_path: str, name: Optional[str] = None, /) -> Callable[..., Awaitable[Any]]: ...
@@ -9,11 +9,21 @@ class CaptchaSettings(BaseModel):
9
9
  enabled: bool = Field(default=False)
10
10
 
11
11
 
12
- class CustomCaptchaSettings(CaptchaSettings):
12
+ class CaptchaSolverSolveSettings(BaseModel):
13
13
  model_config = {
14
14
  "populate_by_name": True,
15
15
  "serialize_by_alias": True,
16
16
  }
17
+ auto_solve: bool = Field(default=True, alias="autoSolve")
18
+ solve_delay: int = Field(default=2000, alias="solveDelay")
19
+ max_retries: int = Field(default=3, alias="maxRetries")
20
+ timeout: int = Field(default=30000)
21
+
22
+
23
+ class CustomCaptchaSettings(CaptchaSettings):
24
+ model_config = {
25
+ "serialize_by_alias": True,
26
+ }
17
27
 
18
28
  image_locators: List[str] = Field(alias="imageLocators", default=[])
19
29
  submit_locators: List[str] = Field(alias="submitLocators", default=[])
@@ -47,9 +57,7 @@ class CaptchaSolverSettings(BaseModel):
47
57
  lemin: CaptchaSettings = Field(default_factory=CaptchaSettings)
48
58
  custom_captcha: CustomCaptchaSettings = Field(alias="customCaptcha", default_factory=CustomCaptchaSettings)
49
59
  text: TextCaptchaSettings = Field(default_factory=TextCaptchaSettings)
50
- settings: dict[str, int | bool] = Field(
51
- default={"autoSolve": True, "solveDelay": 2000, "maxRetries": 3, "timeout": 30000}
52
- )
60
+ settings: CaptchaSolverSolveSettings = Field(default_factory=CaptchaSolverSolveSettings)
53
61
 
54
62
 
55
63
  class IntunedJsonDisabledAuthSessions(BaseModel):
runtime/utils/anyio.py ADDED
@@ -0,0 +1,26 @@
1
+ import functools
2
+ import inspect
3
+ from functools import wraps
4
+ from typing import Any
5
+ from typing import Callable
6
+ from typing import TypeVar
7
+
8
+ import anyio
9
+
10
+ T = TypeVar("T")
11
+
12
+
13
+ def run_sync(func: Callable[..., T]) -> Callable[..., T]:
14
+ """
15
+ Wrapper that runs a function synchronously.
16
+ If the function is async, it will be run using anyio.run instead of asyncio.run.
17
+ """
18
+
19
+ @wraps(func)
20
+ def wrapper(*args: Any, **kwargs: Any) -> T:
21
+ if inspect.iscoroutinefunction(func):
22
+ func_with_args_kwargs = functools.partial(func, *args, **kwargs)
23
+ return anyio.run(func_with_args_kwargs, backend="asyncio")
24
+ return func(*args, **kwargs)
25
+
26
+ return wrapper
@@ -1,4 +0,0 @@
1
- from .ai_source import ai_source # type: ignore
2
- from .deploy import ai_source__deploy # type: ignore
3
-
4
- __all__ = ["ai_source", "ai_source__deploy"]
@@ -1,10 +0,0 @@
1
- import arguably
2
-
3
-
4
- @arguably.command # type: ignore
5
- def ai_source():
6
- """
7
- Commands to run on AI source projects.
8
- """
9
-
10
- pass
@@ -1,64 +0,0 @@
1
- import json
2
-
3
- import arguably
4
- from more_termcolor import bold # type: ignore
5
- from more_termcolor import cyan # type: ignore
6
- from more_termcolor import green # type: ignore
7
- from more_termcolor import red # type: ignore
8
-
9
- from intuned_internal_cli.utils.code_tree import convert_project_to_code_tree
10
-
11
- from ...utils.ai_source_project import AiSourceInfo
12
- from ...utils.ai_source_project import deploy_ai_source
13
-
14
-
15
- @arguably.command # type: ignore
16
- def ai_source__deploy(
17
- *,
18
- ai_source_info_str: str,
19
- ai_source_info_path: str,
20
- yes_to_all: bool = False,
21
- ):
22
- """
23
- Commands to run on AI source projects.
24
-
25
- Args:
26
- ai_source_info_str (str): [--ai-source-info] JSON string containing the AI source project information.
27
- ai_source_info_path (str): Path to the JSON file containing the AI source project information. Defaults to <current directory>/ai_source.json.
28
- yes_to_all (bool): [-y/--yes] Skip confirmation prompts.
29
- """
30
-
31
- if ai_source_info_str and ai_source_info_path:
32
- raise ValueError("Only one of ai_source_info or ai_source_info_path should be provided.")
33
-
34
- if not (ai_source_info_str or ai_source_info_path):
35
- ai_source_info_path = "ai_source.json"
36
-
37
- try:
38
- if ai_source_info_str:
39
- ai_source_info_json = json.loads(ai_source_info_str)
40
- else:
41
- with open(ai_source_info_path) as f:
42
- ai_source_info_json = json.load(f)
43
- ai_source_info = AiSourceInfo(**ai_source_info_json)
44
- except json.JSONDecodeError as e:
45
- raise ValueError(f"Invalid JSON in ai_source_info: {e}") from e
46
- except FileNotFoundError as e:
47
- raise ValueError("AI source info file not found") from e
48
- except OSError as e:
49
- raise ValueError("Error reading AI source info file") from e
50
- except TypeError as e:
51
- raise ValueError("AI source info is invalid:", str(e)) from e
52
-
53
- wait_for_confirm = not yes_to_all
54
-
55
- code_tree = convert_project_to_code_tree(".", wait_for_confirm=wait_for_confirm)
56
-
57
- success = deploy_ai_source(code_tree, ai_source_info)
58
-
59
- if success:
60
- print(
61
- f"🚀 AI source deployment triggered for {bold(green(ai_source_info.id))} ({bold(green(ai_source_info.version_id))}). Check progress at {cyan(f"{ai_source_info.environment_url}/__internal-ai-sources/{ai_source_info.id}?version_id={ai_source_info.version_id}")}"
62
- )
63
- else:
64
- print(red(bold("Deployment failed")))