kev-0.5b declared architecture "ggmlc", which llama.cpp does not know. It was fetched, catalogued and placed, and failed on every node — while the answer was in the first kilobytes of the file. internal/gguf reads a GGUF header (v1-v3) up to general.architecture, over HTTP with a Range request, and judges it against the architectures llama.cpp b10991 lists in LLM_ARCH_NAMES (152, copied from the source at that tag); a vision projector is not a model on its own. An unknown build is not refused, only not vouched for, and a header that cannot be fetched does not refuse anything. Checked in three places: the registry listing (from the architecture Hugging Face reports with expand[]=gguf, so one request per repository) shows it and withholds the fetch button; a fetch reads the header and refuses unless "fetch anyway"; and the model service refuses to add such a model, which covers the serve form and ctl model add. Tried on real files: the mirror's qwen2.5-1.5b (qwen2) and bge-m3 (bert), and Qwen2.5-0.5B on Hugging Face through its redirect. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
97 lines
3.1 KiB
Go
97 lines
3.1 KiB
Go
package web
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"io"
|
|
"log/slog"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"net/url"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/hf"
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/store"
|
|
)
|
|
|
|
// ggufServer serves a GGUF whose header names an architecture.
|
|
func ggufServer(t *testing.T, arch string) string {
|
|
t.Helper()
|
|
var b bytes.Buffer
|
|
w := func(v any) { _ = binary.Write(&b, binary.LittleEndian, v) }
|
|
str := func(s string) { w(uint64(len(s))); b.WriteString(s) }
|
|
b.WriteString("GGUF")
|
|
w(uint32(3))
|
|
w(uint64(0))
|
|
w(uint64(2))
|
|
str("general.architecture")
|
|
w(uint32(8))
|
|
str(arch)
|
|
str("general.name")
|
|
w(uint32(8))
|
|
str("m")
|
|
body := b.Bytes()
|
|
srv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
|
http.ServeContent(rw, r, "m.gguf", time.Time{}, bytes.NewReader(body))
|
|
}))
|
|
t.Cleanup(srv.Close)
|
|
return srv.URL + "/m.gguf"
|
|
}
|
|
|
|
func mirrorPageLlama(t *testing.T, d MirrorDeps) *http.ServeMux {
|
|
t.Helper()
|
|
a := fakeAccounts{user: store.User{ID: "u1", Email: "a@example.com", IsAdmin: true}}
|
|
p := NewAccountPages(a, nil, nil, "v0", slog.New(slog.NewTextHandler(io.Discard, nil)))
|
|
p.SetLlamaCppVersion("b10991")
|
|
mux := http.NewServeMux()
|
|
p.RegisterAdminMirror(mux, d)
|
|
return mux
|
|
}
|
|
|
|
// The file that started this: kev-0.5b, architecture "ggmlc", downloaded,
|
|
// catalogued, and refused by llama.cpp on every node it was placed on.
|
|
func TestAFileTheNodesCannotLoadIsNotFetched(t *testing.T) {
|
|
m := &fakeMirror{}
|
|
mux := mirrorPageLlama(t, MirrorDeps{Mirror: m})
|
|
src := ggufServer(t, "ggmlc")
|
|
|
|
body := mirrorPost(t, mux, "/admin/mirror/fetch", url.Values{"csrf": {"tok"},
|
|
"source": {src}, "model": {"kev"}, "version": {"v1"}}).Body.String()
|
|
if len(m.all) != 0 {
|
|
t.Fatal("a file llama.cpp cannot load was sent to the mirror")
|
|
}
|
|
if !strings.Contains(body, "ggmlc") || !strings.Contains(body, "cannot load") {
|
|
t.Errorf("the refusal should say why; got %s", body)
|
|
}
|
|
|
|
// Asked for regardless, it is fetched.
|
|
mirrorPost(t, mux, "/admin/mirror/fetch", url.Values{"csrf": {"tok"},
|
|
"source": {src}, "model": {"kev"}, "version": {"v1"}, "force": {"1"}})
|
|
if len(m.all) != 1 {
|
|
t.Error("fetch anyway did not fetch")
|
|
}
|
|
|
|
// And one it can load goes straight through.
|
|
m.all = nil
|
|
mirrorPost(t, mux, "/admin/mirror/fetch", url.Values{"csrf": {"tok"},
|
|
"source": {ggufServer(t, "qwen2")}, "model": {"q"}, "version": {"v1"}})
|
|
if len(m.all) != 1 {
|
|
t.Error("a qwen2 GGUF was refused")
|
|
}
|
|
}
|
|
|
|
func TestTheRegistryListingSaysWhatCannotBeServed(t *testing.T) {
|
|
reg := &fakeRegistry{repo: hf.Repo{ID: "someone/kev-gguf", Revision: "abc12345", Architecture: "ggmlc",
|
|
Files: []hf.File{{Path: "kev-q4_k_m.gguf", Bytes: 500 << 20}}}}
|
|
body := mirrorGet(t, mirrorPageLlama(t, MirrorDeps{Mirror: &fakeMirror{}, Registry: reg}),
|
|
"/admin/mirror?q=kev&repo=someone/kev-gguf").Body.String()
|
|
if !strings.Contains(body, "cannot be served") {
|
|
t.Error("the listing does not say the file cannot be served")
|
|
}
|
|
if strings.Contains(body, `value="`+"https://huggingface.co") && strings.Contains(body, ">Fetch</button>") {
|
|
t.Error("the listing still offers to fetch it")
|
|
}
|
|
}
|