lightning-sdk 2025.8.19.post0__py3-none-any.whl → 2025.8.26__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 (61) 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 +168 -2
  4. lightning_sdk/api/teamspace_api.py +60 -30
  5. lightning_sdk/api/user_api.py +49 -1
  6. lightning_sdk/api/utils.py +1 -1
  7. lightning_sdk/cli/config/set.py +6 -18
  8. lightning_sdk/cli/legacy/create.py +12 -14
  9. lightning_sdk/cli/legacy/delete.py +3 -3
  10. lightning_sdk/cli/legacy/deploy/_auth.py +4 -4
  11. lightning_sdk/cli/legacy/download.py +7 -7
  12. lightning_sdk/cli/legacy/job_and_mmt_action.py +4 -4
  13. lightning_sdk/cli/legacy/list.py +9 -9
  14. lightning_sdk/cli/legacy/open.py +3 -3
  15. lightning_sdk/cli/legacy/start.py +1 -0
  16. lightning_sdk/cli/legacy/switch.py +1 -0
  17. lightning_sdk/cli/legacy/upload.py +3 -3
  18. lightning_sdk/cli/studio/create.py +14 -23
  19. lightning_sdk/cli/studio/delete.py +28 -27
  20. lightning_sdk/cli/studio/list.py +5 -6
  21. lightning_sdk/cli/studio/ssh.py +19 -22
  22. lightning_sdk/cli/studio/start.py +23 -23
  23. lightning_sdk/cli/studio/stop.py +22 -26
  24. lightning_sdk/cli/studio/switch.py +20 -23
  25. lightning_sdk/cli/utils/resolve.py +1 -1
  26. lightning_sdk/cli/utils/save_to_config.py +27 -0
  27. lightning_sdk/cli/utils/studio_selection.py +106 -0
  28. lightning_sdk/cli/utils/teamspace_selection.py +125 -0
  29. lightning_sdk/lightning_cloud/openapi/__init__.py +3 -0
  30. lightning_sdk/lightning_cloud/openapi/api/billing_service_api.py +170 -0
  31. lightning_sdk/lightning_cloud/openapi/api/k8_s_cluster_service_api.py +101 -0
  32. lightning_sdk/lightning_cloud/openapi/models/__init__.py +3 -0
  33. lightning_sdk/lightning_cloud/openapi/models/assistant_id_conversations_body.py +15 -15
  34. lightning_sdk/lightning_cloud/openapi/models/externalv1_user_status.py +27 -1
  35. lightning_sdk/lightning_cloud/openapi/models/v1_cluster_metrics.py +270 -36
  36. lightning_sdk/lightning_cloud/openapi/models/v1_container_metrics.py +21 -21
  37. lightning_sdk/lightning_cloud/openapi/models/v1_list_cluster_metric_timestamps_response.py +123 -0
  38. lightning_sdk/lightning_cloud/openapi/models/v1_namespace_metrics.py +11 -11
  39. lightning_sdk/lightning_cloud/openapi/models/v1_namespace_user_metrics.py +16 -16
  40. lightning_sdk/lightning_cloud/openapi/models/v1_node_metrics.py +156 -26
  41. lightning_sdk/lightning_cloud/openapi/models/v1_pod_metrics.py +281 -21
  42. lightning_sdk/lightning_cloud/openapi/models/v1_project_cluster_binding.py +27 -1
  43. lightning_sdk/lightning_cloud/openapi/models/v1_purchase_annual_upsell_response.py +123 -0
  44. lightning_sdk/lightning_cloud/openapi/models/v1_quote_annual_upsell_response.py +201 -0
  45. lightning_sdk/lightning_cloud/openapi/models/v1_storage_asset.py +107 -3
  46. lightning_sdk/lightning_cloud/openapi/models/v1_user_features.py +1 -27
  47. lightning_sdk/llm/llm.py +2 -2
  48. lightning_sdk/llm/public_assistants.py +4 -0
  49. lightning_sdk/studio.py +92 -28
  50. lightning_sdk/teamspace.py +25 -2
  51. lightning_sdk/user.py +19 -1
  52. lightning_sdk/utils/config.py +6 -0
  53. lightning_sdk/utils/names.py +1179 -0
  54. lightning_sdk/utils/progress.py +284 -0
  55. lightning_sdk/utils/resolve.py +6 -6
  56. {lightning_sdk-2025.8.19.post0.dist-info → lightning_sdk-2025.8.26.dist-info}/METADATA +1 -1
  57. {lightning_sdk-2025.8.19.post0.dist-info → lightning_sdk-2025.8.26.dist-info}/RECORD +61 -53
  58. {lightning_sdk-2025.8.19.post0.dist-info → lightning_sdk-2025.8.26.dist-info}/LICENSE +0 -0
  59. {lightning_sdk-2025.8.19.post0.dist-info → lightning_sdk-2025.8.26.dist-info}/WHEEL +0 -0
  60. {lightning_sdk-2025.8.19.post0.dist-info → lightning_sdk-2025.8.26.dist-info}/entry_points.txt +0 -0
  61. {lightning_sdk-2025.8.19.post0.dist-info → lightning_sdk-2025.8.26.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,106 @@
1
+ import os
2
+ from contextlib import suppress
3
+ from typing import Dict, List, Optional
4
+
5
+ import click
6
+ from simple_term_menu import TerminalMenu
7
+
8
+ from lightning_sdk.cli.legacy.exceptions import StudioCliError
9
+ from lightning_sdk.studio import Studio
10
+ from lightning_sdk.teamspace import Teamspace
11
+ from lightning_sdk.utils.resolve import _get_authed_user
12
+
13
+
14
+ class StudiosMenu:
15
+ """This class is used to select a studio from a list of possible studios within a teamspace.
16
+
17
+ It can be used to select a studio from a list of possible studios, or to resolve a studio from a name.
18
+ """
19
+
20
+ def __init__(self, teamspace: Teamspace) -> None:
21
+ """Initialize the StudiosMenu with a teamspace.
22
+
23
+ Args:
24
+ teamspace: The teamspace to list studios from
25
+ """
26
+ self.teamspace = teamspace
27
+
28
+ def _get_studio_from_interactive_menu(self, possible_studios: Dict[str, Studio]) -> Studio:
29
+ studio_names = sorted(possible_studios.keys())
30
+ terminal_menu = self._prepare_terminal_menu_studios(studio_names)
31
+ terminal_menu.show()
32
+
33
+ selected_name = studio_names[terminal_menu.chosen_menu_index]
34
+ return possible_studios[selected_name]
35
+
36
+ def _get_studio_from_name(self, studio: str, possible_studios: Dict[str, Studio]) -> Studio:
37
+ if studio in possible_studios:
38
+ return possible_studios[studio]
39
+
40
+ click.echo(f"Could not find Studio {studio}, please select it from the list:")
41
+ return self._get_studio_from_interactive_menu(possible_studios)
42
+
43
+ @staticmethod
44
+ def _prepare_terminal_menu_studios(studio_names: List[str], title: Optional[str] = None) -> TerminalMenu:
45
+ if title is None:
46
+ title = "Please select a Studio out of the following:"
47
+
48
+ return TerminalMenu(studio_names, title=title, clear_menu_on_exit=True)
49
+
50
+ def _get_possible_studios(self) -> Dict[str, Studio]:
51
+ """Get all available studios in the teamspace."""
52
+ studios = {}
53
+
54
+ user = _get_authed_user()
55
+ for studio in self.teamspace.studios:
56
+ if studio._studio.user_id == user.id:
57
+ studios[studio.name] = studio
58
+ return studios
59
+
60
+ def __call__(self, studio: Optional[str] = None) -> Studio:
61
+ """Select a studio from the teamspace.
62
+
63
+ Args:
64
+ studio: Optional studio name to select. If not provided, will show interactive menu.
65
+
66
+ Returns:
67
+ Selected Studio object
68
+
69
+ Raises:
70
+ StudioCliError: If studio selection fails
71
+ """
72
+ try:
73
+ # try to resolve the studio from the name, environment or config
74
+ resolved_studio = None
75
+
76
+ with suppress(Exception):
77
+ resolved_studio = Studio(name=studio, teamspace=self.teamspace, create_ok=False)
78
+
79
+ if resolved_studio is not None:
80
+ return resolved_studio
81
+
82
+ if os.environ.get("LIGHTNING_NON_INTERACTIVE", "0") == "1" and studio is None:
83
+ raise ValueError(
84
+ "Studio selection is not supported in non-interactive mode. Please provide a studio name."
85
+ )
86
+
87
+ click.echo(f"Listing studios in teamspace {self.teamspace.owner.name}/{self.teamspace.name}...")
88
+
89
+ possible_studios = self._get_possible_studios()
90
+
91
+ if not possible_studios:
92
+ raise ValueError(f"No studios found in teamspace {self.teamspace.name}")
93
+
94
+ if studio is None:
95
+ return self._get_studio_from_interactive_menu(possible_studios)
96
+
97
+ return self._get_studio_from_name(studio, possible_studios)
98
+
99
+ except KeyboardInterrupt:
100
+ raise KeyboardInterrupt from None
101
+
102
+ except Exception as e:
103
+ raise StudioCliError(
104
+ "Could not resolve a Studio. "
105
+ "Please pass it as an argument or contact Lightning AI directly to resolve this issue."
106
+ ) from e
@@ -0,0 +1,125 @@
1
+ import os
2
+ from typing import Dict, List, Optional
3
+
4
+ import click
5
+ from simple_term_menu import TerminalMenu
6
+
7
+ from lightning_sdk.api import OrgApi
8
+ from lightning_sdk.cli.legacy.exceptions import StudioCliError
9
+ from lightning_sdk.cli.utils.resolve import resolve_teamspace_owner_name_format
10
+ from lightning_sdk.teamspace import Teamspace
11
+ from lightning_sdk.user import User
12
+ from lightning_sdk.utils.resolve import _get_authed_user
13
+
14
+
15
+ class TeamspacesMenu:
16
+ """This class is used to select a teamspace from a list of possible teamspaces.
17
+
18
+ It can be used to select a teamspace from a list of possible teamspaces, or to resolve a teamspace from a name.
19
+ """
20
+
21
+ def _get_teamspace_from_interactive_menu(self, possible_teamspaces: Dict[str, Dict[str, str]]) -> Dict[str, str]:
22
+ teamspace_ids = sorted(possible_teamspaces.keys())
23
+ terminal_menu = self._prepare_terminal_menu_teamspaces([possible_teamspaces[k] for k in teamspace_ids])
24
+ terminal_menu.show()
25
+
26
+ selected_id = teamspace_ids[terminal_menu.chosen_menu_index]
27
+ return possible_teamspaces[selected_id]
28
+
29
+ def _get_teamspace_from_name(
30
+ self, teamspace: str, possible_teamspaces: Dict[str, Dict[str, str]]
31
+ ) -> Dict[str, str]:
32
+ try:
33
+ owner, name = teamspace.split("/", maxsplit=1)
34
+ except ValueError as e:
35
+ raise ValueError(
36
+ f"Invalid teamspace format: '{teamspace}'. "
37
+ "Teamspace should be specified as '{teamspace_owner}/{teamspace_name}' "
38
+ "(e.g., 'my-org/my-teamspace')."
39
+ ) from e
40
+
41
+ for _, ts in possible_teamspaces.items():
42
+ if ts["name"] == name and (ts["user"] == owner or ts["org"] == owner):
43
+ return ts
44
+
45
+ click.echo(f"Could not find Teamspace {teamspace}, please select it from the list:")
46
+ return self._get_teamspace_from_interactive_menu(possible_teamspaces)
47
+
48
+ @staticmethod
49
+ def _prepare_terminal_menu_teamspaces(
50
+ possible_teamspaces: List[Dict[str, str]], title: Optional[str] = None
51
+ ) -> TerminalMenu:
52
+ if title is None:
53
+ title = "Please select a Teamspace out of the following:"
54
+
55
+ return TerminalMenu(
56
+ [f"{t['user'] or t['org']}/{t['name']}" for t in possible_teamspaces], title=title, clear_menu_on_exit=True
57
+ )
58
+
59
+ @staticmethod
60
+ def _get_possible_teamspaces(user: User) -> Dict[str, Dict[str, str]]:
61
+ org_api = OrgApi()
62
+ user_api = user._user_api
63
+
64
+ user_api._get_organizations_for_authed_user()
65
+ memberships = user_api._get_all_teamspace_memberships(user_id=user.id)
66
+
67
+ teamspaces = {}
68
+ # get all teamspace memberships
69
+ for membership in memberships:
70
+ teamspace_id = membership.project_id
71
+ teamspace_name = membership.name
72
+
73
+ # get organization if necessary
74
+ if membership.owner_type == "organization":
75
+ org_name = org_api._get_org_by_id(membership.owner_id).name
76
+ user_name = None
77
+ else:
78
+ org_name = None
79
+
80
+ # don't do a request if not necessary
81
+ if membership.owner_id == user.id:
82
+ user_name = user.name
83
+ else:
84
+ user_name = user_api._get_user_by_id(membership.owner_id).username
85
+
86
+ teamspaces[teamspace_id] = {"user": user_name, "org": org_name, "name": teamspace_name}
87
+
88
+ return teamspaces
89
+
90
+ def __call__(self, teamspace: Optional[str] = None) -> Teamspace:
91
+ try:
92
+ # try to resolve the teamspace from the name, environment or config
93
+ resolved_teamspace = resolve_teamspace_owner_name_format(teamspace)
94
+
95
+ if resolved_teamspace is not None:
96
+ return resolved_teamspace
97
+
98
+ if os.environ.get("LIGHTNING_NON_INTERACTIVE", "0") == "1":
99
+ raise ValueError(
100
+ "Teamspace selection is not supported in non-interactive mode. "
101
+ "Please provide a teamspace name in the format of 'owner/teamspace'."
102
+ )
103
+
104
+ # if the teamspace is not resolved, try to get the teamspace from the interactive menu
105
+ # this could mean that either no teamspace was provided or the provided teamspace is not valid
106
+ user = _get_authed_user()
107
+
108
+ possible_teamspaces = self._get_possible_teamspaces(user)
109
+ if teamspace is None:
110
+ teamspace = resolve_teamspace_owner_name_format(teamspace)
111
+ teamspace_dict = self._get_teamspace_from_interactive_menu(possible_teamspaces=possible_teamspaces)
112
+ else:
113
+ teamspace_dict = self._get_teamspace_from_name(
114
+ teamspace=teamspace, possible_teamspaces=possible_teamspaces
115
+ )
116
+
117
+ return Teamspace(**teamspace_dict)
118
+ except KeyboardInterrupt:
119
+ raise KeyboardInterrupt from None
120
+
121
+ except Exception as e:
122
+ raise StudioCliError(
123
+ f"Could not find the given Teamspace {teamspace}. "
124
+ "Please contact Lightning AI directly to resolve this issue."
125
+ ) from e
@@ -656,6 +656,7 @@ from lightning_sdk.lightning_cloud.openapi.models.v1_list_cloudy_experts_respons
656
656
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_cluster_accelerators_response import V1ListClusterAcceleratorsResponse
657
657
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_cluster_availabilities_response import V1ListClusterAvailabilitiesResponse
658
658
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_cluster_capacity_reservations_response import V1ListClusterCapacityReservationsResponse
659
+ from lightning_sdk.lightning_cloud.openapi.models.v1_list_cluster_metric_timestamps_response import V1ListClusterMetricTimestampsResponse
659
660
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_cluster_metrics_response import V1ListClusterMetricsResponse
660
661
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_cluster_namespace_metrics_response import V1ListClusterNamespaceMetricsResponse
661
662
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_cluster_namespace_user_metrics_response import V1ListClusterNamespaceUserMetricsResponse
@@ -844,6 +845,7 @@ from lightning_sdk.lightning_cloud.openapi.models.v1_project_storage import V1Pr
844
845
  from lightning_sdk.lightning_cloud.openapi.models.v1_prompt_suggestion import V1PromptSuggestion
845
846
  from lightning_sdk.lightning_cloud.openapi.models.v1_publish_cloud_space_response import V1PublishCloudSpaceResponse
846
847
  from lightning_sdk.lightning_cloud.openapi.models.v1_published_cloud_space_response import V1PublishedCloudSpaceResponse
848
+ from lightning_sdk.lightning_cloud.openapi.models.v1_purchase_annual_upsell_response import V1PurchaseAnnualUpsellResponse
847
849
  from lightning_sdk.lightning_cloud.openapi.models.v1_purchase_capacity_block_response import V1PurchaseCapacityBlockResponse
848
850
  from lightning_sdk.lightning_cloud.openapi.models.v1_python_dependency_info import V1PythonDependencyInfo
849
851
  from lightning_sdk.lightning_cloud.openapi.models.v1_query_param import V1QueryParam
@@ -853,6 +855,7 @@ from lightning_sdk.lightning_cloud.openapi.models.v1_quest import V1Quest
853
855
  from lightning_sdk.lightning_cloud.openapi.models.v1_quest_status import V1QuestStatus
854
856
  from lightning_sdk.lightning_cloud.openapi.models.v1_queue_server_type import V1QueueServerType
855
857
  from lightning_sdk.lightning_cloud.openapi.models.v1_quotas import V1Quotas
858
+ from lightning_sdk.lightning_cloud.openapi.models.v1_quote_annual_upsell_response import V1QuoteAnnualUpsellResponse
856
859
  from lightning_sdk.lightning_cloud.openapi.models.v1_quote_subscription_response import V1QuoteSubscriptionResponse
857
860
  from lightning_sdk.lightning_cloud.openapi.models.v1_r2_data_connection import V1R2DataConnection
858
861
  from lightning_sdk.lightning_cloud.openapi.models.v1_refresh_index_response import V1RefreshIndexResponse
@@ -1356,6 +1356,176 @@ class BillingServiceApi(object):
1356
1356
  _request_timeout=params.get('_request_timeout'),
1357
1357
  collection_formats=collection_formats)
1358
1358
 
1359
+ def billing_service_purchase_annual_upsell(self, **kwargs) -> 'V1PurchaseAnnualUpsellResponse': # noqa: E501
1360
+ """billing_service_purchase_annual_upsell # noqa: E501
1361
+
1362
+ This method makes a synchronous HTTP request by default. To make an
1363
+ asynchronous HTTP request, please pass async_req=True
1364
+ >>> thread = api.billing_service_purchase_annual_upsell(async_req=True)
1365
+ >>> result = thread.get()
1366
+
1367
+ :param async_req bool
1368
+ :return: V1PurchaseAnnualUpsellResponse
1369
+ If the method is called asynchronously,
1370
+ returns the request thread.
1371
+ """
1372
+ kwargs['_return_http_data_only'] = True
1373
+ if kwargs.get('async_req'):
1374
+ return self.billing_service_purchase_annual_upsell_with_http_info(**kwargs) # noqa: E501
1375
+ else:
1376
+ (data) = self.billing_service_purchase_annual_upsell_with_http_info(**kwargs) # noqa: E501
1377
+ return data
1378
+
1379
+ def billing_service_purchase_annual_upsell_with_http_info(self, **kwargs) -> 'V1PurchaseAnnualUpsellResponse': # noqa: E501
1380
+ """billing_service_purchase_annual_upsell # noqa: E501
1381
+
1382
+ This method makes a synchronous HTTP request by default. To make an
1383
+ asynchronous HTTP request, please pass async_req=True
1384
+ >>> thread = api.billing_service_purchase_annual_upsell_with_http_info(async_req=True)
1385
+ >>> result = thread.get()
1386
+
1387
+ :param async_req bool
1388
+ :return: V1PurchaseAnnualUpsellResponse
1389
+ If the method is called asynchronously,
1390
+ returns the request thread.
1391
+ """
1392
+
1393
+ all_params = [] # noqa: E501
1394
+ all_params.append('async_req')
1395
+ all_params.append('_return_http_data_only')
1396
+ all_params.append('_preload_content')
1397
+ all_params.append('_request_timeout')
1398
+
1399
+ params = locals()
1400
+ for key, val in six.iteritems(params['kwargs']):
1401
+ if key not in all_params:
1402
+ raise TypeError(
1403
+ "Got an unexpected keyword argument '%s'"
1404
+ " to method billing_service_purchase_annual_upsell" % key
1405
+ )
1406
+ params[key] = val
1407
+ del params['kwargs']
1408
+
1409
+ collection_formats = {}
1410
+
1411
+ path_params = {}
1412
+
1413
+ query_params = []
1414
+
1415
+ header_params = {}
1416
+
1417
+ form_params = []
1418
+ local_var_files = {}
1419
+
1420
+ body_params = None
1421
+ # HTTP header `Accept`
1422
+ header_params['Accept'] = self.api_client.select_header_accept(
1423
+ ['application/json']) # noqa: E501
1424
+
1425
+ # Authentication setting
1426
+ auth_settings = [] # noqa: E501
1427
+
1428
+ return self.api_client.call_api(
1429
+ '/v1/billing/annual-upsell', 'POST',
1430
+ path_params,
1431
+ query_params,
1432
+ header_params,
1433
+ body=body_params,
1434
+ post_params=form_params,
1435
+ files=local_var_files,
1436
+ response_type='V1PurchaseAnnualUpsellResponse', # noqa: E501
1437
+ auth_settings=auth_settings,
1438
+ async_req=params.get('async_req'),
1439
+ _return_http_data_only=params.get('_return_http_data_only'),
1440
+ _preload_content=params.get('_preload_content', True),
1441
+ _request_timeout=params.get('_request_timeout'),
1442
+ collection_formats=collection_formats)
1443
+
1444
+ def billing_service_quote_annual_upsell(self, **kwargs) -> 'V1QuoteAnnualUpsellResponse': # noqa: E501
1445
+ """billing_service_quote_annual_upsell # noqa: E501
1446
+
1447
+ This method makes a synchronous HTTP request by default. To make an
1448
+ asynchronous HTTP request, please pass async_req=True
1449
+ >>> thread = api.billing_service_quote_annual_upsell(async_req=True)
1450
+ >>> result = thread.get()
1451
+
1452
+ :param async_req bool
1453
+ :return: V1QuoteAnnualUpsellResponse
1454
+ If the method is called asynchronously,
1455
+ returns the request thread.
1456
+ """
1457
+ kwargs['_return_http_data_only'] = True
1458
+ if kwargs.get('async_req'):
1459
+ return self.billing_service_quote_annual_upsell_with_http_info(**kwargs) # noqa: E501
1460
+ else:
1461
+ (data) = self.billing_service_quote_annual_upsell_with_http_info(**kwargs) # noqa: E501
1462
+ return data
1463
+
1464
+ def billing_service_quote_annual_upsell_with_http_info(self, **kwargs) -> 'V1QuoteAnnualUpsellResponse': # noqa: E501
1465
+ """billing_service_quote_annual_upsell # noqa: E501
1466
+
1467
+ This method makes a synchronous HTTP request by default. To make an
1468
+ asynchronous HTTP request, please pass async_req=True
1469
+ >>> thread = api.billing_service_quote_annual_upsell_with_http_info(async_req=True)
1470
+ >>> result = thread.get()
1471
+
1472
+ :param async_req bool
1473
+ :return: V1QuoteAnnualUpsellResponse
1474
+ If the method is called asynchronously,
1475
+ returns the request thread.
1476
+ """
1477
+
1478
+ all_params = [] # noqa: E501
1479
+ all_params.append('async_req')
1480
+ all_params.append('_return_http_data_only')
1481
+ all_params.append('_preload_content')
1482
+ all_params.append('_request_timeout')
1483
+
1484
+ params = locals()
1485
+ for key, val in six.iteritems(params['kwargs']):
1486
+ if key not in all_params:
1487
+ raise TypeError(
1488
+ "Got an unexpected keyword argument '%s'"
1489
+ " to method billing_service_quote_annual_upsell" % key
1490
+ )
1491
+ params[key] = val
1492
+ del params['kwargs']
1493
+
1494
+ collection_formats = {}
1495
+
1496
+ path_params = {}
1497
+
1498
+ query_params = []
1499
+
1500
+ header_params = {}
1501
+
1502
+ form_params = []
1503
+ local_var_files = {}
1504
+
1505
+ body_params = None
1506
+ # HTTP header `Accept`
1507
+ header_params['Accept'] = self.api_client.select_header_accept(
1508
+ ['application/json']) # noqa: E501
1509
+
1510
+ # Authentication setting
1511
+ auth_settings = [] # noqa: E501
1512
+
1513
+ return self.api_client.call_api(
1514
+ '/v1/billing/annual-upsell', 'GET',
1515
+ path_params,
1516
+ query_params,
1517
+ header_params,
1518
+ body=body_params,
1519
+ post_params=form_params,
1520
+ files=local_var_files,
1521
+ response_type='V1QuoteAnnualUpsellResponse', # noqa: E501
1522
+ auth_settings=auth_settings,
1523
+ async_req=params.get('async_req'),
1524
+ _return_http_data_only=params.get('_return_http_data_only'),
1525
+ _preload_content=params.get('_preload_content', True),
1526
+ _request_timeout=params.get('_request_timeout'),
1527
+ collection_formats=collection_formats)
1528
+
1359
1529
  def billing_service_quote_subscription(self, **kwargs) -> 'V1QuoteSubscriptionResponse': # noqa: E501
1360
1530
  """billing_service_quote_subscription # noqa: E501
1361
1531
 
@@ -273,6 +273,107 @@ class K8SClusterServiceApi(object):
273
273
  _request_timeout=params.get('_request_timeout'),
274
274
  collection_formats=collection_formats)
275
275
 
276
+ def k8_s_cluster_service_list_cluster_metric_timestamps(self, project_id: 'str', cluster_id: 'str', **kwargs) -> 'V1ListClusterMetricTimestampsResponse': # noqa: E501
277
+ """k8_s_cluster_service_list_cluster_metric_timestamps # noqa: E501
278
+
279
+ This method makes a synchronous HTTP request by default. To make an
280
+ asynchronous HTTP request, please pass async_req=True
281
+ >>> thread = api.k8_s_cluster_service_list_cluster_metric_timestamps(project_id, cluster_id, async_req=True)
282
+ >>> result = thread.get()
283
+
284
+ :param async_req bool
285
+ :param str project_id: (required)
286
+ :param str cluster_id: (required)
287
+ :return: V1ListClusterMetricTimestampsResponse
288
+ If the method is called asynchronously,
289
+ returns the request thread.
290
+ """
291
+ kwargs['_return_http_data_only'] = True
292
+ if kwargs.get('async_req'):
293
+ return self.k8_s_cluster_service_list_cluster_metric_timestamps_with_http_info(project_id, cluster_id, **kwargs) # noqa: E501
294
+ else:
295
+ (data) = self.k8_s_cluster_service_list_cluster_metric_timestamps_with_http_info(project_id, cluster_id, **kwargs) # noqa: E501
296
+ return data
297
+
298
+ def k8_s_cluster_service_list_cluster_metric_timestamps_with_http_info(self, project_id: 'str', cluster_id: 'str', **kwargs) -> 'V1ListClusterMetricTimestampsResponse': # noqa: E501
299
+ """k8_s_cluster_service_list_cluster_metric_timestamps # noqa: E501
300
+
301
+ This method makes a synchronous HTTP request by default. To make an
302
+ asynchronous HTTP request, please pass async_req=True
303
+ >>> thread = api.k8_s_cluster_service_list_cluster_metric_timestamps_with_http_info(project_id, cluster_id, async_req=True)
304
+ >>> result = thread.get()
305
+
306
+ :param async_req bool
307
+ :param str project_id: (required)
308
+ :param str cluster_id: (required)
309
+ :return: V1ListClusterMetricTimestampsResponse
310
+ If the method is called asynchronously,
311
+ returns the request thread.
312
+ """
313
+
314
+ all_params = ['project_id', 'cluster_id'] # noqa: E501
315
+ all_params.append('async_req')
316
+ all_params.append('_return_http_data_only')
317
+ all_params.append('_preload_content')
318
+ all_params.append('_request_timeout')
319
+
320
+ params = locals()
321
+ for key, val in six.iteritems(params['kwargs']):
322
+ if key not in all_params:
323
+ raise TypeError(
324
+ "Got an unexpected keyword argument '%s'"
325
+ " to method k8_s_cluster_service_list_cluster_metric_timestamps" % key
326
+ )
327
+ params[key] = val
328
+ del params['kwargs']
329
+ # verify the required parameter 'project_id' is set
330
+ if ('project_id' not in params or
331
+ params['project_id'] is None):
332
+ raise ValueError("Missing the required parameter `project_id` when calling `k8_s_cluster_service_list_cluster_metric_timestamps`") # noqa: E501
333
+ # verify the required parameter 'cluster_id' is set
334
+ if ('cluster_id' not in params or
335
+ params['cluster_id'] is None):
336
+ raise ValueError("Missing the required parameter `cluster_id` when calling `k8_s_cluster_service_list_cluster_metric_timestamps`") # noqa: E501
337
+
338
+ collection_formats = {}
339
+
340
+ path_params = {}
341
+ if 'project_id' in params:
342
+ path_params['projectId'] = params['project_id'] # noqa: E501
343
+ if 'cluster_id' in params:
344
+ path_params['clusterId'] = params['cluster_id'] # noqa: E501
345
+
346
+ query_params = []
347
+
348
+ header_params = {}
349
+
350
+ form_params = []
351
+ local_var_files = {}
352
+
353
+ body_params = None
354
+ # HTTP header `Accept`
355
+ header_params['Accept'] = self.api_client.select_header_accept(
356
+ ['application/json']) # noqa: E501
357
+
358
+ # Authentication setting
359
+ auth_settings = [] # noqa: E501
360
+
361
+ return self.api_client.call_api(
362
+ '/v1/projects/{projectId}/clusters/{clusterId}/cluster-metrics-timestamps', 'GET',
363
+ path_params,
364
+ query_params,
365
+ header_params,
366
+ body=body_params,
367
+ post_params=form_params,
368
+ files=local_var_files,
369
+ response_type='V1ListClusterMetricTimestampsResponse', # noqa: E501
370
+ auth_settings=auth_settings,
371
+ async_req=params.get('async_req'),
372
+ _return_http_data_only=params.get('_return_http_data_only'),
373
+ _preload_content=params.get('_preload_content', True),
374
+ _request_timeout=params.get('_request_timeout'),
375
+ collection_formats=collection_formats)
376
+
276
377
  def k8_s_cluster_service_list_cluster_metrics(self, project_id: 'str', cluster_id: 'str', **kwargs) -> 'V1ListClusterMetricsResponse': # noqa: E501
277
378
  """k8_s_cluster_service_list_cluster_metrics # noqa: E501
278
379
 
@@ -608,6 +608,7 @@ from lightning_sdk.lightning_cloud.openapi.models.v1_list_cloudy_experts_respons
608
608
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_cluster_accelerators_response import V1ListClusterAcceleratorsResponse
609
609
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_cluster_availabilities_response import V1ListClusterAvailabilitiesResponse
610
610
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_cluster_capacity_reservations_response import V1ListClusterCapacityReservationsResponse
611
+ from lightning_sdk.lightning_cloud.openapi.models.v1_list_cluster_metric_timestamps_response import V1ListClusterMetricTimestampsResponse
611
612
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_cluster_metrics_response import V1ListClusterMetricsResponse
612
613
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_cluster_namespace_metrics_response import V1ListClusterNamespaceMetricsResponse
613
614
  from lightning_sdk.lightning_cloud.openapi.models.v1_list_cluster_namespace_user_metrics_response import V1ListClusterNamespaceUserMetricsResponse
@@ -796,6 +797,7 @@ from lightning_sdk.lightning_cloud.openapi.models.v1_project_storage import V1Pr
796
797
  from lightning_sdk.lightning_cloud.openapi.models.v1_prompt_suggestion import V1PromptSuggestion
797
798
  from lightning_sdk.lightning_cloud.openapi.models.v1_publish_cloud_space_response import V1PublishCloudSpaceResponse
798
799
  from lightning_sdk.lightning_cloud.openapi.models.v1_published_cloud_space_response import V1PublishedCloudSpaceResponse
800
+ from lightning_sdk.lightning_cloud.openapi.models.v1_purchase_annual_upsell_response import V1PurchaseAnnualUpsellResponse
799
801
  from lightning_sdk.lightning_cloud.openapi.models.v1_purchase_capacity_block_response import V1PurchaseCapacityBlockResponse
800
802
  from lightning_sdk.lightning_cloud.openapi.models.v1_python_dependency_info import V1PythonDependencyInfo
801
803
  from lightning_sdk.lightning_cloud.openapi.models.v1_query_param import V1QueryParam
@@ -805,6 +807,7 @@ from lightning_sdk.lightning_cloud.openapi.models.v1_quest import V1Quest
805
807
  from lightning_sdk.lightning_cloud.openapi.models.v1_quest_status import V1QuestStatus
806
808
  from lightning_sdk.lightning_cloud.openapi.models.v1_queue_server_type import V1QueueServerType
807
809
  from lightning_sdk.lightning_cloud.openapi.models.v1_quotas import V1Quotas
810
+ from lightning_sdk.lightning_cloud.openapi.models.v1_quote_annual_upsell_response import V1QuoteAnnualUpsellResponse
808
811
  from lightning_sdk.lightning_cloud.openapi.models.v1_quote_subscription_response import V1QuoteSubscriptionResponse
809
812
  from lightning_sdk.lightning_cloud.openapi.models.v1_r2_data_connection import V1R2DataConnection
810
813
  from lightning_sdk.lightning_cloud.openapi.models.v1_refresh_index_response import V1RefreshIndexResponse
@@ -46,7 +46,7 @@ class AssistantIdConversationsBody(object):
46
46
  'conversation_id': 'str',
47
47
  'ephemeral': 'bool',
48
48
  'internal_conversation': 'bool',
49
- 'max_tokens': 'str',
49
+ 'max_completion_tokens': 'str',
50
50
  'message': 'V1Message',
51
51
  'metadata': 'dict(str, str)',
52
52
  'name': 'str',
@@ -66,7 +66,7 @@ class AssistantIdConversationsBody(object):
66
66
  'conversation_id': 'conversationId',
67
67
  'ephemeral': 'ephemeral',
68
68
  'internal_conversation': 'internalConversation',
69
- 'max_tokens': 'maxTokens',
69
+ 'max_completion_tokens': 'maxCompletionTokens',
70
70
  'message': 'message',
71
71
  'metadata': 'metadata',
72
72
  'name': 'name',
@@ -80,14 +80,14 @@ class AssistantIdConversationsBody(object):
80
80
  'tools': 'tools'
81
81
  }
82
82
 
83
- def __init__(self, auto_name: 'bool' =None, billing_project_id: 'str' =None, conversation_id: 'str' =None, ephemeral: 'bool' =None, internal_conversation: 'bool' =None, max_tokens: 'str' =None, message: 'V1Message' =None, metadata: 'dict(str, str)' =None, name: 'str' =None, parent_conversation_id: 'str' =None, parent_message_id: 'str' =None, reasoning_effort: 'str' =None, sent_at: 'datetime' =None, store: 'bool' =None, stream: 'bool' =None, system_prompt: 'str' =None, tools: 'list[V1Tool]' =None): # noqa: E501
83
+ def __init__(self, auto_name: 'bool' =None, billing_project_id: 'str' =None, conversation_id: 'str' =None, ephemeral: 'bool' =None, internal_conversation: 'bool' =None, max_completion_tokens: 'str' =None, message: 'V1Message' =None, metadata: 'dict(str, str)' =None, name: 'str' =None, parent_conversation_id: 'str' =None, parent_message_id: 'str' =None, reasoning_effort: 'str' =None, sent_at: 'datetime' =None, store: 'bool' =None, stream: 'bool' =None, system_prompt: 'str' =None, tools: 'list[V1Tool]' =None): # noqa: E501
84
84
  """AssistantIdConversationsBody - a model defined in Swagger""" # noqa: E501
85
85
  self._auto_name = None
86
86
  self._billing_project_id = None
87
87
  self._conversation_id = None
88
88
  self._ephemeral = None
89
89
  self._internal_conversation = None
90
- self._max_tokens = None
90
+ self._max_completion_tokens = None
91
91
  self._message = None
92
92
  self._metadata = None
93
93
  self._name = None
@@ -110,8 +110,8 @@ class AssistantIdConversationsBody(object):
110
110
  self.ephemeral = ephemeral
111
111
  if internal_conversation is not None:
112
112
  self.internal_conversation = internal_conversation
113
- if max_tokens is not None:
114
- self.max_tokens = max_tokens
113
+ if max_completion_tokens is not None:
114
+ self.max_completion_tokens = max_completion_tokens
115
115
  if message is not None:
116
116
  self.message = message
117
117
  if metadata is not None:
@@ -241,25 +241,25 @@ class AssistantIdConversationsBody(object):
241
241
  self._internal_conversation = internal_conversation
242
242
 
243
243
  @property
244
- def max_tokens(self) -> 'str':
245
- """Gets the max_tokens of this AssistantIdConversationsBody. # noqa: E501
244
+ def max_completion_tokens(self) -> 'str':
245
+ """Gets the max_completion_tokens of this AssistantIdConversationsBody. # noqa: E501
246
246
 
247
247
 
248
- :return: The max_tokens of this AssistantIdConversationsBody. # noqa: E501
248
+ :return: The max_completion_tokens of this AssistantIdConversationsBody. # noqa: E501
249
249
  :rtype: str
250
250
  """
251
- return self._max_tokens
251
+ return self._max_completion_tokens
252
252
 
253
- @max_tokens.setter
254
- def max_tokens(self, max_tokens: 'str'):
255
- """Sets the max_tokens of this AssistantIdConversationsBody.
253
+ @max_completion_tokens.setter
254
+ def max_completion_tokens(self, max_completion_tokens: 'str'):
255
+ """Sets the max_completion_tokens of this AssistantIdConversationsBody.
256
256
 
257
257
 
258
- :param max_tokens: The max_tokens of this AssistantIdConversationsBody. # noqa: E501
258
+ :param max_completion_tokens: The max_completion_tokens of this AssistantIdConversationsBody. # noqa: E501
259
259
  :type: str
260
260
  """
261
261
 
262
- self._max_tokens = max_tokens
262
+ self._max_completion_tokens = max_completion_tokens
263
263
 
264
264
  @property
265
265
  def message(self) -> 'V1Message':