Files
magpie/internal/plugin/plugin_list_error_test.go
yetone 4788cf2bbd plugin, gui: a plugin's account whose model list failed says why, rather than listing Auto alone (gnayiab on X) — with magpie in WSL, Cursor's plugin account offered only Auto: the plugin's models hook couldn't get the account's list and magpie, with no list kept from before, showed the plugin's defaults with nothing saying so, its editor even calling them "vendor list", and Refresh answered "1 models". The host now keeps why a models hook fell back (what it threw, else how its last fetch failed) for the provider and each account; plugin.Cached carries it with the accounts it reads again from the sign-ins; provider.ListError gives it for a plugin's account. The editor says "<provider> couldn't list its models: <why>" under the models (amber, no left border) and no longer calls the defaults the vendor's list, and Refresh fails with it. A list kept from before, or one that comes in, says nothing. en/zh/ja/de. Tried with the real Cursor plugin (0.1.9) in a sandbox: a key Cursor refuses shows "Cursor couldn't list its models: Cursor didn't take this API key" and Refresh says it; the owner's real account lists 72 models with nothing said, and Claude Code -p through the gateway ran a Bash tool on cursor/auto, composer-2.5 and claude-opus-5-thinking. The plugin itself, in WSL (magpie-desktop), listed 254 models and streamed chats with tools. TestFallenBackListSaysWhy (hook returns its defaults, throws, or hands back its own) fails without the change; plugin-list-error.test.cjs (Chromium and WebKit, en and zh) too; TestFallenBackListKeepsTheLastOne, account-models, plugin-signin and click-scroll pass. go vet, go build (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui ./... under a temp HOME pass.
2026-10-05 17:39:29 +08:00

82 lines
2.4 KiB
Go

package plugin
import (
"context"
"net/http"
"net/http/httptest"
"path/filepath"
"sync/atomic"
"testing"
"time"
)
// A plugin that never got its vendor's list says why, for the provider
// and each account: the editor shows it over the plugin's short defaults
// (gnayiab on X: Cursor in WSL listing Auto alone, with nothing saying
// its list had failed). Its list come in, nothing is said.
func TestFallenBackListSaysWhy(t *testing.T) {
for _, throws := range []string{"", "1", "own"} {
t.Run("throws="+throws, func(t *testing.T) { listSaysWhy(t, throws) })
}
}
func listSaysWhy(t *testing.T, throws string) {
sandbox(t)
t.Setenv("FAKE_MODELS_THROW", throws)
// no list told before this one, in memory or on disk
Restart()
provMu.Lock()
provCache = nil
provMu.Unlock()
var up atomic.Bool
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if !up.Load() {
c, _, _ := w.(http.Hijacker).Hijack()
c.Close()
return
}
w.Write([]byte("extra"))
}))
defer srv.Close()
t.Setenv("FAKE_MODELS", srv.URL+"/models")
ctx, cancel := context.WithTimeout(context.Background(), time.Minute)
defer cancel()
abs, _ := filepath.Abs("testdata/fake/index.js")
if _, err := Add(ctx, abs); err != nil {
t.Fatal(err)
}
for _, k := range []string{"k1", "k2"} {
if _, err := APIKey(ctx, "fakeco", 0, nil, k, NewAccount); err != nil {
t.Fatal(err)
}
}
ps, err := Providers(ctx)
if err != nil || len(ps) != 1 || len(ps[0].Accounts) != 2 {
t.Fatalf("Providers = %+v, %v", ps, err)
}
if !ps[0].FellBack || ps[0].ListError == "" {
t.Fatalf("the provider fell back saying %q (fellBack %v)", ps[0].ListError, ps[0].FellBack)
}
for _, a := range ps[0].Accounts {
if !a.FellBack || a.ListError == "" {
t.Fatalf("account %s fell back saying %q (fellBack %v)", a.Key, a.ListError, a.FellBack)
}
}
// and so as magpie reads it, its accounts read again from the sign-ins
for _, a := range Cached()[0].Accounts {
if !a.FellBack || a.ListError == "" {
t.Fatalf("Cached: account %s fell back saying %q (fellBack %v)", a.Key, a.ListError, a.FellBack)
}
}
up.Store(true)
if ps, err = Providers(ctx); err != nil || ps[0].FellBack || ps[0].ListError != "" {
t.Fatalf("with the list in, Providers = %+v, %v", ps, err)
}
for _, a := range ps[0].Accounts {
if a.FellBack || a.ListError != "" {
t.Fatalf("with the list in, account %s says %q", a.Key, a.ListError)
}
}
}