ui : show the context the model reports before it is loaded

Assisted-by: pi:llama.cpp/DeepSeek-V4.1-Flash
This commit is contained in:
Aleksander Grygier
2026-09-28 12:10:13 +02:00
parent a1d4ace40d
commit f0cd8ee289
2 changed files with 22 additions and 29 deletions
@@ -44,15 +44,18 @@
let loadProgress = $derived(
isOperationInProgress ? modelsStore.status.getLoadProgress(option.model) : null
);
let contextMax = $derived(
option.contextLength ??
serverProps?.default_generation_settings?.n_ctx ??
LOAD_DEFAULTS.contextLength
);
// The server only reports the full metadata once a model is loaded, which loads
// it. When discovery is on, the Hub fills those gaps instead.
let hubDetails = $state<HfModelDetailInfo | null>(null);
// the window the model can take, from the listing or the Hub; a loaded model's runtime
// context only bounds it when nothing else says otherwise
let contextMax = $derived(
option.contextLength ??
hubDetails?.gguf?.context_length ??
serverProps?.default_generation_settings?.n_ctx ??
LOAD_DEFAULTS.contextLength
);
$effect(() => {
const repo = option.model.split(':')[0] ?? option.model;
@@ -47,29 +47,29 @@
};
});
// the window a model can take, from the listing or from the Hub
let contextLabel = $derived(
option.contextLength
? `${formatParameters(option.contextLength)} tokens`
: hub?.gguf?.context_length
? `${formatNumber(hub.gguf.context_length)} tokens`
: null
);
let meta = $derived(option.meta);
// the server reports these once the model is loaded; the Hub knows them anyway
let gguf = $derived(hub?.gguf ?? null);
let modalities = $derived(modelsStore.props.getModelModalitiesArray(option.id));
let isMissingContext = $derived(!serverProps);
let rows = $derived([
{ isCopyable: true, isMono: true, label: 'File Path', value: serverProps?.model_path ?? null },
{
label: 'Context Size',
// the server reports the context it runs with once the model is loaded; until then
// the listing, or the Hub, still says what the model can take
value: serverProps
? `${formatNumber(serverProps.default_generation_settings.n_ctx)} tokens`
: null
},
{
label: 'Training Context',
value: meta?.n_ctx_train
? `${formatNumber(meta.n_ctx_train)} tokens`
: option.contextLength
? `${formatParameters(option.contextLength)} tokens`
: gguf?.context_length
? `${formatNumber(gguf.context_length)} tokens`
: null
: (contextLabel ?? null)
},
{ label: 'Training Context', value: contextLabel },
{
label: 'Model Size',
value: meta?.size ? formatFileSize(meta.size) : (resolvedSize ?? size)
@@ -124,21 +124,11 @@
{#each rows as row (row.label)}
<div class="flex items-center gap-3 border-b border-border/30 py-2.5 last:border-b-0">
<span
class="text-sm text-muted-foreground {row.label === 'Context Size' && isMissingContext
? 'text-destructive'
: ''}">{row.label}</span
>
<span class="text-sm text-muted-foreground">{row.label}</span>
<span class="ml-auto flex min-w-0 items-center gap-2">
{#if row.value === null}
<span
class={isMissingContext && row.label === 'Context Size'
? 'text-destructive'
: 'text-muted-foreground'}
>
{isMissingContext && row.label === 'Context Size' ? 'Not available' : '—'}
</span>
<span class="text-muted-foreground">—</span>
{:else}
<span
class={[