mirror of
https://github.com/mudler/LocalAI.git
synced 2026-09-22 06:04:55 -04:00
fix(api): report an alias's target in /v1/models/capabilities (#12183)
An alias config is a pure redirect with no backend of its own, so the capabilities listing described it from its stub: no capabilities, no modalities, and the default 4096 context_size. Clients that size their context budget from this endpoint (nib, for one) then compacted every turn against a model that really serves 100k. Resolve the alias and report the target's capabilities, modalities and context_size under the alias's id. A dangling or chained alias now reports no enrichment instead of defaults no model runs with. Co-authored-by: Ettore Di Giacinto <mudler@localai.io> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2 files changed
+60
-1
No files matched your search
@@ -35,7 +35,7 @@ func ListModelCapabilitiesEndpoint(bcl *config.ModelConfigLoader, ml *model.Mode
|
||||
dataModels := []schema.ModelCapabilities{}
|
||||
for _, m := range modelNames {
|
||||
entry := schema.ModelCapabilities{ID: m, Object: "model"}
|
||||
if cfg, ok := bcl.GetModelConfig(m); ok {
|
||||
if cfg, ok := modelConfigFor(bcl, m); ok {
|
||||
entry.Capabilities = cfg.Capabilities()
|
||||
entry.ThreeDOperations = cfg.ThreeDOperations()
|
||||
entry.InputModalities = cfg.InputModalities()
|
||||
@@ -53,3 +53,22 @@ func ListModelCapabilitiesEndpoint(bcl *config.ModelConfigLoader, ml *model.Mode
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// modelConfigFor returns the config that describes what a listed model can
|
||||
// do. An alias is a pure redirect whose own config carries no backend, so its
|
||||
// capabilities, modalities and context_size would all be empty defaults;
|
||||
// report the target's instead, since that is the model a request for the
|
||||
// alias reaches. A dangling or chained alias returns false: the endpoint then
|
||||
// reports the entry without enrichment rather than advertise defaults no
|
||||
// model runs with.
|
||||
func modelConfigFor(bcl *config.ModelConfigLoader, name string) (config.ModelConfig, bool) {
|
||||
cfg, ok := bcl.GetModelConfig(name)
|
||||
if !ok {
|
||||
return config.ModelConfig{}, false
|
||||
}
|
||||
resolved, _, err := bcl.ResolveAlias(&cfg)
|
||||
if err != nil {
|
||||
return config.ModelConfig{}, false
|
||||
}
|
||||
return *resolved, true
|
||||
}
|
||||
@@ -142,4 +142,44 @@ parameters:
|
||||
Expect(entry).NotTo(BeNil())
|
||||
Expect(entry.ContextSize).To(Equal(backend.DefaultContextSize))
|
||||
})
|
||||
It("reports an alias with its target's capabilities and context_size", func() {
|
||||
writeConfig("real-llm", `
|
||||
name: real-llm
|
||||
backend: llama-cpp
|
||||
context_size: 100000
|
||||
known_usecases:
|
||||
- FLAG_CHAT
|
||||
- FLAG_VISION
|
||||
template:
|
||||
chat: "{{ .Input }}"
|
||||
parameters:
|
||||
model: model.gguf
|
||||
`)
|
||||
writeConfig("friendly", `
|
||||
name: friendly
|
||||
alias: real-llm
|
||||
`)
|
||||
resp := call()
|
||||
target := entryFor(resp, "real-llm")
|
||||
Expect(target).NotTo(BeNil())
|
||||
|
||||
entry := entryFor(resp, "friendly")
|
||||
Expect(entry).NotTo(BeNil())
|
||||
Expect(entry.ID).To(Equal("friendly"))
|
||||
Expect(entry.ContextSize).To(Equal(100000))
|
||||
Expect(entry.Capabilities).To(Equal(target.Capabilities))
|
||||
Expect(entry.InputModalities).To(Equal(target.InputModalities))
|
||||
Expect(entry.OutputModalities).To(Equal(target.OutputModalities))
|
||||
})
|
||||
|
||||
It("reports no context_size for an alias whose target does not exist", func() {
|
||||
writeConfig("dangling", `
|
||||
name: dangling
|
||||
alias: missing-model
|
||||
`)
|
||||
entry := entryFor(call(), "dangling")
|
||||
Expect(entry).NotTo(BeNil())
|
||||
Expect(entry.ContextSize).To(BeZero())
|
||||
Expect(entry.Capabilities).To(BeEmpty())
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user