detached a7ef8c2

Respect ollama model baseUrl before default

commit
a7ef8c22a1e1694ab93b033628e5d015ab0975a6
author
patriceckhart · · 2026-06-08 05:41 UTC
parent
7da9114
signature
unsigned
refs
tag: v0.2.16
2 files · +44 -4
M packages/agent/build.go +6 -4
@@ -305,9 +305,6 @@ func Resolve(args Args, requireCred bool) (Resolved, error) {
305305 credErr error
306306 )
307307 if provName == "ollama" {
308- if args.BaseURL == "" {
309- args.BaseURL = "http://localhost:11434"
310- }
311308 cred = firstNonEmpty(args.APIKey, "ollama")
312309 method = "apikey"
313310 } else {
@@ -398,10 +395,15 @@ func Resolve(args Args, requireCred bool) (Resolved, error) {
398395 }
399396
400397 // If the model defines a base URL (e.g. local ollama) and the
401- // user didn't pass --base-url, use the model's URL.
398+ // user didn't pass --base-url, use the model's URL. For ollama,
399+ // keep http://localhost:11434 as a fallback only after the model
400+ // metadata has had a chance to provide a custom baseUrl.
402401 if args.BaseURL == "" && resolvedModel.BaseURL != "" {
403402 args.BaseURL = resolvedModel.BaseURL
404403 }
404+ if args.BaseURL == "" && provName == "ollama" {
405+ args.BaseURL = "http://localhost:11434"
406+ }
405407
406408 // If the model has a base URL, credentials are optional (local
407409 // models like ollama don't need real API keys).
@@ -305,9 +305,6 @@ func Resolve(args Args, requireCred bool) (Resolved, error) {
305 credErr error305 credErr error
306 )306 )
307 if provName == "ollama" {307 if provName == "ollama" {
308- if args.BaseURL == "" {
309- args.BaseURL = "http://localhost:11434"
310- }
311 cred = firstNonEmpty(args.APIKey, "ollama")308 cred = firstNonEmpty(args.APIKey, "ollama")
312 method = "apikey"309 method = "apikey"
313 } else {310 } else {
@@ -398,10 +395,15 @@ func Resolve(args Args, requireCred bool) (Resolved, error) {
398 }395 }
399 396
400 // If the model defines a base URL (e.g. local ollama) and the397 // If the model defines a base URL (e.g. local ollama) and the
401- // user didn't pass --base-url, use the model's URL.398+ // user didn't pass --base-url, use the model's URL. For ollama,
399+ // keep http://localhost:11434 as a fallback only after the model
400+ // metadata has had a chance to provide a custom baseUrl.
402 if args.BaseURL == "" && resolvedModel.BaseURL != "" {401 if args.BaseURL == "" && resolvedModel.BaseURL != "" {
403 args.BaseURL = resolvedModel.BaseURL402 args.BaseURL = resolvedModel.BaseURL
404 }403 }
404+ if args.BaseURL == "" && provName == "ollama" {
405+ args.BaseURL = "http://localhost:11434"
406+ }
405 407
406 // If the model has a base URL, credentials are optional (local408 // If the model has a base URL, credentials are optional (local
407 // models like ollama don't need real API keys).409 // models like ollama don't need real API keys).
M packages/agent/build_test.go +38 -0
@@ -5,6 +5,8 @@ import (
55 "path/filepath"
66 "strings"
77 "testing"
8+
9+ "github.com/patriceckhart/zot/packages/provider"
810 )
911
1012 func TestReadAgentsContextLoadsGlobalAndAncestors(t *testing.T) {
@@ -109,6 +111,42 @@ func TestResolveExplicitFlagStaleDoesNotRepairConfig(t *testing.T) {
109111 }
110112 }
111113
114+func TestResolveOllamaUsesModelBaseURLBeforeDefault(t *testing.T) {
115+ t.Setenv("ZOT_HOME", t.TempDir())
116+ provider.SetLiveModels(nil)
117+ defer provider.SetLiveModels(nil)
118+ provider.SetUserModels([]provider.Model{{
119+ Provider: "ollama",
120+ ID: "qwen-local",
121+ DisplayName: "Qwen Local",
122+ ContextWindow: 32768,
123+ MaxOutput: 8192,
124+ BaseURL: "http://localhost:8000/v1",
125+ }})
126+
127+ r, err := Resolve(Args{Provider: "ollama", Model: "qwen-local"}, false)
128+ if err != nil {
129+ t.Fatalf("Resolve failed: %v", err)
130+ }
131+ if r.BaseURL != "http://localhost:8000/v1" {
132+ t.Fatalf("BaseURL = %q, want models.json baseUrl", r.BaseURL)
133+ }
134+}
135+
136+func TestResolveOllamaFallsBackToDefaultBaseURL(t *testing.T) {
137+ t.Setenv("ZOT_HOME", t.TempDir())
138+ provider.SetLiveModels(nil)
139+ defer provider.SetLiveModels(nil)
140+
141+ r, err := Resolve(Args{Provider: "ollama", Model: "any-local-model"}, false)
142+ if err != nil {
143+ t.Fatalf("Resolve failed: %v", err)
144+ }
145+ if r.BaseURL != "http://localhost:11434" {
146+ t.Fatalf("BaseURL = %q, want ollama default", r.BaseURL)
147+ }
148+}
149+
112150 func TestCanonicalProviderResolvesAliases(t *testing.T) {
113151 cases := map[string]string{
114152 "bedrock": "amazon-bedrock",
@@ -5,6 +5,8 @@ import (
5 "path/filepath"5 "path/filepath"
6 "strings"6 "strings"
7 "testing"7 "testing"
8+
9+ "github.com/patriceckhart/zot/packages/provider"
8 )10 )
9 11
10 func TestReadAgentsContextLoadsGlobalAndAncestors(t *testing.T) {12 func TestReadAgentsContextLoadsGlobalAndAncestors(t *testing.T) {
@@ -109,6 +111,42 @@ func TestResolveExplicitFlagStaleDoesNotRepairConfig(t *testing.T) {
109 }111 }
110 }112 }
111 113
114+func TestResolveOllamaUsesModelBaseURLBeforeDefault(t *testing.T) {
115+ t.Setenv("ZOT_HOME", t.TempDir())
116+ provider.SetLiveModels(nil)
117+ defer provider.SetLiveModels(nil)
118+ provider.SetUserModels([]provider.Model{{
119+ Provider: "ollama",
120+ ID: "qwen-local",
121+ DisplayName: "Qwen Local",
122+ ContextWindow: 32768,
123+ MaxOutput: 8192,
124+ BaseURL: "http://localhost:8000/v1",
125+ }})
126+
127+ r, err := Resolve(Args{Provider: "ollama", Model: "qwen-local"}, false)
128+ if err != nil {
129+ t.Fatalf("Resolve failed: %v", err)
130+ }
131+ if r.BaseURL != "http://localhost:8000/v1" {
132+ t.Fatalf("BaseURL = %q, want models.json baseUrl", r.BaseURL)
133+ }
134+}
135+
136+func TestResolveOllamaFallsBackToDefaultBaseURL(t *testing.T) {
137+ t.Setenv("ZOT_HOME", t.TempDir())
138+ provider.SetLiveModels(nil)
139+ defer provider.SetLiveModels(nil)
140+
141+ r, err := Resolve(Args{Provider: "ollama", Model: "any-local-model"}, false)
142+ if err != nil {
143+ t.Fatalf("Resolve failed: %v", err)
144+ }
145+ if r.BaseURL != "http://localhost:11434" {
146+ t.Fatalf("BaseURL = %q, want ollama default", r.BaseURL)
147+ }
148+}
149+
112 func TestCanonicalProviderResolvesAliases(t *testing.T) {150 func TestCanonicalProviderResolvesAliases(t *testing.T) {
113 cases := map[string]string{151 cases := map[string]string{
114 "bedrock": "amazon-bedrock",152 "bedrock": "amazon-bedrock",

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 477

↑↓ moveenter openesc close