-
-
- 🦥
-
-
-
- Package update available: {status.latestVersion}
+
+
+ New Unsloth version
+
+
+
+ {status.currentVersion} →{" "}
+
+ {status.latestVersion}
+
-
- Installed package: {status.currentVersion}. To update Unsloth,
- run this in your terminal, then restart Unsloth.
-
-
-
-
-
-
-
+
+
+
+
diff --git a/studio/frontend/src/hooks/use-llama-update-check.ts b/studio/frontend/src/hooks/use-llama-update-check.ts
index 5c609558d6..9532ee0735 100644
--- a/studio/frontend/src/hooks/use-llama-update-check.ts
+++ b/studio/frontend/src/hooks/use-llama-update-check.ts
@@ -11,8 +11,9 @@ const FIRST_CHECK_DELAY_MS = 1000;
const REMINDER_INTERVAL_MS = 60 * 60 * 1000; // ~1 hour
// "Remind me later" re-surfaces sooner than the hourly reminder.
const SNOOZE_DELAY_MS = 15 * 60 * 1000; // ~15 minutes
-// While an update is applying, poll the job state at this cadence.
-const JOB_POLL_INTERVAL_MS = 1500;
+// Poll cadence while applying. Short so the installer's ~5% milestones are
+// observed instead of a fast download finishing between two slow polls.
+const JOB_POLL_INTERVAL_MS = 500;
export interface LlamaUpdateJob {
state: "idle" | "running" | "success" | "error";
@@ -149,7 +150,14 @@ export function useLlamaUpdateCheck({
);
useEffect(() => {
- if (!enabled) return;
+ if (!enabled) {
+ // Disabled mid-update: stop showing and tracking, and clear `applying`
+ // so the banner's animation loop stops too. Re-enabling re-detects a
+ // still-running job below and resumes tracking via surfaceIfAvailable.
+ setVisible(false);
+ setApplying(false);
+ return;
+ }
let canceled = false;
const firstTimer = setTimeout(() => {
diff --git a/studio/frontend/src/hooks/use-web-update-check.ts b/studio/frontend/src/hooks/use-web-update-check.ts
index 1ad0fe544c..78d53528f4 100644
--- a/studio/frontend/src/hooks/use-web-update-check.ts
+++ b/studio/frontend/src/hooks/use-web-update-check.ts
@@ -5,6 +5,8 @@ import { getAuthToken } from "@/features/auth";
import { apiUrl, isTauri } from "@/lib/api-base";
import { useCallback, useEffect, useState } from "react";
+// Checked once per launch only (no polling), to avoid background load. A
+// re-check happens naturally the next time the user reopens the app.
const WEB_UPDATE_CHECK_DELAY_MS = 5000;
const DISMISS_PREFIX = "unsloth_web_update_dismissed";
const CAN_SHOW_KEY = "can_show_web_notification";
@@ -119,24 +121,21 @@ export function useWebUpdateCheck({
useEffect(() => {
if (isTauri || !enabled || !getAuthToken()) {
- const clearTimer = window.setTimeout(() => setStatus(null), 0);
- return () => window.clearTimeout(clearTimer);
+ setStatus(null);
+ return;
}
let canceled = false;
+ // One check per launch, 5s after load. No polling: the next re-check is
+ // simply the next time the user opens the app.
const timer = window.setTimeout(() => {
fetchDisplayableUpdateStatus()
- .then((nextStatus) => {
- if (canceled) {
- return;
+ .then((next) => {
+ if (!canceled && next && !isDismissed(next)) {
+ setStatus(next);
}
- setStatus(nextStatus && !isDismissed(nextStatus) ? nextStatus : null);
})
- .catch(() => {
- if (!canceled) {
- setStatus(null);
- }
- });
+ .catch(() => {});
}, delayMs);
return () => {
@@ -145,6 +144,7 @@ export function useWebUpdateCheck({
};
}, [delayMs, enabled]);
+ // X: silence this version for good (persists across launches).
const dismiss = useCallback(() => {
setStatus((current) => {
if (current) {
@@ -154,5 +154,12 @@ export function useWebUpdateCheck({
});
}, []);
- return { status: enabled && !isTauri ? status : null, dismiss };
+ // "Remind me later" / post-copy: hide without persisting a dismissal, so the
+ // banner returns on the next launch if the install is still behind. Copying
+ // the command is not the same as having updated.
+ const snooze = useCallback(() => {
+ setStatus(null);
+ }, []);
+
+ return { status: enabled && !isTauri ? status : null, dismiss, snooze };
}