Fix/adjust llama update toast for PR #6493

This commit is contained in:
wasimysaid 2026-06-21 12:09:39 +02:00
commit 6ffa4bfe90
7 changed files with 54 additions and 14 deletions

View file

@ -30,6 +30,7 @@ class LlamaUpdateJob(BaseModel):
message: str = ""
from_tag: Optional[str] = None
to_tag: Optional[str] = None
reload_required: Optional[bool] = None
error: Optional[str] = None
progress: Optional[float] = Field(None, description = "0..1 while running, 1 on success.")
started_at: Optional[str] = None

View file

@ -445,6 +445,7 @@ def test_start_update_happy_path(monkeypatch, tmp_path):
time.sleep(0.05)
assert job["state"] == "success", job
assert job["to_tag"] == "b9518"
assert job["reload_required"] is False
# Installer was invoked with the resolved install dir + latest + repo.
assert "--install-dir" in captured["cmd"]
assert str(install_dir) in captured["cmd"]
@ -456,6 +457,35 @@ def test_start_update_happy_path(monkeypatch, tmp_path):
assert popen_kwargs["env"]["UNSLOTH_PROGRESS_PERCENT_STEP"] == "5"
def test_start_update_reports_full_release_tag(monkeypatch, tmp_path):
install_dir = tmp_path / "llama.cpp"
binary = _write_install(install_dir, "b9595")
monkeypatch.setattr(upd, "_find_binary", lambda: binary)
monkeypatch.setattr(upd, "_installer_script", lambda: tmp_path / "install_llama_prebuilt.py")
monkeypatch.setattr(
freshness,
"_fetch_latest_release_tag",
lambda repo, timeout = 5.0: "b9596-mix-e6f2453",
)
def _on_start(cmd):
_write_install(install_dir, "b9596", release_tag = "b9596-mix-e6f2453")
_patch_installer_popen(monkeypatch, on_start = _on_start)
res = upd.start_update()
assert res["started"] is True
deadline = time.time() + 10
while time.time() < deadline:
job = upd.get_update_status()["job"]
if job["state"] in ("success", "error"):
break
time.sleep(0.05)
assert job["state"] == "success", job
assert job["to_tag"] == "b9596-mix-e6f2453"
assert "Updated llama.cpp to b9596-mix-e6f2453." in job["message"]
def test_start_update_installer_failure_reports_error(monkeypatch, tmp_path):
install_dir = tmp_path / "llama.cpp"
binary = _write_install(install_dir, "b9493")
@ -674,6 +704,7 @@ def test_update_sets_maintenance_flag_and_unloads(monkeypatch, tmp_path):
time.sleep(0.05)
assert backend.unloaded is True
assert upd.get_update_status()["job"]["reload_required"] is True
assert seen.get("flag_during_install") is True
# Cleared in the finally so model loads work again after the swap.
assert backend._llama_update_in_progress is False

View file

@ -70,10 +70,11 @@ def test_status_response_exposes_source_build():
"installed_at_utc": None,
"age_days": None,
"source_build": True,
"job": {"state": "idle"},
"job": {"state": "idle", "reload_required": False},
}
model = rl.LlamaUpdateStatusResponse(**payload)
assert model.model_dump()["source_build"] is True
assert model.model_dump()["job"]["reload_required"] is False
# Extra/unknown keys must not crash the response model.
rl.LlamaUpdateStatusResponse(**{**payload, "unexpected": 1})

View file

@ -62,6 +62,7 @@ _job: dict = {
"message": "",
"from_tag": None,
"to_tag": None,
"reload_required": None,
"error": None,
"progress": None,
"started_at": None,
@ -505,7 +506,7 @@ def _run_update(install_dir: Path, repo: str, asset: Optional[str], script: Path
except Exception as exc: # pragma: no cover - network defensive
logger.debug("llama update: post-install freshness refresh failed", error = str(exc))
new_marker = read_install_marker(_find_binary())
new_tag = (new_marker or {}).get("tag") or (new_marker or {}).get("release_tag")
new_tag = (new_marker or {}).get("release_tag") or (new_marker or {}).get("tag")
with _job_lock:
_job.update(
@ -515,6 +516,7 @@ def _run_update(install_dir: Path, repo: str, asset: Optional[str], script: Path
+ (" Reload your model to use it." if model_was_active else "")
),
to_tag = new_tag,
reload_required = model_was_active,
error = None,
progress = 1.0,
finished_at = _utcnow(),
@ -618,6 +620,7 @@ def start_update() -> dict:
message = "Downloading and installing the latest llama.cpp prebuilt...",
from_tag = from_tag,
to_tag = None,
reload_required = None,
error = None,
progress = 0.0,
started_at = _utcnow(),
@ -643,6 +646,7 @@ def _reset_job_for_tests() -> None:
message = "",
from_tag = None,
to_tag = None,
reload_required = None,
error = None,
progress = None,
started_at = None,

View file

@ -2,7 +2,6 @@
// Copyright 2026-present the Unsloth AI Inc. team. All rights reserved. See /studio/LICENSE.AGPL-3.0
import { Button } from "@/components/ui/button";
import { isExternalModelId, useChatRuntimeStore } from "@/features/chat";
import { useLlamaUpdateCheck } from "@/hooks/use-llama-update-check";
import { useShowLlamaUpdateBanner } from "@/hooks/use-llama-update-pref";
import { toast } from "@/lib/toast";
@ -100,15 +99,8 @@ export function LlamaUpdateBanner({
async function handleUpdate() {
const result = await apply();
if (result?.ok) {
// Prefer the full release tag (e.g. b9726-mix-<sha>); the job's to_tag and
// installed_tag are the bare bNNNN build number.
const updatedTag = status?.latest_tag ?? result.tag ?? "the latest build";
// Only a loaded local model can be reloaded to pick up the new binary;
// external-provider models do not use llama.cpp at all.
const checkpoint = useChatRuntimeStore.getState().params.checkpoint;
const hasLocalModel =
Boolean(checkpoint) && !isExternalModelId(checkpoint);
const reloadHint = hasLocalModel
const updatedTag = result.tag ?? status?.latest_tag ?? "the latest build";
const reloadHint = result.reloadRequired
? " Reload your model to use it."
: "";
toast.success(`llama.cpp updated to ${updatedTag}.${reloadHint}`);

View file

@ -518,8 +518,11 @@ export function ChatSettingsPanel({
const handleMtpUpdate = useCallback(async () => {
const result = await applyLlamaUpdate();
if (result.ok) {
const reloadHint = result.reloadRequired
? " Reload your model to enable MTP."
: "";
toast.success(
`llama.cpp updated to ${result.tag ?? "the latest build"}. Reload your model to enable MTP.`,
`llama.cpp updated to ${result.tag ?? "the latest build"}.${reloadHint}`,
);
} else {
toast.error(`llama.cpp update failed: ${result.error ?? "unknown error"}`);

View file

@ -21,6 +21,7 @@ export interface LlamaUpdateJob {
message: string;
from_tag: string | null;
to_tag: string | null;
reload_required: boolean | null;
error: string | null;
// Download fraction (0..1) while running, 1 on success, null when unknown.
progress: number | null;
@ -52,6 +53,8 @@ function parseStatus(value: unknown): LlamaUpdateStatus | null {
message: typeof job.message === "string" ? job.message : "",
from_tag: typeof job.from_tag === "string" ? job.from_tag : null,
to_tag: typeof job.to_tag === "string" ? job.to_tag : null,
reload_required:
typeof job.reload_required === "boolean" ? job.reload_required : null,
error: typeof job.error === "string" ? job.error : null,
progress: typeof job.progress === "number" ? job.progress : null,
},
@ -85,6 +88,7 @@ interface UseLlamaUpdateCheckOptions {
export interface LlamaApplyResult {
ok: boolean;
tag?: string | null;
reloadRequired?: boolean | null;
error?: string | null;
}
@ -126,7 +130,11 @@ export function useLlamaUpdateCheck({
if (s.job.state === "success") {
setVisible(false);
void refreshHardwareInfo();
onDone?.({ ok: true, tag: s.job.to_tag });
onDone?.({
ok: true,
tag: s.job.to_tag,
reloadRequired: s.job.reload_required,
});
} else if (s.job.state === "error") {
// Leave the banner up so the user can retry; clearing applying drops
// the "Updating..." state.