launch: respect OLLAMA_HOST when configuring Pi (#18039)

Pi's Edit() only set baseUrl when creating a new ollama provider entry.
On subsequent launches it preserved whatever baseUrl was already in
~/.pi/agent/models.json, so switching OLLAMA_HOST to a remote server had
no effect — Pi would still connect to localhost.

Edit() now ensures baseUrl reflects the current OLLAMA_HOST. Models()
returns nil when the stored baseUrl no longer matches, so the launcher
only calls Edit() when the host has actually drifted. User-customized api
and apiKey fields are still preserved.
This commit is contained in:
Daniel Hiltgen 2026-08-26 13:24:05 -07:00 • committed by GitHub
parent a773b7affa
commit 91cf995996
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 97 additions and 8 deletions

View file

@ -530,6 +530,10 @@ func (p *Pi) Paths() []string {
return paths
}
func piBaseURL() string {
return strings.TrimRight(envconfig.Host().String(), "/") + "/v1"
}
func (p *Pi) Edit(models []LaunchModel) error {
if len(models) == 0 {
return nil
@ -557,11 +561,16 @@ func (p *Pi) Edit(models []LaunchModel) error {
ollama, ok := providers["ollama"].(map[string]any)
if !ok {
ollama = map[string]any{
"baseUrl": envconfig.Host().String() + "/v1",
"api": "openai-completions",
"apiKey": "ollama",
}
ollama = map[string]any{}
}
ollama["baseUrl"] = piBaseURL()
if _, exists := ollama["api"]; !exists {
ollama["api"] = "openai-completions"
}
if _, exists := ollama["apiKey"]; !exists {
ollama["apiKey"] = "ollama"
}
existingModels, ok := ollama["models"].([]any)
@ -652,6 +661,14 @@ func (p *Pi) Models() []string {
providers, _ := config["providers"].(map[string]any)
ollama, _ := providers["ollama"].(map[string]any)
// Returning nil on host drift forces launchEditorIntegration to call Edit.
if configured, _ := ollama["baseUrl"].(string); configured != "" {
if strings.TrimRight(configured, "/") != strings.TrimRight(piBaseURL(), "/") {
return nil
}
}
models, _ := ollama["models"].([]any)
var result []string

View file

@ -984,7 +984,7 @@ func TestPiEdit(t *testing.T) {
}
})
t.Run("updates existing config preserving ollama provider settings", func(t *testing.T) {
t.Run("updates existing config overwriting baseUrl with current host", func(t *testing.T) {
cleanup()
os.MkdirAll(configDir, 0o755)
@ -1013,9 +1013,12 @@ func TestPiEdit(t *testing.T) {
providers := cfg["providers"].(map[string]any)
ollama := providers["ollama"].(map[string]any)
if ollama["baseUrl"] != "http://custom:8080/v1" {
t.Errorf("Custom baseUrl not preserved, got %v", ollama["baseUrl"])
// baseUrl must be overwritten to match OLLAMA_HOST (the test server)
expectedBaseURL := strings.TrimRight(srv.URL, "/") + "/v1"
if ollama["baseUrl"] != expectedBaseURL {
t.Errorf("baseUrl = %v, want %v", ollama["baseUrl"], expectedBaseURL)
}
// User-customized api and apiKey are preserved
if ollama["api"] != "custom-api" {
t.Errorf("Custom api not preserved, got %v", ollama["api"])
}
@ -1569,6 +1572,75 @@ func TestPiModels(t *testing.T) {
t.Errorf("Models() = %v, want nil for corrupt config", models)
}
})
t.Run("returns nil when baseUrl does not match OLLAMA_HOST", func(t *testing.T) {
tmpDir := t.TempDir()
setTestHome(t, tmpDir)
configDir := filepath.Join(tmpDir, ".pi", "agent")
if err := os.MkdirAll(configDir, 0o755); err != nil {
t.Fatal(err)
}
config := `{
"providers": {
"ollama": {
"baseUrl": "http://remote-host:9999/v1",
"models": [
{"id": "llama3.2"},
{"id": "qwen3:8b"}
]
}
}
}`
configPath := filepath.Join(configDir, "models.json")
if err := os.WriteFile(configPath, []byte(config), 0o644); err != nil {
t.Fatal(err)
}
// OLLAMA_HOST defaults to 127.0.0.1:11434, which differs from the
// baseUrl in the config, so Models() should return nil.
models := pi.Models()
if models != nil {
t.Errorf("Models() = %v, want nil when baseUrl is stale", models)
}
})
t.Run("returns models when baseUrl matches OLLAMA_HOST", func(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
}))
defer srv.Close()
t.Setenv("OLLAMA_HOST", srv.URL)
tmpDir := t.TempDir()
setTestHome(t, tmpDir)
configDir := filepath.Join(tmpDir, ".pi", "agent")
if err := os.MkdirAll(configDir, 0o755); err != nil {
t.Fatal(err)
}
expectedBaseURL := strings.TrimRight(srv.URL, "/") + "/v1"
config := fmt.Sprintf(`{
"providers": {
"ollama": {
"baseUrl": "%s",
"models": [
{"id": "llama3.2"},
{"id": "qwen3:8b"}
]
}
}
}`, expectedBaseURL)
configPath := filepath.Join(configDir, "models.json")
if err := os.WriteFile(configPath, []byte(config), 0o644); err != nil {
t.Fatal(err)
}
models := pi.Models()
if len(models) != 2 {
t.Errorf("Models() returned %d models, want 2", len(models))
}
})
}
func TestIsPiOllamaModel(t *testing.T) {