lightning-sdk 2025.8.19.post0__py3-none-any.whl → 2025.8.21__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 (25) hide show
  1. lightning_sdk/__init__.py +1 -1
  2. lightning_sdk/api/llm_api.py +6 -2
  3. lightning_sdk/api/studio_api.py +99 -0
  4. lightning_sdk/cli/legacy/create.py +9 -11
  5. lightning_sdk/cli/legacy/start.py +1 -0
  6. lightning_sdk/cli/legacy/switch.py +1 -0
  7. lightning_sdk/cli/studio/start.py +1 -0
  8. lightning_sdk/cli/studio/switch.py +1 -0
  9. lightning_sdk/lightning_cloud/openapi/__init__.py +1 -0
  10. lightning_sdk/lightning_cloud/openapi/api/billing_service_api.py +85 -0
  11. lightning_sdk/lightning_cloud/openapi/models/__init__.py +1 -0
  12. lightning_sdk/lightning_cloud/openapi/models/assistant_id_conversations_body.py +15 -15
  13. lightning_sdk/lightning_cloud/openapi/models/v1_pod_metrics.py +157 -1
  14. lightning_sdk/lightning_cloud/openapi/models/v1_project_cluster_binding.py +27 -1
  15. lightning_sdk/lightning_cloud/openapi/models/v1_quote_annual_upsell_response.py +201 -0
  16. lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +1 -27
  17. lightning_sdk/llm/llm.py +2 -2
  18. lightning_sdk/studio.py +39 -6
  19. lightning_sdk/utils/progress.py +284 -0
  20. {lightning_sdk-2025.8.19.post0.dist-info → lightning_sdk-2025.8.21.dist-info}/METADATA +1 -1
  21. {lightning_sdk-2025.8.19.post0.dist-info → lightning_sdk-2025.8.21.dist-info}/RECORD +25 -23
  22. {lightning_sdk-2025.8.19.post0.dist-info → lightning_sdk-2025.8.21.dist-info}/LICENSE +0 -0
  23. {lightning_sdk-2025.8.19.post0.dist-info → lightning_sdk-2025.8.21.dist-info}/WHEEL +0 -0
  24. {lightning_sdk-2025.8.19.post0.dist-info → lightning_sdk-2025.8.21.dist-info}/entry_points.txt +0 -0
  25. {lightning_sdk-2025.8.19.post0.dist-info → lightning_sdk-2025.8.21.dist-info}/top_level.txt +0 -0
@@ -48,6 +48,7 @@ class V1ProjectClusterBinding(object):
48
48
  'is_cluster_healthy': 'bool',
49
49
  'project_id': 'str',
50
50
  'sa_key': 'str',
51
+ 'sa_key_created_at': 'datetime',
51
52
  'updated_at': 'datetime'
52
53
  }
53
54
 
@@ -59,10 +60,11 @@ class V1ProjectClusterBinding(object):
59
60
  'is_cluster_healthy': 'isClusterHealthy',
60
61
  'project_id': 'projectId',
61
62
  'sa_key': 'saKey',
63
+ 'sa_key_created_at': 'saKeyCreatedAt',
62
64
  'updated_at': 'updatedAt'
63
65
  }
64
66
 
65
- def __init__(self, cluster_id: 'str' =None, cluster_name: 'str' =None, cluster_region: 'str' =None, created_at: 'datetime' =None, is_cluster_healthy: 'bool' =None, project_id: 'str' =None, sa_key: 'str' =None, updated_at: 'datetime' =None): # noqa: E501
67
+ def __init__(self, cluster_id: 'str' =None, cluster_name: 'str' =None, cluster_region: 'str' =None, created_at: 'datetime' =None, is_cluster_healthy: 'bool' =None, project_id: 'str' =None, sa_key: 'str' =None, sa_key_created_at: 'datetime' =None, updated_at: 'datetime' =None): # noqa: E501
66
68
  """V1ProjectClusterBinding - a model defined in Swagger""" # noqa: E501
67
69
  self._cluster_id = None
68
70
  self._cluster_name = None
@@ -71,6 +73,7 @@ class V1ProjectClusterBinding(object):
71
73
  self._is_cluster_healthy = None
72
74
  self._project_id = None
73
75
  self._sa_key = None
76
+ self._sa_key_created_at = None
74
77
  self._updated_at = None
75
78
  self.discriminator = None
76
79
  if cluster_id is not None:
@@ -87,6 +90,8 @@ class V1ProjectClusterBinding(object):
87
90
  self.project_id = project_id
88
91
  if sa_key is not None:
89
92
  self.sa_key = sa_key
93
+ if sa_key_created_at is not None:
94
+ self.sa_key_created_at = sa_key_created_at
90
95
  if updated_at is not None:
91
96
  self.updated_at = updated_at
92
97
 
@@ -237,6 +242,27 @@ class V1ProjectClusterBinding(object):
237
242
 
238
243
  self._sa_key = sa_key
239
244
 
245
+ @property
246
+ def sa_key_created_at(self) -> 'datetime':
247
+ """Gets the sa_key_created_at of this V1ProjectClusterBinding. # noqa: E501
248
+
249
+
250
+ :return: The sa_key_created_at of this V1ProjectClusterBinding. # noqa: E501
251
+ :rtype: datetime
252
+ """
253
+ return self._sa_key_created_at
254
+
255
+ @sa_key_created_at.setter
256
+ def sa_key_created_at(self, sa_key_created_at: 'datetime'):
257
+ """Sets the sa_key_created_at of this V1ProjectClusterBinding.
258
+
259
+
260
+ :param sa_key_created_at: The sa_key_created_at of this V1ProjectClusterBinding. # noqa: E501
261
+ :type: datetime
262
+ """
263
+
264
+ self._sa_key_created_at = sa_key_created_at
265
+
240
266
  @property
241
267
  def updated_at(self) -> 'datetime':
242
268
  """Gets the updated_at of this V1ProjectClusterBinding. # noqa: E501
@@ -0,0 +1,201 @@
1
+ # coding: utf-8
2
+
3
+ """
4
+ external/v1/auth_service.proto
5
+
6
+ No description provided (generated by Swagger Codegen https://github.com/swagger-api/swagger-codegen) # noqa: E501
7
+
8
+ OpenAPI spec version: version not set
9
+
10
+ Generated by: https://github.com/swagger-api/swagger-codegen.git
11
+
12
+ NOTE
13
+ ----
14
+ standard swagger-codegen-cli for this python client has been modified
15
+ by custom templates. The purpose of these templates is to include
16
+ typing information in the API and Model code. Please refer to the
17
+ main grid repository for more info
18
+ """
19
+
20
+ import pprint
21
+ import re # noqa: F401
22
+
23
+ from typing import TYPE_CHECKING
24
+
25
+ import six
26
+
27
+ if TYPE_CHECKING:
28
+ from datetime import datetime
29
+ from lightning_sdk.lightning_cloud.openapi.models import *
30
+
31
+ class V1QuoteAnnualUpsellResponse(object):
32
+ """NOTE: This class is auto generated by the swagger code generator program.
33
+
34
+ Do not edit the class manually.
35
+ """
36
+ """
37
+ Attributes:
38
+ swagger_types (dict): The key is attribute name
39
+ and the value is attribute type.
40
+ attribute_map (dict): The key is attribute name
41
+ and the value is json key in definition.
42
+ """
43
+ swagger_types = {
44
+ 'academic': 'bool',
45
+ 'additional_months': 'int',
46
+ 'annual_amount': 'int',
47
+ 'discounted_amount': 'int'
48
+ }
49
+
50
+ attribute_map = {
51
+ 'academic': 'academic',
52
+ 'additional_months': 'additionalMonths',
53
+ 'annual_amount': 'annualAmount',
54
+ 'discounted_amount': 'discountedAmount'
55
+ }
56
+
57
+ def __init__(self, academic: 'bool' =None, additional_months: 'int' =None, annual_amount: 'int' =None, discounted_amount: 'int' =None): # noqa: E501
58
+ """V1QuoteAnnualUpsellResponse - a model defined in Swagger""" # noqa: E501
59
+ self._academic = None
60
+ self._additional_months = None
61
+ self._annual_amount = None
62
+ self._discounted_amount = None
63
+ self.discriminator = None
64
+ if academic is not None:
65
+ self.academic = academic
66
+ if additional_months is not None:
67
+ self.additional_months = additional_months
68
+ if annual_amount is not None:
69
+ self.annual_amount = annual_amount
70
+ if discounted_amount is not None:
71
+ self.discounted_amount = discounted_amount
72
+
73
+ @property
74
+ def academic(self) -> 'bool':
75
+ """Gets the academic of this V1QuoteAnnualUpsellResponse. # noqa: E501
76
+
77
+
78
+ :return: The academic of this V1QuoteAnnualUpsellResponse. # noqa: E501
79
+ :rtype: bool
80
+ """
81
+ return self._academic
82
+
83
+ @academic.setter
84
+ def academic(self, academic: 'bool'):
85
+ """Sets the academic of this V1QuoteAnnualUpsellResponse.
86
+
87
+
88
+ :param academic: The academic of this V1QuoteAnnualUpsellResponse. # noqa: E501
89
+ :type: bool
90
+ """
91
+
92
+ self._academic = academic
93
+
94
+ @property
95
+ def additional_months(self) -> 'int':
96
+ """Gets the additional_months of this V1QuoteAnnualUpsellResponse. # noqa: E501
97
+
98
+
99
+ :return: The additional_months of this V1QuoteAnnualUpsellResponse. # noqa: E501
100
+ :rtype: int
101
+ """
102
+ return self._additional_months
103
+
104
+ @additional_months.setter
105
+ def additional_months(self, additional_months: 'int'):
106
+ """Sets the additional_months of this V1QuoteAnnualUpsellResponse.
107
+
108
+
109
+ :param additional_months: The additional_months of this V1QuoteAnnualUpsellResponse. # noqa: E501
110
+ :type: int
111
+ """
112
+
113
+ self._additional_months = additional_months
114
+
115
+ @property
116
+ def annual_amount(self) -> 'int':
117
+ """Gets the annual_amount of this V1QuoteAnnualUpsellResponse. # noqa: E501
118
+
119
+
120
+ :return: The annual_amount of this V1QuoteAnnualUpsellResponse. # noqa: E501
121
+ :rtype: int
122
+ """
123
+ return self._annual_amount
124
+
125
+ @annual_amount.setter
126
+ def annual_amount(self, annual_amount: 'int'):
127
+ """Sets the annual_amount of this V1QuoteAnnualUpsellResponse.
128
+
129
+
130
+ :param annual_amount: The annual_amount of this V1QuoteAnnualUpsellResponse. # noqa: E501
131
+ :type: int
132
+ """
133
+
134
+ self._annual_amount = annual_amount
135
+
136
+ @property
137
+ def discounted_amount(self) -> 'int':
138
+ """Gets the discounted_amount of this V1QuoteAnnualUpsellResponse. # noqa: E501
139
+
140
+
141
+ :return: The discounted_amount of this V1QuoteAnnualUpsellResponse. # noqa: E501
142
+ :rtype: int
143
+ """
144
+ return self._discounted_amount
145
+
146
+ @discounted_amount.setter
147
+ def discounted_amount(self, discounted_amount: 'int'):
148
+ """Sets the discounted_amount of this V1QuoteAnnualUpsellResponse.
149
+
150
+
151
+ :param discounted_amount: The discounted_amount of this V1QuoteAnnualUpsellResponse. # noqa: E501
152
+ :type: int
153
+ """
154
+
155
+ self._discounted_amount = discounted_amount
156
+
157
+ def to_dict(self) -> dict:
158
+ """Returns the model properties as a dict"""
159
+ result = {}
160
+
161
+ for attr, _ in six.iteritems(self.swagger_types):
162
+ value = getattr(self, attr)
163
+ if isinstance(value, list):
164
+ result[attr] = list(map(
165
+ lambda x: x.to_dict() if hasattr(x, "to_dict") else x,
166
+ value
167
+ ))
168
+ elif hasattr(value, "to_dict"):
169
+ result[attr] = value.to_dict()
170
+ elif isinstance(value, dict):
171
+ result[attr] = dict(map(
172
+ lambda item: (item[0], item[1].to_dict())
173
+ if hasattr(item[1], "to_dict") else item,
174
+ value.items()
175
+ ))
176
+ else:
177
+ result[attr] = value
178
+ if issubclass(V1QuoteAnnualUpsellResponse, dict):
179
+ for key, value in self.items():
180
+ result[key] = value
181
+
182
+ return result
183
+
184
+ def to_str(self) -> str:
185
+ """Returns the string representation of the model"""
186
+ return pprint.pformat(self.to_dict())
187
+
188
+ def __repr__(self) -> str:
189
+ """For `print` and `pprint`"""
190
+ return self.to_str()
191
+
192
+ def __eq__(self, other: 'V1QuoteAnnualUpsellResponse') -> bool:
193
+ """Returns true if both objects are equal"""
194
+ if not isinstance(other, V1QuoteAnnualUpsellResponse):
195
+ return False
196
+
197
+ return self.__dict__ == other.__dict__
198
+
199
+ def __ne__(self, other: 'V1QuoteAnnualUpsellResponse') -> bool:
200
+ """Returns true if both objects are not equal"""
201
+ return not self == other
@@ -79,7 +79,6 @@ class V1UserFeatures(object):
79
79
  'featured_studios_admin': 'bool',
80
80
  'gcp_overprovisioning': 'bool',
81
81
  'gcs_connections_optimized': 'bool',
82
- 'gcs_folders': 'bool',
83
82
  'instant_capacity_reservation': 'bool',
84
83
  'job_artifacts_v2': 'bool',
85
84
  'kubernetes_cluster_ui': 'bool',
@@ -165,7 +164,6 @@ class V1UserFeatures(object):
165
164
  'featured_studios_admin': 'featuredStudiosAdmin',
166
165
  'gcp_overprovisioning': 'gcpOverprovisioning',
167
166
  'gcs_connections_optimized': 'gcsConnectionsOptimized',
168
- 'gcs_folders': 'gcsFolders',
169
167
  'instant_capacity_reservation': 'instantCapacityReservation',
170
168
  'job_artifacts_v2': 'jobArtifactsV2',
171
169
  'kubernetes_cluster_ui': 'kubernetesClusterUi',
@@ -212,7 +210,7 @@ class V1UserFeatures(object):
212
210
  'writable_s3_connections': 'writableS3Connections'
213
211
  }
214
212
 
215
- def __init__(self, affiliate_links: 'bool' =None, agents_v2: 'bool' =None, ai_hub_monetization: 'bool' =None, auto_fast_load: 'bool' =None, auto_join_orgs: 'bool' =None, b2c_experience: 'bool' =None, byo_machine_type: 'bool' =None, cap_add: 'list[str]' =None, cap_drop: 'list[str]' =None, capacity_reservation_byoc: 'bool' =None, capacity_reservation_dry_run: 'bool' =None, chat_models: 'bool' =None, cloudspace_schedules: 'bool' =None, code_tab: 'bool' =None, collab_screen_sharing: 'bool' =None, control_center_monitoring: 'bool' =None, cost_attribution_settings: 'bool' =None, custom_app_domain: 'bool' =None, datasets: 'bool' =None, default_one_cluster: 'bool' =None, deployment_persistent_disk: 'bool' =None, drive_v2: 'bool' =None, enterprise_compute_admin: 'bool' =None, f227: 'bool' =None, f234: 'bool' =None, f236: 'bool' =None, f237: 'bool' =None, f238: 'bool' =None, f239: 'bool' =None, f240: 'bool' =None, f241: 'bool' =None, f242: 'bool' =None, f243: 'bool' =None, f245: 'bool' =None, fair_share: 'bool' =None, featured_studios_admin: 'bool' =None, gcp_overprovisioning: 'bool' =None, gcs_connections_optimized: 'bool' =None, gcs_folders: 'bool' =None, instant_capacity_reservation: 'bool' =None, job_artifacts_v2: 'bool' =None, kubernetes_cluster_ui: 'bool' =None, kubernetes_clusters: 'bool' =None, landing_studios: 'bool' =None, lit_logger: 'bool' =None, marketplace: 'bool' =None, mmt_fault_tolerance: 'bool' =None, mmt_strategy_selector: 'bool' =None, model_api_dashboard: 'bool' =None, multiple_studio_versions: 'bool' =None, nerf_fs_nonpaying: 'bool' =None, onboarding_v2: 'bool' =None, org_level_member_permissions: 'bool' =None, org_usage_limits: 'bool' =None, persistent_disk: 'bool' =None, plugin_distributed: 'bool' =None, plugin_inference: 'bool' =None, plugin_label_studio: 'bool' =None, plugin_langflow: 'bool' =None, plugin_python_profiler: 'bool' =None, plugin_sweeps: 'bool' =None, pricing_updates: 'bool' =None, product_generator: 'bool' =None, product_license: 'bool' =None, project_selector: 'bool' =None, publish_pipelines: 'bool' =None, reserved_machines_tab: 'bool' =None, restartable_jobs: 'bool' =None, runnable_public_studio_page: 'bool' =None, security_docs: 'bool' =None, show_dev_admin: 'bool' =None, single_wallet: 'bool' =None, slurm: 'bool' =None, specialised_studios: 'bool' =None, storage_overuse_deletion: 'bool' =None, studio_config: 'bool' =None, studio_sharing_v2: 'bool' =None, studio_version_visibility: 'bool' =None, trainium2: 'bool' =None, use_rclone_mounts_only: 'bool' =None, vultr: 'bool' =None, weka: 'bool' =None, writable_s3_connections: 'bool' =None): # noqa: E501
213
+ def __init__(self, affiliate_links: 'bool' =None, agents_v2: 'bool' =None, ai_hub_monetization: 'bool' =None, auto_fast_load: 'bool' =None, auto_join_orgs: 'bool' =None, b2c_experience: 'bool' =None, byo_machine_type: 'bool' =None, cap_add: 'list[str]' =None, cap_drop: 'list[str]' =None, capacity_reservation_byoc: 'bool' =None, capacity_reservation_dry_run: 'bool' =None, chat_models: 'bool' =None, cloudspace_schedules: 'bool' =None, code_tab: 'bool' =None, collab_screen_sharing: 'bool' =None, control_center_monitoring: 'bool' =None, cost_attribution_settings: 'bool' =None, custom_app_domain: 'bool' =None, datasets: 'bool' =None, default_one_cluster: 'bool' =None, deployment_persistent_disk: 'bool' =None, drive_v2: 'bool' =None, enterprise_compute_admin: 'bool' =None, f227: 'bool' =None, f234: 'bool' =None, f236: 'bool' =None, f237: 'bool' =None, f238: 'bool' =None, f239: 'bool' =None, f240: 'bool' =None, f241: 'bool' =None, f242: 'bool' =None, f243: 'bool' =None, f245: 'bool' =None, fair_share: 'bool' =None, featured_studios_admin: 'bool' =None, gcp_overprovisioning: 'bool' =None, gcs_connections_optimized: 'bool' =None, instant_capacity_reservation: 'bool' =None, job_artifacts_v2: 'bool' =None, kubernetes_cluster_ui: 'bool' =None, kubernetes_clusters: 'bool' =None, landing_studios: 'bool' =None, lit_logger: 'bool' =None, marketplace: 'bool' =None, mmt_fault_tolerance: 'bool' =None, mmt_strategy_selector: 'bool' =None, model_api_dashboard: 'bool' =None, multiple_studio_versions: 'bool' =None, nerf_fs_nonpaying: 'bool' =None, onboarding_v2: 'bool' =None, org_level_member_permissions: 'bool' =None, org_usage_limits: 'bool' =None, persistent_disk: 'bool' =None, plugin_distributed: 'bool' =None, plugin_inference: 'bool' =None, plugin_label_studio: 'bool' =None, plugin_langflow: 'bool' =None, plugin_python_profiler: 'bool' =None, plugin_sweeps: 'bool' =None, pricing_updates: 'bool' =None, product_generator: 'bool' =None, product_license: 'bool' =None, project_selector: 'bool' =None, publish_pipelines: 'bool' =None, reserved_machines_tab: 'bool' =None, restartable_jobs: 'bool' =None, runnable_public_studio_page: 'bool' =None, security_docs: 'bool' =None, show_dev_admin: 'bool' =None, single_wallet: 'bool' =None, slurm: 'bool' =None, specialised_studios: 'bool' =None, storage_overuse_deletion: 'bool' =None, studio_config: 'bool' =None, studio_sharing_v2: 'bool' =None, studio_version_visibility: 'bool' =None, trainium2: 'bool' =None, use_rclone_mounts_only: 'bool' =None, vultr: 'bool' =None, weka: 'bool' =None, writable_s3_connections: 'bool' =None): # noqa: E501
216
214
  """V1UserFeatures - a model defined in Swagger""" # noqa: E501
217
215
  self._affiliate_links = None
218
216
  self._agents_v2 = None
@@ -252,7 +250,6 @@ class V1UserFeatures(object):
252
250
  self._featured_studios_admin = None
253
251
  self._gcp_overprovisioning = None
254
252
  self._gcs_connections_optimized = None
255
- self._gcs_folders = None
256
253
  self._instant_capacity_reservation = None
257
254
  self._job_artifacts_v2 = None
258
255
  self._kubernetes_cluster_ui = None
@@ -374,8 +371,6 @@ class V1UserFeatures(object):
374
371
  self.gcp_overprovisioning = gcp_overprovisioning
375
372
  if gcs_connections_optimized is not None:
376
373
  self.gcs_connections_optimized = gcs_connections_optimized
377
- if gcs_folders is not None:
378
- self.gcs_folders = gcs_folders
379
374
  if instant_capacity_reservation is not None:
380
375
  self.instant_capacity_reservation = instant_capacity_reservation
381
376
  if job_artifacts_v2 is not None:
@@ -1263,27 +1258,6 @@ class V1UserFeatures(object):
1263
1258
 
1264
1259
  self._gcs_connections_optimized = gcs_connections_optimized
1265
1260
 
1266
- @property
1267
- def gcs_folders(self) -> 'bool':
1268
- """Gets the gcs_folders of this V1UserFeatures. # noqa: E501
1269
-
1270
-
1271
- :return: The gcs_folders of this V1UserFeatures. # noqa: E501
1272
- :rtype: bool
1273
- """
1274
- return self._gcs_folders
1275
-
1276
- @gcs_folders.setter
1277
- def gcs_folders(self, gcs_folders: 'bool'):
1278
- """Sets the gcs_folders of this V1UserFeatures.
1279
-
1280
-
1281
- :param gcs_folders: The gcs_folders of this V1UserFeatures. # noqa: E501
1282
- :type: bool
1283
- """
1284
-
1285
- self._gcs_folders = gcs_folders
1286
-
1287
1261
  @property
1288
1262
  def instant_capacity_reservation(self) -> 'bool':
1289
1263
  """Gets the instant_capacity_reservation of this V1UserFeatures. # noqa: E501
lightning_sdk/llm/llm.py CHANGED
@@ -285,7 +285,7 @@ class LLM:
285
285
  self,
286
286
  prompt: str,
287
287
  system_prompt: Optional[str] = None,
288
- max_completion_tokens: Optional[int] = 500,
288
+ max_completion_tokens: Optional[int] = None,
289
289
  images: Optional[Union[List[str], str]] = None,
290
290
  conversation: Optional[str] = None,
291
291
  metadata: Optional[Dict[str, str]] = None,
@@ -319,7 +319,7 @@ class LLM:
319
319
  self,
320
320
  prompt: str,
321
321
  system_prompt: Optional[str] = None,
322
- max_completion_tokens: Optional[int] = 500,
322
+ max_completion_tokens: Optional[int] = None,
323
323
  images: Optional[Union[List[str], str]] = None,
324
324
  conversation: Optional[str] = None,
325
325
  metadata: Optional[Dict[str, str]] = None,
lightning_sdk/studio.py CHANGED
@@ -59,6 +59,9 @@ class Studio:
59
59
  _skip_init = False
60
60
  _skip_setup = False
61
61
 
62
+ # whether to show progress bars during operations
63
+ show_progress = False
64
+
62
65
  def __init__(
63
66
  self,
64
67
  name: Optional[str] = None,
@@ -254,9 +257,26 @@ class Studio:
254
257
 
255
258
  if status != Status.Stopped:
256
259
  raise RuntimeError(f"Cannot start a studio that is not stopped. Studio {self.name} is {status}.")
257
- self._studio_api.start_studio(
258
- self._studio.id, self._teamspace.id, machine, interruptible=interruptible, max_runtime=max_runtime
259
- )
260
+
261
+ # Show progress bar during startup
262
+ if self.show_progress:
263
+ from lightning_sdk.utils.progress import StudioProgressTracker
264
+
265
+ with StudioProgressTracker("start", show_progress=True) as progress:
266
+ # Start the studio without blocking
267
+ self._studio_api.start_studio_async(
268
+ self._studio.id, self._teamspace.id, machine, interruptible=interruptible, max_runtime=max_runtime
269
+ )
270
+
271
+ # Track progress through completion
272
+ progress.track_startup_phases(
273
+ lambda: self._studio_api.get_studio_status(self._studio.id, self._teamspace.id)
274
+ )
275
+ else:
276
+ # Use the blocking version if no progress is needed
277
+ self._studio_api.start_studio(
278
+ self._studio.id, self._teamspace.id, machine, interruptible=interruptible, max_runtime=max_runtime
279
+ )
260
280
 
261
281
  self._setup()
262
282
 
@@ -324,9 +344,22 @@ class Studio:
324
344
  raise RuntimeError(
325
345
  f"Cannot switch machine on a studio that is not running. Studio {self.name} is {status}."
326
346
  )
327
- self._studio_api.switch_studio_machine(
328
- self._studio.id, self._teamspace.id, machine, interruptible=interruptible
329
- )
347
+
348
+ if self.show_progress:
349
+ from lightning_sdk.utils.progress import StudioProgressTracker
350
+
351
+ with StudioProgressTracker("switch", show_progress=True) as progress:
352
+ # Update progress before starting the switch
353
+ progress.update_progress(5, "Initiating machine switch...")
354
+
355
+ # Start the switch operation with progress tracking
356
+ self._studio_api.switch_studio_machine_with_progress(
357
+ self._studio.id, self._teamspace.id, machine, interruptible=interruptible, progress=progress
358
+ )
359
+ else:
360
+ self._studio_api.switch_studio_machine(
361
+ self._studio.id, self._teamspace.id, machine, interruptible=interruptible
362
+ )
330
363
 
331
364
  def run_and_detach(self, *commands: str, timeout: float = 10, check_interval: float = 1) -> str:
332
365
  """Runs given commands on the Studio and returns immediately.