ui : fold the oai providers under one repo

Assisted-by: pi:llama.cpp/DeepSeek-V4.1-Flash
This commit is contained in:
Aleksander Grygier
2026-09-28 12:10:12 +02:00
parent 5f6aa1b91f
commit 0fad79b867
3 changed files with 33 additions and 14 deletions
@@ -148,7 +148,11 @@
ordered.push({
backendId: null,
isLocal: false,
items: leading(chatOnly),
// one repo, one row per provider that serves it
items: groupModelQuants(
chatOnly.flatMap((entry) => entry.quants),
true
),
key: 'oai-compat',
kind: 'compat',
label: 'OAI-compat'
@@ -229,10 +229,13 @@
{#snippet repoRow(entry: ModelQuantGroup, indent = 0, compact = false)}
{@const isExpanded = !collapsedQuants.has(entry.key)}
{@const providerCount = new Set(entry.quants.map((option) => option.backendId ?? '')).size}
{@const groupLabel =
entry.kind === 'variants'
? `${entry.quants.length} variants`
: `${entry.quants.length} quants available`}
entry.kind === 'providers'
? `${providerCount} provider${providerCount === 1 ? '' : 's'}`
: entry.kind === 'variants'
? `${entry.quants.length} variants`
: `${entry.quants.length} quants available`}
{@const anyLoaded = entry.quants.some(isLoadedOption)}
<div class="px-2">
@@ -295,7 +298,7 @@
</div>
{/snippet}
{#snippet quantRow(option: ModelOption, indent = 0, compact = false)}
{#snippet quantRow(option: ModelOption, indent = 0, compact = false, showProvider = false)}
{@const favorite = isFavorite(option)}
{@const canLoad = getBackendCapabilities(getBackend(option.backendId)).loadUnload}
{@const isHidden = modelsStore.isHidden(option.id)}
@@ -316,7 +319,9 @@
tabindex="0"
>
<span class="flex min-w-0 items-center gap-3" style="padding-left: {indent}px">
<Badge class="h-5 shrink-0 px-1.5 text-[10px]" variant="secondary">{quant}</Badge>
<Badge class="h-5 shrink-0 px-1.5 text-[10px]" variant="secondary">
{showProvider ? (getBackend(option.backendId)?.name ?? quant) : quant}
</Badge>
<span class="truncate text-sm text-muted-foreground">{option.model}</span>
</span>
@@ -347,7 +352,7 @@
{#if !collapsedQuants.has(entry.key)}
{#each entry.quants as quant (quant.id)}
{@render quantRow(quant, indent + 24, compact)}
{@render quantRow(quant, indent + 24, compact, entry.kind === 'providers')}
{/each}
{/if}
{:else}
@@ -41,7 +41,7 @@ export type ModelOverrideMap = Record<string, ModelOverride>;
export type { ModelLoadProgress };
/** What a group folds, which decides its label. */
export type ModelGroupKind = 'quants' | 'variants';
export type ModelGroupKind = 'providers' | 'quants' | 'variants';
/** One repo of the table, with the rows it ships as. */
export interface ModelQuantGroup {
@@ -181,14 +181,15 @@ export function modelRepoKey(model: string): string {
}
/** Fold the quants of one repo into a single entry, so the table shows one row per model. */
export function groupModelQuants(models: ModelOption[]): ModelQuantGroup[] {
export function groupModelQuants(models: ModelOption[], mergeProviders = false): ModelQuantGroup[] {
const groups = new SvelteMap<string, ModelQuantGroup>();
for (const option of models) {
const repo = modelRepoKey(option.model);
// groups stay within one backend, so the same repo served by two providers
// is not read as two quants of one model
const key = `${option.backendId ?? ''}::${repo}`;
// is not read as two quants of one model. The OAI-compat block asks for the
// opposite: one repo, one row per provider that serves it.
const key = mergeProviders ? repo : `${option.backendId ?? ''}::${repo}`;
const group = groups.get(key);
if (group) {
@@ -204,8 +205,13 @@ export function groupModelQuants(models: ModelOption[]): ModelQuantGroup[] {
const kind = groupKind(group.quants);
const modelIds = group.quants.map((option) => option.model);
// the very same id twice is not a quant set; keep those rows apart
if (modelIds.length > 1 && modelIds.every((model) => model === modelIds[0])) {
// the very same id twice is not a quant set; keep those rows apart, unless
// the group exists to list the providers that serve it
if (
kind !== 'providers' &&
modelIds.length > 1 &&
modelIds.every((model) => model === modelIds[0])
) {
return group.quants.map((option) => ({
...group,
base: option,
@@ -219,8 +225,12 @@ export function groupModelQuants(models: ModelOption[]): ModelQuantGroup[] {
});
}
/** Quants share a quantization suffix; anything else is a variant. */
/** What a group folds: providers, quants, or variants of one repo. */
function groupKind(quants: ModelOption[]): ModelGroupKind {
const backends = new Set(quants.map((option) => option.backendId ?? ''));
if (backends.size > 1) return 'providers';
const isQuant = quants.every(
(option) => (option.parsedId ?? ModelsService.parseModelId(option.model)).quantization
);