mirror of
https://github.com/mudler/LocalAI.git
synced 2026-09-19 03:32:29 -04:00
feat(gallery): add nanbeige4.1-3b meta entry with hardware-resolved variants
Adds the first real meta entry to the gallery index. It resolves to the Q8_0 build on hosts with at least 6GiB of VRAM and to the Q4_K_M build everywhere else, installing either payload under the stable name nanbeige4.1-3b. The entry carries a url equal to its final candidate's url. LocalAI releases that predate candidates support parse the index non-strictly and drop the key silently, so without that url they would list the entry and install nothing. A regression spec parses the index the way those releases do and asserts every meta entry stays installable for them. Also teaches core/schema/gallery-model.schema.json about candidates. The schema sets additionalProperties: false at the top level, so an author following CONTRIBUTING.md and adding the yaml-language-server comment would otherwise get a validation error on this entry. Assisted-by: Claude:claude-opus-4-8 Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
1 parent
98a0e3d7fa
commit
d0d441bb43
3 files changed
+102
No files matched your search
@@ -368,3 +368,40 @@ var _ = Describe("InstallModelFromGallery with meta entries", func() {
|
||||
Expect(record.URLs).To(ConsistOf("https://example.invalid/qwen3"))
|
||||
})
|
||||
})
|
||||
|
||||
var _ = Describe("legacy client compatibility", func() {
|
||||
It("exposes a url on every meta entry to clients that ignore candidates", func() {
|
||||
data, err := os.ReadFile(filepath.Join("..", "..", "gallery", "index.yaml"))
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
// Parse exactly as an older LocalAI release would: non-strictly, with
|
||||
// no knowledge of the candidates key.
|
||||
var legacy []struct {
|
||||
Name string `yaml:"name"`
|
||||
URL string `yaml:"url"`
|
||||
}
|
||||
Expect(yaml.Unmarshal(data, &legacy)).To(Succeed())
|
||||
|
||||
var current []gallery.GalleryModel
|
||||
Expect(yaml.Unmarshal(data, ¤t)).To(Succeed())
|
||||
|
||||
urlByName := map[string]string{}
|
||||
for _, e := range legacy {
|
||||
urlByName[e.Name] = e.URL
|
||||
}
|
||||
|
||||
metaCount := 0
|
||||
for _, e := range current {
|
||||
if !e.IsMeta() {
|
||||
continue
|
||||
}
|
||||
metaCount++
|
||||
// Without a url an old client lists the entry and installs an
|
||||
// empty model, because it silently drops candidates.
|
||||
Expect(urlByName[e.Name]).ToNot(BeEmpty(),
|
||||
"meta entry %q is invisible payload-wise to older clients", e.Name)
|
||||
}
|
||||
Expect(metaCount).To(BeNumerically(">", 0),
|
||||
"expected at least one meta entry in the gallery index")
|
||||
})
|
||||
})
|
||||
@@ -56,6 +56,42 @@
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"candidates": {
|
||||
"type": "array",
|
||||
"description": "Ordered variant list of a meta entry. The first candidate the host satisfies is installed, under the meta entry's own name. An entry carrying candidates must not also carry files or config_file.",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["model"],
|
||||
"properties": {
|
||||
"model": {
|
||||
"type": "string",
|
||||
"description": "Name of a concrete (non-meta) gallery entry"
|
||||
},
|
||||
"capability": {
|
||||
"type": "string",
|
||||
"description": "Host capability this candidate requires, matched exactly and case-sensitively (for example metal, nvidia-cuda-12). Absent matches any host."
|
||||
},
|
||||
"min_vram": {
|
||||
"type": "string",
|
||||
"description": "Authored VRAM floor, for example 20GiB. Authoritative: inference never overwrites it."
|
||||
},
|
||||
"backend": {
|
||||
"type": "string",
|
||||
"description": "Denormalized by the nightly job for display. Never authored by hand."
|
||||
},
|
||||
"quantization": {
|
||||
"type": "string",
|
||||
"description": "Denormalized by the nightly job for display. Never authored by hand."
|
||||
},
|
||||
"inferred_min_vram": {
|
||||
"type": "string",
|
||||
"description": "Denormalized by the nightly job as a fallback floor. Never authored by hand; min_vram wins."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"prompt_templates": {
|
||||
"type": "array",
|
||||
"description": "Prompt templates written as .tmpl files",
|
||||
|
||||
Reference in new issue
Block a user