package config import ( "fmt" "os" "gopkg.in/yaml.v3" ) type skillChain struct { Chain []string `yaml:"chain"` } type modelsFile struct { Verifier string `yaml:"verifier"` LlamaSwapURL string `yaml:"llama_swap_url"` DefaultChain []string `yaml:"default_chain"` Skills map[string]skillChain `yaml:"skills"` } type Models struct { data modelsFile } func LoadModels(path string) (Models, error) { raw, err := os.ReadFile(path) if err != nil { return Models{}, fmt.Errorf("load models: %w", err) } var f modelsFile if err := yaml.Unmarshal(raw, &f); err != nil { return Models{}, fmt.Errorf("parse models: %w", err) } return Models{data: f}, nil } // Verifier returns the model name to use for all local-tier output verification. func (m Models) Verifier() string { return m.data.Verifier } // LlamaSwapURL returns the llama-swap base URL for warm-state probing. func (m Models) LlamaSwapURL() string { return m.data.LlamaSwapURL } // ChainFor returns the ordered list of model names for a skill. // If override is non-empty, returns a single-entry chain (no escalation). // Falls back to default_chain when the skill has no explicit entry. func (m Models) ChainFor(skill, override string) []string { if override != "" { return []string{override} } if sc, ok := m.data.Skills[skill]; ok && len(sc.Chain) > 0 { return sc.Chain } out := make([]string, len(m.data.DefaultChain)) copy(out, m.data.DefaultChain) return out }