From b0dff621b6f473b7152178c5b65e01363e4f0573 Mon Sep 17 00:00:00 2001 From: shimmyshimmer Date: Thu, 11 Jun 2026 10:16:40 -0700 Subject: [PATCH 1/2] Fix llama.cpp update banner offering a downgrade when /releases/latest lags The update banner decided update_available with a plain tag inequality (installed != latest). GitHub's /releases/latest endpoint sorts by the commit date of the release target, not by build number, so when fork releases land out of order it can return an older build than the one the installer just resolved from upstream. Users then saw a persistent banner like b9596 -> b9594 right after updating, which looks like a downgrade prompt and never goes away. Compare bNNNN build numbers on the prebuilt marker path (mirroring what the source-build path already did) and only offer real upgrades, with tag inequality kept as the fallback for non-bNNNN tags. Apply the same guard to the freshness stale flag so the CLI warning cannot report a downgrade either. Reported in https://www.reddit.com/r/unsloth/comments/1u34fa3/ --- .../backend/tests/test_llama_cpp_freshness.py | 28 +++++++++++++++++++ studio/backend/tests/test_llama_cpp_update.py | 20 +++++++++++++ studio/backend/utils/llama_cpp_freshness.py | 17 +++++++++++ studio/backend/utils/llama_cpp_update.py | 15 ++++++++-- 4 files changed, 78 insertions(+), 2 deletions(-) diff --git a/studio/backend/tests/test_llama_cpp_freshness.py b/studio/backend/tests/test_llama_cpp_freshness.py index cb17e0d5e7..7f7a433494 100644 --- a/studio/backend/tests/test_llama_cpp_freshness.py +++ b/studio/backend/tests/test_llama_cpp_freshness.py @@ -222,6 +222,34 @@ def test_check_prebuilt_freshness_not_stale_when_tag_matches(monkeypatch, tmp_pa assert info["latest_tag"] == "b9300" +def test_check_prebuilt_freshness_not_stale_when_installed_newer(monkeypatch, tmp_path): + """/releases/latest can lag behind out-of-order fork releases; an installed + build newer than "latest" must never be flagged stale.""" + install_dir = tmp_path / "llama.cpp" + _write_marker( + install_dir, + tag = "b9596", + installed_at_utc = (datetime.now(tz = timezone.utc) - timedelta(days = 30)) + .isoformat() + .replace("+00:00", "Z"), + ) + bin_path = _fake_binary(install_dir, layout = "root") + monkeypatch.setattr(fr, "_fetch_latest_release_tag", lambda repo, timeout = 5.0: "b9594") + info = fr.check_prebuilt_freshness(str(bin_path)) + assert info["stale"] is False + assert info["installed_tag"] == "b9596" + assert info["latest_tag"] == "b9594" + + +def test_parse_build_number(): + assert fr.parse_build_number("b9596") == 9596 + assert fr.parse_build_number(" b9596 ") == 9596 + assert fr.parse_build_number("9596") is None + assert fr.parse_build_number("b9596-custom") is None + assert fr.parse_build_number("") is None + assert fr.parse_build_number(None) is None + + def test_check_prebuilt_freshness_not_stale_within_threshold(monkeypatch, tmp_path): # Behind by tag but within the 3-day grace window. install_dir = tmp_path / "llama.cpp" diff --git a/studio/backend/tests/test_llama_cpp_update.py b/studio/backend/tests/test_llama_cpp_update.py index d21d653b76..83ab028d5e 100644 --- a/studio/backend/tests/test_llama_cpp_update.py +++ b/studio/backend/tests/test_llama_cpp_update.py @@ -275,6 +275,26 @@ def test_status_up_to_date(monkeypatch, tmp_path): assert st["update_available"] is False +def test_status_installed_newer_than_latest_release_not_offered(monkeypatch, tmp_path): + """GitHub /releases/latest sorts by commit date and can return an older + build than the one just installed; never offer that as an "update".""" + binary = _write_install(tmp_path, "b9596") + monkeypatch.setattr(upd, "_find_binary", lambda: binary) + monkeypatch.setattr(freshness, "_fetch_latest_release_tag", lambda repo, timeout = 5.0: "b9594") + st = upd.get_update_status(force_refresh = True) + assert st["installed_tag"] == "b9596" + assert st["latest_tag"] == "b9594" + assert st["update_available"] is False + + +def test_status_non_numeric_tags_fall_back_to_inequality(monkeypatch, tmp_path): + binary = _write_install(tmp_path, "custom-build") + monkeypatch.setattr(upd, "_find_binary", lambda: binary) + monkeypatch.setattr(freshness, "_fetch_latest_release_tag", lambda repo, timeout = 5.0: "b9594") + st = upd.get_update_status(force_refresh = True) + assert st["update_available"] is True + + def test_start_update_no_marker_no_prebuilt_refuses(monkeypatch, tmp_path): binary = tmp_path / "llama-server" binary.write_text("stub") # no marker diff --git a/studio/backend/utils/llama_cpp_freshness.py b/studio/backend/utils/llama_cpp_freshness.py index 3e5066ca2d..556ea71d69 100644 --- a/studio/backend/utils/llama_cpp_freshness.py +++ b/studio/backend/utils/llama_cpp_freshness.py @@ -13,6 +13,7 @@ from __future__ import annotations import json import os +import re import time from datetime import datetime, timezone from pathlib import Path @@ -43,6 +44,14 @@ def _cache_dir() -> Path: return Path.home() / ".unsloth" / "studio" / "cache" / "llama_cpp_freshness" +def parse_build_number(tag: object) -> Optional[int]: + """Numeric build from a ``bNNNN`` tag, None for anything else.""" + if not isinstance(tag, str): + return None + m = re.fullmatch(r"b(\d+)", tag.strip()) + return int(m.group(1)) if m else None + + def read_install_marker(binary_path: Optional[str]) -> Optional[dict]: """Walk up from binary_path to find UNSLOTH_PREBUILT_INFO.json. None = no marker (source build / custom path) or invalid JSON.""" @@ -208,6 +217,14 @@ def check_prebuilt_freshness( if not latest or latest == out["installed_tag"]: return out + # GitHub /releases/latest sorts by commit date, not build number, so it can + # lag the installed build when releases land out of order; never call a + # downgrade stale. + installed_build = parse_build_number(out["installed_tag"]) + latest_build = parse_build_number(latest) + if installed_build is not None and latest_build is not None and latest_build <= installed_build: + return out + installed_at = _parse_installed_at(out["installed_at_utc"]) if installed_at is None: return out diff --git a/studio/backend/utils/llama_cpp_update.py b/studio/backend/utils/llama_cpp_update.py index 55bf4b3d84..e5b6a537be 100644 --- a/studio/backend/utils/llama_cpp_update.py +++ b/studio/backend/utils/llama_cpp_update.py @@ -10,7 +10,8 @@ the next model load uses it. Design notes: - Detection is delegated to check_prebuilt_freshness(). We surface an - ``update_available`` flag (installed_tag != latest_tag) which is laxer than + ``update_available`` flag (installed build older than the latest release; + tag inequality only when either tag is not bNNNN) which is laxer than freshness' ``stale`` (which additionally requires the install to be >= 3 days old). The UI shows the "Update llama.cpp" affordance on update_available. - The install is slow (download + extract + validate), so it runs on a daemon @@ -37,6 +38,7 @@ from utils.llama_cpp_freshness import ( _INSTALL_MARKER_NAME, check_prebuilt_freshness, latest_published_release, + parse_build_number, read_install_marker, reset_caches, ) @@ -286,8 +288,17 @@ def get_update_status(*, force_refresh: bool = False) -> dict: freshness = check_prebuilt_freshness(binary) installed = freshness.get("installed_tag") latest = freshness.get("latest_tag") + # GitHub /releases/latest sorts by commit date, so it can point at an older + # build than the one the installer just resolved; compare build numbers and + # only offer real upgrades. Tag inequality is the fallback for non-bNNNN tags. + installed_build = parse_build_number(installed) + latest_build = parse_build_number(latest) + if installed_build is not None and latest_build is not None: + behind = installed_build < latest_build + else: + behind = installed != latest update_available = bool( - freshness.get("has_marker") and installed and latest and installed != latest + freshness.get("has_marker") and installed and latest and behind ) with _job_lock: From 410299b5a617ef044371a0b28f9c22197008211f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 11 Jun 2026 17:17:28 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- studio/backend/utils/llama_cpp_update.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/studio/backend/utils/llama_cpp_update.py b/studio/backend/utils/llama_cpp_update.py index e5b6a537be..58963f0f85 100644 --- a/studio/backend/utils/llama_cpp_update.py +++ b/studio/backend/utils/llama_cpp_update.py @@ -297,9 +297,7 @@ def get_update_status(*, force_refresh: bool = False) -> dict: behind = installed_build < latest_build else: behind = installed != latest - update_available = bool( - freshness.get("has_marker") and installed and latest and behind - ) + update_available = bool(freshness.get("has_marker") and installed and latest and behind) with _job_lock: job = dict(_job)