agent: replace hardcoded model maps with models.yaml config

- Remove defaultCompactionModels map from compaction.go
- Add agent/models.go: load ~/.config/ollie/models.yaml for all backend/model settings
- Completion (Complete()) falls back to models.yaml completion section when env vars unset
- Compaction falls back to models.yaml compaction section per-backend
- Priority chain: agent config > OLLIE_*_MODEL env > models.yaml > session model
This commit is contained in:
Levi Neely 2026-08-07 07:24:40 +02:00
parent 267f438e9e
commit 1eacb4f42d
3 changed files with 57 additions and 12 deletions

View File

@ -2,21 +2,13 @@ package agent
import "os"
// defaultCompactionModels maps backend names to cheap models suitable for compaction.
var defaultCompactionModels = map[string]string{
"anthropic": "claude-3-5-haiku-latest",
"openai": "gpt-4o-mini",
"openrouter": "deepseek-v4-flash",
"gemini": "gemini-2.0-flash",
}
// backendNamer is the subset of backend.Backend needed for compaction model resolution.
// backendNamer is the subset of backend.Backend needed for model resolution.
type backendNamer interface {
Name() string
}
// resolveCompactionModel returns the model to use for compaction.
// Priority: agent config > OLLIE_COMPACTION_MODEL env > per-backend default.
// Priority: agent config > OLLIE_COMPACTION_MODEL env > per-backend default from models.yaml > session's current model.
// Returns "" if no override is configured (use the session's current model).
func resolveCompactionModel(cfgModel string, b backendNamer) string {
if cfgModel != "" {
@ -25,8 +17,11 @@ func resolveCompactionModel(cfgModel string, b backendNamer) string {
if env := os.Getenv("OLLIE_COMPACTION_MODEL"); env != "" {
return env
}
cfg := loadModelsConfig()
if b != nil {
return defaultCompactionModels[b.Name()]
if m, ok := cfg.Compaction[b.Name()]; ok {
return m
}
}
return ""
}

View File

@ -24,7 +24,16 @@ func Complete(cwd, filePath, prefix, suffix, extraContext string) (string, error
model := os.Getenv("OLLIE_COMPLETE_MODEL")
backendName := os.Getenv("OLLIE_COMPLETE_BACKEND")
if model == "" || backendName == "" {
return "", fmt.Errorf("OLLIE_COMPLETE_MODEL and OLLIE_COMPLETE_BACKEND must be set")
cfg := loadModelsConfig()
if model == "" && cfg.Completion.Model != "" {
model = cfg.Completion.Model
}
if backendName == "" && cfg.Completion.Backend != "" {
backendName = cfg.Completion.Backend
}
}
if model == "" || backendName == "" {
return "", fmt.Errorf("OLLIE_COMPLETE_MODEL and OLLIE_COMPLETE_BACKEND must be set (or configured in models.yaml)")
}
const prefixMax = 12000

41
agent/models.go Normal file
View File

@ -0,0 +1,41 @@
package agent
import (
"os"
"path/filepath"
"gopkg.in/yaml.v3"
)
// modelsConfig holds the parsed contents of ~/.config/ollie/models.yaml.
type modelsConfig struct {
Compaction map[string]string `yaml:"compaction"`
Completion struct {
Model string `yaml:"model"`
Backend string `yaml:"backend"`
} `yaml:"completion"`
}
// loadModelsConfig reads and parses the models config file.
// Returns zero value if the file doesn't exist or is invalid.
func loadModelsConfig() modelsConfig {
path := filepath.Join(cfgDir(), "models.yaml")
data, err := os.ReadFile(path)
if err != nil {
return modelsConfig{}
}
var cfg modelsConfig
if err := yaml.Unmarshal(data, &cfg); err != nil {
return modelsConfig{}
}
return cfg
}
// cfgDir returns the ollie config directory, respecting XDG_CONFIG_HOME.
func cfgDir() string {
if xdg := os.Getenv("XDG_CONFIG_HOME"); xdg != "" {
return filepath.Join(xdg, "ollie")
}
home, _ := os.UserHomeDir()
return filepath.Join(home, ".config", "ollie")
}