diff --git a/dashboard/src/routes/+page.svelte b/dashboard/src/routes/+page.svelte
index 73de742b..031f2575 100644
--- a/dashboard/src/routes/+page.svelte
+++ b/dashboard/src/routes/+page.svelte
@@ -229,7 +229,7 @@
const showOnboarding = $derived(onboardingStep > 0);
// Recommended models for onboarding (sorted by fit, then size desc, limited to 6)
- const onboardingModels = $derived(() => {
+ const onboardingModels = $derived.by(() => {
if (models.length === 0) return [];
return [...models]
.filter((m) => getModelMemoryFitStatus(m) !== "too_large")
@@ -242,19 +242,30 @@
.slice(0, 6);
});
- // Track onboarding instance status for auto-advancing steps
+ // Track onboarding instance status for auto-advancing steps.
+ // Handles cached models: if no download is needed, skip step 4 entirely.
$effect(() => {
if (onboardingStep === 4 && instanceCount > 0) {
- // Check if any instance is past downloading
let anyDownloading = false;
+ let anyReady = false;
for (const [id, inst] of Object.entries(instanceData)) {
const status = getInstanceDownloadStatus(id, inst);
if (status.isDownloading) {
anyDownloading = true;
- break;
+ }
+ if (
+ status.statusText === "READY" ||
+ status.statusText === "LOADED" ||
+ status.statusText === "RUNNING"
+ ) {
+ anyReady = true;
}
}
- if (!anyDownloading) {
+ // Model already cached & ready — skip download AND loading steps
+ if (anyReady) {
+ onboardingStep = 6;
+ } else if (!anyDownloading) {
+ // Download finished (or was never needed) but not ready yet
onboardingStep = 5;
}
}
@@ -285,8 +296,11 @@
}
}
+ let onboardingError = $state(null);
+
async function onboardingLaunchModel(modelId: string) {
onboardingModelId = modelId;
+ onboardingError = null;
selectPreviewModel(modelId);
onboardingStep = 4;
// Launch via API
@@ -295,10 +309,8 @@
`/instance/placement?model_id=${encodeURIComponent(modelId)}&sharding=${selectedSharding}&instance_meta=${selectedInstanceType}&min_nodes=1`,
);
if (!placementResponse.ok) {
- console.error(
- "Onboarding placement failed:",
- await placementResponse.text(),
- );
+ const errorText = await placementResponse.text();
+ onboardingError = `Could not place model: ${errorText}`;
onboardingStep = 3;
return;
}
@@ -309,20 +321,21 @@
body: JSON.stringify({ instance: placementData }),
});
if (!response.ok) {
- console.error("Onboarding launch failed:", await response.text());
+ const errorText = await response.text();
+ onboardingError = `Failed to launch: ${errorText}`;
onboardingStep = 3;
return;
}
setSelectedChatModel(modelId);
recordRecentLaunch(modelId);
} catch (error) {
- console.error("Onboarding launch error:", error);
+ onboardingError = `Network error: ${error}`;
onboardingStep = 3;
}
}
// Helper to get onboarding download progress
- const onboardingDownloadProgress = $derived(() => {
+ const onboardingDownloadProgress = $derived.by(() => {
if (instanceCount === 0) return null;
for (const [id, inst] of Object.entries(instanceData)) {
const status = getInstanceDownloadStatus(id, inst);
@@ -2628,7 +2641,16 @@
- {#if onboardingModels().length === 0}
+ {#if onboardingError}
+
Loading models...
@@ -2636,7 +2658,7 @@
{:else}
- {#each onboardingModels() as model}
+ {#each onboardingModels as model}
{@const sizeGB = getModelSizeGB(model)}
{@const fitsNow = hasEnoughMemory(model)}
{@const tags = modelTags()[model.id] || []}
@@ -2712,28 +2734,24 @@
- {#if onboardingDownloadProgress()}
+ {#if onboardingDownloadProgress}
+ {onboardingDownloadProgress.percentage.toFixed(1)}%
{onboardingDownloadProgress()!.percentage.toFixed(1)}%
- {formatBytes(onboardingDownloadProgress()!.downloadedBytes)} /
- {formatBytes(onboardingDownloadProgress()!.totalBytes)}{formatBytes(onboardingDownloadProgress.downloadedBytes)} /
+ {formatBytes(onboardingDownloadProgress.totalBytes)}
- {formatSpeed(onboardingDownloadProgress()!.speed)}
- ETA: {formatEta(onboardingDownloadProgress()!.etaMs)}
+ {formatSpeed(onboardingDownloadProgress.speed)}
+ ETA: {formatEta(onboardingDownloadProgress.etaMs)}
{:else}
@@ -3373,11 +3391,9 @@
>
{getInstanceModelId(instance)}
- {#if debugEnabled}
-
- {instanceInfo.sharding} · {instanceInfo.instanceType}
-
- {/if}
+
+ {instanceInfo.sharding} · {instanceInfo.instanceType}
+
{#if instanceModelId && instanceModelId !== "Unknown" && instanceModelId !== "Unknown Model"}
{getInstanceModelId(instance)}
- {#if debugEnabled}
-
- {instanceInfo.sharding} · {instanceInfo.instanceType}
-
- {/if}
+
+ {instanceInfo.sharding} · {instanceInfo.instanceType}
+
{#if instanceModelId && instanceModelId !== "Unknown" && instanceModelId !== "Unknown Model"}