lightning-sdk 2025.8.6rc2__py3-none-any.whl → 2025.8.8__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.
Files changed (24) hide show
  1. lightning_sdk/__init__.py +1 -1
  2. lightning_sdk/cli/clusters_menu.py +9 -6
  3. lightning_sdk/cli/deploy/serve.py +17 -6
  4. lightning_sdk/cli/download.py +2 -2
  5. lightning_sdk/cli/list.py +2 -3
  6. lightning_sdk/lightning_cloud/openapi/__init__.py +3 -0
  7. lightning_sdk/lightning_cloud/openapi/api/assistants_service_api.py +110 -1
  8. lightning_sdk/lightning_cloud/openapi/api/schedules_service_api.py +347 -0
  9. lightning_sdk/lightning_cloud/openapi/configuration.py +3 -19
  10. lightning_sdk/lightning_cloud/openapi/models/__init__.py +3 -0
  11. lightning_sdk/lightning_cloud/openapi/models/cluster_id_metrics_body.py +27 -1
  12. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_metrics.py +877 -0
  13. lightning_sdk/lightning_cloud/openapi/models/v1_list_schedule_runs_response.py +123 -0
  14. lightning_sdk/lightning_cloud/openapi/models/v1_node_metrics.py +53 -1
  15. lightning_sdk/lightning_cloud/openapi/models/v1_schedule_run.py +357 -0
  16. lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +27 -1
  17. lightning_sdk/llm/llm.py +15 -10
  18. lightning_sdk/llm/public_assistants.py +40 -7
  19. {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.8.8.dist-info}/METADATA +1 -1
  20. {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.8.8.dist-info}/RECORD +24 -21
  21. {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.8.8.dist-info}/LICENSE +0 -0
  22. {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.8.8.dist-info}/WHEEL +0 -0
  23. {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.8.8.dist-info}/entry_points.txt +0 -0
  24. {lightning_sdk-2025.8.6rc2.dist-info → lightning_sdk-2025.8.8.dist-info}/top_level.txt +0 -0
lightning_sdk/__init__.py CHANGED
@@ -32,6 +32,6 @@ __all__ = [
32
32
  "User",
33
33
  ]
34
34
 
35
- __version__ = "2025.08.06rc2"
35
+ __version__ = "2025.08.08"
36
36
  _check_version_and_prompt_upgrade(__version__)
37
37
  _set_tqdm_envvars_noninteractive()
@@ -1,12 +1,12 @@
1
1
  import sys
2
- from typing import List
2
+ from typing import List, Optional
3
3
 
4
4
  from rich.console import Console
5
5
  from simple_term_menu import TerminalMenu
6
6
 
7
7
  from lightning_sdk import Teamspace
8
8
  from lightning_sdk.api.cloud_account_api import CloudAccountApi
9
- from lightning_sdk.lightning_cloud.openapi import Externalv1Cluster, V1ProjectClusterBinding
9
+ from lightning_sdk.lightning_cloud.openapi import V1ClusterType, V1ProjectClusterBinding
10
10
 
11
11
 
12
12
  class _ClustersMenu:
@@ -22,18 +22,21 @@ class _ClustersMenu:
22
22
 
23
23
  return TerminalMenu(cluster_ids, title=title, clear_menu_on_exit=True)
24
24
 
25
- def _resolve_cluster(self, teamspace: Teamspace) -> Externalv1Cluster:
25
+ def _resolve_cluster(self, teamspace: Teamspace) -> Optional[str]:
26
26
  selected_cluster_id = None
27
27
  console = Console()
28
28
  try:
29
- selected_cluster_id = self._get_cluster_from_interactive_menu(
29
+ selected_cluster_id = teamspace.default_cloud_account or self._get_cluster_from_interactive_menu(
30
30
  possible_clusters=teamspace.cloud_account_objs
31
31
  )
32
+
32
33
  cloud_account_api = CloudAccountApi()
33
34
 
34
- return cloud_account_api.get_cloud_account(
35
- cluster_id=selected_cluster_id, org_id=teamspace.owner.id, project_id=teamspace.id
35
+ resolved_cluster_obj = cloud_account_api.get_cloud_account(
36
+ cloud_account_id=selected_cluster_id, org_id=teamspace.owner.id, teamspace_id=teamspace.id
36
37
  )
38
+
39
+ return None if resolved_cluster_obj.spec.cluster_type == V1ClusterType.GLOBAL else resolved_cluster_obj.id
37
40
  except KeyboardInterrupt:
38
41
  console.print("Operation cancelled by user")
39
42
  sys.exit(0)
@@ -15,6 +15,7 @@ from rich.prompt import Confirm
15
15
  from lightning_sdk import Machine, Teamspace
16
16
  from lightning_sdk.api.lit_container_api import LitContainerApi
17
17
  from lightning_sdk.api.utils import _get_registry_url
18
+ from lightning_sdk.cli.clusters_menu import _ClustersMenu
18
19
  from lightning_sdk.cli.deploy._auth import (
19
20
  _AuthMode,
20
21
  _Onboarding,
@@ -377,18 +378,24 @@ def _handle_cloud(
377
378
  else:
378
379
  resolved_teamspace = select_teamspace(teamspace, org, user)
379
380
 
381
+ lightning_containers_cloud_account = cloud_account
382
+ if not cloud_account:
383
+ clusters_menu = _ClustersMenu()
384
+ lightning_containers_cloud_account = clusters_menu._resolve_cluster(resolved_teamspace)
385
+ cloud_account = resolved_teamspace.default_cloud_account
386
+
380
387
  # list containers to create the project if it doesn't exist
381
388
  lit_cr = LitContainerApi()
382
- lit_cr.list_containers(resolved_teamspace.id, cloud_account=cloud_account)
389
+ lit_cr.list_containers(resolved_teamspace.id, cloud_account=lightning_containers_cloud_account)
383
390
 
384
391
  registry_url = _get_registry_url()
385
392
  container_basename = repository.split("/")[-1]
386
393
  image = (
387
- f"{registry_url}/lit-container{f'-{cloud_account}' if cloud_account is not None else ''}/"
388
- f"{resolved_teamspace.owner.name}/{resolved_teamspace.name}/{container_basename}"
394
+ f"{registry_url}/lit-container"
395
+ + (f"-{lightning_containers_cloud_account}" if lightning_containers_cloud_account is not None else "")
396
+ + f"/{resolved_teamspace.owner.name}/{resolved_teamspace.name}/{container_basename}"
389
397
  )
390
398
 
391
- cloud_account = cloud_account or resolved_teamspace.default_cloud_account
392
399
  if from_onboarding:
393
400
  thread = Thread(
394
401
  target=ls_deployer.run_on_cloud,
@@ -411,13 +418,17 @@ def _handle_cloud(
411
418
  )
412
419
  thread.start()
413
420
  console.print("🚀 Deployment started")
414
- if not _upload_container(console, ls_deployer, repository, tag, resolved_teamspace, lit_cr, cloud_account):
421
+ if not _upload_container(
422
+ console, ls_deployer, repository, tag, resolved_teamspace, lit_cr, lightning_containers_cloud_account
423
+ ):
415
424
  thread.join()
416
425
  return
417
426
  thread.join()
418
427
  return
419
428
 
420
- if not _upload_container(console, ls_deployer, repository, tag, resolved_teamspace, lit_cr, cloud_account):
429
+ if not _upload_container(
430
+ console, ls_deployer, repository, tag, resolved_teamspace, lit_cr, lightning_containers_cloud_account
431
+ ):
421
432
  return
422
433
 
423
434
  deployment_status = ls_deployer.run_on_cloud(
@@ -136,7 +136,7 @@ def folder(
136
136
  "--studio",
137
137
  default=None,
138
138
  help=(
139
- "The name of the studio to upload to. "
139
+ "The name of the studio to download from. "
140
140
  "Will show a menu with user's owned studios for selection if not specified. "
141
141
  "If provided, should be in the form of <TEAMSPACE-NAME>/<STUDIO-NAME> where the names are case-sensitive. "
142
142
  "The teamspace and studio names can be regular expressions to match, "
@@ -256,7 +256,7 @@ def _resolve_studio(studio: Optional[str]) -> Studio:
256
256
  # give user friendlier error message
257
257
  except Exception as e:
258
258
  raise StudioCliError(
259
- f"Could not find the given Studio {studio} to upload files to. "
259
+ f"Could not find the given Studio {studio} to download files from. "
260
260
  "Please contact Lightning AI directly to resolve this issue."
261
261
  ) from e
262
262
 
lightning_sdk/cli/list.py CHANGED
@@ -9,7 +9,7 @@ from typing_extensions import Literal
9
9
  from lightning_sdk import Job, Machine, Studio, Teamspace
10
10
  from lightning_sdk.cli.clusters_menu import _ClustersMenu
11
11
  from lightning_sdk.cli.teamspace_menu import _TeamspacesMenu
12
- from lightning_sdk.lightning_cloud.openapi import V1ClusterType, V1MultiMachineJob
12
+ from lightning_sdk.lightning_cloud.openapi import V1MultiMachineJob
13
13
  from lightning_sdk.lit_container import LitContainer
14
14
  from lightning_sdk.utils.resolve import _get_authed_user
15
15
 
@@ -247,8 +247,7 @@ def containers(teamspace: Optional[str] = None, cloud_account: Optional[str] = N
247
247
  resolved_teamspace = menu._resolve_teamspace(teamspace=teamspace)
248
248
 
249
249
  if not cloud_account:
250
- cloud_account_obj = clusters_menu._resolve_cluster(resolved_teamspace)
251
- cloud_account = "" if cloud_account_obj.spec.cluster_type == V1ClusterType.GLOBAL else cloud_account_obj.id
250
+ cloud_account = clusters_menu._resolve_cluster(resolved_teamspace)
252
251
 
253
252
  result = api.list_containers(
254
253
  teamspace=resolved_teamspace.name, org=resolved_teamspace.owner.name, cloud_account=cloud_account
@@ -326,6 +326,7 @@ from lightning_sdk.lightning_cloud.openapi.models.v1_cluster_availability import
326
326
  from lightning_sdk.lightning_cloud.openapi.models.v1_cluster_capacity_reservation import V1ClusterCapacityReservation
327
327
  from lightning_sdk.lightning_cloud.openapi.models.v1_cluster_deletion_options import V1ClusterDeletionOptions
328
328
  from lightning_sdk.lightning_cloud.openapi.models.v1_cluster_encryption_key import V1ClusterEncryptionKey
329
+ from lightning_sdk.lightning_cloud.openapi.models.v1_cluster_metrics import V1ClusterMetrics
329
330
  from lightning_sdk.lightning_cloud.openapi.models.v1_cluster_names import V1ClusterNames
330
331
  from lightning_sdk.lightning_cloud.openapi.models.v1_cluster_proxy import V1ClusterProxy
331
332
  from lightning_sdk.lightning_cloud.openapi.models.v1_cluster_resource_tag import V1ClusterResourceTag
@@ -730,6 +731,7 @@ from lightning_sdk.lightning_cloud.openapi.models.v1_list_published_managed_endp
730
731
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_quests_response import V1ListQuestsResponse
731
732
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_slurm_cluster_users_response import V1ListSLURMClusterUsersResponse
732
733
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_ssh_public_keys_response import V1ListSSHPublicKeysResponse
734
+ from lightning_sdk.lightning_cloud.openapi.models.v1_list_schedule_runs_response import V1ListScheduleRunsResponse
733
735
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_schedules_response import V1ListSchedulesResponse
734
736
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_secrets_response import V1ListSecretsResponse
735
737
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_studio_jobs_response import V1ListStudioJobsResponse
@@ -884,6 +886,7 @@ from lightning_sdk.lightning_cloud.openapi.models.v1_ssh_public_key import V1SSH
884
886
  from lightning_sdk.lightning_cloud.openapi.models.v1_schedule import V1Schedule
885
887
  from lightning_sdk.lightning_cloud.openapi.models.v1_schedule_action_type import V1ScheduleActionType
886
888
  from lightning_sdk.lightning_cloud.openapi.models.v1_schedule_resource_type import V1ScheduleResourceType
889
+ from lightning_sdk.lightning_cloud.openapi.models.v1_schedule_run import V1ScheduleRun
887
890
  from lightning_sdk.lightning_cloud.openapi.models.v1_search_job_logs_response import V1SearchJobLogsResponse
888
891
  from lightning_sdk.lightning_cloud.openapi.models.v1_search_user import V1SearchUser
889
892
  from lightning_sdk.lightning_cloud.openapi.models.v1_search_users_response import V1SearchUsersResponse
@@ -965,6 +965,7 @@ class AssistantsServiceApi(object):
965
965
  :param str user_name:
966
966
  :param str org_name:
967
967
  :param str model_provider:
968
+ :param str model_display_name:
968
969
  :return: V1Assistant
969
970
  If the method is called asynchronously,
970
971
  returns the request thread.
@@ -989,12 +990,13 @@ class AssistantsServiceApi(object):
989
990
  :param str user_name:
990
991
  :param str org_name:
991
992
  :param str model_provider:
993
+ :param str model_display_name:
992
994
  :return: V1Assistant
993
995
  If the method is called asynchronously,
994
996
  returns the request thread.
995
997
  """
996
998
 
997
- all_params = ['model_name', 'user_name', 'org_name', 'model_provider'] # noqa: E501
999
+ all_params = ['model_name', 'user_name', 'org_name', 'model_provider', 'model_display_name'] # noqa: E501
998
1000
  all_params.append('async_req')
999
1001
  all_params.append('_return_http_data_only')
1000
1002
  all_params.append('_preload_content')
@@ -1027,6 +1029,8 @@ class AssistantsServiceApi(object):
1027
1029
  query_params.append(('orgName', params['org_name'])) # noqa: E501
1028
1030
  if 'model_provider' in params:
1029
1031
  query_params.append(('modelProvider', params['model_provider'])) # noqa: E501
1032
+ if 'model_display_name' in params:
1033
+ query_params.append(('modelDisplayName', params['model_display_name'])) # noqa: E501
1030
1034
 
1031
1035
  header_params = {}
1032
1036
 
@@ -1057,6 +1061,111 @@ class AssistantsServiceApi(object):
1057
1061
  _request_timeout=params.get('_request_timeout'),
1058
1062
  collection_formats=collection_formats)
1059
1063
 
1064
+ def assistants_service_get_managed_model_assistant2(self, **kwargs) -> 'V1Assistant': # noqa: E501
1065
+ """Each managed model has a dedicated assistant for direct interaction. By using user_name, org_name, or model_provider as query parameters, this endpoint retrieves that specific assistant only—excluding any other assistants that may use the same model. # noqa: E501
1066
+
1067
+ This method makes a synchronous HTTP request by default. To make an
1068
+ asynchronous HTTP request, please pass async_req=True
1069
+ >>> thread = api.assistants_service_get_managed_model_assistant2(async_req=True)
1070
+ >>> result = thread.get()
1071
+
1072
+ :param async_req bool
1073
+ :param str user_name:
1074
+ :param str org_name:
1075
+ :param str model_provider:
1076
+ :param str model_name:
1077
+ :param str model_display_name:
1078
+ :return: V1Assistant
1079
+ If the method is called asynchronously,
1080
+ returns the request thread.
1081
+ """
1082
+ kwargs['_return_http_data_only'] = True
1083
+ if kwargs.get('async_req'):
1084
+ return self.assistants_service_get_managed_model_assistant2_with_http_info(**kwargs) # noqa: E501
1085
+ else:
1086
+ (data) = self.assistants_service_get_managed_model_assistant2_with_http_info(**kwargs) # noqa: E501
1087
+ return data
1088
+
1089
+ def assistants_service_get_managed_model_assistant2_with_http_info(self, **kwargs) -> 'V1Assistant': # noqa: E501
1090
+ """Each managed model has a dedicated assistant for direct interaction. By using user_name, org_name, or model_provider as query parameters, this endpoint retrieves that specific assistant only—excluding any other assistants that may use the same model. # noqa: E501
1091
+
1092
+ This method makes a synchronous HTTP request by default. To make an
1093
+ asynchronous HTTP request, please pass async_req=True
1094
+ >>> thread = api.assistants_service_get_managed_model_assistant2_with_http_info(async_req=True)
1095
+ >>> result = thread.get()
1096
+
1097
+ :param async_req bool
1098
+ :param str user_name:
1099
+ :param str org_name:
1100
+ :param str model_provider:
1101
+ :param str model_name:
1102
+ :param str model_display_name:
1103
+ :return: V1Assistant
1104
+ If the method is called asynchronously,
1105
+ returns the request thread.
1106
+ """
1107
+
1108
+ all_params = ['user_name', 'org_name', 'model_provider', 'model_name', 'model_display_name'] # noqa: E501
1109
+ all_params.append('async_req')
1110
+ all_params.append('_return_http_data_only')
1111
+ all_params.append('_preload_content')
1112
+ all_params.append('_request_timeout')
1113
+
1114
+ params = locals()
1115
+ for key, val in six.iteritems(params['kwargs']):
1116
+ if key not in all_params:
1117
+ raise TypeError(
1118
+ "Got an unexpected keyword argument '%s'"
1119
+ " to method assistants_service_get_managed_model_assistant2" % key
1120
+ )
1121
+ params[key] = val
1122
+ del params['kwargs']
1123
+
1124
+ collection_formats = {}
1125
+
1126
+ path_params = {}
1127
+
1128
+ query_params = []
1129
+ if 'user_name' in params:
1130
+ query_params.append(('userName', params['user_name'])) # noqa: E501
1131
+ if 'org_name' in params:
1132
+ query_params.append(('orgName', params['org_name'])) # noqa: E501
1133
+ if 'model_provider' in params:
1134
+ query_params.append(('modelProvider', params['model_provider'])) # noqa: E501
1135
+ if 'model_name' in params:
1136
+ query_params.append(('modelName', params['model_name'])) # noqa: E501
1137
+ if 'model_display_name' in params:
1138
+ query_params.append(('modelDisplayName', params['model_display_name'])) # noqa: E501
1139
+
1140
+ header_params = {}
1141
+
1142
+ form_params = []
1143
+ local_var_files = {}
1144
+
1145
+ body_params = None
1146
+ # HTTP header `Accept`
1147
+ header_params['Accept'] = self.api_client.select_header_accept(
1148
+ ['application/json']) # noqa: E501
1149
+
1150
+ # Authentication setting
1151
+ auth_settings = [] # noqa: E501
1152
+
1153
+ return self.api_client.call_api(
1154
+ '/v1/agents/managed-model', 'GET',
1155
+ path_params,
1156
+ query_params,
1157
+ header_params,
1158
+ body=body_params,
1159
+ post_params=form_params,
1160
+ files=local_var_files,
1161
+ response_type='V1Assistant', # noqa: E501
1162
+ auth_settings=auth_settings,
1163
+ async_req=params.get('async_req'),
1164
+ _return_http_data_only=params.get('_return_http_data_only'),
1165
+ _preload_content=params.get('_preload_content', True),
1166
+ _request_timeout=params.get('_request_timeout'),
1167
+ collection_formats=collection_formats)
1168
+
1060
1169
  def assistants_service_get_managed_model_by_name(self, project_id: 'str', managed_endpoint_id: 'str', name: 'str', **kwargs) -> 'V1ManagedModel': # noqa: E501
1061
1170
  """assistants_service_get_managed_model_by_name # noqa: E501
1062
1171