Skip to content

Commit 5327bdd

Browse files
AlexCheemaclaude
andauthored
Fix custom model add requiring two attempts + enlarge sidebar buttons (#1805)
## Motivation Adding a custom model from the Hub tab shows "Added" toast but the model doesn't appear in the All tab. You have to add it a second time for it to work. Also, the "All" button in the model picker sidebar is too small to read comfortably. ## Changes **Race condition fix (`src/exo/api/main.py`):** - Call `add_to_card_cache(card)` directly in `add_custom_model()` after sending the `ForwarderCommand`, before the API response returns **Sidebar sizing (`dashboard/src/lib/components/FamilySidebar.svelte`):** - Increased sidebar min-width from 72/64px to 80/72px - Increased "All" icon from `w-5 h-5` to `w-6 h-6` - Increased all sidebar labels from 9px to 11px ## Why It Works `POST /models/add` sends a `ForwarderCommand(AddCustomModelCard)` and returns immediately. The frontend then calls `GET /models` which reads from `_card_cache`. But the cache was only updated by the worker event handler after the event round-trips through the master — a race the frontend almost always loses. By updating the cache directly in the API handler, `GET /models` immediately reflects the new model. The worker's later `add_to_card_cache` call is idempotent (dict key assignment). ## Test Plan ### Manual Testing <!-- Hardware: any Mac --> - Open model picker → Hub tab → add a custom model → verify it appears in All tab on the first attempt - Verify sidebar "All" button and other labels are visually larger and readable ### Automated Testing - `uv run basedpyright` passes with 0 errors - `uv run ruff check` passes --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 15f1b61 commit 5327bdd

3 files changed

Lines changed: 13 additions & 19 deletions

File tree

dashboard/src/lib/components/FamilySidebar.svelte

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -42,31 +42,20 @@
4242
</script>
4343

4444
<div
45-
class="flex flex-col gap-1 py-2 px-1 border-r border-exo-yellow/10 bg-exo-medium-gray/30 min-w-[72px] sm:min-w-[64px] overflow-y-auto scrollbar-hide"
45+
class="flex flex-col gap-1 py-2 px-1 border-r border-exo-yellow/10 bg-exo-medium-gray/30 min-w-[80px] sm:min-w-[72px] overflow-y-auto scrollbar-hide"
4646
>
4747
<!-- All models (no filter) -->
4848
<button
4949
type="button"
5050
onclick={() => onSelect(null)}
51-
class="group flex flex-col items-center justify-center p-2 sm:p-2 rounded transition-all duration-200 cursor-pointer min-h-[44px] sm:min-h-0 {selectedFamily ===
51+
class="group flex items-center justify-center px-3 py-2.5 rounded transition-all duration-200 cursor-pointer min-h-[44px] sm:min-h-0 {selectedFamily ===
5252
null
5353
? 'bg-exo-yellow/20 border-l-2 border-exo-yellow'
5454
: 'hover:bg-white/5 border-l-2 border-transparent'}"
5555
title="All models"
5656
>
57-
<svg
58-
class="w-5 h-5 {selectedFamily === null
59-
? 'text-exo-yellow'
60-
: 'text-white/50 group-hover:text-white/70'}"
61-
viewBox="0 0 24 24"
62-
fill="currentColor"
63-
>
64-
<path
65-
d="M4 8h4V4H4v4zm6 12h4v-4h-4v4zm-6 0h4v-4H4v4zm0-6h4v-4H4v4zm6 0h4v-4h-4v4zm6-10v4h4V4h-4zm-6 4h4V4h-4v4zm6 6h4v-4h-4v4zm0 6h4v-4h-4v4z"
66-
/>
67-
</svg>
6857
<span
69-
class="text-[9px] font-mono mt-0.5 {selectedFamily === null
58+
class="text-[12px] font-mono font-medium {selectedFamily === null
7059
? 'text-exo-yellow'
7160
: 'text-white/40 group-hover:text-white/60'}">All</span
7261
>
@@ -90,7 +79,7 @@
9079
: "text-white/50 group-hover:text-amber-400/70"}
9180
/>
9281
<span
93-
class="text-[9px] font-mono mt-0.5 {selectedFamily === 'favorites'
82+
class="text-[11px] font-mono mt-0.5 {selectedFamily === 'favorites'
9483
? 'text-amber-400'
9584
: 'text-white/40 group-hover:text-white/60'}">Faves</span
9685
>
@@ -115,7 +104,7 @@
115104
: "text-white/50 group-hover:text-white/70"}
116105
/>
117106
<span
118-
class="text-[9px] font-mono mt-0.5 {selectedFamily === 'recents'
107+
class="text-[11px] font-mono mt-0.5 {selectedFamily === 'recents'
119108
? 'text-exo-yellow'
120109
: 'text-white/40 group-hover:text-white/60'}">Recent</span
121110
>
@@ -139,7 +128,7 @@
139128
: "text-white/50 group-hover:text-orange-400/70"}
140129
/>
141130
<span
142-
class="text-[9px] font-mono mt-0.5 {selectedFamily === 'huggingface'
131+
class="text-[11px] font-mono mt-0.5 {selectedFamily === 'huggingface'
143132
? 'text-orange-400'
144133
: 'text-white/40 group-hover:text-white/60'}">Hub</span
145134
>
@@ -165,7 +154,7 @@
165154
: "text-white/50 group-hover:text-white/70"}
166155
/>
167156
<span
168-
class="text-[9px] font-mono mt-0.5 truncate max-w-full {selectedFamily ===
157+
class="text-[11px] font-mono mt-0.5 truncate max-w-full {selectedFamily ===
169158
family
170159
? 'text-exo-yellow'
171160
: 'text-white/40 group-hover:text-white/60'}"

dashboard/src/lib/components/ModelFilterPopover.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373

7474
<!-- svelte-ignore a11y_no_static_element_interactions -->
7575
<div
76-
class="filter-popover absolute right-0 top-full mt-2 w-64 bg-exo-dark-gray border border-exo-yellow/10 rounded-lg shadow-xl z-10"
76+
class="filter-popover absolute right-0 top-full mt-2 w-64 bg-exo-dark-gray border border-exo-yellow/10 rounded-lg shadow-xl z-20"
7777
transition:fly={{ y: -10, duration: 200, easing: cubicOut }}
7878
onclick={(e) => e.stopPropagation()}
7979
role="dialog"

src/exo/api/main.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
from exo.shared.models.model_cards import (
130130
ModelCard,
131131
ModelId,
132+
add_to_card_cache,
132133
get_card,
133134
get_model_cards,
134135
)
@@ -1587,6 +1588,10 @@ async def add_custom_model(self, payload: AddCustomModelParams) -> ModelListMode
15871588
)
15881589
)
15891590

1591+
# Immediately update the local cache so the subsequent GET /models
1592+
# returns the new model without waiting for the event round-trip.
1593+
add_to_card_cache(card)
1594+
15901595
return ModelListModel(
15911596
id=card.model_id,
15921597
hugging_face_id=card.model_id,

0 commit comments

Comments
 (0)