lyceum-cli 1.0.13__tar.gz → 1.0.18__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (138) hide show
  1. {lyceum_cli-1.0.13 → lyceum_cli-1.0.18}/PKG-INFO +1 -1
  2. {lyceum_cli-1.0.13 → lyceum_cli-1.0.18}/lyceum/external/compute/execution/python.py +33 -30
  3. lyceum_cli-1.0.18/lyceum/external/compute/inference/__init__.py +2 -0
  4. {lyceum_cli-1.0.13 → lyceum_cli-1.0.18}/lyceum/main.py +0 -8
  5. lyceum_cli-1.0.18/lyceum/shared/__init__.py +0 -0
  6. {lyceum_cli-1.0.13 → lyceum_cli-1.0.18}/lyceum/shared/config.py +7 -8
  7. lyceum_cli-1.0.18/lyceum/shared/display.py +195 -0
  8. {lyceum_cli-1.0.13 → lyceum_cli-1.0.18}/lyceum/shared/streaming.py +57 -7
  9. {lyceum_cli-1.0.13 → lyceum_cli-1.0.18}/lyceum_cli.egg-info/PKG-INFO +1 -1
  10. lyceum_cli-1.0.18/lyceum_cli.egg-info/SOURCES.txt +27 -0
  11. lyceum_cli-1.0.18/lyceum_cloud_execution_api_client/__init__.py +0 -0
  12. lyceum_cli-1.0.18/lyceum_cloud_execution_api_client/api/__init__.py +0 -0
  13. {lyceum_cli-1.0.13 → lyceum_cli-1.0.18}/setup.py +1 -1
  14. lyceum_cli-1.0.13/lyceum/__init__.py +0 -3
  15. lyceum_cli-1.0.13/lyceum/external/auth/api_keys.py +0 -58
  16. lyceum_cli-1.0.13/lyceum/external/compute/execution/docker.py +0 -134
  17. lyceum_cli-1.0.13/lyceum/external/compute/execution/workloads.py +0 -129
  18. lyceum_cli-1.0.13/lyceum/external/compute/inference/__init__.py +0 -5
  19. lyceum_cli-1.0.13/lyceum/external/general/resources.py +0 -51
  20. lyceum_cli-1.0.13/lyceum/shared/display.py +0 -32
  21. lyceum_cli-1.0.13/lyceum_cli.egg-info/SOURCES.txt +0 -130
  22. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/__init__.py +0 -8
  23. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/__init__.py +0 -1
  24. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/api_keys/__init__.py +0 -1
  25. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/api_keys/create_api_key_api_v1_api_keys_post.py +0 -172
  26. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/api_keys/list_api_keys_api_v1_api_keys_get.py +0 -139
  27. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/api_keys/revoke_api_key_api_v1_api_keys_api_key_id_delete.py +0 -161
  28. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/api_keys/toggle_api_key_api_v1_api_keys_api_key_id_toggle_patch.py +0 -161
  29. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/authentication/__init__.py +0 -1
  30. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/authentication/get_current_user_info_api_v1_auth_me_get.py +0 -83
  31. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/authentication/login_api_v2_external_auth_login_post.py +0 -176
  32. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/authentication/validate_token_api_v1_auth_validate_post.py +0 -85
  33. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/billing_credits/__init__.py +0 -1
  34. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/billing_credits/create_checkout_session_api_v2_external_billing_checkout_post.py +0 -172
  35. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/billing_credits/get_execution_history_api_v2_external_billing_history_get.py +0 -181
  36. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/billing_credits/get_user_credits_api_v2_external_billing_credits_get.py +0 -134
  37. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/billing_credits/get_user_credits_details_api_v2_external_billing_credits_details_get.py +0 -130
  38. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/cloud_storage/__init__.py +0 -1
  39. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/cloud_storage/connect_cloud_storage_api_v1_api_cloud_storage_connect_post.py +0 -170
  40. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/cloud_storage/disconnect_cloud_storage_api_v1_api_cloud_storage_provider_delete.py +0 -161
  41. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/cloud_storage/get_cloud_storage_credentials_api_v1_api_cloud_storage_credentials_provider_get.py +0 -161
  42. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/cloud_storage/get_cloud_storage_status_api_v1_api_cloud_storage_status_get.py +0 -134
  43. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/code_execution/__init__.py +0 -1
  44. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/code_execution/run_code_api_v1_execution_run_post.py +0 -172
  45. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/code_execution/start_execution_api_v1_execution_start_post.py +0 -188
  46. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/code_execution/start_execution_api_v2_external_compute_execution_run_post.py +0 -206
  47. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/code_execution/start_prebuilt_api_v1_execution_start_prebuilt_post.py +0 -164
  48. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/code_execution/stream_execution_api_v1_execution_stream_execution_id_get.py +0 -161
  49. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/default/__init__.py +0 -1
  50. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/default/create_checkout_session_api_v1_create_checkout_session_post.py +0 -162
  51. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/default/delete_user_api_v1_delete_user_post.py +0 -162
  52. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/default/root_get.py +0 -79
  53. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/default/stripe_webhook_api_v1_webhook_post.py +0 -79
  54. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/default/upload_file_api_v1_upload_file_post.py +0 -162
  55. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/docker_execution/__init__.py +0 -1
  56. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/docker_execution/start_docker_execution_api_v2_external_compute_execution_docker_post.py +0 -172
  57. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/docker_execution/stream_docker_execution_api_v2_external_compute_execution_stream_execution_id_get.py +0 -161
  58. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/execution_history/__init__.py +0 -1
  59. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/execution_history/get_execution_detail_api_v1_history_execution_id_get.py +0 -161
  60. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/execution_history/get_execution_history_api_v1_history_get.py +0 -184
  61. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/machine_types/__init__.py +0 -1
  62. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/machine_types/get_machine_types_api_v2_external_compute_machine_types_get.py +0 -134
  63. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/storage_credentials/__init__.py +0 -1
  64. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/storage_credentials/get_storage_credentials_api_v2_external_storage_credentials_post.py +0 -134
  65. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/storage_files/__init__.py +0 -1
  66. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/storage_files/delete_file_api_v2_external_storage_delete_file_key_delete.py +0 -161
  67. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/storage_files/delete_folder_api_v2_external_storage_delete_folder_folder_prefix_delete.py +0 -161
  68. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/storage_files/download_file_api_v2_external_storage_download_file_key_get.py +0 -161
  69. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/storage_files/list_files_api_v2_external_storage_list_files_get.py +0 -191
  70. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/storage_files/upload_bulk_files_api_v2_external_storage_upload_bulk_post.py +0 -172
  71. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/storage_files/upload_file_api_v2_external_storage_upload_post.py +0 -195
  72. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/workload_management/__init__.py +0 -1
  73. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/workload_management/abort_execution_api_v1_workloads_abort_execution_id_post.py +0 -163
  74. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/api/workload_management/list_non_complete_executions_api_v1_workloads_list_get.py +0 -139
  75. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/client.py +0 -268
  76. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/errors.py +0 -16
  77. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/abort_response.py +0 -76
  78. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/api_key_create.py +0 -93
  79. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/api_key_create_response.py +0 -119
  80. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/api_key_response.py +0 -143
  81. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/body_upload_bulk_files_api_v2_external_storage_upload_bulk_post.py +0 -109
  82. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/body_upload_file_api_v1_upload_file_post.py +0 -78
  83. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/body_upload_file_api_v2_external_storage_upload_post.py +0 -73
  84. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/bulk_upload_response.py +0 -105
  85. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/bulk_upload_result.py +0 -105
  86. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/checkout_session_request.py +0 -101
  87. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/checkout_session_response.py +0 -67
  88. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/cloud_storage_status.py +0 -85
  89. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/cloud_storage_status_aws_s3.py +0 -44
  90. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/cloud_storage_status_azure_blob.py +0 -44
  91. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/cloud_storage_status_gcp_storage.py +0 -44
  92. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/code_execution.py +0 -221
  93. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/connect_request.py +0 -73
  94. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/connect_request_credentials.py +0 -44
  95. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/create_checkout_session_request.py +0 -79
  96. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/credits_balance.py +0 -83
  97. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/delete_user_request.py +0 -59
  98. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/docker_execution.py +0 -228
  99. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/docker_execution_docker_env_type_0.py +0 -44
  100. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/docker_execution_response.py +0 -83
  101. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/execution_response.py +0 -211
  102. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/execution_response_result_files_type_0.py +0 -63
  103. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/execution_response_result_files_type_0_additional_property.py +0 -44
  104. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/execution_summary.py +0 -114
  105. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/file_info.py +0 -85
  106. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/http_validation_error.py +0 -75
  107. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/login_request.py +0 -67
  108. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/login_response.py +0 -83
  109. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/machine_type.py +0 -67
  110. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/machine_types_response.py +0 -81
  111. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/start_execution_api_v1_execution_start_post_response_start_execution_api_v1_execution_start_post.py +0 -44
  112. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/start_execution_api_v2_external_compute_execution_run_post_response_start_execution_api_v2_external_compute_execution_run_post.py +0 -47
  113. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/start_prebuilt_execution_aws_credentials.py +0 -59
  114. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/start_prebuilt_execution_request.py +0 -209
  115. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/start_prebuilt_execution_request_docker_run_env_type_0.py +0 -44
  116. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/start_prebuilt_execution_response.py +0 -59
  117. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/storage_credentials.py +0 -113
  118. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/upload_response.py +0 -83
  119. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/user_credits.py +0 -131
  120. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/models/validation_error.py +0 -88
  121. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/py.typed +0 -1
  122. lyceum_cli-1.0.13/lyceum_cloud_execution_api_client/types.py +0 -54
  123. {lyceum_cli-1.0.13/lyceum/external → lyceum_cli-1.0.18/lyceum}/__init__.py +0 -0
  124. {lyceum_cli-1.0.13/lyceum/external/auth → lyceum_cli-1.0.18/lyceum/external}/__init__.py +0 -0
  125. {lyceum_cli-1.0.13/lyceum/external/compute → lyceum_cli-1.0.18/lyceum/external/auth}/__init__.py +0 -0
  126. {lyceum_cli-1.0.13 → lyceum_cli-1.0.18}/lyceum/external/auth/login.py +0 -0
  127. {lyceum_cli-1.0.13/lyceum/external/compute/execution → lyceum_cli-1.0.18/lyceum/external/compute}/__init__.py +0 -0
  128. {lyceum_cli-1.0.13/lyceum/external/general → lyceum_cli-1.0.18/lyceum/external/compute/execution}/__init__.py +0 -0
  129. {lyceum_cli-1.0.13 → lyceum_cli-1.0.18}/lyceum/external/compute/inference/batch.py +0 -0
  130. {lyceum_cli-1.0.13 → lyceum_cli-1.0.18}/lyceum/external/compute/inference/chat.py +0 -0
  131. {lyceum_cli-1.0.13 → lyceum_cli-1.0.18}/lyceum/external/compute/inference/models.py +0 -0
  132. {lyceum_cli-1.0.13/lyceum/shared → lyceum_cli-1.0.18/lyceum/external/general}/__init__.py +0 -0
  133. {lyceum_cli-1.0.13 → lyceum_cli-1.0.18}/lyceum_cli.egg-info/dependency_links.txt +0 -0
  134. {lyceum_cli-1.0.13 → lyceum_cli-1.0.18}/lyceum_cli.egg-info/entry_points.txt +0 -0
  135. {lyceum_cli-1.0.13 → lyceum_cli-1.0.18}/lyceum_cli.egg-info/requires.txt +0 -0
  136. {lyceum_cli-1.0.13 → lyceum_cli-1.0.18}/lyceum_cli.egg-info/top_level.txt +0 -0
  137. {lyceum_cli-1.0.13 → lyceum_cli-1.0.18}/lyceum_cloud_execution_api_client/models/__init__.py +0 -0
  138. {lyceum_cli-1.0.13 → lyceum_cli-1.0.18}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lyceum-cli
3
- Version: 1.0.13
3
+ Version: 1.0.18
4
4
  Summary: Command-line interface for Lyceum Cloud Execution API
5
5
  Home-page: https://lyceum.technology
6
6
  Author: Lyceum Team
@@ -6,16 +6,13 @@ from pathlib import Path
6
6
  from typing import Optional
7
7
  import typer
8
8
  from rich.console import Console
9
+ import httpx
9
10
 
10
11
  from ....shared.config import config
11
12
  from ....shared.streaming import stream_execution_output
12
13
 
13
14
  console = Console()
14
15
 
15
- # Import generated client modules
16
- from lyceum_cloud_execution_api_client.api.code_execution import start_execution_api_v2_external_compute_execution_run_post
17
- from lyceum_cloud_execution_api_client.models import CodeExecution
18
-
19
16
  python_app = typer.Typer(name="python", help="Python execution commands")
20
17
 
21
18
 
@@ -29,8 +26,6 @@ def run_python(
29
26
  imports: Optional[list[str]] = typer.Option(None, "--import", help="Pre-import modules (can be used multiple times)"),
30
27
  ):
31
28
  """Execute Python code or file on Lyceum Cloud"""
32
- client = config.get_client()
33
-
34
29
  try:
35
30
  # Check if it's a file path
36
31
  code_to_execute = code_or_file
@@ -41,7 +36,7 @@ def run_python(
41
36
  # Use filename as execution name if not provided
42
37
  if not file_name:
43
38
  file_name = Path(code_or_file).name
44
-
39
+
45
40
  # Handle requirements
46
41
  requirements_content = None
47
42
  if requirements:
@@ -53,39 +48,47 @@ def run_python(
53
48
  else:
54
49
  # Treat as direct pip requirements string
55
50
  requirements_content = requirements
56
-
57
- # Create execution request
58
- execution_request = CodeExecution(
59
- code=code_to_execute,
60
- execution_type=machine_type,
61
- timeout=timeout,
62
- file_name=file_name,
63
- requirements_content=requirements_content,
64
- prior_imports=imports
65
- )
66
-
67
- response = start_execution_api_v2_external_compute_execution_run_post.sync_detailed(
68
- client=client,
69
- body=execution_request
51
+
52
+ # Create execution request payload
53
+ payload = {
54
+ "code": code_to_execute,
55
+ "nbcode": 0,
56
+ "execution_type": machine_type,
57
+ "timeout": timeout,
58
+ }
59
+
60
+ if file_name:
61
+ payload["file_name"] = file_name
62
+ if requirements_content:
63
+ payload["requirements_content"] = requirements_content
64
+ if imports:
65
+ payload["prior_imports"] = imports
66
+
67
+ # Make API request
68
+ response = httpx.post(
69
+ f"{config.base_url}/api/v2/external/execution/streaming/start",
70
+ headers={"Authorization": f"Bearer {config.api_key}"},
71
+ json=payload,
72
+ timeout=30.0
70
73
  )
71
-
74
+
72
75
  if response.status_code != 200:
73
76
  console.print(f"[red]Error: HTTP {response.status_code}[/red]")
74
- if hasattr(response, 'content'):
75
- console.print(f"[red]{response.content}[/red]")
77
+ console.print(f"[red]{response.content.decode()}[/red]")
76
78
  raise typer.Exit(1)
77
-
78
- data = response.parsed
79
+
80
+ data = response.json()
79
81
  execution_id = data['execution_id']
80
-
82
+ streaming_url = data.get('streaming_url')
83
+
81
84
  console.print(f"[green]✅ Execution started![/green]")
82
85
  console.print(f"[dim]Execution ID: {execution_id}[/dim]")
83
-
86
+
84
87
  if 'pythia_decision' in data:
85
88
  console.print(f"[dim]Pythia recommendation: {data['pythia_decision']}[/dim]")
86
-
89
+
87
90
  # Stream the execution output
88
- success = stream_execution_output(execution_id, client)
91
+ success = stream_execution_output(execution_id, streaming_url)
89
92
 
90
93
  if not success:
91
94
  console.print(f"[yellow]💡 You can check the execution later with: lyceum status[/yellow]")
@@ -0,0 +1,2 @@
1
+ # Empty init - import modules directly in main.py to avoid circular imports
2
+ __all__ = []
@@ -9,14 +9,10 @@ from rich.console import Console
9
9
 
10
10
  # Import all command modules
11
11
  from .external.auth.login import auth_app
12
- from .external.auth.api_keys import api_keys_app
13
12
  from .external.compute.execution.python import python_app
14
- from .external.compute.execution.docker import docker_app
15
- from .external.compute.execution.workloads import workloads_app
16
13
  from .external.compute.inference.batch import batch_app
17
14
  from .external.compute.inference.chat import chat_app
18
15
  from .external.compute.inference.models import models_app
19
- from .external.general.resources import resources_app
20
16
 
21
17
  app = typer.Typer(
22
18
  name="lyceum",
@@ -28,14 +24,10 @@ console = Console()
28
24
 
29
25
  # Add all command groups
30
26
  app.add_typer(auth_app, name="auth")
31
- app.add_typer(api_keys_app, name="api-keys")
32
27
  app.add_typer(python_app, name="python")
33
- app.add_typer(docker_app, name="docker")
34
- app.add_typer(workloads_app, name="workloads")
35
28
  app.add_typer(batch_app, name="batch")
36
29
  app.add_typer(chat_app, name="chat")
37
30
  app.add_typer(models_app, name="models")
38
- app.add_typer(resources_app, name="resources")
39
31
 
40
32
  # Legacy aliases for backward compatibility
41
33
 
File without changes
@@ -17,7 +17,8 @@ from supabase import create_client
17
17
  import sys
18
18
  sys.path.insert(0, str(Path(__file__).parent.parent.parent / "lyceum-cloud-execution-api-client"))
19
19
 
20
- from lyceum_cloud_execution_api_client.client import AuthenticatedClient
20
+ # Commented out - using httpx directly instead
21
+ # from lyceum_cloud_execution_api_client.client import AuthenticatedClient
21
22
 
22
23
  console = Console()
23
24
 
@@ -122,23 +123,21 @@ class Config:
122
123
  console.print(f"[yellow]⚠️ Token refresh error: {e}[/yellow]")
123
124
  return False
124
125
 
125
- def get_client(self) -> AuthenticatedClient:
126
+ def get_client(self):
126
127
  """Get authenticated API client with automatic token refresh"""
127
128
  if not self.api_key:
128
129
  console.print("[red]Error: Not authenticated. Run 'lyceum login' first.[/red]")
129
130
  raise typer.Exit(1)
130
-
131
+
131
132
  # Check if token is expired and try to refresh
132
133
  if self.is_token_expired():
133
134
  console.print("[dim]🔄 Token expired, attempting refresh...[/dim]")
134
135
  if not self.refresh_access_token():
135
136
  console.print("[red]❌ Token refresh failed. Please run 'lyceum login' again.[/red]")
136
137
  raise typer.Exit(1)
137
-
138
- return AuthenticatedClient(
139
- base_url=self.base_url,
140
- token=self.api_key
141
- )
138
+
139
+ # Return config instance - commands use httpx directly
140
+ return self
142
141
 
143
142
 
144
143
  # Global config instance
@@ -0,0 +1,195 @@
1
+ """
2
+ Display utilities for CLI output formatting
3
+ """
4
+
5
+ from rich.table import Table
6
+ from datetime import datetime
7
+ from typing import Optional
8
+
9
+
10
+ def create_table(title: str, columns: list[tuple[str, str]]) -> Table:
11
+ """
12
+ Create a Rich table with the given title and columns.
13
+
14
+ Args:
15
+ title: Table title
16
+ columns: List of (column_name, style) tuples
17
+
18
+ Returns:
19
+ Rich Table instance
20
+ """
21
+ table = Table(title=title)
22
+ for col_name, style in columns:
23
+ table.add_column(col_name, style=style)
24
+ return table
25
+
26
+
27
+ def format_timestamp(timestamp: str | int | datetime, relative: bool = False) -> str:
28
+ """
29
+ Format a timestamp for display.
30
+
31
+ Args:
32
+ timestamp: Unix timestamp (int/float), ISO string, or datetime object
33
+ relative: If True, show relative time (e.g., "2 hours ago")
34
+
35
+ Returns:
36
+ Formatted timestamp string
37
+ """
38
+ try:
39
+ # Convert to datetime if needed
40
+ if isinstance(timestamp, (int, float)):
41
+ dt = datetime.fromtimestamp(timestamp)
42
+ elif isinstance(timestamp, str):
43
+ # Try parsing ISO format
44
+ dt = datetime.fromisoformat(timestamp.replace('Z', '+00:00'))
45
+ elif isinstance(timestamp, datetime):
46
+ dt = timestamp
47
+ else:
48
+ return str(timestamp)
49
+
50
+ if relative:
51
+ # Calculate relative time
52
+ now = datetime.now(dt.tzinfo) if dt.tzinfo else datetime.now()
53
+ diff = now - dt
54
+
55
+ seconds = diff.total_seconds()
56
+ if seconds < 60:
57
+ return f"{int(seconds)}s ago"
58
+ elif seconds < 3600:
59
+ return f"{int(seconds / 60)}m ago"
60
+ elif seconds < 86400:
61
+ return f"{int(seconds / 3600)}h ago"
62
+ elif seconds < 604800:
63
+ return f"{int(seconds / 86400)}d ago"
64
+ else:
65
+ return dt.strftime("%Y-%m-%d")
66
+ else:
67
+ # Return absolute time
68
+ return dt.strftime("%Y-%m-%d %H:%M:%S")
69
+
70
+ except Exception:
71
+ return str(timestamp)
72
+
73
+
74
+ def truncate_id(id_str: str, length: int = 8) -> str:
75
+ """
76
+ Truncate an ID string for display.
77
+
78
+ Args:
79
+ id_str: The ID string to truncate
80
+ length: Number of characters to keep from the start
81
+
82
+ Returns:
83
+ Truncated ID string
84
+ """
85
+ if not id_str:
86
+ return ""
87
+
88
+ if len(id_str) <= length:
89
+ return id_str
90
+
91
+ return f"{id_str[:length]}..."
92
+
93
+
94
+ def format_file_size(bytes: int) -> str:
95
+ """
96
+ Format file size in human-readable format.
97
+
98
+ Args:
99
+ bytes: Size in bytes
100
+
101
+ Returns:
102
+ Formatted size string (e.g., "1.5 MB")
103
+ """
104
+ for unit in ['B', 'KB', 'MB', 'GB', 'TB']:
105
+ if bytes < 1024.0:
106
+ return f"{bytes:.1f} {unit}"
107
+ bytes /= 1024.0
108
+ return f"{bytes:.1f} PB"
109
+
110
+
111
+ def format_duration(seconds: float) -> str:
112
+ """
113
+ Format duration in human-readable format.
114
+
115
+ Args:
116
+ seconds: Duration in seconds
117
+
118
+ Returns:
119
+ Formatted duration string (e.g., "2h 15m 30s")
120
+ """
121
+ if seconds < 60:
122
+ return f"{seconds:.1f}s"
123
+
124
+ minutes = int(seconds / 60)
125
+ secs = int(seconds % 60)
126
+
127
+ if minutes < 60:
128
+ return f"{minutes}m {secs}s"
129
+
130
+ hours = int(minutes / 60)
131
+ mins = int(minutes % 60)
132
+
133
+ if hours < 24:
134
+ return f"{hours}h {mins}m"
135
+
136
+ days = int(hours / 24)
137
+ hrs = int(hours % 24)
138
+
139
+ return f"{days}d {hrs}h"
140
+
141
+
142
+ def status_color(status: str) -> str:
143
+ """
144
+ Get color for status display.
145
+
146
+ Args:
147
+ status: Status string
148
+
149
+ Returns:
150
+ Color name for Rich formatting
151
+ """
152
+ status_lower = status.lower()
153
+
154
+ if status_lower in ['completed', 'success', 'running']:
155
+ return 'green'
156
+ elif status_lower in ['failed', 'error', 'failed_user', 'failed_system']:
157
+ return 'red'
158
+ elif status_lower in ['pending', 'queued', 'in_progress', 'validating', 'finalizing']:
159
+ return 'yellow'
160
+ elif status_lower in ['cancelled', 'expired', 'timeout']:
161
+ return 'dim'
162
+ else:
163
+ return 'white'
164
+
165
+
166
+ def status_emoji(status: str) -> str:
167
+ """
168
+ Get emoji for status display.
169
+
170
+ Args:
171
+ status: Status string
172
+
173
+ Returns:
174
+ Emoji character
175
+ """
176
+ status_lower = status.lower()
177
+
178
+ if status_lower in ['completed', 'success']:
179
+ return '✅'
180
+ elif status_lower in ['failed', 'error', 'failed_user', 'failed_system']:
181
+ return '❌'
182
+ elif status_lower in ['running', 'in_progress']:
183
+ return '🔄'
184
+ elif status_lower in ['pending', 'queued']:
185
+ return '⏳'
186
+ elif status_lower in ['validating']:
187
+ return '🔍'
188
+ elif status_lower in ['finalizing']:
189
+ return '📦'
190
+ elif status_lower in ['cancelled']:
191
+ return '🛑'
192
+ elif status_lower in ['expired', 'timeout']:
193
+ return '⏰'
194
+ else:
195
+ return '⚪'
@@ -18,13 +18,18 @@ def strip_ansi_codes(text: str) -> str:
18
18
  return ansi_escape.sub('', text)
19
19
 
20
20
 
21
- def stream_execution_output(execution_id: str, client) -> bool:
21
+ def stream_execution_output(execution_id: str, streaming_url: str = None) -> bool:
22
22
  """Stream execution output in real-time. Returns True if successful, False if failed."""
23
- stream_url = f"{config.base_url}/api/v2/external/compute/execution/stream/{execution_id}"
24
-
23
+ if not streaming_url:
24
+ # Fallback to old endpoint if no streaming URL provided
25
+ stream_url = f"{config.base_url}/api/v2/external/execution/streaming/{execution_id}"
26
+ else:
27
+ stream_url = streaming_url
28
+
25
29
  try:
26
30
  console.print(f"[dim]🔗 Connecting to execution stream...[/dim]")
27
-
31
+ console.print(f"[dim]Stream URL: {stream_url}[/dim]")
32
+
28
33
  with httpx.stream("GET", stream_url, headers={"Authorization": f"Bearer {config.api_key}"}, timeout=600.0) as response:
29
34
  if response.status_code != 200:
30
35
  console.print(f"[red]❌ Stream failed: HTTP {response.status_code}[/red]")
@@ -77,8 +82,53 @@ def stream_execution_output(execution_id: str, client) -> bool:
77
82
  continue
78
83
 
79
84
  console.print(f"\n[yellow]⚠️ Stream ended without completion signal[/yellow]")
80
- return False
81
-
85
+ # Fallback: poll execution status
86
+ return check_execution_status(execution_id)
87
+
82
88
  except Exception as e:
83
89
  console.print(f"\n[red]❌ Streaming error: {e}[/red]")
84
- return False
90
+ # Fallback: poll execution status
91
+ return check_execution_status(execution_id)
92
+
93
+
94
+ def check_execution_status(execution_id: str) -> bool:
95
+ """Check execution status as fallback when streaming fails."""
96
+ import time
97
+
98
+ console.print("[dim]⏳ Checking execution status...[/dim]")
99
+
100
+ for _ in range(30): # Poll for up to 30 seconds
101
+ try:
102
+ response = httpx.get(
103
+ f"{config.base_url}/api/v2/external/execution/streaming/{execution_id}/status",
104
+ headers={"Authorization": f"Bearer {config.api_key}"},
105
+ timeout=10.0
106
+ )
107
+
108
+ if response.status_code == 200:
109
+ data = response.json()
110
+ status = data.get('status', 'unknown')
111
+
112
+ if status == 'completed':
113
+ console.print(f"[green]✅ Execution completed successfully![/green]")
114
+ return True
115
+ elif status in ['failed_user', 'failed_system', 'failed']:
116
+ console.print(f"[red]❌ Execution failed: {status}[/red]")
117
+ errors = data.get('errors')
118
+ if errors:
119
+ console.print(f"[red]Error: {errors}[/red]")
120
+ return False
121
+ elif status in ['timeout', 'cancelled']:
122
+ console.print(f"[yellow]⚠️ Execution {status}[/yellow]")
123
+ return False
124
+ elif status in ['running', 'pending', 'queued']:
125
+ # Still running, continue polling
126
+ time.sleep(1)
127
+ continue
128
+
129
+ except Exception as e:
130
+ console.print(f"[red]Error checking status: {e}[/red]")
131
+ break
132
+
133
+ console.print("[yellow]⚠️ Status check timed out[/yellow]")
134
+ return False
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lyceum-cli
3
- Version: 1.0.13
3
+ Version: 1.0.18
4
4
  Summary: Command-line interface for Lyceum Cloud Execution API
5
5
  Home-page: https://lyceum.technology
6
6
  Author: Lyceum Team
@@ -0,0 +1,27 @@
1
+ setup.py
2
+ lyceum/__init__.py
3
+ lyceum/main.py
4
+ lyceum/external/__init__.py
5
+ lyceum/external/auth/__init__.py
6
+ lyceum/external/auth/login.py
7
+ lyceum/external/compute/__init__.py
8
+ lyceum/external/compute/execution/__init__.py
9
+ lyceum/external/compute/execution/python.py
10
+ lyceum/external/compute/inference/__init__.py
11
+ lyceum/external/compute/inference/batch.py
12
+ lyceum/external/compute/inference/chat.py
13
+ lyceum/external/compute/inference/models.py
14
+ lyceum/external/general/__init__.py
15
+ lyceum/shared/__init__.py
16
+ lyceum/shared/config.py
17
+ lyceum/shared/display.py
18
+ lyceum/shared/streaming.py
19
+ lyceum_cli.egg-info/PKG-INFO
20
+ lyceum_cli.egg-info/SOURCES.txt
21
+ lyceum_cli.egg-info/dependency_links.txt
22
+ lyceum_cli.egg-info/entry_points.txt
23
+ lyceum_cli.egg-info/requires.txt
24
+ lyceum_cli.egg-info/top_level.txt
25
+ lyceum_cloud_execution_api_client/__init__.py
26
+ lyceum_cloud_execution_api_client/api/__init__.py
27
+ lyceum_cloud_execution_api_client/models/__init__.py
@@ -15,7 +15,7 @@ if readme_file.exists():
15
15
 
16
16
  setup(
17
17
  name="lyceum-cli",
18
- version="1.0.13",
18
+ version="1.0.18",
19
19
  description="Command-line interface for Lyceum Cloud Execution API",
20
20
  long_description=long_description,
21
21
  long_description_content_type="text/markdown",
@@ -1,3 +0,0 @@
1
- """
2
- Lyceum CLI - Command-line interface for Lyceum Cloud Execution API
3
- """
@@ -1,58 +0,0 @@
1
- """
2
- API key management commands
3
- """
4
-
5
- import typer
6
- from rich.console import Console
7
-
8
- from ...shared.config import config
9
- from ...shared.display import create_table, format_timestamp, truncate_id
10
-
11
- console = Console()
12
-
13
- # Import generated client modules
14
- from lyceum_cloud_execution_api_client.api.api_keys import list_api_keys_api_v1_api_keys_get
15
-
16
- api_keys_app = typer.Typer(name="api-keys", help="API key management")
17
-
18
-
19
- @api_keys_app.command("list")
20
- def list_api_keys():
21
- """List your API keys"""
22
- client = config.get_client()
23
-
24
- try:
25
- response = list_api_keys_api_v1_api_keys_get.sync_detailed(client=client)
26
-
27
- if response.status_code != 200:
28
- console.print(f"[red]Error: HTTP {response.status_code}[/red]")
29
- raise typer.Exit(1)
30
-
31
- api_keys = response.parsed if response.parsed else []
32
-
33
- if not api_keys:
34
- console.print("[dim]No API keys found[/dim]")
35
- return
36
-
37
- columns = [
38
- {"header": "ID", "style": "cyan", "no_wrap": True, "max_width": 12},
39
- {"header": "Name", "style": "yellow"},
40
- {"header": "Active", "style": "green"},
41
- {"header": "Created", "style": "dim"}
42
- ]
43
-
44
- table = create_table("API Keys", columns)
45
-
46
- for key in api_keys:
47
- table.add_row(
48
- truncate_id(key.id, 8),
49
- key.key_name,
50
- "✅" if key.is_active else "❌",
51
- format_timestamp(getattr(key, 'created_at', None))
52
- )
53
-
54
- console.print(table)
55
-
56
- except Exception as e:
57
- console.print(f"[red]Error: {e}[/red]")
58
- raise typer.Exit(1)