|
|
|
|
@@ -420,7 +420,7 @@ func names(items []ModelItem) []string {
|
|
|
|
|
func TestBuildModelList_NoExistingModels(t *testing.T) {
|
|
|
|
|
items, _, _, _ := buildModelList(nil, nil, "")
|
|
|
|
|
|
|
|
|
|
want := []string{"minimax-m2.5:cloud", "glm-5:cloud", "kimi-k2.5:cloud", "glm-4.7-flash", "qwen3:8b"}
|
|
|
|
|
want := []string{"kimi-k2.5:cloud", "qwen3.5:cloud", "glm-5:cloud", "minimax-m2.5:cloud", "glm-4.7-flash", "qwen3.5"}
|
|
|
|
|
if diff := cmp.Diff(want, names(items)); diff != "" {
|
|
|
|
|
t.Errorf("with no existing models, items should be recommended in order (-want +got):\n%s", diff)
|
|
|
|
|
}
|
|
|
|
|
@@ -448,7 +448,7 @@ func TestBuildModelList_OnlyLocalModels_CloudRecsAtBottom(t *testing.T) {
|
|
|
|
|
got := names(items)
|
|
|
|
|
|
|
|
|
|
// Recommended pinned at top (local recs first, then cloud recs when only-local), then installed non-recs
|
|
|
|
|
want := []string{"glm-4.7-flash", "qwen3:8b", "minimax-m2.5:cloud", "glm-5:cloud", "kimi-k2.5:cloud", "llama3.2", "qwen2.5"}
|
|
|
|
|
want := []string{"glm-4.7-flash", "qwen3.5", "kimi-k2.5:cloud", "qwen3.5:cloud", "glm-5:cloud", "minimax-m2.5:cloud", "llama3.2", "qwen2.5"}
|
|
|
|
|
if diff := cmp.Diff(want, got); diff != "" {
|
|
|
|
|
t.Errorf("recs pinned at top, local recs before cloud recs (-want +got):\n%s", diff)
|
|
|
|
|
}
|
|
|
|
|
@@ -464,7 +464,7 @@ func TestBuildModelList_BothCloudAndLocal_RegularSort(t *testing.T) {
|
|
|
|
|
got := names(items)
|
|
|
|
|
|
|
|
|
|
// All recs pinned at top (cloud before local in mixed case), then non-recs
|
|
|
|
|
want := []string{"minimax-m2.5:cloud", "glm-5:cloud", "kimi-k2.5:cloud", "glm-4.7-flash", "qwen3:8b", "llama3.2"}
|
|
|
|
|
want := []string{"kimi-k2.5:cloud", "qwen3.5:cloud", "glm-5:cloud", "minimax-m2.5:cloud", "glm-4.7-flash", "qwen3.5", "llama3.2"}
|
|
|
|
|
if diff := cmp.Diff(want, got); diff != "" {
|
|
|
|
|
t.Errorf("recs pinned at top, cloud recs first in mixed case (-want +got):\n%s", diff)
|
|
|
|
|
}
|
|
|
|
|
@@ -498,11 +498,11 @@ func TestBuildModelList_ExistingRecommendedMarked(t *testing.T) {
|
|
|
|
|
if strings.HasSuffix(item.Description, "(not downloaded)") {
|
|
|
|
|
t.Errorf("installed recommended %q should not have '(not downloaded)' suffix, got %q", item.Name, item.Description)
|
|
|
|
|
}
|
|
|
|
|
case "qwen3:8b":
|
|
|
|
|
case "qwen3.5":
|
|
|
|
|
if !strings.HasSuffix(item.Description, "(not downloaded)") {
|
|
|
|
|
t.Errorf("non-installed recommended %q should have '(not downloaded)' suffix, got %q", item.Name, item.Description)
|
|
|
|
|
}
|
|
|
|
|
case "minimax-m2.5:cloud", "kimi-k2.5:cloud":
|
|
|
|
|
case "minimax-m2.5:cloud", "kimi-k2.5:cloud", "qwen3.5:cloud":
|
|
|
|
|
if strings.HasSuffix(item.Description, "(not downloaded)") {
|
|
|
|
|
t.Errorf("cloud model %q should not have '(not downloaded)' suffix, got %q", item.Name, item.Description)
|
|
|
|
|
}
|
|
|
|
|
@@ -520,9 +520,9 @@ func TestBuildModelList_ExistingCloudModelsNotPushedToBottom(t *testing.T) {
|
|
|
|
|
got := names(items)
|
|
|
|
|
|
|
|
|
|
// glm-4.7-flash and glm-5:cloud are installed so they sort normally;
|
|
|
|
|
// kimi-k2.5:cloud and qwen3:8b are not installed so they go to the bottom
|
|
|
|
|
// kimi-k2.5:cloud, qwen3.5:cloud, and qwen3.5 are not installed so they go to the bottom
|
|
|
|
|
// All recs: cloud first in mixed case, then local, in rec order within each
|
|
|
|
|
want := []string{"minimax-m2.5:cloud", "glm-5:cloud", "kimi-k2.5:cloud", "glm-4.7-flash", "qwen3:8b"}
|
|
|
|
|
want := []string{"kimi-k2.5:cloud", "qwen3.5:cloud", "glm-5:cloud", "minimax-m2.5:cloud", "glm-4.7-flash", "qwen3.5"}
|
|
|
|
|
if diff := cmp.Diff(want, got); diff != "" {
|
|
|
|
|
t.Errorf("all recs, cloud first in mixed case (-want +got):\n%s", diff)
|
|
|
|
|
}
|
|
|
|
|
@@ -540,7 +540,7 @@ func TestBuildModelList_HasRecommendedCloudModel_OnlyNonInstalledAtBottom(t *tes
|
|
|
|
|
// kimi-k2.5:cloud is installed so it sorts normally;
|
|
|
|
|
// the rest of the recommendations are not installed so they go to the bottom
|
|
|
|
|
// All recs pinned at top (cloud first in mixed case), then non-recs
|
|
|
|
|
want := []string{"minimax-m2.5:cloud", "glm-5:cloud", "kimi-k2.5:cloud", "glm-4.7-flash", "qwen3:8b", "llama3.2"}
|
|
|
|
|
want := []string{"kimi-k2.5:cloud", "qwen3.5:cloud", "glm-5:cloud", "minimax-m2.5:cloud", "glm-4.7-flash", "qwen3.5", "llama3.2"}
|
|
|
|
|
if diff := cmp.Diff(want, got); diff != "" {
|
|
|
|
|
t.Errorf("recs pinned at top, cloud first in mixed case (-want +got):\n%s", diff)
|
|
|
|
|
}
|
|
|
|
|
@@ -617,6 +617,9 @@ func TestBuildModelList_ReturnsExistingAndCloudMaps(t *testing.T) {
|
|
|
|
|
if !cloudModels["kimi-k2.5:cloud"] {
|
|
|
|
|
t.Error("kimi-k2.5:cloud should be in cloudModels (recommended cloud)")
|
|
|
|
|
}
|
|
|
|
|
if !cloudModels["qwen3.5:cloud"] {
|
|
|
|
|
t.Error("qwen3.5:cloud should be in cloudModels (recommended cloud)")
|
|
|
|
|
}
|
|
|
|
|
if cloudModels["llama3.2"] {
|
|
|
|
|
t.Error("llama3.2 should not be in cloudModels")
|
|
|
|
|
}
|
|
|
|
|
@@ -632,7 +635,7 @@ func TestBuildModelList_RecommendedFieldSet(t *testing.T) {
|
|
|
|
|
|
|
|
|
|
for _, item := range items {
|
|
|
|
|
switch item.Name {
|
|
|
|
|
case "glm-4.7-flash", "qwen3:8b", "glm-5:cloud", "kimi-k2.5:cloud":
|
|
|
|
|
case "glm-4.7-flash", "qwen3.5", "glm-5:cloud", "kimi-k2.5:cloud", "qwen3.5:cloud":
|
|
|
|
|
if !item.Recommended {
|
|
|
|
|
t.Errorf("%q should have Recommended=true", item.Name)
|
|
|
|
|
}
|
|
|
|
|
@@ -690,7 +693,7 @@ func TestBuildModelList_RecsAboveNonRecs(t *testing.T) {
|
|
|
|
|
lastRecIdx := -1
|
|
|
|
|
firstNonRecIdx := len(got)
|
|
|
|
|
for i, name := range got {
|
|
|
|
|
isRec := name == "glm-4.7-flash" || name == "qwen3:8b" || name == "minimax-m2.5:cloud" || name == "glm-5:cloud" || name == "kimi-k2.5:cloud"
|
|
|
|
|
isRec := name == "glm-4.7-flash" || name == "qwen3.5" || name == "minimax-m2.5:cloud" || name == "glm-5:cloud" || name == "kimi-k2.5:cloud" || name == "qwen3.5:cloud"
|
|
|
|
|
if isRec && i > lastRecIdx {
|
|
|
|
|
lastRecIdx = i
|
|
|
|
|
}
|
|
|
|
|
@@ -796,7 +799,7 @@ func TestResolveEditorLaunchModels_FiltersAndSkipsPickerWhenLocalRemains(t *test
|
|
|
|
|
pickerCalled := false
|
|
|
|
|
models, err := resolveEditorModels("droid", []string{"llama3.2", "glm-5:cloud"}, func() ([]string, error) {
|
|
|
|
|
pickerCalled = true
|
|
|
|
|
return []string{"qwen3:8b"}, nil
|
|
|
|
|
return []string{"qwen3.5"}, nil
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
t.Fatalf("resolveEditorLaunchModels returned error: %v", err)
|
|
|
|
|
@@ -942,9 +945,9 @@ func TestShowOrPull_ShowCalledWithCorrectModel(t *testing.T) {
|
|
|
|
|
u, _ := url.Parse(srv.URL)
|
|
|
|
|
client := api.NewClient(u, srv.Client())
|
|
|
|
|
|
|
|
|
|
_ = ShowOrPull(context.Background(), client, "qwen3:8b")
|
|
|
|
|
if receivedModel != "qwen3:8b" {
|
|
|
|
|
t.Errorf("expected Show to be called with %q, got %q", "qwen3:8b", receivedModel)
|
|
|
|
|
_ = ShowOrPull(context.Background(), client, "qwen3.5")
|
|
|
|
|
if receivedModel != "qwen3.5" {
|
|
|
|
|
t.Errorf("expected Show to be called with %q, got %q", "qwen3.5", receivedModel)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1424,12 +1427,12 @@ func TestListIntegrationInfos(t *testing.T) {
|
|
|
|
|
func TestBuildModelList_Descriptions(t *testing.T) {
|
|
|
|
|
t.Run("installed recommended has base description", func(t *testing.T) {
|
|
|
|
|
existing := []modelInfo{
|
|
|
|
|
{Name: "qwen3:8b", Remote: false},
|
|
|
|
|
{Name: "qwen3.5", Remote: false},
|
|
|
|
|
}
|
|
|
|
|
items, _, _, _ := buildModelList(existing, nil, "")
|
|
|
|
|
|
|
|
|
|
for _, item := range items {
|
|
|
|
|
if item.Name == "qwen3:8b" {
|
|
|
|
|
if item.Name == "qwen3.5" {
|
|
|
|
|
if strings.HasSuffix(item.Description, "install?") {
|
|
|
|
|
t.Errorf("installed model should not have 'install?' suffix, got %q", item.Description)
|
|
|
|
|
}
|
|
|
|
|
@@ -1439,38 +1442,38 @@ func TestBuildModelList_Descriptions(t *testing.T) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
t.Error("qwen3:8b not found in items")
|
|
|
|
|
t.Error("qwen3.5 not found in items")
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("not-installed local rec has VRAM in description", func(t *testing.T) {
|
|
|
|
|
items, _, _, _ := buildModelList(nil, nil, "")
|
|
|
|
|
|
|
|
|
|
for _, item := range items {
|
|
|
|
|
if item.Name == "qwen3:8b" {
|
|
|
|
|
if item.Name == "qwen3.5" {
|
|
|
|
|
if !strings.Contains(item.Description, "~11GB") {
|
|
|
|
|
t.Errorf("not-installed qwen3:8b should show VRAM hint, got %q", item.Description)
|
|
|
|
|
t.Errorf("not-installed qwen3.5 should show VRAM hint, got %q", item.Description)
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
t.Error("qwen3:8b not found in items")
|
|
|
|
|
t.Error("qwen3.5 not found in items")
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("installed local rec omits VRAM", func(t *testing.T) {
|
|
|
|
|
existing := []modelInfo{
|
|
|
|
|
{Name: "qwen3:8b", Remote: false},
|
|
|
|
|
{Name: "qwen3.5", Remote: false},
|
|
|
|
|
}
|
|
|
|
|
items, _, _, _ := buildModelList(existing, nil, "")
|
|
|
|
|
|
|
|
|
|
for _, item := range items {
|
|
|
|
|
if item.Name == "qwen3:8b" {
|
|
|
|
|
if item.Name == "qwen3.5" {
|
|
|
|
|
if strings.Contains(item.Description, "~11GB") {
|
|
|
|
|
t.Errorf("installed qwen3:8b should not show VRAM hint, got %q", item.Description)
|
|
|
|
|
t.Errorf("installed qwen3.5 should not show VRAM hint, got %q", item.Description)
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
t.Error("qwen3:8b not found in items")
|
|
|
|
|
t.Error("qwen3.5 not found in items")
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1530,11 +1533,11 @@ func TestIntegrationModels(t *testing.T) {
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
t.Run("returns all saved models", func(t *testing.T) {
|
|
|
|
|
if err := SaveIntegration("droid", []string{"llama3.2", "qwen3:8b"}); err != nil {
|
|
|
|
|
if err := SaveIntegration("droid", []string{"llama3.2", "qwen3.5"}); err != nil {
|
|
|
|
|
t.Fatal(err)
|
|
|
|
|
}
|
|
|
|
|
got := IntegrationModels("droid")
|
|
|
|
|
want := []string{"llama3.2", "qwen3:8b"}
|
|
|
|
|
want := []string{"llama3.2", "qwen3.5"}
|
|
|
|
|
if diff := cmp.Diff(want, got); diff != "" {
|
|
|
|
|
t.Errorf("IntegrationModels mismatch (-want +got):\n%s", diff)
|
|
|
|
|
}
|
|
|
|
|
|