From 45ff8a286419bf448a353cb344e5907d99136954 Mon Sep 17 00:00:00 2001 From: Ollie Agent Date: Sun, 16 Aug 2026 19:48:52 +0200 Subject: [PATCH] Remove legacy backend environment configuration --- cmd/olliesrv/internal/agent/history.go | 6 +- cmd/olliesrv/internal/backend/gemini.go | 2 +- cmd/olliesrv/internal/backend/kiro.go | 3 +- cmd/olliesrv/internal/backend/new.go | 74 ++++--------- cmd/olliesrv/internal/backend/new_test.go | 123 +++------------------- data/configs/models.yaml.sample | 2 +- doc/env.sample | 39 +------ 7 files changed, 43 insertions(+), 206 deletions(-) diff --git a/cmd/olliesrv/internal/agent/history.go b/cmd/olliesrv/internal/agent/history.go index 86cf32b..57c76e2 100644 --- a/cmd/olliesrv/internal/agent/history.go +++ b/cmd/olliesrv/internal/agent/history.go @@ -5,7 +5,6 @@ import ( "crypto/sha256" "encoding/hex" "fmt" - "os" "strings" "ollie/cmd/olliesrv/internal/backend" @@ -579,14 +578,11 @@ func (s *History) stripCold(ctx context.Context, b backend.Backend) (backend.Usa } // resolveCompactionModel returns the model to use for compaction. -// Priority: agent config > OLLIE_COMPACTION_MODEL > backends.conf compactionModel > backends.conf model > current model. +// Priority: agent config > backends.conf compactionModel > backends.conf model > current model. func resolveCompactionModel(cfgModel string, b backend.Backend) string { if cfgModel != "" { return cfgModel } - if env := os.Getenv("OLLIE_COMPACTION_MODEL"); env != "" { - return env - } if b != nil { if model := backend.CompactionModel(b.Name()); model != "" { return model diff --git a/cmd/olliesrv/internal/backend/gemini.go b/cmd/olliesrv/internal/backend/gemini.go index 0d36392..51372b7 100644 --- a/cmd/olliesrv/internal/backend/gemini.go +++ b/cmd/olliesrv/internal/backend/gemini.go @@ -6,7 +6,7 @@ const ( ) // NewGemini constructs an OpenAI-compatible backend pointed at Google AI Studio. -// apiKey is the Google AI Studio key (OLLIE_GEMINI_KEY). +// apiKey is the Google AI Studio key configured in backends.conf. // If model is empty the default model is used. func NewGemini(apiKey string) (*OpenAIBackend, error) { b, err := NewOpenAI("gemini", geminiBaseURL, apiKey) diff --git a/cmd/olliesrv/internal/backend/kiro.go b/cmd/olliesrv/internal/backend/kiro.go index 299e33c..0c93d33 100644 --- a/cmd/olliesrv/internal/backend/kiro.go +++ b/cmd/olliesrv/internal/backend/kiro.go @@ -1447,8 +1447,7 @@ func newKiroAuthSource(apiKey string) (kiroAuthSource, error) { apiKey = strings.TrimSpace(apiKey) if !strings.HasPrefix(strings.ToLower(apiKey), "sqlite://") { return &staticKiroAuth{ - token: apiKey, - profileARN: strings.TrimSpace(os.Getenv("OLLIE_KIRO_PROFILE_ARN")), + token: apiKey, }, nil } // Parse sqlite:// URI diff --git a/cmd/olliesrv/internal/backend/new.go b/cmd/olliesrv/internal/backend/new.go index f3318ce..d9d0fea 100644 --- a/cmd/olliesrv/internal/backend/new.go +++ b/cmd/olliesrv/internal/backend/new.go @@ -2,21 +2,17 @@ package backend import ( "fmt" - "os" ) // NewWithName constructs a Backend for the given backend name. -// If name is empty, falls back to backends.conf default, then OLLIE_BACKEND env. +// If name is empty, it falls back to the backends.conf default. func NewWithName(name string) (Backend, error) { cfg := loadConfig() if name == "" { name = cfg.Default } if name == "" { - name = os.Getenv("OLLIE_BACKEND") - } - if name == "" { - return nil, fmt.Errorf("no backend specified: set 'backend' in backends.conf, OLLIE_BACKEND, or pass backend= to the session") + return nil, fmt.Errorf("no backend specified: set 'backend' in backends.conf or pass backend= to the session") } return newBackendFromConfig(name, cfg) } @@ -34,78 +30,44 @@ func newBackendFromConfig(which string, cfg configFile) (Backend, error) { switch which { case "ollama": host := bc.Host - if host == "" { - host = os.Getenv("OLLAMA_HOST") - } b, err = NewOllama(host) case "openai": - url := bc.URL - if url == "" { - url = os.Getenv("OLLIE_OPENAI_URL") + if bc.Key == "" { + return nil, fmt.Errorf("openai: key required (backends.conf [openai] key=)") } - key := bc.Key - if key == "" { - key = os.Getenv("OLLIE_OPENAI_KEY") - } - if key == "" { - return nil, fmt.Errorf("openai: key required (backends.conf [openai] key= or OLLIE_OPENAI_KEY)") - } - b, err = NewOpenAI("openai", url, key) + b, err = NewOpenAI("openai", bc.URL, bc.Key) case "openrouter": url := bc.URL - if url == "" { - url = os.Getenv("OLLIE_OPENAI_URL") - } if url == "" { url = "https://openrouter.ai/api" } - key := bc.Key - if key == "" { - key = os.Getenv("OLLIE_OPENAI_KEY") + if bc.Key == "" { + return nil, fmt.Errorf("openrouter: key required (backends.conf [openrouter] key=)") } - if key == "" { - return nil, fmt.Errorf("openrouter: key required (backends.conf [openrouter] key= or OLLIE_OPENAI_KEY)") - } - b, err = NewOpenAI("openrouter", url, key) + b, err = NewOpenAI("openrouter", url, bc.Key) case "anthropic": - key := bc.Key - if key == "" { - key = os.Getenv("OLLIE_ANTHROPIC_KEY") + if bc.Key == "" { + return nil, fmt.Errorf("anthropic: key required (backends.conf [anthropic] key=)") } - if key == "" { - return nil, fmt.Errorf("anthropic: key required (backends.conf [anthropic] key= or OLLIE_ANTHROPIC_KEY)") - } - b, err = NewAnthropic(key) + b, err = NewAnthropic(bc.Key) case "copilot": - token := bc.Key - if token == "" { - token = os.Getenv("OLLIE_COPILOT_TOKEN") + if bc.Key == "" { + return nil, fmt.Errorf("copilot: key required (backends.conf [copilot] key=)") } - if token == "" { - return nil, fmt.Errorf("copilot: key required (backends.conf [copilot] key= or OLLIE_COPILOT_TOKEN)") - } - b, err = NewCopilot(token) + b, err = NewCopilot(bc.Key) case "kiro", "codewhisperer": - token := bc.Key - if token == "" { - token = os.Getenv("OLLIE_KIRO_TOKEN") - } - b, err = NewKiro(token) + b, err = NewKiro(bc.Key) case "gemini": - key := bc.Key - if key == "" { - key = os.Getenv("OLLIE_GEMINI_KEY") + if bc.Key == "" { + return nil, fmt.Errorf("gemini: key required (backends.conf [gemini] key=)") } - if key == "" { - return nil, fmt.Errorf("gemini: key required (backends.conf [gemini] key= or OLLIE_GEMINI_KEY)") - } - b, err = NewGemini(key) + b, err = NewGemini(bc.Key) default: return nil, fmt.Errorf("unknown backend %q (supported: ollama, openai, openrouter, anthropic, copilot, kiro, gemini)", which) diff --git a/cmd/olliesrv/internal/backend/new_test.go b/cmd/olliesrv/internal/backend/new_test.go index 2200908..2518ec2 100644 --- a/cmd/olliesrv/internal/backend/new_test.go +++ b/cmd/olliesrv/internal/backend/new_test.go @@ -1,56 +1,20 @@ package backend import ( - "fmt" - "os" "testing" ) -// newFromEnv constructs a Backend from OLLIE_BACKEND env var (test helper). -func newFromEnv() (Backend, error) { - which := os.Getenv("OLLIE_BACKEND") - if which == "" { - return nil, fmt.Errorf("OLLIE_BACKEND is not set") - } - return newBackend(which) -} - -// setEnv sets env vars for a test and restores them on cleanup. -func setEnv(t *testing.T, vars map[string]string) { - t.Helper() - for k, v := range vars { - old, existed := os.LookupEnv(k) - os.Setenv(k, v) - if existed { - t.Cleanup(func() { os.Setenv(k, old) }) - } else { - t.Cleanup(func() { os.Unsetenv(k) }) - } - } -} - -func clearEnv(t *testing.T, keys ...string) { - t.Helper() - for _, k := range keys { - old, existed := os.LookupEnv(k) - os.Unsetenv(k) - if existed { - t.Cleanup(func() { os.Setenv(k, old) }) - } - } -} - -func TestNewFromEnv_NoBackendErrors(t *testing.T) { - clearEnv(t, "OLLIE_BACKEND", "OLLIE_OLLAMA_URL") - _, err := newFromEnv() +func TestNewWithName_NoBackendErrors(t *testing.T) { + _, err := newBackendFromConfig("", configFile{Backends: map[string]BackendConfig{}}) if err == nil { - t.Fatal("expected error when OLLIE_BACKEND is unset, got nil") + t.Fatal("expected error when backend is unset") } } -func TestNewFromEnv_Ollama(t *testing.T) { - setEnv(t, map[string]string{"OLLIE_BACKEND": "ollama"}) - b, err := newFromEnv() +func TestNewBackendFromConfig_Ollama(t *testing.T) { + b, err := newBackendFromConfig("ollama", configFile{Backends: map[string]BackendConfig{ + "ollama": {Host: "http://localhost:11434"}, + }}) if err != nil { t.Fatal(err) } @@ -59,9 +23,10 @@ func TestNewFromEnv_Ollama(t *testing.T) { } } -func TestNewFromEnv_OpenAI(t *testing.T) { - setEnv(t, map[string]string{"OLLIE_BACKEND": "openai", "OLLIE_OPENAI_URL": "https://api.openai.com", "OLLIE_OPENAI_KEY": "sk-test"}) - b, err := newFromEnv() +func TestNewBackendFromConfig_OpenAI(t *testing.T) { + b, err := newBackendFromConfig("openai", configFile{Backends: map[string]BackendConfig{ + "openai": {URL: "https://api.openai.com", Key: "sk-test"}, + }}) if err != nil { t.Fatal(err) } @@ -70,71 +35,17 @@ func TestNewFromEnv_OpenAI(t *testing.T) { } } -func TestNewFromEnv_OpenRouter(t *testing.T) { - setEnv(t, map[string]string{"OLLIE_BACKEND": "openrouter", "OLLIE_OPENAI_URL": "https://openrouter.ai/api", "OLLIE_OPENAI_KEY": "sk-or-test"}) - b, err := newFromEnv() - if err != nil { - t.Fatal(err) - } - if b.Name() != "openrouter" { - t.Errorf("name = %q", b.Name()) - } -} - -func TestNewFromEnv_Anthropic(t *testing.T) { - setEnv(t, map[string]string{"OLLIE_BACKEND": "anthropic", "OLLIE_ANTHROPIC_KEY": "sk-ant-test"}) - b, err := newFromEnv() - if err != nil { - t.Fatal(err) - } - if b.Name() != "anthropic" { - t.Errorf("name = %q", b.Name()) - } -} - -func TestNewFromEnv_AnthropicMissingKey(t *testing.T) { - setEnv(t, map[string]string{"OLLIE_BACKEND": "anthropic"}) - clearEnv(t, "OLLIE_ANTHROPIC_KEY") - _, err := newFromEnv() +func TestNewBackendFromConfig_AnthropicMissingKey(t *testing.T) { + _, err := newBackendFromConfig("anthropic", configFile{Backends: map[string]BackendConfig{ + "anthropic": {}, + }}) if err == nil { t.Fatal("expected error for missing key") } } -func TestNewFromEnv_Copilot(t *testing.T) { - setEnv(t, map[string]string{"OLLIE_BACKEND": "copilot", "OLLIE_COPILOT_TOKEN": "tok"}) - b, err := newFromEnv() - if err != nil { - t.Fatal(err) - } - if b.Name() != "copilot" { - t.Errorf("name = %q", b.Name()) - } -} - -func TestNewFromEnv_CopilotMissingToken(t *testing.T) { - setEnv(t, map[string]string{"OLLIE_BACKEND": "copilot"}) - clearEnv(t, "OLLIE_COPILOT_TOKEN") - _, err := newFromEnv() - if err == nil { - t.Fatal("expected error for missing token") - } -} - -func TestNewFromEnv_Kiro(t *testing.T) { - setEnv(t, map[string]string{"OLLIE_BACKEND": "kiro", "OLLIE_KIRO_TOKEN": "fake"}) - b, err := newFromEnv() - if err != nil { - t.Fatal(err) - } - if b.Name() != "kiro" { - t.Errorf("name = %q", b.Name()) - } -} - -func TestNewFromEnv_Unknown(t *testing.T) { - setEnv(t, map[string]string{"OLLIE_BACKEND": "bogus"}) - _, err := newFromEnv() +func TestNewBackendFromConfig_Unknown(t *testing.T) { + _, err := newBackendFromConfig("bogus", configFile{Backends: map[string]BackendConfig{}}) if err == nil { t.Fatal("expected error for unknown backend") } diff --git a/data/configs/models.yaml.sample b/data/configs/models.yaml.sample index dce0204..1673c28 100644 --- a/data/configs/models.yaml.sample +++ b/data/configs/models.yaml.sample @@ -1,6 +1,6 @@ # Model configuration for ollie agent operations. # Each section specifies backend→model mappings or global defaults. -# Environment variables (OLLIE_COMPACTION_MODEL, OLLIE_COMPLETE_*) take priority. +# Backend and compaction model settings are configured in backends.conf. # Agent-level config fields override everything. # Compaction: cheap models per backend, used when context exceeds threshold. diff --git a/doc/env.sample b/doc/env.sample index 5900e01..e037254 100644 --- a/doc/env.sample +++ b/doc/env.sample @@ -3,15 +3,8 @@ # Lines beginning with # and blank lines are ignored. # Inline comments are supported: KEY=value # comment -# Default backend (default: ollama) -# Supported: ollama, openai, openrouter, anthropic, copilot, kiro -#OLLIE_BACKEND=ollama - -# Default model name (backend-specific default if unset) -#OLLIE_MODEL= - -# Default agent config (default: default) -#OLLIE_DEFAULT_AGENT=default +# Log level (default: warn) +#OLLIE_LOG=warn # All paths follow XDG Base Directory conventions: # Tools: $XDG_CONFIG_HOME/ollie/tools (default: ~/.config/ollie/tools) @@ -21,29 +14,5 @@ # Data: $XDG_DATA_HOME/ollie (default: ~/.local/share/ollie) # Override XDG_CONFIG_HOME or XDG_DATA_HOME if you want non-default locations. -# Backend-specific settings - -# openai / openrouter -#OLLIE_OPENAI_URL= -#OLLIE_OPENAI_KEY= - -# anthropic -#OLLIE_ANTHROPIC_KEY= - -# copilot -#OLLIE_COPILOT_TOKEN= - -# kiro / codewhisperer (bearer token or sqlite:// path) -#OLLIE_KIRO_TOKEN= - -# u/complete: backend and model for acme code completion (required by u/complete) -#OLLIE_COMPLETE_BACKEND=ollama -#OLLIE_COMPLETE_MODEL=qwen3:latest - -# cascade: planner (orchestrator) model for u/cascade script -#OLLIE_CASCADE_PLAN_BACKEND=openrouter -#OLLIE_CASCADE_PLAN_MODEL=deepseek/deepseek-v4-pro - -# cascade: worker model for spawned agents -#OLLIE_CASCADE_BACKEND=openrouter -#OLLIE_CASCADE_MODEL=deepseek/deepseek-v4-flash \ No newline at end of file +# Backend credentials, endpoints, models, and the default backend belong in +# ~/.config/ollie/backends.conf, not this file. \ No newline at end of file