Remove legacy backend environment configuration

This commit is contained in:
Ollie Agent 2026-08-16 19:48:52 +02:00
parent 16240b3e12
commit 45ff8a2864
7 changed files with 43 additions and 206 deletions

View File

@ -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

View File

@ -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)

View File

@ -1448,7 +1448,6 @@ func newKiroAuthSource(apiKey string) (kiroAuthSource, error) {
if !strings.HasPrefix(strings.ToLower(apiKey), "sqlite://") {
return &staticKiroAuth{
token: apiKey,
profileARN: strings.TrimSpace(os.Getenv("OLLIE_KIRO_PROFILE_ARN")),
}, nil
}
// Parse sqlite:// URI

View File

@ -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)

View File

@ -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")
}

View File

@ -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.

View File

@ -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
# Backend credentials, endpoints, models, and the default backend belong in
# ~/.config/ollie/backends.conf, not this file.