diff --git a/server/model_list.go b/server/model_list.go index 9976b4b66..6be286281 100644 --- a/server/model_list.go +++ b/server/model_list.go @@ -18,7 +18,7 @@ import ( // listModels builds /api/tags from the manifests and the per-blob metadata // files, extracting for any blob that has none yet. Manifest lists contribute -// one row per child runner. +// one row for the locally preferred child. func listModels(ctx context.Context) ([]api.ListModelResponse, error) { manifests, err := manifest.Manifests(true) if err != nil { @@ -32,6 +32,10 @@ func listModels(ctx context.Context) ([]api.ListModelResponse, error) { return nil, err } } + // Suppress showing the downgrade guard tag + if name.EqualFold(model.ParseName(manifest.RunnerLlamaCPP + ":" + mf.Digest())) { + continue + } rows, err := describeModelRows(name, mf) if err != nil { @@ -46,7 +50,7 @@ func listModels(ctx context.Context) ([]api.ListModelResponse, error) { } // describeModelRows describes one named manifest for /api/tags. A manifest -// list describes one row per child runner, keyed by the child digest and +// list describes its selected child, keyed by the child digest and // carrying the parent's modification time; every other manifest describes // itself. func describeModelRows(name model.Name, mf *manifest.Manifest) ([]api.ListModelResponse, error) { @@ -79,6 +83,9 @@ func describeModelRows(name model.Name, mf *manifest.Manifest) ([]api.ListModelR if err != nil { return nil, err } + if !manifest.SameDigest(digest, mf.SelectedDigest()) { + continue + } resolved, ok, err := resolveLocalShowManifestChild(child) if err != nil { return nil, err diff --git a/server/routes_list_test.go b/server/routes_list_test.go index f12188e85..08f50cfb6 100644 --- a/server/routes_list_test.go +++ b/server/routes_list_test.go @@ -235,7 +235,7 @@ func writeManifestListFixture(t *testing.T, name string, children ...manifestLis return manifests } -func TestListIncludesManifestListChildrenAsSeparateRows(t *testing.T) { +func TestListShowsPreferredManifestListChild(t *testing.T) { gin.SetMode(gin.TestMode) t.Setenv("OLLAMA_MODELS", t.TempDir()) @@ -281,6 +281,10 @@ func TestListIncludesManifestListChildrenAsSeparateRows(t *testing.T) { manifestListFixtureChild{name: "test-mlx", runner: manifest.RunnerMLX, format: manifest.FormatSafetensors}, ) ggufManifest, mlxManifest := children[0], children[1] + selected, err := manifest.ParseNamedManifest(model.ParseName("test-list")) + if err != nil { + t.Fatal(err) + } parentPath, err := manifest.ResolvePathForName(model.ParseName("test-list")) if err != nil { t.Fatal(err) @@ -309,8 +313,11 @@ func TestListIncludesManifestListChildrenAsSeparateRows(t *testing.T) { listed = append(listed, resp.Models[i]) } } - if len(listed) != 2 { - t.Fatalf("test-list:latest rows = %d, want 2: %+v", len(listed), listed) + if len(listed) != 1 { + t.Fatalf("test-list:latest rows = %d, want 1: %+v", len(listed), listed) + } + if listed[0].Digest != selected.SelectedDigest() { + t.Fatalf("listed digest = %s, want selected digest %s", listed[0].Digest, selected.SelectedDigest()) } wantSizes := map[string]int64{ @@ -335,10 +342,6 @@ func TestListIncludesManifestListChildrenAsSeparateRows(t *testing.T) { if row.Details.Runner != wantRunners[row.Digest] { t.Fatalf("runner for %s = %q, want %q", row.Digest, row.Details.Runner, wantRunners[row.Digest]) } - delete(wantSizes, row.Digest) - } - if len(wantSizes) != 0 { - t.Fatalf("missing list rows for digests: %+v", wantSizes) } }