Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 153 additions & 3 deletions studio/install_llama_prebuilt.py
Original file line number Diff line number Diff line change
Expand Up @@ -2355,10 +2355,9 @@ def pinned_published_release_bundle(
return bundle


def validated_checksums_for_bundle(
repo: str, bundle: PublishedReleaseBundle
def _validate_checksums_against_bundle(
repo: str, bundle: PublishedReleaseBundle, checksums: ApprovedReleaseChecksums
) -> ApprovedReleaseChecksums:
checksums = load_approved_release_checksums(repo, bundle.release_tag)
manifest_hash = checksums.artifacts.get(bundle.manifest_asset_name)
if manifest_hash is not None and bundle.manifest_sha256 is not None:
if manifest_hash.sha256 != bundle.manifest_sha256:
Expand All @@ -2382,6 +2381,129 @@ def validated_checksums_for_bundle(
return checksums


def validated_checksums_for_bundle(
repo: str, bundle: PublishedReleaseBundle
) -> ApprovedReleaseChecksums:
checksums = load_approved_release_checksums(repo, bundle.release_tag)
return _validate_checksums_against_bundle(repo, bundle, checksums)


def _download_host_resolve_enabled() -> bool:
"""Escape hatch to force the legacy GitHub API path instead of the
download-host fast path (which avoids the api.github.com rate limit)."""
return os.environ.get(
"UNSLOTH_LLAMA_DISABLE_DOWNLOAD_HOST_RESOLVE", ""
).strip().lower() not in {"1", "true", "yes", "on"}


def _release_asset_download_url(repo: str, tag: str, asset_name: str) -> str:
"""Tag-pinned asset URL on the release-assets CDN (not api.github.com, so no
rate limit)."""
return (
f"https://github.com/{urllib.parse.quote(repo, safe = '/')}/releases/download/"
f"{urllib.parse.quote(tag, safe = '')}/"
f"{urllib.parse.quote(asset_name, safe = '')}"
)


def _download_host_latest_release_tag(repo: str) -> str | None:
"""Authoritative latest tag from GitHub's /releases/latest redirect target
(github.com, no api.github.com rate limit); the fast path pins URLs to it rather
than the checksum asset's self-reported release_tag. /releases/latest resolves by
created_at/make_latest, which can lag the published_at newest the freshness
detection uses. None on 404 so the caller falls back to the API."""
url = f"https://github.com/{urllib.parse.quote(repo, safe = '/')}/releases/latest"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve latest by published_at in the fast path

On default-repo latest installs this pins the fast path to GitHub's /releases/latest redirect, but studio/backend/utils/llama_cpp_freshness.py still resolves latest as the non-draft/non-prerelease release with the maximum published_at and explicitly avoids that pointer. When GitHub's latest pointer lags or is manually set, --resolve-prebuilt/install can install the older redirected release while the update checker reports the newer published release, recreating the sticky update/downgrade behavior the freshness code is designed to avoid.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A published_at-correct resolution only exists in the api.github.com response, so it cannot be reproduced from the CDN in a zero-API path. The fast path pins to the verified /releases/latest redirect tag; the residual created_at/make_latest vs published_at divergence is called out in the _download_host_latest_release_tag docstring and is mitigated: today /releases/latest for unslothai/llama.cpp equals the published_at newest (GitHub's semver tiebreak), and is_behind()'s base-build guard prevents a divergence from surfacing as the downgrade / sticky "update available" banner the freshness code guards against. UNSLOTH_LLAMA_DISABLE_DOWNLOAD_HOST_RESOLVE=1 forces the published_at API path if a future release stream ever makes it matter.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve published_at latest semantics

When GitHub's /releases/latest pointer is behind the newest published_at release (the case the freshness helper explicitly handles in studio/backend/utils/llama_cpp_freshness.py:109-155), this fast path now installs the older redirect tag and returns before the API enumeration that previously matched freshness. The backend will still report the newer published release as available, so applying an update can leave the banner stuck or cause repeated/downgrade attempts for users in that repo state; the CDN path needs to select the same published_at-newest tag or the freshness code must be changed with it.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A published_at-correct resolution only exists in the api.github.com response, so it cannot be reproduced from the CDN in a zero-API path. The fast path pins to the verified /releases/latest redirect tag; the residual created_at/make_latest vs published_at divergence is called out in the _download_host_latest_release_tag docstring and is mitigated: today /releases/latest for unslothai/llama.cpp equals the published_at newest (GitHub's semver tiebreak), and is_behind()'s base-build guard prevents a divergence from surfacing as the downgrade / sticky "update available" banner the freshness code guards against. UNSLOTH_LLAMA_DISABLE_DOWNLOAD_HOST_RESOLVE=1 forces the published_at API path if a future release stream ever makes it matter.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep latest resolution aligned with freshness

For default latest installs this switches the resolver to GitHub's /releases/latest pointer, but the adjacent comment notes that pointer can lag the newest published_at release, and studio/backend/utils/llama_cpp_freshness.py deliberately avoids it because that mismatch caused stale/downgrade banners. In that lag window the fast path installs the older pointer target and returns before the API enumeration can find the newest published prebuilt, so users can still be prompted to update immediately after an update/install.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A published_at-correct resolution only exists in the api.github.com response, so it cannot be reproduced from the CDN in a zero-API path. The fast path pins to the verified /releases/latest redirect tag; the residual created_at/make_latest vs published_at divergence is called out in the _download_host_latest_release_tag docstring and is mitigated: today /releases/latest for unslothai/llama.cpp equals the published_at newest (GitHub's semver tiebreak), and is_behind()'s base-build guard prevents a divergence from surfacing as the downgrade / sticky "update available" banner the freshness code guards against. UNSLOTH_LLAMA_DISABLE_DOWNLOAD_HOST_RESOLVE=1 forces the published_at API path if a future release stream ever makes it matter.

request = urllib.request.Request(
url,
method = "HEAD",
headers = {"User-Agent": "unsloth-studio-llama-prebuilt"},
)
try:
with _URL_OPENER.open(request, timeout = 30) as response:
final_url = response.geturl()
except urllib.error.HTTPError as exc:
if exc.code == 404:
return None
raise
marker = "/releases/tag/"
index = final_url.find(marker)
if index == -1:
return None
tag = urllib.parse.unquote(final_url[index + len(marker) :]).strip("/")
return tag or None


def _fetch_download_host_json(url: str) -> Any:
# Public CDN asset: plain unauthenticated GET, not the rate-limited API.
data = download_bytes(
url,
timeout = 30,
headers = {"User-Agent": "unsloth-studio-llama-prebuilt"},
)
return json.loads(data.decode("utf-8"))


def _download_host_resolved_release(repo: str) -> ResolvedPublishedRelease | None:
"""Resolve the latest fork release from the download host with zero
api.github.com calls, reusing the API path's parsing and validation. The latest
tag is the authoritative /releases/latest redirect tag, and the checksum asset's
self-reported release_tag is cross-checked against it. Returns None (caller falls
back to the API) on a missing JSON asset or a tag mismatch."""
release_tag = _download_host_latest_release_tag(repo)
if not release_tag:
return None
sha_url = _release_asset_download_url(repo, release_tag, DEFAULT_PUBLISHED_SHA256_ASSET)
try:
sha_payload = _fetch_download_host_json(sha_url)
except urllib.error.HTTPError as exc:
if exc.code == 404:
return None
raise
if not isinstance(sha_payload, dict):
return None
# Cross-check the asset's self-reported release_tag against the authoritative
# redirect tag: parse_approved_release_checksums raises on a mismatch.
checksums = parse_approved_release_checksums(repo, release_tag, sha_payload)
# Synthesize the API release payload with tag-pinned CDN URLs for every named
# asset; parse_published_release_bundle then reads the manifest, still no API.
asset_names = set(checksums.artifacts) | {
DEFAULT_PUBLISHED_MANIFEST_ASSET,
DEFAULT_PUBLISHED_SHA256_ASSET,
}
synthetic_release: dict[str, Any] = {
"tag_name": release_tag,
"draft": False,
"prerelease": False,
"assets": [
{
"name": name,
"browser_download_url": _release_asset_download_url(repo, release_tag, name),
}
Comment on lines +2477 to +2481

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not fabricate availability for unchecked assets

If the latest manifest/checksum JSON advertises an asset whose upload failed or was deleted, this synthetic release map still invents a browser_download_url for it, so the normal selectors treat the binary as present and only discover the 404/hash failure during installation. The API path used the real release asset list, so the same release would skip the missing asset during planning and could report no prebuilt or try another candidate instead of failing after selection.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This only triggers on a malformed or incomplete release (the manifest or checksum JSON names an asset that was never uploaded or was deleted). It cannot install an unverified binary: every download is sha256-checked (download_file_verified) and apply_approved_hashes fails closed. The only difference from the API path is discovering the missing asset at download time rather than during planning, after which validate_prebuilt_attempts moves to the next attempt / source build exactly as the API path would. The real asset list only exists in the api.github.com response, so this cannot be tightened without the call the fast path exists to avoid; it is noted as an accepted tradeoff in the doc.

for name in sorted(asset_names)
],
}
try:
bundle = parse_published_release_bundle(repo, synthetic_release)
except urllib.error.HTTPError as exc:
# In-progress release: the checksum asset can land before the manifest;
# treat a manifest 404 like the sha256 404 above and fall back to the API.
if exc.code == 404:
return None
raise
if bundle is None:
return None
# A manifest artifact can be keyed in the checksum JSON under an upstream-tag
# alias, so add a tag-pinned URL for any manifest artifact missing above (the
# API path gets these from the real asset list); sha256 is still verified.
for artifact in bundle.artifacts:
bundle.assets.setdefault(
artifact.asset_name,
_release_asset_download_url(repo, release_tag, artifact.asset_name),
Comment on lines +2498 to +2501

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid treating manifest-only assets as uploaded

When the latest release is partially published or the manifest contains a stale/typoed artifact, this adds a download URL for every manifest artifact even if that asset is not actually present on the GitHub release. The existing API path only exposes names from the release asset list, so selectors skip missing artifacts via release.assets.get(...); the fast path can instead select a non-existent targeted bundle and only fail later with a 404, bypassing an available fallback asset in the same release or falling straight to source build.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I verified the sharper form of this (a partial-publish best-fit falling through to another in-release asset on the API path but not the fast path), and it is a real behavioral difference in theory, but it is unreachable on the fork's real release input, so it stays below the fix bar.

Why it cannot be observed in practice:

  • The fork uploads llama-prebuilt-manifest.json and llama-prebuilt-sha256.json LAST, after every binary, and marks the release published only after that. On the current latest (b9987-mix-53618c5) all 38 binaries uploaded at 01:33:58-01:34:52, both JSONs at 01:34:53, and the release published at 01:35:05.
  • The fast path only engages once it can fetch sha256.json AND /releases/latest resolves to the release. /releases/latest points at a release only once it is marked latest/published, and sha256.json is the last asset. So by the time the fast path can see the release, every asset its manifest/checksums reference is already present. There is no window where sha256.json lists a binary that is not yet uploaded.

Defense in depth if a future release tool ever changed that order:

  • Fail-closed install: an asset installs only if its name (or alias) is in the approved sha256.json (install_llama_prebuilt.py:6156); sha256.json is produced by hashing built files, so a manifest that over-lists a typoed/absent artifact has no approved hash and is dropped, never installed unverified.
  • Graceful degradation: a fabricated URL for a not-yet-uploaded binary 404s as a plain urllib HTTPError, caught at install_llama_prebuilt.py:6838 and wrapped into PrebuiltFallback -> next attempt -> source build; never a crash or a zero-byte install, and checksum verification still gates any 200.
  • Self-healing + opt-out: the state would clear the moment the release finishes uploading, and UNSLOTH_LLAMA_DISABLE_DOWNLOAD_HOST_RESOLVE=1 restores the API asset-list check for anyone who needs planning-time rejection.

Reproduced and bounded in an isolated sandbox: the API path skips the mid-upload best-fit and selects the second compatible in-release bundle while the fast path commits to the fabricated best-fit, and for a fully published release (the only state /releases/latest exposes) the two paths are identical for every host in the cuda12 overlap.

Comment on lines +2498 to +2501

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Verify manifest-only assets before planning them

Here the fast path turns every artifact listed in the manifest into a presumed release asset, but the selection code treats bundle.assets as evidence that the archive actually exists. In a partially published or malformed release where the manifest is present but one binary upload is missing, --resolve-prebuilt can report the asset as available and install will only fail later with a 404; the API path would not include that missing asset in release_asset_map and would skip or fall back instead.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I verified the sharper form of this (a partial-publish best-fit falling through to another in-release asset on the API path but not the fast path), and it is a real behavioral difference in theory, but it is unreachable on the fork's real release input, so it stays below the fix bar.

Why it cannot be observed in practice:

  • The fork uploads llama-prebuilt-manifest.json and llama-prebuilt-sha256.json LAST, after every binary, and marks the release published only after that. On the current latest (b9987-mix-53618c5) all 38 binaries uploaded at 01:33:58-01:34:52, both JSONs at 01:34:53, and the release published at 01:35:05.
  • The fast path only engages once it can fetch sha256.json AND /releases/latest resolves to the release. /releases/latest points at a release only once it is marked latest/published, and sha256.json is the last asset. So by the time the fast path can see the release, every asset its manifest/checksums reference is already present. There is no window where sha256.json lists a binary that is not yet uploaded.

Defense in depth if a future release tool ever changed that order:

  • Fail-closed install: an asset installs only if its name (or alias) is in the approved sha256.json (install_llama_prebuilt.py:6156); sha256.json is produced by hashing built files, so a manifest that over-lists a typoed/absent artifact has no approved hash and is dropped, never installed unverified.
  • Graceful degradation: a fabricated URL for a not-yet-uploaded binary 404s as a plain urllib HTTPError, caught at install_llama_prebuilt.py:6838 and wrapped into PrebuiltFallback -> next attempt -> source build; never a crash or a zero-byte install, and checksum verification still gates any 200.
  • Self-healing + opt-out: the state would clear the moment the release finishes uploading, and UNSLOTH_LLAMA_DISABLE_DOWNLOAD_HOST_RESOLVE=1 restores the API asset-list check for anyone who needs planning-time rejection.

Reproduced and bounded in an isolated sandbox: the API path skips the mid-upload best-fit and selects the second compatible in-release bundle while the fast path commits to the fabricated best-fit, and for a fully published release (the only state /releases/latest exposes) the two paths are identical for every host in the cuda12 overlap.

)
Comment on lines +2498 to +2502

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not fabricate missing release asset URLs

When the manifest is available before one of the binary assets is uploaded, or the manifest is stale, this unconditionally adds a tag-pinned URL for each manifest artifact even though the fast path never checked the release's real asset list. That bypasses the existing release.assets.get(...) missing-asset rejection used by the API path, so --resolve-prebuilt can report an unavailable prebuilt and installs can select a URL that only fails later with a 404 instead of rejecting the release during planning.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a real difference from the API path, but it is bounded to a transient in-progress-publish window and degrades to the same outcome, so it stays below the fix bar.

  • Fail-closed install: an asset is only ever installed if its name (or alias) is in the approved sha256.json (apply_approved_hashes, install_llama_prebuilt.py:6156). sha256.json is produced by hashing the built files, so in a finished release every hashed asset exists; a manifest that over-lists an artifact with no approved hash is dropped, never installed unverified.
  • Graceful degradation: a fabricated URL for a not-yet-uploaded binary 404s at download; download_file surfaces that as a plain urllib HTTPError, which validate_prebuilt_attempts catches (install_llama_prebuilt.py:6838) and wraps into PrebuiltFallback, moving to the next attempt and finally the source build. It is never a crash or a silent/zero-byte install, and checksum verification still gates any 200 response.
  • Net effect: for a host whose only covering asset is mid-upload, both paths end at the source build; the fast path just takes one doomed download first, and it self-heals the moment the release finishes uploading.

Verified in an isolated sandbox: the API path rejects the missing asset during planning while the fast path fabricates its URL (divergence reproduced), the fabricated URL 404s as a catchable HTTPError, a present asset with the wrong hash is still refused, and an artifact absent from sha256.json is dropped fail-closed.

The --resolve-prebuilt probe can briefly report the soon-to-exist URL during that window; UNSLOTH_LLAMA_DISABLE_DOWNLOAD_HOST_RESOLVE=1 restores the API asset-list check for anyone who needs planning-time rejection.

_validate_checksums_against_bundle(repo, bundle, checksums)
return ResolvedPublishedRelease(bundle = bundle, checksums = checksums)
Comment on lines +2494 to +2504

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Defensively wrap the call to parse_published_release_bundle in a try-except block to catch urllib.error.HTTPError with a 404 status code. Just like with the SHA256 asset, if the manifest asset is missing (e.g., during an incomplete or in-progress release publication), we should fail silently and return None to trigger the API fallback, rather than propagating the exception and logging a noisy/misleading warning message to the user.

Suggested change
return None
_validate_checksums_against_bundle(repo, bundle, checksums)
return ResolvedPublishedRelease(bundle = bundle, checksums = checksums)
try:
bundle = parse_published_release_bundle(repo, synthetic_release)
except urllib.error.HTTPError as exc:
if exc.code == 404:
return None
raise
if bundle is None:
return None

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 1d01768. The call to parse_published_release_bundle is now wrapped so a manifest 404 (an in-progress release that published the checksum asset before the manifest) returns None and falls back to the API, mirroring the sha256 404 handling, instead of surfacing the generic "resolve unavailable" warning.



def published_release_matches_request(bundle: PublishedReleaseBundle, requested_ref: str) -> bool:
if requested_ref == "latest":
return True
Expand Down Expand Up @@ -2448,6 +2570,8 @@ def iter_resolved_published_releases(
requested_tag: str | None,
published_repo: str,
published_release_tag: str = "",
*,
allow_download_host_fast_path: bool = True,
) -> Iterable[ResolvedPublishedRelease]:
repo = published_repo or DEFAULT_PUBLISHED_REPO
normalized_requested = normalized_requested_llama_tag(requested_tag)
Expand All @@ -2466,6 +2590,29 @@ def iter_resolved_published_releases(
)
return

# Fast path: resolve the fork's latest release from the download host (no
# api.github.com rate limit). It surfaces only the single latest release, so the
# caller disables it when the multi-release walk-back is needed (macOS skipping
# too-new prebuilts); a broken latest then drops to source build, not an older
# release. Any rejection/network error is non-fatal and falls through to the API.
if (
allow_download_host_fast_path
and repo == DEFAULT_PUBLISHED_REPO
and normalized_requested == "latest"
and _download_host_resolve_enabled()
):
try:
resolved = _download_host_resolved_release(repo)
except PrebuiltFallback as exc:
log(f"download-host latest release rejected for {repo} ({exc}); trying GitHub API")
resolved = None
except Exception as exc:
log(f"download-host latest resolve unavailable for {repo} ({exc}); trying GitHub API")
resolved = None
if resolved is not None:
yield resolved
return
Comment on lines +2613 to +2614

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep older fallback releases reachable from fast path

For latest installs of the default fork, returning immediately after the CDN-resolved latest release prevents _fork_manifest_release_plans from walking older releases when that bundle is incompatible with the host. This regresses the existing fallback path for cases such as older macOS hosts (which explicitly raise the limit via DEFAULT_MAX_MACOS_RELEASE_FALLBACKS) or a latest release that lacks a matching GPU/arch asset: the latest bundle is yielded, planning skips it, and no older usable release is ever considered.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

macOS is already excluded from the fast path (the caller passes allow_download_host_fast_path = not host.is_macos), so its DEFAULT_MAX_MACOS_RELEASE_FALLBACKS walk-back is preserved. On Windows/Linux the single-latest behavior is the documented, intentional tradeoff for a zero-API resolve: a latest release whose asset is unusable drops to a source build rather than an older release (the 2-deep fallback reduced to 1). That degrades to a source build, not a failure, and older tags are not enumerable from the CDN without the API this path exists to avoid.

Comment on lines +2612 to +2614

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve older-release walk-back after fast path

When the CDN-resolved latest release exists but has no usable asset for the current non-macOS host (for example a Linux CUDA host whose SM/runtime is not covered, or a release with no fork bundle), this early return prevents _fork_manifest_release_plans() from walking back through older releases even though that function still enables older-release fallback for all latest installs and continues after per-release PrebuiltFallback. The result is a source-build fallback where an older published prebuilt would previously be selected; the existing test_latest_skips_non_installable_release_and_keeps_searching behavior is bypassed because the new tests disable this fast path.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the intended, documented tradeoff (see the comments on iter_resolved_published_releases and _fork_manifest_release_plans). macOS keeps the full API walk-back: the caller passes allow_download_host_fast_path = not host.is_macos. On Windows/Linux the single-latest resolve degrades a broken latest to a source build rather than an older release, and the fork releases are comprehensive (the latest bundle covers every gfx/sm/arch/OS: gfx103X/110X/1150/1151/120X/908/90a, all CUDA lines, CPU, arm64, macOS), so the older-release fallback was effectively never exercised. Older tags are not enumerable from the CDN without the api.github.com calls this path exists to avoid. UNSLOTH_LLAMA_DISABLE_DOWNLOAD_HOST_RESOLVE=1 restores the API walk-back.

Comment on lines +2612 to +2614

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve older-release walk-back after CDN resolution

When the CDN fast path successfully resolves the latest release but that release is not installable for the host (for example a Linux/Windows latest manifest with no compatible GPU/CPU asset, or a latest plan that later fails validation), this early return prevents _fork_manifest_release_plans from seeing any older releases. The existing planner has allow_older_release_fallback for all latest installs and tests such as test_latest_skips_non_installable_release_and_keeps_searching cover skipping a bad latest release, but the new default path only disables the fast path on macOS, so Linux/Windows now source-build instead of trying the older valid prebuilt.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the intended, documented tradeoff (see the comments on iter_resolved_published_releases and _fork_manifest_release_plans). macOS keeps the full API walk-back: the caller passes allow_download_host_fast_path = not host.is_macos. On Windows/Linux the single-latest resolve degrades a broken latest to a source build rather than an older release, and the fork releases are comprehensive (the latest bundle covers every gfx/sm/arch/OS: gfx103X/110X/1150/1151/120X/908/90a, all CUDA lines, CPU, arm64, macOS), so the older-release fallback was effectively never exercised. Older tags are not enumerable from the CDN without the api.github.com calls this path exists to avoid. UNSLOTH_LLAMA_DISABLE_DOWNLOAD_HOST_RESOLVE=1 restores the API walk-back.


matched_any = False
skipped_invalid = 0
yielded_valid = False
Expand Down Expand Up @@ -6190,6 +6337,9 @@ def _fork_manifest_release_plans(
llama_tag,
published_repo,
published_release_tag,
# macOS relies on the multi-release walk-back to skip too-new prebuilts,
# which the single-latest download-host path cannot provide.
allow_download_host_fast_path = not host.is_macos,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve older-release fallback with the fast path

For non-macOS latest installs this enables the download-host path even though _fork_manifest_release_plans() still has allow_older_release_fallback set. That fast path yields only the latest release and then returns, while install_prebuilt() can only retry releases that were precomputed in release_plans; if the latest Linux/Windows bundle is missing, incompatible with the host, or fails validation/download, the installer now goes straight to source build instead of trying the older releases that the previous API enumeration collected up to DEFAULT_MAX_PREBUILT_RELEASE_FALLBACKS. Please either keep enumerating older releases after the fast-path latest candidate or disable the single-release fast path whenever the older-release fallback is needed.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the intended, documented tradeoff (see the comments on iter_resolved_published_releases and _fork_manifest_release_plans). macOS keeps the full API walk-back: the caller passes allow_download_host_fast_path = not host.is_macos. On Windows/Linux the single-latest resolve degrades a broken latest to a source build rather than an older release, and the fork releases are comprehensive (the latest bundle covers every gfx/sm/arch/OS: gfx103X/110X/1150/1151/120X/908/90a, all CUDA lines, CPU, arm64, macOS), so the older-release fallback was effectively never exercised. Older tags are not enumerable from the CDN without the api.github.com calls this path exists to avoid. UNSLOTH_LLAMA_DISABLE_DOWNLOAD_HOST_RESOLVE=1 restores the API walk-back.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve latest-release walk-back outside macOS

When latest is requested on Linux or Windows, _fork_manifest_release_plans still sets allow_older_release_fallback=True and callers expect up to DEFAULT_MAX_PREBUILT_RELEASE_FALLBACKS plans, but this passes allow_download_host_fast_path=True; the fast path yields only the latest release and returns. If that release has no compatible asset for the host (for example the existing test_latest_skips_non_installable_release_and_keeps_searching scenario), the planner exhausts the iterator and falls back to source build instead of trying the next older prebuilt.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the intended, documented tradeoff (see the comments on iter_resolved_published_releases and _fork_manifest_release_plans). macOS keeps the full API walk-back: the caller passes allow_download_host_fast_path = not host.is_macos. On Windows/Linux the single-latest resolve degrades a broken latest to a source build rather than an older release, and the fork releases are comprehensive (the latest bundle covers every gfx/sm/arch/OS: gfx103X/110X/1150/1151/120X/908/90a, all CUDA lines, CPU, arm64, macOS), so the older-release fallback was effectively never exercised. Older tags are not enumerable from the CDN without the api.github.com calls this path exists to avoid. UNSLOTH_LLAMA_DISABLE_DOWNLOAD_HOST_RESOLVE=1 restores the API walk-back.

):
bundle = resolved_release.bundle
checksums = resolved_release.checksums
Expand Down
Loading
Loading