ui : keep sidecar files out of the model lists

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 92d30df3f3
commit 7ef906bfc5
3 changed files with 26 additions and 7 deletions
@@ -7,6 +7,7 @@
*/
import { API_MODELS, LOCAL_BACKEND_ID } from '$lib/constants';
import { ModelsService } from '$lib/services/models.service';
import type { ApiModelsListResponse, Backend, ModelOption } from '$lib/types';
import { isAbortError } from '$lib/utils/abort';
import { apiUrl } from '$lib/utils/api-base';
@@ -130,6 +131,9 @@ function normalizeBackendModel(entry: unknown): ModelOption[] {
if (!id) return [];
// a llama-compat server lists its projector and draft sidecars as models too
if (ModelsService.isSidecarEntry(id)) return [];
return [
{ capabilities: [], contextLength: readModelContextLength(raw), id, model: id, name: id }
];
+15 -5
View File
@@ -131,13 +131,23 @@ export class ModelsService {
static isSidecarEntry(modelId: string): boolean {
const idx = modelId.indexOf(MODEL_ID.QUANTIZATION_SEPARATOR);
if (idx === MODEL_ID.NOT_FOUND) return false;
if (idx !== MODEL_ID.NOT_FOUND) {
const tag = modelId.slice(idx + 1).toLowerCase();
const dash = tag.lastIndexOf(MODEL_ID.SEGMENT_SEPARATOR);
const token = dash === -1 ? tag : tag.slice(dash + 1);
const tag = modelId.slice(idx + 1).toLowerCase();
const dash = tag.lastIndexOf(MODEL_ID.SEGMENT_SEPARATOR);
const token = dash === -1 ? tag : tag.slice(dash + 1);
if (SIDECAR_TOKENS.includes(token)) return true;
}
return SIDECAR_TOKENS.includes(token);
// the router also lists projector and draft files by filename, e.g.
// `org/model-mmproj-F16.gguf` or `mmproj-model.gguf`
const name = modelId.split('/').pop() ?? modelId;
return (
MODEL_ID.SIDECAR_INFIX_REGEX.test(name) ||
MODEL_ID.SIDECAR_PREFIX_REGEX.test(name) ||
MODEL_ID.SIDECAR_SUFFIX_REGEX.test(name)
);
}
/**
@@ -668,8 +668,13 @@ class ModelsStore implements ModelPropsHost, ModelStatusHost {
return (
entries
// sidecar entries mark downloaded sidecar files, not loadable models
.filter(({ item }) => !ModelsService.isSidecarEntry(item.id))
// sidecar entries mark downloaded sidecar files, not loadable models;
// the router also lists projector files by filename, which carry the
// sidecar token inside the id rather than after a colon
.filter(
({ item }) =>
!ModelsService.isSidecarEntry(item.id) && !ModelsService.parseModelId(item.id).sidecar
)
// in-flight downloads are not usable models yet; the selector tracks
// them in its "Download in progress" section instead
.filter(({ item }) => item.status?.value !== ServerModelStatus.DOWNLOADING)