Skip to content

feat(models): let people hide models they never use - #85

Merged
JairEsk merged 3 commits into
mainfrom
jair/hide-models
Aug 30, 2026
Merged

feat(models): let people hide models they never use#85
JairEsk merged 3 commits into
mainfrom
jair/hide-models

Conversation

@JairEsk

@JairEsk JairEsk commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

A gateway provider reports 300-600 models and the picker lists every connected provider at once, so choosing a model means scrolling past hundreds you will never run. Pinning promotes a few to the top; it does nothing about the length of the list underneath. This is the other half.

Settings gains a Models section: one collapsible row per provider with a count, a search box, per-model Hide/Unhide, and Hide all / Show all scoped to whatever the search is filtering - so "gpt" + Hide all hides those matches rather than silently wiping the catalog.

Stored as a DENY-list, not an allow-list. Catalogs grow under us (a provider ships a model, a plan gains access to one), and an allow-list would withhold everything new until the user came back and ticked it. Connecting a provider still means "everything it offers", minus what you explicitly removed.

Hiding is display-only: it never touches a session's stored model, so a session already on a hidden model keeps running it. Taking something out of a menu must not silently reroute work already using it.

Details worth knowing:

  • Hiding also unpins, in SQL and in the store. A pinned+hidden model would otherwise sit at the top of the very list it was removed from, and modelRows drops hidden pins too so the intermediate state can't render.
  • The filter runs over all three picker sections, not just the catalog. Recents are usage history and keep listing a model after it is hidden, so a model hidden right after being used would keep reappearing under Latest.
  • An empty picker now distinguishes "you hid everything" (with a link to Settings) from "models.dev failed". Telling someone their network is broken when they hid the models themselves sends them debugging nothing.
  • The Settings list is windowed on a fixed row height: an expanded provider is 600 rows, which is exactly the mount cost ModelPicker already exists to avoid.
  • Row actions sit on the RIGHT, in the same column as Hide all / Show all, with an always-visible label. A hover-only affordance on a 600-row list is something you have to hunt for.

hiddenModels is a Set of provider:model rather than the array shape pinnedModels uses: it is only ever asked "is THIS model hidden?", once per row over a long list, and carries no order worth preserving.

Tests: 5 checks over buildModelRows (hidden in no section, per-provider keying, a fully hidden provider drops its header, omitting the set changes nothing) and 6 against the real DB (hide unpins, idempotent, bulk replace stays scoped to its provider).

A gateway provider reports 300-600 models and the picker lists every
connected provider at once, so choosing a model means scrolling past
hundreds you will never run. Pinning promotes a few to the top; it does
nothing about the length of the list underneath. This is the other half.

Settings gains a Models section: one collapsible row per provider with a
count, a search box, per-model Hide/Unhide, and Hide all / Show all
scoped to whatever the search is filtering - so "gpt" + Hide all hides
those matches rather than silently wiping the catalog.

Stored as a DENY-list, not an allow-list. Catalogs grow under us (a
provider ships a model, a plan gains access to one), and an allow-list
would withhold everything new until the user came back and ticked it.
Connecting a provider still means "everything it offers", minus what you
explicitly removed.

Hiding is display-only: it never touches a session's stored model, so a
session already on a hidden model keeps running it. Taking something out
of a menu must not silently reroute work already using it.

Details worth knowing:

- Hiding also unpins, in SQL and in the store. A pinned+hidden model
  would otherwise sit at the top of the very list it was removed from,
  and modelRows drops hidden pins too so the intermediate state can't
  render.
- The filter runs over all three picker sections, not just the catalog.
  Recents are usage history and keep listing a model after it is hidden,
  so a model hidden right after being used would keep reappearing under
  Latest.
- An empty picker now distinguishes "you hid everything" (with a link to
  Settings) from "models.dev failed". Telling someone their network is
  broken when they hid the models themselves sends them debugging
  nothing.
- The Settings list is windowed on a fixed row height: an expanded
  provider is 600 rows, which is exactly the mount cost ModelPicker
  already exists to avoid.
- Row actions sit on the RIGHT, in the same column as Hide all / Show
  all, with an always-visible label. A hover-only affordance on a
  600-row list is something you have to hunt for.

hiddenModels is a Set of `provider:model` rather than the array shape
pinnedModels uses: it is only ever asked "is THIS model hidden?", once
per row over a long list, and carries no order worth preserving.

Tests: 5 checks over buildModelRows (hidden in no section, per-provider
keying, a fully hidden provider drops its header, omitting the set
changes nothing) and 6 against the real DB (hide unpins, idempotent,
bulk replace stays scoped to its provider).
# Conflicts:
#	src/main/db/migrations.ts
#	src/renderer/src/components/ModelPicker.tsx
#	src/renderer/src/lib/store.ts
#	src/renderer/src/routes/Settings.tsx
The v22 assertions replayed the ladder up to MIGRATIONS.length - 1, which assumed the Exa-key DELETE was the last rung. The hidden_models migration now sits on top of it, so the replay stopped one step too early and the DELETE never ran.
@FreddyJD

Copy link
Copy Markdown
Collaborator

Thank you for the change!

@JairEsk
JairEsk merged commit 92f36b4 into main Aug 30, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants