diff --git a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptions.svelte b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptions.svelte index 7e7a38e681..1eba25bc16 100644 --- a/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptions.svelte +++ b/tools/ui/src/lib/components/app/models/discover/ModelsDiscoverModelDetailsDownloadOptions.svelte @@ -236,6 +236,9 @@ draftEntry ? (HuggingFaceService.extractQuantMeta(draftEntry.path)?.sidecar ?? null) : null ); + /** True when the picked draft is the shared (target-borrowing) variant. */ + let draftShared = $derived(draftEntry ? (HuggingFaceService.extractQuantMeta(draftEntry.path)?.shared ?? false) : false); + // LLAMA-APP-REUSE: --spec-type value for each draft sidecar const SPEC_TYPE: Record = { [ModelAuxSidecar.MMPROJ]: '', @@ -341,7 +344,7 @@ */ let downloadLabel = $derived.by(() => { const main = mainEntry ?? commandMain; - const draftLabel = draftSidecar?.toUpperCase(); + const draftLabel = draftSidecar ? `${draftSidecar.toUpperCase()}${draftShared ? ' shared' : ''}` : undefined; let label = 'Download'; @@ -396,7 +399,7 @@ - or download from your terminal + or run in your terminal diff --git a/tools/ui/src/lib/components/app/models/discover/download-options.utils.ts b/tools/ui/src/lib/components/app/models/discover/download-options.utils.ts index a76ca621fd..e643a7f2e0 100644 --- a/tools/ui/src/lib/components/app/models/discover/download-options.utils.ts +++ b/tools/ui/src/lib/components/app/models/discover/download-options.utils.ts @@ -33,11 +33,11 @@ export function classify(path: string): 'main' | 'draft' | 'aux' { return isAuxSidecar(sidecar) ? 'aux' : 'draft'; } -/** Display label of a file: its quant, else the file name without the extension. */ +/** Display label of a file: its quant (plus `shared` for shared draft variants), else the file name without the extension. */ export function labelFor(path: string): string { - const quant = HuggingFaceService.extractQuantMeta(path)?.quant; + const meta = HuggingFaceService.extractQuantMeta(path); - if (quant) return quant; + if (meta?.quant) return meta.shared ? `${meta.quant} shared` : meta.quant; const basename = path.split('/').pop() ?? path; diff --git a/tools/ui/src/lib/services/huggingface.service.ts b/tools/ui/src/lib/services/huggingface.service.ts index 0772fa1a1a..e2f3ad1d27 100644 --- a/tools/ui/src/lib/services/huggingface.service.ts +++ b/tools/ui/src/lib/services/huggingface.service.ts @@ -179,6 +179,8 @@ export class HuggingFaceService { // LLAMA-APP-REUSE: quant + sidecar filename parser static extractQuantMeta(filename: string): { quant: string | null; + /** Draft-head-only variant borrowing embed/output weights from the target model. */ + shared: boolean; sidecar: ModelSidecar | null; sidecarForm: SidecarForm | null; } | null { @@ -220,6 +222,9 @@ export class HuggingFaceService { // - For main files like `Llama-3-8B-Q4_K_M.gguf` we land on the trailing quant. const segments = source.split(MODEL_ID.SEGMENT_SEPARATOR); const quantIdx = segments.findIndex((seg) => MODEL_ID.QUANTIZATION_SEGMENT_REGEX.test(seg)); + // Unsloth ships draft heads in two layouts: `shared-` files borrow the + // embedding/output weights from the target model, others are self-contained. + const shared = segments.some((seg) => seg.toLowerCase() === 'shared'); let quant = quantIdx >= 0 ? segments[quantIdx].toUpperCase() : null; @@ -232,7 +237,7 @@ export class HuggingFaceService { quant = `${HF_UD_QUANT_PREFIX}-${quant}`; } - return { quant, sidecar, sidecarForm }; + return { quant, shared, sidecar, sidecarForm }; } /**