feat(desktop): default the model picker to the featured shortlist

expandProviderDefaults prefers a provider's featured_models when present and
falls back to the existing top-N for providers that ship none (single-lab,
local, custom). Only aggregators get curated, so exactly the providers with
the everything-under-the-sun problem are trimmed; the rest are unchanged.
Every non-featured model stays one search or Edit Models toggle away.
This commit is contained in:
Brooklyn Nicholson 2026-07-28 03:52:33 -05:00
parent d4449c47e2
commit 64166f87ba
3 changed files with 161 additions and 3 deletions

View file

@ -10,6 +10,7 @@ import {
isProviderSentinel,
modelVisibilityKey,
resolveVisibleKeys,
setProviderVisibility,
toggleModelVisibility
} from './model-visibility'
@ -224,3 +225,105 @@ describe('resolveVisibleKeys', () => {
expect([...resolveVisibleKeys(new Set(), providers)]).toEqual([])
})
})
describe('featured defaults', () => {
const featuredProvider = (slug: string, models: string[], featured_models: string[]): ModelOptionProvider => ({
featured_models,
models,
name: slug,
slug
})
it('defaults to the featured shortlist when a provider publishes one', () => {
const nous = featuredProvider(
'nous',
['anthropic/opus', 'anthropic/haiku', 'google/gemini', 'x-ai/grok'],
['anthropic/opus', 'google/gemini', 'x-ai/grok']
)
const visible = defaultVisibleKeys([nous])
// Featured are visible; the non-featured model is hidden by default.
expect(visible.has(modelVisibilityKey('nous', 'anthropic/opus'))).toBe(true)
expect(visible.has(modelVisibilityKey('nous', 'google/gemini'))).toBe(true)
expect(visible.has(modelVisibilityKey('nous', 'x-ai/grok'))).toBe(true)
expect(visible.has(modelVisibilityKey('nous', 'anthropic/haiku'))).toBe(false)
})
it('falls back to top-N when a provider ships no featured list', () => {
const plain = provider('ollama', ['qwen3:latest', 'llama3.2:latest'])
const visible = defaultVisibleKeys([plain])
// No featured_models → every model stays a default (top-N, N ≫ 2 here).
expect(visible.has(modelVisibilityKey('ollama', 'qwen3:latest'))).toBe(true)
expect(visible.has(modelVisibilityKey('ollama', 'llama3.2:latest'))).toBe(true)
})
it('ignores an empty featured list and falls back to top-N', () => {
const plain = featuredProvider('ollama', ['qwen3:latest', 'llama3.2:latest'], [])
const visible = defaultVisibleKeys([plain])
expect(visible.has(modelVisibilityKey('ollama', 'qwen3:latest'))).toBe(true)
expect(visible.has(modelVisibilityKey('ollama', 'llama3.2:latest'))).toBe(true)
})
})
describe('setProviderVisibility', () => {
const providers = [provider('openai', ['gpt-a', 'gpt-b']), provider('nous', ['hermes-x', 'hermes-y'])]
it('enabling a provider makes every one of its models visible', () => {
// Start from a hidden-all openai; flip it on.
const stored = new Set([emptyProviderSentinelKey('openai')])
const next = setProviderVisibility(stored, providers, 'openai', true)
const visible = effectiveVisibleKeys(next, providers)
expect(visible.has(modelVisibilityKey('openai', 'gpt-a'))).toBe(true)
expect(visible.has(modelVisibilityKey('openai', 'gpt-b'))).toBe(true)
// Sentinel is cleared.
expect(next.has(emptyProviderSentinelKey('openai'))).toBe(false)
})
it('disabling a provider hides all its models and records the sentinel', () => {
const next = setProviderVisibility(null, providers, 'openai', false)
expect(next.has(emptyProviderSentinelKey('openai'))).toBe(true)
const visible = effectiveVisibleKeys(next, providers)
expect(visible.has(modelVisibilityKey('openai', 'gpt-a'))).toBe(false)
expect(visible.has(modelVisibilityKey('openai', 'gpt-b'))).toBe(false)
})
it('leaves other providers untouched (their sentinels survive)', () => {
const stored = new Set([emptyProviderSentinelKey('nous')])
// Turn openai fully on; nous must stay hidden.
const next = setProviderVisibility(stored, providers, 'openai', true)
expect(next.has(emptyProviderSentinelKey('nous'))).toBe(true)
const visible = effectiveVisibleKeys(next, providers)
expect(visible.has(modelVisibilityKey('nous', 'hermes-x'))).toBe(false)
expect(visible.has(modelVisibilityKey('openai', 'gpt-a'))).toBe(true)
})
it('round-trips: enable then disable returns to a clean hidden-all', () => {
const enabled = setProviderVisibility(null, providers, 'openai', true)
const disabled = setProviderVisibility(enabled, providers, 'openai', false)
expect(disabled.has(emptyProviderSentinelKey('openai'))).toBe(true)
// No stray real keys left for the provider.
expect([...disabled].some(k => k.startsWith('openai::') && !isProviderSentinel(k))).toBe(false)
})
it('collapses model families to one key per family when enabling', () => {
// A base + its -fast sibling collapse to a single family row/key.
const ps = [provider('nous', ['model', 'model-fast'])]
const next = setProviderVisibility(null, ps, 'nous', true)
expect(next.has(modelVisibilityKey('nous', 'model'))).toBe(true)
// The -fast sibling is represented by its base family, not its own key.
expect(next.has(modelVisibilityKey('nous', 'model-fast'))).toBe(false)
})
})

View file

@ -111,13 +111,21 @@ export function defaultVisibleKeys(providers: readonly ModelOptionProvider[]): S
return keys
}
/** Add a provider's curated default model keys (top-N collapsed families) to
* `target`. Shared by `defaultVisibleKeys` and `resolveVisibleKeys` so the
/** Add a provider's curated default model keys to `target`. Prefers the
* backend's `featured_models` shortlist (one flagship per lab) for aggregator
* providers that would otherwise flood the default view with dozens of models;
* falls back to the top-N collapsed families when a provider ships no featured
* list. Shared by `defaultVisibleKeys` and `resolveVisibleKeys` so the
* expansion rule lives in exactly one place. */
function expandProviderDefaults(provider: ModelOptionProvider, target: Set<string>): void {
const families = collapseModelFamilies(provider.models ?? [])
for (const family of families.slice(0, DEFAULT_VISIBLE_PER_PROVIDER)) {
const featured = provider.featured_models ?? []
const defaults = featured.length
? families.filter(family => featured.includes(family.id))
: families.slice(0, DEFAULT_VISIBLE_PER_PROVIDER)
for (const family of defaults) {
target.add(modelVisibilityKey(provider.slug, family.id))
}
}
@ -209,3 +217,45 @@ export function toggleModelVisibility(
return next
}
/** Compute the next persisted visibility set when a provider's master switch is
* flipped. `visible=true` enables every one of the provider's collapsed model
* families (and clears its hide-all sentinel); `visible=false` removes them all
* and records the sentinel so the defaults are not silently re-expanded.
* Seeds from `resolveVisibleKeys` so other providers' state (including their
* sentinels) survives the persist, mirroring `toggleModelVisibility`. */
export function setProviderVisibility(
stored: Set<string> | null,
providers: readonly ModelOptionProvider[],
providerSlug: string,
visible: boolean
): Set<string> {
const next = resolveVisibleKeys(stored, providers)
const sentinel = emptyProviderSentinelKey(providerSlug)
const provider = providers.find(p => p.slug === providerSlug)
const families = collapseModelFamilies(provider?.models ?? [])
// Drop every existing entry for this provider (real keys + sentinel); we
// rebuild its state from scratch below.
for (const key of [...next]) {
if (key.startsWith(`${providerSlug}::`)) {
next.delete(key)
}
}
if (visible) {
for (const family of families) {
next.add(modelVisibilityKey(providerSlug, family.id))
}
// A provider with zero models can't be "all on" — leave it empty rather
// than stranding a sentinel that reads as an explicit hide-all.
if (families.length === 0) {
next.delete(sentinel)
}
} else {
next.add(sentinel)
}
return next
}

View file

@ -363,6 +363,11 @@ export interface ModelOptionProvider {
slug: string
total_models?: number
warning?: string
/** Curated shortlist (one flagship per lab) the picker shows by default for
* aggregator providers that serve dozens of models across many labs. Empty
* for providers with no manifest entry the picker falls back to top-N.
* The rest of `models` stays reachable via search / Edit Models. */
featured_models?: string[]
/** True when the provider has usable credentials. False for canonical
* providers surfaced by `include_unconfigured` that the user hasn't set up
* yet render these with a setup affordance instead of hiding them. */