diff --git a/tools/ui/src/lib/utils/backend.ts b/tools/ui/src/lib/utils/backend.ts index 0677988d7b..21555a7e8a 100644 --- a/tools/ui/src/lib/utils/backend.ts +++ b/tools/ui/src/lib/utils/backend.ts @@ -228,19 +228,43 @@ function parseOptionalPath(raw: unknown): string | undefined { * `top_provider`, so try the flat fields first and the nested one after. */ export function readModelContextLength(entry: Record): number | undefined { + const flat = readContextField(entry); + + if (flat !== undefined) return flat; + + const topProvider = entry.top_provider; + + if (topProvider && typeof topProvider === 'object') { + const nested = readContextField(topProvider as Record); + + if (nested !== undefined) return nested; + } + + // Hugging Face lists one entry per inference provider, and they disagree on + // the budget; take the largest so the gauge does not undersell the model. + const providers = entry.providers; + + if (Array.isArray(providers)) { + const sizes = providers + .map((provider) => + provider && typeof provider === 'object' + ? readContextField(provider as Record) + : undefined + ) + .filter((size): size is number => size !== undefined); + + if (sizes.length > 0) return Math.max(...sizes); + } + + return undefined; +} + +function readContextField(entry: Record): number | undefined { for (const field of MODEL_CONTEXT_LENGTH_FIELDS) { const value = entry[field]; if (typeof value === 'number' && value > 0) return value; } - const topProvider = entry.top_provider; - - if (topProvider && typeof topProvider === 'object') { - const value = (topProvider as Record).context_length; - - if (typeof value === 'number' && value > 0) return value; - } - return undefined; }