mirror of
https://github.com/mudler/LocalAI.git
synced 2026-05-18 05:33:09 -04:00
fix(gallery): Use YAML v3 to avoid merging maps with incompatible keys (#8580)
Signed-off-by: Richard Palethorpe <io@richiejp.com>
This commit is contained in:
committed by
GitHub
parent
109f29cc24
commit
074a982853
@@ -12,7 +12,7 @@ import (
|
||||
"github.com/mudler/LocalAI/pkg/system"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"gopkg.in/yaml.v2"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
"github.com/mudler/LocalAI/pkg/xsync"
|
||||
"github.com/mudler/xlog"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
func GetGalleryConfigFromURL[T any](url string, basePath string) (T, error) {
|
||||
|
||||
@@ -4,11 +4,12 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"dario.cat/mergo"
|
||||
"github.com/mudler/LocalAI/core/config"
|
||||
. "github.com/mudler/LocalAI/core/gallery"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"gopkg.in/yaml.v2"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var _ = Describe("Gallery", func() {
|
||||
@@ -462,4 +463,60 @@ var _ = Describe("Gallery", func() {
|
||||
Expect(result).To(BeNil())
|
||||
})
|
||||
})
|
||||
|
||||
Describe("YAML merge with nested maps", func() {
|
||||
It("should handle YAML anchors and merges with nested overrides (regression test for nanbeige4.1)", func() {
|
||||
// This tests the fix for the panic that occurred with yaml.v2:
|
||||
// yaml.v2 produces map[interface{}]interface{} for nested maps
|
||||
// which caused mergo.Merge to panic with "value of type interface {} is not assignable to type string"
|
||||
// The exact YAML structure from gallery/index.yaml nanbeige4.1 entries
|
||||
yamlContent := `---
|
||||
- &nanbeige4
|
||||
name: "nanbeige4.1-3b-q8"
|
||||
overrides:
|
||||
parameters:
|
||||
model: nanbeige4.1-3b-q8_0.gguf
|
||||
- !!merge <<: *nanbeige4
|
||||
name: "nanbeige4.1-3b-q4"
|
||||
overrides:
|
||||
parameters:
|
||||
model: nanbeige4.1-3b-q4_k_m.gguf
|
||||
`
|
||||
var models []GalleryModel
|
||||
err := yaml.Unmarshal([]byte(yamlContent), &models)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(models).To(HaveLen(2))
|
||||
|
||||
// Verify first model
|
||||
Expect(models[0].Name).To(Equal("nanbeige4.1-3b-q8"))
|
||||
Expect(models[0].Overrides).NotTo(BeNil())
|
||||
Expect(models[0].Overrides["parameters"]).To(BeAssignableToTypeOf(map[string]interface{}{}))
|
||||
params := models[0].Overrides["parameters"].(map[string]interface{})
|
||||
Expect(params["model"]).To(Equal("nanbeige4.1-3b-q8_0.gguf"))
|
||||
|
||||
// Verify second model (merged)
|
||||
Expect(models[1].Name).To(Equal("nanbeige4.1-3b-q4"))
|
||||
Expect(models[1].Overrides).NotTo(BeNil())
|
||||
Expect(models[1].Overrides["parameters"]).To(BeAssignableToTypeOf(map[string]interface{}{}))
|
||||
params = models[1].Overrides["parameters"].(map[string]interface{})
|
||||
Expect(params["model"]).To(Equal("nanbeige4.1-3b-q4_k_m.gguf"))
|
||||
|
||||
// Simulate the mergo.Merge call that was failing in models.go:251
|
||||
// This should not panic with yaml.v3
|
||||
configMap := make(map[string]interface{})
|
||||
configMap["name"] = "test"
|
||||
configMap["backend"] = "llama-cpp"
|
||||
configMap["parameters"] = map[string]interface{}{
|
||||
"model": "original.gguf",
|
||||
}
|
||||
|
||||
err = mergo.Merge(&configMap, models[1].Overrides, mergo.WithOverride)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(configMap["parameters"]).NotTo(BeNil())
|
||||
|
||||
// Verify the merge worked correctly
|
||||
mergedParams := configMap["parameters"].(map[string]interface{})
|
||||
Expect(mergedParams["model"]).To(Equal("nanbeige4.1-3b-q4_k_m.gguf"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"gopkg.in/yaml.v2"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
var _ = Describe("InstallExternalBackend", func() {
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/mudler/LocalAI/pkg/system"
|
||||
"github.com/mudler/LocalAI/pkg/utils"
|
||||
"github.com/mudler/xlog"
|
||||
"gopkg.in/yaml.v2"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
4
go.mod
4
go.mod
@@ -61,7 +61,7 @@ require (
|
||||
go.opentelemetry.io/otel/metric v1.40.0
|
||||
go.opentelemetry.io/otel/sdk/metric v1.40.0
|
||||
google.golang.org/grpc v1.78.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
google.golang.org/protobuf v1.36.11
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
oras.land/oras-go/v2 v2.6.0
|
||||
)
|
||||
@@ -75,7 +75,7 @@ require (
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tidwall/sjson v1.2.5 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||
google.golang.org/protobuf v1.36.11 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
|
||||
2
go.sum
2
go.sum
@@ -509,8 +509,6 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P
|
||||
github.com/mr-tron/base58 v1.1.2/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/mr-tron/base58 v1.2.0 h1:T/HDJBh4ZCPbU39/+c3rRvE0uKBQlU27+QI8LJ4t64o=
|
||||
github.com/mr-tron/base58 v1.2.0/go.mod h1:BinMc/sQntlIE1frQmRFPUoPA1Zkr8VRgBdjWI2mNwc=
|
||||
github.com/mudler/cogito v0.8.1 h1:66qPJkAMrq/Vo8AC/PvXWuVxYPhi7X2DQuJIilL8+3I=
|
||||
github.com/mudler/cogito v0.8.1/go.mod h1:6sfja3lcu2nWRzEc0wwqGNu/eCG3EWgij+8s7xyUeQ4=
|
||||
github.com/mudler/cogito v0.8.2-0.20260214201734-da0d4ceb2b44 h1:joGszpItINnZdoL/0p2077Wz2xnxMGRSRgYN5mS7I4c=
|
||||
github.com/mudler/cogito v0.8.2-0.20260214201734-da0d4ceb2b44/go.mod h1:6sfja3lcu2nWRzEc0wwqGNu/eCG3EWgij+8s7xyUeQ4=
|
||||
github.com/mudler/edgevpn v0.31.1 h1:7qegiDWd0kAg6ljhNHxqvp8hbo/6BbzSdbb7/2WZfiY=
|
||||
|
||||
Reference in New Issue
Block a user