Studio Hub: default downloads to Xet transport (#6433)

* Studio Hub: default downloads to Xet transport

Model and dataset downloads defaulted to HTTP; flip the default to Xet for faster parallel chunked transfers.

- Frontend: DEFAULT_TRANSPORT_MODE is now Xet, so a user with no saved preference starts on Xet. effectiveTransportMode() already downgrades to HTTP and warns when hf_xet is unavailable, so this degrades gracefully.
- Backend: DownloadModelRequest.use_xet and DownloadDatasetRequest.use_xet default to True, keeping the API in step with the UI. Set use_xet=False for sequential HTTP Range-resume.
- Align the internal _spawn_download_worker default so no caller silently falls back to HTTP.

Inference and training model loads were already Xet-first with an HTTP stall fallback, so this brings explicit downloads in line with the rest of Studio.

* Studio Hub: gracefully fall back to HTTP when Xet is unavailable

With Xet now the default, an omitted or explicit use_xet=True from a non-UI API caller would 400 on installs without hf_xet, since resolve_transport raises when the transport is unavailable.

Add resolve_effective_use_xet(), which downgrades a Xet request to HTTP (with a warning) when hf_xet is missing, mirroring the frontend's own downgrade. Both the model and dataset flows now derive a single effective use_xet and feed it to resolve_transport and spawn_worker, so the recorded transport and the worker env can never disagree. The UI is unaffected: it already resolves availability and passes use_xet explicitly.

* Add tests for resolve_effective_use_xet Xet to HTTP fallback

* Trim comments for PR #6433

---------

Co-authored-by: Daniel Han <danielhanchen@gmail.com>
This commit is contained in:
Michael Han 2026-06-18 04:39:07 -07:00 committed by GitHub
commit 93572648b6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 57 additions and 10 deletions

View file

@ -25,8 +25,8 @@ class DownloadModelRequest(BaseModel):
description = "Quantization label (e.g. 'Q4_K_M'). Required for GGUF repos.",
)
use_xet: bool = Field(
False,
description = "Enable Xet parallel chunked transport. Default False uses HTTP Range-resume.",
True,
description = "Use Xet parallel chunked transport. Default True; set False for HTTP Range-resume.",
)
@ -125,8 +125,8 @@ class DownloadDatasetRequest(BaseModel):
repo_id: str = Field(..., description = "HuggingFace dataset repo ID")
use_xet: bool = Field(
False,
description = "Enable Xet parallel chunked transport. Default False uses HTTP Range-resume.",
True,
description = "Use Xet parallel chunked transport. Default True; set False for HTTP Range-resume.",
)

View file

@ -157,7 +157,8 @@ async def download_dataset_response(
repo_id = await asyncio.to_thread(resolve_cached_repo_id_case, repo_id, repo_type = "dataset")
key = _download_job_key(repo_id)
transport = download_lifecycle.resolve_transport(body.use_xet)
use_xet = download_lifecycle.resolve_effective_use_xet(body.use_xet)
transport = download_lifecycle.resolve_transport(use_xet)
claimed, claim_state = _registry.claim(
key,
@ -183,7 +184,7 @@ async def download_dataset_response(
spawn = lambda: download_lifecycle.spawn_worker(
["--repo-id", repo_id, "--dataset"],
hf_token,
use_xet = body.use_xet,
use_xet = use_xet,
),
hf_token = hf_token,
label = repo_id,

View file

@ -3,6 +3,7 @@
from __future__ import annotations
import logging
import os
import signal
import subprocess
@ -20,11 +21,27 @@ from hub.utils import inventory_scan as hf_cache_scan
from hub.utils.hf_cache_state import EXIT_CANCELLED
from hub.utils.state_dir import RepoType
logger = logging.getLogger(__name__)
def backend_dir() -> Path:
return Path(__file__).resolve().parent.parent.parent
def resolve_effective_use_xet(use_xet: bool) -> bool:
"""Downgrade an Xet request to HTTP when hf_xet is unavailable, so a defaulted
or explicit Xet request never hard-fails on installs without the Xet extra."""
if not use_xet:
return False
reason = download_registry.download_transport_unavailable_reason(
download_registry.TRANSPORT_XET
)
if reason is None:
return True
logger.warning("Xet transport unavailable, falling back to HTTP: %s", reason)
return False
def resolve_transport(use_xet: bool) -> str:
transport = download_registry.TRANSPORT_XET if use_xet else download_registry.TRANSPORT_HTTP
unavailable_reason = download_registry.download_transport_unavailable_reason(transport)

View file

@ -64,7 +64,7 @@ def _spawn_download_worker(
repo_id: str,
variant: Optional[str],
hf_token: Optional[str],
use_xet: bool = False,
use_xet: bool = True,
protected_blob_hashes: Optional[frozenset[str]] = None,
) -> subprocess.Popen:
args = ["--repo-id", repo_id]
@ -96,7 +96,8 @@ async def download_model_response(body: DownloadModelRequest, hf_token: Optional
detail = f"Invalid gguf_variant: {variant!r}",
)
key = _download_job_key(repo_id, variant)
transport = download_lifecycle.resolve_transport(body.use_xet)
use_xet = download_lifecycle.resolve_effective_use_xet(body.use_xet)
transport = download_lifecycle.resolve_transport(use_xet)
variant_blob_hashes = frozenset()
variant_progress_blob_hashes = frozenset()
completed_baseline_bytes = 0
@ -171,7 +172,7 @@ async def download_model_response(body: DownloadModelRequest, hf_token: Optional
repo_id,
variant,
hf_token,
use_xet = body.use_xet,
use_xet = use_xet,
protected_blob_hashes = protected_blob_hashes,
),
hf_token = hf_token,

View file

@ -0,0 +1,27 @@
# SPDX-License-Identifier: AGPL-3.0-only
# Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
from hub.services import download_lifecycle
def _set_xet_reason(monkeypatch, reason):
monkeypatch.setattr(
download_lifecycle.download_registry,
"download_transport_unavailable_reason",
lambda _transport: reason,
)
def test_resolve_effective_use_xet_keeps_http_when_not_requested(monkeypatch):
_set_xet_reason(monkeypatch, "should not be consulted")
assert download_lifecycle.resolve_effective_use_xet(False) is False
def test_resolve_effective_use_xet_keeps_xet_when_available(monkeypatch):
_set_xet_reason(monkeypatch, None)
assert download_lifecycle.resolve_effective_use_xet(True) is True
def test_resolve_effective_use_xet_downgrades_when_xet_unavailable(monkeypatch):
_set_xet_reason(monkeypatch, "Xet transport is unavailable because hf_xet is not installed.")
assert download_lifecycle.resolve_effective_use_xet(True) is False

View file

@ -8,7 +8,8 @@ export const TRANSPORT = {
export const TRANSPORT_MODES = [TRANSPORT.HTTP, TRANSPORT.XET] as const;
export type TransportMode = (typeof TRANSPORT_MODES)[number];
export const DEFAULT_TRANSPORT_MODE: TransportMode = TRANSPORT.HTTP;
// Xet by default; effectiveTransportMode() downgrades to HTTP if hf_xet is missing.
export const DEFAULT_TRANSPORT_MODE: TransportMode = TRANSPORT.XET;
export function isTransportMode(value: unknown): value is TransportMode {
return (