iop/packages/go/agentconfig/load.go

72 lines
2.1 KiB
Go

package agentconfig
import (
"fmt"
"io"
"os"
"sort"
"gopkg.in/yaml.v3"
)
// Load reads exactly one strict YAML document, normalizes deterministic order,
// and validates all references before returning.
func Load(path string) (Catalog, error) {
file, err := os.Open(path)
if err != nil {
return Catalog{}, fmt.Errorf("agentconfig: open catalog: %w", err)
}
defer file.Close()
decoder := yaml.NewDecoder(file)
decoder.KnownFields(true)
var catalog Catalog
if err := decoder.Decode(&catalog); err != nil {
return Catalog{}, fmt.Errorf("agentconfig: decode catalog: %w", err)
}
var extra any
if err := decoder.Decode(&extra); err != io.EOF {
if err == nil {
return Catalog{}, fmt.Errorf("agentconfig: catalog must contain exactly one YAML document")
}
return Catalog{}, fmt.Errorf("agentconfig: decode trailing document: %w", err)
}
return Normalize(catalog)
}
// Normalize applies non-policy defaults and stable ordering, then validates.
func Normalize(catalog Catalog) (Catalog, error) {
for i := range catalog.Providers {
provider := &catalog.Providers[i]
if provider.VersionProbe.TimeoutMS == 0 {
provider.VersionProbe.TimeoutMS = DefaultProbeTimeoutMS
}
if provider.Authentication.TimeoutMS == 0 {
provider.Authentication.TimeoutMS = DefaultProbeTimeoutMS
}
if len(provider.ModelProbe.Args) > 0 && provider.ModelProbe.TimeoutMS == 0 {
provider.ModelProbe.TimeoutMS = DefaultProbeTimeoutMS
}
sort.Strings(provider.Capabilities)
}
for i := range catalog.Profiles {
if catalog.Profiles[i].MaxConcurrency == 0 {
catalog.Profiles[i].MaxConcurrency = 1
}
sort.Strings(catalog.Profiles[i].Capabilities)
}
sort.Slice(catalog.Providers, func(i, j int) bool {
return catalog.Providers[i].ID < catalog.Providers[j].ID
})
sort.Slice(catalog.Models, func(i, j int) bool {
return catalog.Models[i].ID < catalog.Models[j].ID
})
sort.Slice(catalog.Profiles, func(i, j int) bool {
return catalog.Profiles[i].ID < catalog.Profiles[j].ID
})
if err := catalog.Validate(); err != nil {
return Catalog{}, err
}
return catalog, nil
}