fix: address PR review comments — onboarding file, layer callback indexing, RDMA warning

- Move onboarding_complete file to EXO_CACHE_HOME and make it a module-level constant
- Fix layer loaded callback to use 0-indexed layer count
- Update runner's current_status in on_layer_loaded callback via nonlocal
- Apply RDMA "NOT ENABLED" warning styling from main (yellow + tooltip)

Co-Authored-By: Claude Opus 4.6 <[email protected]>
This commit is contained in:
Alex Cheema
2026-02-21 11:10:57 -08:00
co-authored by Claude Opus 4.6
parent d6af5126bc
commit 296ec9eeab
5 changed files with 175 additions and 94 deletions
+155 -75
View File
@@ -2324,17 +2324,28 @@
if (!prevStatus || prevStatus === currentStatus) continue;
const modelId = getInstanceModelId(instanceData[id]);
const shortName = modelId ? (modelId.split("/").pop() ?? modelId) : id.slice(0, 8);
const shortName = modelId
? (modelId.split("/").pop() ?? modelId)
: id.slice(0, 8);
// Downloading -> non-downloading, non-failure = download complete
if (prevStatus === "DOWNLOADING" && currentStatus !== "DOWNLOADING" && currentStatus !== "FAILED") {
addToast({ type: "success", message: `Download complete: ${shortName}` });
if (
prevStatus === "DOWNLOADING" &&
currentStatus !== "DOWNLOADING" &&
currentStatus !== "FAILED"
) {
addToast({
type: "success",
message: `Download complete: ${shortName}`,
});
}
// Loading/Warming Up -> Ready/Loaded/Running = model ready
if (
(prevStatus === "LOADING" || prevStatus === "WARMING UP") &&
(currentStatus === "READY" || currentStatus === "LOADED" || currentStatus === "RUNNING")
(currentStatus === "READY" ||
currentStatus === "LOADED" ||
currentStatus === "RUNNING")
) {
addToast({ type: "success", message: `Model ready: ${shortName}` });
}
@@ -2361,7 +2372,11 @@
const connected = isConnected();
if (previousConnectionStatus !== null) {
if (previousConnectionStatus && !connected) {
addToast({ type: "warning", message: "Connection to server lost", persistent: true });
addToast({
type: "warning",
message: "Connection to server lost",
persistent: true,
});
} else if (!previousConnectionStatus && connected) {
dismissByMessage("Connection to server lost");
addToast({ type: "success", message: "Connection restored" });
@@ -2618,32 +2633,12 @@
{/if}
{#if tb5WithoutRdma && !tb5InfoDismissed}
<div
class="flex items-center gap-2 px-3 py-2 rounded border border-blue-400/50 bg-blue-400/10 backdrop-blur-sm"
role="status"
>
<svg
class="w-5 h-5 text-blue-400 flex-shrink-0"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d={infoIconPath}
/>
</svg>
<span class="text-sm font-mono text-blue-200"> RDMA AVAILABLE </span>
<button
type="button"
onclick={() => (tb5InfoDismissed = true)}
class="ml-1 text-blue-300/60 hover:text-blue-200 transition-colors cursor-pointer"
title="Dismiss"
<div class="group relative" role="status">
<div
class="flex items-center gap-2 px-3 py-2 rounded border border-yellow-500/50 bg-yellow-500/10 backdrop-blur-sm cursor-help"
>
<svg
class="w-4 h-4"
class="w-5 h-5 text-yellow-400 flex-shrink-0"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
@@ -2652,10 +2647,61 @@
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M6 18L18 6M6 6l12 12"
d={warningIconPath}
/>
</svg>
</button>
<span class="text-sm font-mono text-yellow-200">
RDMA NOT ENABLED
</span>
<button
type="button"
onclick={() => (tb5InfoDismissed = true)}
class="ml-1 text-yellow-300/60 hover:text-yellow-200 transition-colors cursor-pointer"
title="Dismiss"
>
<svg
class="w-4 h-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
<!-- Tooltip on hover -->
<div
class="absolute top-full left-0 mt-2 w-80 p-3 rounded border border-yellow-500/30 bg-exo-dark-gray/95 backdrop-blur-sm opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50 shadow-lg"
>
<p class="text-xs text-white/80 mb-2">
Thunderbolt 5 hardware detected on multiple nodes. Enable RDMA for
significantly faster inter-node communication.
</p>
<p class="text-xs text-white/60 mb-1.5">
<span class="text-yellow-300">To enable:</span>
</p>
<ol
class="text-xs text-white/60 list-decimal list-inside space-y-0.5 mb-1.5"
>
<li>Connect nodes with TB5 cables</li>
<li>Boot to Recovery (hold power 10s Options)</li>
<li>
Run
<code class="text-yellow-300 bg-yellow-400/10 px-1 rounded"
>rdma_ctl enable</code
>
</li>
<li>Reboot</li>
</ol>
<p class="text-xs text-white/40">
Requires macOS 26.2+, TB5 cables, and matching OS versions.
</p>
</div>
</div>
{/if}
@@ -2959,11 +3005,11 @@
{/if}
{#if tb5WithoutRdma && !tb5InfoDismissed}
<div
class="flex items-center gap-1.5 px-2 py-1 rounded border border-blue-400/50 bg-blue-400/10 backdrop-blur-sm"
title="Thunderbolt 5 detected — RDMA can be enabled for better performance"
class="flex items-center gap-1.5 px-2 py-1 rounded border border-yellow-500/50 bg-yellow-500/10 backdrop-blur-sm"
title="Thunderbolt 5 detected — RDMA not enabled. Enable for faster inter-node communication."
>
<svg
class="w-3.5 h-3.5 text-blue-400"
class="w-3.5 h-3.5 text-yellow-400"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
@@ -2972,10 +3018,11 @@
<path
stroke-linecap="round"
stroke-linejoin="round"
d={infoIconPath}
d={warningIconPath}
/>
</svg>
<span class="text-[10px] font-mono text-blue-200">RDMA AVAILABLE</span
<span class="text-[10px] font-mono text-yellow-200"
>RDMA NOT ENABLED</span
>
</div>
{/if}
@@ -3938,39 +3985,19 @@
{@render clusterWarnings()}
<!-- TB5 RDMA Available Info -->
<!-- TB5 RDMA Not Enabled Warning -->
{#if tb5WithoutRdma && !tb5InfoDismissed}
<div
class="absolute left-4 flex items-center gap-2 px-3 py-2 rounded border border-blue-400/50 bg-blue-400/10 backdrop-blur-sm"
class="absolute left-4 group"
class:top-16={tbBridgeCycles.length > 0}
class:top-4={tbBridgeCycles.length === 0}
role="status"
>
<svg
class="w-5 h-5 text-blue-400 flex-shrink-0"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
/>
</svg>
<span class="text-sm font-mono text-blue-200">
RDMA AVAILABLE
</span>
<button
type="button"
onclick={() => (tb5InfoDismissed = true)}
class="ml-1 text-blue-300/60 hover:text-blue-200 transition-colors cursor-pointer"
title="Dismiss"
aria-label="Dismiss RDMA available notification"
<div
class="flex items-center gap-2 px-3 py-2 rounded border border-yellow-500/50 bg-yellow-500/10 backdrop-blur-sm cursor-help"
>
<svg
class="w-4 h-4"
class="w-5 h-5 text-yellow-400 flex-shrink-0"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
@@ -3979,10 +4006,61 @@
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M6 18L18 6M6 6l12 12"
d={warningIconPath}
/>
</svg>
</button>
<span class="text-sm font-mono text-yellow-200">
RDMA NOT ENABLED
</span>
<button
type="button"
onclick={() => (tb5InfoDismissed = true)}
class="ml-1 text-yellow-300/60 hover:text-yellow-200 transition-colors cursor-pointer"
title="Dismiss"
>
<svg
class="w-4 h-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
</div>
<!-- Tooltip on hover -->
<div
class="absolute top-full left-0 mt-2 w-80 p-3 rounded border border-yellow-500/30 bg-exo-dark-gray/95 backdrop-blur-sm opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50 shadow-lg"
>
<p class="text-xs text-white/80 mb-2">
Thunderbolt 5 hardware detected on multiple nodes. Enable RDMA
for significantly faster inter-node communication.
</p>
<p class="text-xs text-white/60 mb-1.5">
<span class="text-yellow-300">To enable:</span>
</p>
<ol
class="text-xs text-white/60 list-decimal list-inside space-y-0.5 mb-1.5"
>
<li>Connect nodes with TB5 cables</li>
<li>Boot to Recovery (hold power 10s Options)</li>
<li>
Run
<code class="text-yellow-300 bg-yellow-400/10 px-1 rounded"
>rdma_ctl enable</code
>
</li>
<li>Reboot</li>
</ol>
<p class="text-xs text-white/40">
Requires macOS 26.2+, TB5 cables, and matching OS versions.
</p>
</div>
</div>
{/if}
@@ -4052,7 +4130,7 @@
{@render clusterWarnings()}
<!-- TB5 RDMA Available Info -->
<!-- TB5 RDMA Not Enabled Warning -->
{#if tb5WithoutRdma && !tb5InfoDismissed}
<div
class="absolute left-4 group"
@@ -4061,10 +4139,10 @@
role="status"
>
<div
class="flex items-center gap-2 px-3 py-2 rounded border border-blue-400/50 bg-blue-400/10 backdrop-blur-sm"
class="flex items-center gap-2 px-3 py-2 rounded border border-yellow-500/50 bg-yellow-500/10 backdrop-blur-sm cursor-help"
>
<svg
class="w-5 h-5 text-blue-400 flex-shrink-0"
class="w-5 h-5 text-yellow-400 flex-shrink-0"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
@@ -4073,16 +4151,16 @@
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
d={warningIconPath}
/>
</svg>
<span class="text-sm font-mono text-blue-200">
RDMA AVAILABLE
<span class="text-sm font-mono text-yellow-200">
RDMA NOT ENABLED
</span>
<button
type="button"
onclick={() => (tb5InfoDismissed = true)}
class="ml-1 text-blue-300/60 hover:text-blue-200 transition-colors cursor-pointer"
class="ml-1 text-yellow-300/60 hover:text-yellow-200 transition-colors cursor-pointer"
title="Dismiss"
>
<svg
@@ -4103,14 +4181,14 @@
<!-- Tooltip on hover -->
<div
class="absolute top-full left-0 mt-2 w-80 p-3 rounded border border-blue-400/30 bg-exo-dark-gray/95 backdrop-blur-sm opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50 shadow-lg"
class="absolute top-full left-0 mt-2 w-80 p-3 rounded border border-yellow-500/30 bg-exo-dark-gray/95 backdrop-blur-sm opacity-0 invisible group-hover:opacity-100 group-hover:visible transition-all duration-200 z-50 shadow-lg"
>
<p class="text-xs text-white/80 mb-2">
Thunderbolt 5 hardware detected on multiple nodes. Enable
RDMA for significantly faster inter-node communication.
</p>
<p class="text-xs text-white/60 mb-1.5">
<span class="text-blue-300">To enable:</span>
<span class="text-yellow-300">To enable:</span>
</p>
<ol
class="text-xs text-white/60 list-decimal list-inside space-y-0.5 mb-1.5"
@@ -4119,7 +4197,8 @@
<li>Boot to Recovery (hold power 10s Options)</li>
<li>
Run
<code class="text-blue-300 bg-blue-400/10 px-1 rounded"
<code
class="text-yellow-300 bg-yellow-400/10 px-1 rounded"
>rdma_ctl enable</code
>
</li>
@@ -4615,8 +4694,9 @@
<p
class="text-[11px] text-white/50 leading-relaxed"
>
Downloading model files. Model runs on your devices
so needs to be downloaded before you can chat.
Downloading model files. Model runs on your
devices so needs to be downloaded before you can
chat.
</p>
</div>
{:else}
+5 -6
View File
@@ -51,7 +51,7 @@ from exo.master.placement import place_instance as get_instance_placements
from exo.shared.apply import apply
from exo.shared.constants import (
DASHBOARD_DIR,
EXO_CONFIG_HOME,
EXO_CACHE_HOME,
EXO_EVENT_LOG_DIR,
EXO_IMAGE_CACHE_DIR,
EXO_MAX_CHUNK_SIZE,
@@ -176,6 +176,7 @@ from exo.utils.channels import Receiver, Sender, channel
from exo.utils.event_buffer import OrderedBuffer
_API_EVENT_LOG_DIR = EXO_EVENT_LOG_DIR / "api"
ONBOARDING_COMPLETE_FILE = EXO_CACHE_HOME / "onboarding_complete"
def _format_to_content_type(image_format: Literal["png", "jpeg", "webp"] | None) -> str:
@@ -1818,12 +1819,10 @@ class API:
filename=f"trace_{task_id}.json",
)
_ONBOARDING_FILE = EXO_CONFIG_HOME / "onboarding_complete"
async def get_onboarding(self) -> JSONResponse:
return JSONResponse({"completed": self._ONBOARDING_FILE.exists()})
return JSONResponse({"completed": ONBOARDING_COMPLETE_FILE.exists()})
async def complete_onboarding(self) -> JSONResponse:
self._ONBOARDING_FILE.parent.mkdir(parents=True, exist_ok=True)
self._ONBOARDING_FILE.write_text("true")
ONBOARDING_COMPLETE_FILE.parent.mkdir(parents=True, exist_ok=True)
ONBOARDING_COMPLETE_FILE.write_text("true")
return JSONResponse({"completed": True})
+9 -9
View File
@@ -244,7 +244,7 @@ def pipeline_auto_parallel(
for i, layer in enumerate(layers):
mx.eval(layer) # type: ignore
if on_layer_loaded is not None:
on_layer_loaded(i + 1, total)
on_layer_loaded(i, total)
layers[0] = PipelineFirstLayer(layers[0], device_rank, group=group)
layers[-1] = PipelineLastLayer(
@@ -525,7 +525,7 @@ class LlamaShardingStrategy(TensorParallelShardingStrategy):
layer.mlp.up_proj = self.all_to_sharded_linear(layer.mlp.up_proj)
mx.eval(layer)
if on_layer_loaded is not None:
on_layer_loaded(i + 1, total)
on_layer_loaded(i, total)
return model
@@ -619,7 +619,7 @@ class DeepSeekShardingStrategy(TensorParallelShardingStrategy):
mx.eval(layer)
if on_layer_loaded is not None:
on_layer_loaded(i + 1, total)
on_layer_loaded(i, total)
return model
@@ -703,7 +703,7 @@ class GLM4MoeLiteShardingStrategy(TensorParallelShardingStrategy):
layer.mlp.sharding_group = self.group # type: ignore
mx.eval(layer)
if on_layer_loaded is not None:
on_layer_loaded(i + 1, total)
on_layer_loaded(i, total)
return model
@@ -823,7 +823,7 @@ class MiniMaxShardingStrategy(TensorParallelShardingStrategy):
layer.block_sparse_moe.sharding_group = self.group # pyright: ignore[reportAttributeAccessIssue]
mx.eval(layer)
if on_layer_loaded is not None:
on_layer_loaded(i + 1, total)
on_layer_loaded(i, total)
return model
@@ -948,7 +948,7 @@ class QwenShardingStrategy(TensorParallelShardingStrategy):
mx.eval(layer)
if on_layer_loaded is not None:
on_layer_loaded(i + 1, total)
on_layer_loaded(i, total)
return model
@@ -996,7 +996,7 @@ class Glm4MoeShardingStrategy(TensorParallelShardingStrategy):
mx.eval(layer)
if on_layer_loaded is not None:
on_layer_loaded(i + 1, total)
on_layer_loaded(i, total)
return model
@@ -1039,7 +1039,7 @@ class GptOssShardingStrategy(TensorParallelShardingStrategy):
layer.mlp.sharding_group = self.group # pyright: ignore[reportAttributeAccessIssue]
mx.eval(layer)
if on_layer_loaded is not None:
on_layer_loaded(i + 1, total)
on_layer_loaded(i, total)
return model
@@ -1084,5 +1084,5 @@ class Step35ShardingStrategy(TensorParallelShardingStrategy):
mx.eval(layer)
if on_layer_loaded is not None:
on_layer_loaded(i + 1, total)
on_layer_loaded(i, total)
return model
+1 -1
View File
@@ -190,7 +190,7 @@ def load_mlx_items(
for i, layer in enumerate(layers):
mx.eval(layer) # type: ignore
if on_layer_loaded is not None:
on_layer_loaded(i + 1, total)
on_layer_loaded(i, total)
except ValueError:
pass
mx.eval(model)
@@ -174,12 +174,14 @@ def main(
time.sleep(0.5)
def on_layer_loaded(layers_loaded: int, total: int) -> None:
nonlocal current_status
current_status = RunnerLoading(
layers_loaded=layers_loaded, total_layers=total
)
event_sender.send(
RunnerStatusUpdated(
runner_id=runner_id,
runner_status=RunnerLoading(
layers_loaded=layers_loaded, total_layers=total
),
runner_status=current_status,
)
)