skypilot-nightly 1.0.0.dev20250513__py3-none-any.whl → 1.0.0.dev20250515__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 (59) hide show
  1. sky/__init__.py +2 -2
  2. sky/backends/backend.py +3 -2
  3. sky/backends/backend_utils.py +16 -17
  4. sky/backends/cloud_vm_ray_backend.py +47 -16
  5. sky/clouds/aws.py +11 -9
  6. sky/clouds/azure.py +16 -13
  7. sky/clouds/cloud.py +4 -3
  8. sky/clouds/cudo.py +3 -2
  9. sky/clouds/do.py +3 -2
  10. sky/clouds/fluidstack.py +3 -3
  11. sky/clouds/gcp.py +25 -9
  12. sky/clouds/ibm.py +12 -10
  13. sky/clouds/kubernetes.py +3 -2
  14. sky/clouds/lambda_cloud.py +6 -6
  15. sky/clouds/nebius.py +6 -5
  16. sky/clouds/oci.py +9 -7
  17. sky/clouds/paperspace.py +3 -2
  18. sky/clouds/runpod.py +9 -9
  19. sky/clouds/scp.py +5 -3
  20. sky/clouds/service_catalog/data_fetchers/fetch_gcp.py +33 -11
  21. sky/clouds/service_catalog/gcp_catalog.py +7 -1
  22. sky/clouds/vast.py +8 -7
  23. sky/clouds/vsphere.py +4 -2
  24. sky/core.py +18 -12
  25. sky/dashboard/out/404.html +1 -1
  26. sky/dashboard/out/_next/static/chunks/pages/index-6b0d9e5031b70c58.js +1 -0
  27. sky/dashboard/out/_next/static/{2dkponv64SfFShA8Rnw0D → jFI0Y-uJZ_XDK5IGJpKFU}/_buildManifest.js +1 -1
  28. sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
  29. sky/dashboard/out/clusters/[cluster].html +1 -1
  30. sky/dashboard/out/clusters.html +1 -1
  31. sky/dashboard/out/index.html +1 -1
  32. sky/dashboard/out/jobs/[job].html +1 -1
  33. sky/dashboard/out/jobs.html +1 -1
  34. sky/execution.py +33 -0
  35. sky/jobs/recovery_strategy.py +4 -1
  36. sky/jobs/server/core.py +6 -12
  37. sky/optimizer.py +19 -13
  38. sky/provision/kubernetes/utils.py +26 -1
  39. sky/resources.py +206 -43
  40. sky/serve/server/core.py +0 -5
  41. sky/serve/spot_placer.py +3 -0
  42. sky/server/server.py +51 -13
  43. sky/skylet/log_lib.py +12 -3
  44. sky/skylet/log_lib.pyi +5 -0
  45. sky/task.py +8 -6
  46. sky/templates/nebius-ray.yml.j2 +3 -1
  47. sky/utils/cli_utils/status_utils.py +6 -5
  48. sky/utils/controller_utils.py +39 -43
  49. sky/utils/dag_utils.py +4 -2
  50. sky/utils/resources_utils.py +3 -0
  51. sky/utils/schemas.py +33 -24
  52. {skypilot_nightly-1.0.0.dev20250513.dist-info → skypilot_nightly-1.0.0.dev20250515.dist-info}/METADATA +1 -1
  53. {skypilot_nightly-1.0.0.dev20250513.dist-info → skypilot_nightly-1.0.0.dev20250515.dist-info}/RECORD +58 -58
  54. {skypilot_nightly-1.0.0.dev20250513.dist-info → skypilot_nightly-1.0.0.dev20250515.dist-info}/WHEEL +1 -1
  55. sky/dashboard/out/_next/static/chunks/pages/index-f9f039532ca8cbc4.js +0 -1
  56. /sky/dashboard/out/_next/static/{2dkponv64SfFShA8Rnw0D → jFI0Y-uJZ_XDK5IGJpKFU}/_ssgManifest.js +0 -0
  57. {skypilot_nightly-1.0.0.dev20250513.dist-info → skypilot_nightly-1.0.0.dev20250515.dist-info}/entry_points.txt +0 -0
  58. {skypilot_nightly-1.0.0.dev20250513.dist-info → skypilot_nightly-1.0.0.dev20250515.dist-info}/licenses/LICENSE +0 -0
  59. {skypilot_nightly-1.0.0.dev20250513.dist-info → skypilot_nightly-1.0.0.dev20250515.dist-info}/top_level.txt +0 -0
sky/skylet/log_lib.py CHANGED
@@ -62,6 +62,16 @@ class _ProcessingArgs:
62
62
  self.streaming_prefix = streaming_prefix
63
63
 
64
64
 
65
+ def _get_context():
66
+ # TODO(aylei): remove this after we drop the backward-compatibility for
67
+ # 0.9.x in 0.12.0
68
+ # Keep backward-compatibility for the old version of SkyPilot runtimes.
69
+ if 'context' in globals():
70
+ return context.get()
71
+ else:
72
+ return None
73
+
74
+
65
75
  def _handle_io_stream(io_stream, out_stream, args: _ProcessingArgs):
66
76
  """Process the stream of a process."""
67
77
  out_io = io.TextIOWrapper(io_stream,
@@ -80,7 +90,7 @@ def _handle_io_stream(io_stream, out_stream, args: _ProcessingArgs):
80
90
  with open(args.log_path, 'a', encoding='utf-8') as fout:
81
91
  with line_processor:
82
92
  while True:
83
- ctx = context.get()
93
+ ctx = _get_context()
84
94
  if ctx is not None and ctx.is_canceled():
85
95
  return
86
96
  line = out_io.readline()
@@ -139,7 +149,6 @@ def process_subprocess_stream(proc, stdout_stream_handler,
139
149
  return stdout, stderr
140
150
 
141
151
 
142
- @context_utils.cancellation_guard
143
152
  def run_with_log(
144
153
  cmd: Union[List[str], str],
145
154
  log_path: str,
@@ -181,7 +190,7 @@ def run_with_log(
181
190
  # Redirect stderr to stdout when using ray, to preserve the order of
182
191
  # stdout and stderr.
183
192
  stdout_arg = stderr_arg = None
184
- ctx = context.get()
193
+ ctx = _get_context()
185
194
  if process_stream or ctx is not None:
186
195
  # Capture stdout/stderr of the subprocess if:
187
196
  # 1. Post-processing is needed (process_stream=True)
sky/skylet/log_lib.pyi CHANGED
@@ -11,6 +11,7 @@ from typing_extensions import Literal
11
11
  from sky import sky_logging as sky_logging
12
12
  from sky.skylet import constants as constants
13
13
  from sky.skylet import job_lib as job_lib
14
+ from sky.utils import context
14
15
  from sky.utils import log_utils as log_utils
15
16
 
16
17
  SKY_LOG_WAITING_GAP_SECONDS: int = ...
@@ -41,6 +42,10 @@ class _ProcessingArgs:
41
42
  ...
42
43
 
43
44
 
45
+ def _get_context() -> Optional[context.Context]:
46
+ ...
47
+
48
+
44
49
  def _handle_io_stream(io_stream, out_stream, args: _ProcessingArgs):
45
50
  ...
46
51
 
sky/task.py CHANGED
@@ -165,7 +165,8 @@ def _with_docker_login_config(
165
165
  f'ignored.{colorama.Style.RESET_ALL}')
166
166
  return resources
167
167
  # Already checked in extract_docker_image
168
- assert len(resources.image_id) == 1, resources.image_id
168
+ assert resources.image_id is not None and len(
169
+ resources.image_id) == 1, resources.image_id
169
170
  region = list(resources.image_id.keys())[0]
170
171
  return resources.copy(image_id={region: 'docker:' + docker_image},
171
172
  _docker_login_config=docker_login_config)
@@ -775,7 +776,7 @@ class Task:
775
776
  for _, storage_obj in self.storage_mounts.items():
776
777
  if storage_obj.mode in storage_lib.MOUNTABLE_STORAGE_MODES:
777
778
  for r in self.resources:
778
- r.requires_fuse = True
779
+ r.set_requires_fuse(True)
779
780
  break
780
781
 
781
782
  return self
@@ -931,7 +932,7 @@ class Task:
931
932
  self.storage_mounts = {}
932
933
  # Clear the requires_fuse flag if no storage mounts are set.
933
934
  for r in self.resources:
934
- r.requires_fuse = False
935
+ r.set_requires_fuse(False)
935
936
  return self
936
937
  for target, storage_obj in storage_mounts.items():
937
938
  # TODO(zhwu): /home/username/sky_workdir as the target path need
@@ -956,7 +957,7 @@ class Task:
956
957
  # If any storage is using MOUNT mode, we need to enable FUSE in
957
958
  # the resources.
958
959
  for r in self.resources:
959
- r.requires_fuse = True
960
+ r.set_requires_fuse(True)
960
961
  # Storage source validation is done in Storage object
961
962
  self.storage_mounts = storage_mounts
962
963
  return self
@@ -1234,13 +1235,14 @@ class Task:
1234
1235
 
1235
1236
  add_if_not_none('name', self.name)
1236
1237
 
1237
- tmp_resource_config = {}
1238
+ tmp_resource_config: Union[Dict[str, Union[str, int]],
1239
+ Dict[str, List[Dict[str, Union[str, int]]]]]
1238
1240
  if len(self.resources) > 1:
1239
1241
  resource_list = []
1240
1242
  for r in self.resources:
1241
1243
  resource_list.append(r.to_yaml_config())
1242
1244
  key = 'ordered' if isinstance(self.resources, list) else 'any_of'
1243
- tmp_resource_config[key] = resource_list
1245
+ tmp_resource_config = {key: resource_list}
1244
1246
  else:
1245
1247
  tmp_resource_config = list(self.resources)[0].to_yaml_config()
1246
1248
 
@@ -105,6 +105,7 @@ file_mounts: {
105
105
  "{{sky_remote_path}}/{{sky_wheel_hash}}": "{{sky_local_path}}",
106
106
  {%- for remote_path, local_path in credentials.items() %}
107
107
  "{{remote_path}}": "{{local_path}}",
108
+ "~/.ssh/sky-cluster-key": "{{ssh_private_key}}",
108
109
  {%- endfor %}
109
110
  }
110
111
 
@@ -120,6 +121,7 @@ initialization_commands: []
120
121
  # Increment the following for catching performance bugs easier:
121
122
  # current num items (num SSH connections): 1
122
123
  setup_commands:
124
+ # Add ~/.ssh/sky-cluster-key to SSH config to allow nodes within a cluster to connect to each other
123
125
  # Disable `unattended-upgrades` to prevent apt-get from hanging. It should be called at the beginning before the process started to avoid being blocked. (This is a temporary fix.)
124
126
  # Create ~/.ssh/config file in case the file does not exist in the image.
125
127
  # Line 'rm ..': there is another installation of pip.
@@ -142,6 +144,6 @@ setup_commands:
142
144
  {{ ray_skypilot_installation_commands }}
143
145
  sudo bash -c 'rm -rf /etc/security/limits.d; echo "* soft nofile 1048576" >> /etc/security/limits.conf; echo "* hard nofile 1048576" >> /etc/security/limits.conf';
144
146
  sudo grep -e '^DefaultTasksMax' /etc/systemd/system.conf || (sudo bash -c 'echo "DefaultTasksMax=infinity" >> /etc/systemd/system.conf'); sudo systemctl set-property user-$(id -u $(whoami)).slice TasksMax=infinity; sudo systemctl daemon-reload;
145
- mkdir -p ~/.ssh; (grep -Pzo -q "Host \*\n StrictHostKeyChecking no" ~/.ssh/config) || printf "Host *\n StrictHostKeyChecking no\n" >> ~/.ssh/config;
147
+ mkdir -p ~/.ssh; (grep -Pzo -q "Host \*\n StrictHostKeyChecking no\n IdentityFile ~/.ssh/sky-cluster-key\n IdentityFile ~/.ssh/id_rsa" ~/.ssh/config) || printf "Host *\n StrictHostKeyChecking no\n IdentityFile ~/.ssh/sky-cluster-key\n IdentityFile ~/.ssh/id_rsa\n" >> ~/.ssh/config;
146
148
  [ -f /etc/fuse.conf ] && sudo sed -i 's/#user_allow_other/user_allow_other/g' /etc/fuse.conf || (sudo sh -c 'echo "user_allow_other" > /etc/fuse.conf');
147
149
  {{ ssh_max_sessions_config }}
@@ -201,12 +201,13 @@ def show_cost_report_table(cluster_records: List[_ClusterCostReportRecord],
201
201
  controller = controller_utils.Controllers.from_name(controller_name)
202
202
  if controller is None:
203
203
  raise ValueError(f'Controller {controller_name} not found.')
204
- autostop_minutes, _ = (
205
- controller_utils.get_controller_autostop_config(
206
- controller=controller))
207
- if autostop_minutes is not None:
204
+ controller_handle: backends.CloudVmRayResourceHandle = (
205
+ cluster_records[0]['handle'])
206
+ autostop_config = (
207
+ controller_handle.launched_resources.autostop_config)
208
+ if autostop_config is not None:
208
209
  autostop_str = (f'{colorama.Style.DIM} (will be autostopped if '
209
- f'idle for {autostop_minutes}min)'
210
+ f'idle for {autostop_config.idle_minutes}min)'
210
211
  f'{colorama.Style.RESET_ALL}')
211
212
  click.echo(f'\n{colorama.Fore.CYAN}{colorama.Style.BRIGHT}'
212
213
  f'{controller_name}{colorama.Style.RESET_ALL}'
@@ -6,7 +6,7 @@ import getpass
6
6
  import os
7
7
  import tempfile
8
8
  import typing
9
- from typing import Any, Dict, Iterable, List, Optional, Set, Tuple
9
+ from typing import Any, Dict, Iterable, List, Optional, Set
10
10
  import uuid
11
11
 
12
12
  import colorama
@@ -517,6 +517,30 @@ def get_controller_resources(
517
517
  if custom_controller_resources_config is not None:
518
518
  controller_resources_config_copied.update(
519
519
  custom_controller_resources_config)
520
+ # Compatibility with the old way of specifying the controller autostop
521
+ # config. TODO(cooperc): Remove this before 0.12.0.
522
+ custom_controller_autostop_config = skypilot_config.get_nested(
523
+ (controller.value.controller_type, 'controller', 'autostop'), None)
524
+ if custom_controller_autostop_config is not None:
525
+ logger.warning(
526
+ f'{colorama.Fore.YELLOW}Warning: Config value '
527
+ f'`{controller.value.controller_type}.controller.autostop` '
528
+ 'is deprecated. Please use '
529
+ f'`{controller.value.controller_type}.controller.resources.'
530
+ f'autostop` instead.{colorama.Style.RESET_ALL}')
531
+ # Only set the autostop config if it is not already specified.
532
+ if controller_resources_config_copied.get('autostop') is None:
533
+ controller_resources_config_copied['autostop'] = (
534
+ custom_controller_autostop_config)
535
+ else:
536
+ logger.warning(f'{colorama.Fore.YELLOW}Ignoring the old '
537
+ 'config, since it is already specified in '
538
+ f'resources.{colorama.Style.RESET_ALL}')
539
+ # Set the default autostop config for the controller, if not already
540
+ # specified.
541
+ if controller_resources_config_copied.get('autostop') is None:
542
+ controller_resources_config_copied['autostop'] = (
543
+ controller.value.default_autostop_config)
520
544
 
521
545
  try:
522
546
  controller_resources = resources.Resources.from_yaml_config(
@@ -547,7 +571,10 @@ def get_controller_resources(
547
571
  if controller_record is not None:
548
572
  handle = controller_record.get('handle', None)
549
573
  if handle is not None:
550
- controller_resources_to_use = handle.launched_resources
574
+ # Use the existing resources, but override the autostop config with
575
+ # the one currently specified in the config.
576
+ controller_resources_to_use = handle.launched_resources.copy(
577
+ autostop=controller_resources_config_copied.get('autostop'))
551
578
 
552
579
  # If the controller and replicas are from the same cloud (and region/zone),
553
580
  # it should provide better connectivity. We will let the controller choose
@@ -608,8 +635,9 @@ def get_controller_resources(
608
635
  controller_zone = controller_resources_to_use.zone
609
636
 
610
637
  # Filter clouds if controller_resources_to_use.cloud is specified.
611
- filtered_clouds = ({controller_cloud} if controller_cloud is not None else
612
- requested_clouds_with_region_zone.keys())
638
+ filtered_clouds: Set[str] = {controller_cloud
639
+ } if controller_cloud is not None else set(
640
+ requested_clouds_with_region_zone.keys())
613
641
 
614
642
  # Filter regions and zones and construct the result.
615
643
  result: Set[resources.Resources] = set()
@@ -618,15 +646,17 @@ def get_controller_resources(
618
646
  {None: {None}})
619
647
 
620
648
  # Filter regions if controller_resources_to_use.region is specified.
621
- filtered_regions = ({controller_region} if controller_region is not None
622
- else regions.keys())
649
+ filtered_regions: Set[Optional[str]] = ({
650
+ controller_region
651
+ } if controller_region is not None else set(regions.keys()))
623
652
 
624
653
  for region in filtered_regions:
625
654
  zones = regions.get(region, {None})
626
655
 
627
656
  # Filter zones if controller_resources_to_use.zone is specified.
628
- filtered_zones = ({controller_zone}
629
- if controller_zone is not None else zones)
657
+ filtered_zones: Set[Optional[str]] = ({
658
+ controller_zone
659
+ } if controller_zone is not None else set(zones))
630
660
 
631
661
  # Create combinations of cloud, region, and zone.
632
662
  for zone in filtered_zones:
@@ -641,40 +671,6 @@ def get_controller_resources(
641
671
  return result
642
672
 
643
673
 
644
- def get_controller_autostop_config(
645
- controller: Controllers) -> Tuple[Optional[int], bool]:
646
- """Get the autostop config for the controller.
647
-
648
- Returns:
649
- A tuple of (idle_minutes_to_autostop, down), which correspond to the
650
- values passed to execution.launch().
651
- """
652
- controller_autostop_config_copied: Dict[str, Any] = copy.copy(
653
- controller.value.default_autostop_config)
654
- if skypilot_config.loaded():
655
- custom_controller_autostop_config = skypilot_config.get_nested(
656
- (controller.value.controller_type, 'controller', 'autostop'), None)
657
- if custom_controller_autostop_config is False:
658
- # Disabled with `autostop: false` in config.
659
- # To indicate autostop is disabled, we return None for
660
- # idle_minutes_to_autostop.
661
- return None, False
662
- elif custom_controller_autostop_config is True:
663
- # Enabled with default values. There is no change in behavior, but
664
- # this is included by for completeness, since `False` is valid.
665
- pass
666
- elif custom_controller_autostop_config is not None:
667
- # We have specific config values.
668
- # Override the controller autostop config with the ones specified in
669
- # the config.
670
- assert isinstance(custom_controller_autostop_config, dict)
671
- controller_autostop_config_copied.update(
672
- custom_controller_autostop_config)
673
-
674
- return (controller_autostop_config_copied['idle_minutes'],
675
- controller_autostop_config_copied['down'])
676
-
677
-
678
674
  def _setup_proxy_command_on_controller(
679
675
  controller_launched_cloud: 'clouds.Cloud',
680
676
  user_config: Dict[str, Any]) -> config_utils.Config:
@@ -703,7 +699,7 @@ def _setup_proxy_command_on_controller(
703
699
  # NOTE: suppose that we have a controller in old VPC, then user
704
700
  # changes 'vpc_name' in the config and does a 'job launch' /
705
701
  # 'serve up'. In general, the old controller may not successfully
706
- # launch the job in the new VPC. This happens if the two VPCs dont
702
+ # launch the job in the new VPC. This happens if the two VPCs don't
707
703
  # have peering set up. Like other places in the code, we assume
708
704
  # properly setting up networking is user's responsibilities.
709
705
  # TODO(zongheng): consider adding a basic check that checks
sky/utils/dag_utils.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """Utilities for loading and dumping DAGs from/to YAML files."""
2
2
  import copy
3
- from typing import Any, Dict, List, Optional, Tuple
3
+ from typing import Any, Dict, List, Optional, Tuple, Union
4
4
 
5
5
  from sky import dag as dag_lib
6
6
  from sky import sky_logging
@@ -195,7 +195,9 @@ def fill_default_config_in_dag_for_job_launch(dag: dag_lib.Dag) -> None:
195
195
  assert default_strategy is not None
196
196
  for resources in list(task_.resources):
197
197
  original_job_recovery = resources.job_recovery
198
- job_recovery = {'strategy': default_strategy}
198
+ job_recovery: Dict[str, Optional[Union[str, int]]] = {
199
+ 'strategy': default_strategy
200
+ }
199
201
  if isinstance(original_job_recovery, str):
200
202
  job_recovery['strategy'] = original_job_recovery
201
203
  elif isinstance(original_job_recovery, dict):
@@ -140,10 +140,12 @@ def simplify_ports(ports: List[str]) -> List[str]:
140
140
  def format_resource(resource: 'resources_lib.Resources',
141
141
  simplify: bool = False) -> str:
142
142
  if simplify:
143
+ resource = resource.assert_launchable()
143
144
  cloud = resource.cloud
144
145
  if resource.accelerators is None:
145
146
  vcpu, _ = cloud.get_vcpus_mem_from_instance_type(
146
147
  resource.instance_type)
148
+ assert vcpu is not None, 'vCPU must be specified'
147
149
  hardware = f'vCPU={int(vcpu)}'
148
150
  else:
149
151
  hardware = f'{resource.accelerators}'
@@ -248,6 +250,7 @@ def make_launchables_for_valid_region_zones(
248
250
  launchables = []
249
251
  regions = launchable_resources.get_valid_regions_for_launchable()
250
252
  for region in regions:
253
+ assert launchable_resources.cloud is not None, 'Cloud must be specified'
251
254
  optimize_by_zone = (override_optimize_by_zone or
252
255
  launchable_resources.cloud.optimize_by_zone())
253
256
  # It is possible that we force the optimize_by_zone but some clouds
sky/utils/schemas.py CHANGED
@@ -33,6 +33,37 @@ def _check_not_both_fields_present(field1: str, field2: str):
33
33
  }
34
34
 
35
35
 
36
+ _AUTOSTOP_SCHEMA = {
37
+ 'anyOf': [
38
+ {
39
+ # Use boolean to disable autostop completely, e.g.
40
+ # autostop: false
41
+ 'type': 'boolean',
42
+ },
43
+ {
44
+ # Shorthand to set idle_minutes by directly specifying, e.g.
45
+ # autostop: 5
46
+ 'type': 'integer',
47
+ 'minimum': 0,
48
+ },
49
+ {
50
+ 'type': 'object',
51
+ 'required': [],
52
+ 'additionalProperties': False,
53
+ 'properties': {
54
+ 'idle_minutes': {
55
+ 'type': 'integer',
56
+ 'minimum': 0,
57
+ },
58
+ 'down': {
59
+ 'type': 'boolean',
60
+ },
61
+ },
62
+ },
63
+ ],
64
+ }
65
+
66
+
36
67
  def _get_single_resources_schema():
37
68
  """Schema for a single resource in a resources list."""
38
69
  # To avoid circular imports, only import when needed.
@@ -165,6 +196,7 @@ def _get_single_resources_schema():
165
196
  'type': 'null',
166
197
  }]
167
198
  },
199
+ 'autostop': _AUTOSTOP_SCHEMA,
168
200
  # The following fields are for internal use only. Should not be
169
201
  # specified in the task config.
170
202
  '_docker_login_config': {
@@ -725,29 +757,6 @@ def get_config_schema():
725
757
  if k != '$schema'
726
758
  }
727
759
  resources_schema['properties'].pop('ports')
728
- autostop_schema = {
729
- 'anyOf': [
730
- {
731
- # Use boolean to disable autostop completely, e.g.
732
- # autostop: false
733
- 'type': 'boolean',
734
- },
735
- {
736
- 'type': 'object',
737
- 'required': [],
738
- 'additionalProperties': False,
739
- 'properties': {
740
- 'idle_minutes': {
741
- 'type': 'integer',
742
- 'minimum': 0,
743
- },
744
- 'down': {
745
- 'type': 'boolean',
746
- },
747
- },
748
- },
749
- ],
750
- }
751
760
  controller_resources_schema = {
752
761
  'type': 'object',
753
762
  'required': [],
@@ -762,7 +771,7 @@ def get_config_schema():
762
771
  'high_availability': {
763
772
  'type': 'boolean',
764
773
  },
765
- 'autostop': autostop_schema,
774
+ 'autostop': _AUTOSTOP_SCHEMA,
766
775
  }
767
776
  },
768
777
  'bucket': {
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skypilot-nightly
3
- Version: 1.0.0.dev20250513
3
+ Version: 1.0.0.dev20250515
4
4
  Summary: SkyPilot: Run AI on Any Infra — Unified, Faster, Cheaper.
5
5
  Author: SkyPilot Team
6
6
  License: Apache 2.0