Files
magpie/internal/provider/cursor_picker_test.go
T
yetone 0887a9d7eb cursor: a model Cursor serves only in Max Mode is asked for again in Max Mode, and the models Cursor's picker offers beyond cursor-agent models (GLM-5.3, GLM-5.3 Flash) are listed (ARNO on Discord: 调用cursor模型报错:AI_APICallError: Cursor: Max Mode Required: The model "gpt-5.6-luna-low" requires Max Mode to be enabled; cursor provider里少了glm-5.3和glm-5.3-flash模型) — the built-in Cursor (deprecated, served by @magpie-community/opencode-cursor-auth once moved; that plugin's 0.1.7, magpie-community/plugins 3ae3e43, carries the same two fixes) asked every model with no max_mode in the Run's ModelDetails (7) or RequestedModel (2), and a model whose picker entry has supportsNonMaxMode false or a variant isMaxMode (gpt-5.6-luna-*) is refused MAX_MODE_REQUIRED, where cursor-agent turns Max Mode on itself. askCursor now asks such a model again with max_mode set in both when Cursor refuses it so, and keeps asking it in Max Mode from then on (cursorMaxOnly). The list came from cursor-agent models (GetUsableModels) alone; Cursor's picker, AiService/AvailableModels, also offers models that list leaves out, so the account's list now adds them (cursorPickerModels: one per variant slug, else the model's name; hidden, Tab-only, chat-only, non-agent ones and the four the CLI drops stay out, and so does a model the list has under any of its slugs), the picker best-effort. TestServeCursorMaxModeRequired (a fake Cursor refusing gpt-5.6-luna-low without Max Mode; it fails without the change) and TestCursorPickerModels (no GLM-5.3 without the change) are new, against fakes; no request was made to Cursor. The mover's min stays 0.1.5 until 0.1.7 is published. go vet ./internal/..., go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui -count=1 ./... under a temp HOME pass (TestProvidersAnswerWhileListsComeIn, TestUserPath and TestFXInState failed once each under load and pass on a rerun).
2026-10-02 22:18:22 +08:00

69 lines
2.6 KiB
Go

package provider
import (
"context"
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"testing"
"github.com/yetone/magpie/internal/catalog"
)
// The picker's models `cursor-agent models` leaves out are listed (ARNO on
// Discord: "cursor provider 里少了 glm-5.3 和 glm-5.3-flash"), against a
// fake Cursor; hidden, Tab-only, chat-only ones and a model the list already
// has (any of its slugs) aren't.
func TestCursorPickerModels(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/aiserver.v1.AiService/AvailableModels" || r.Header.Get("Authorization") != "Bearer tok" {
http.Error(w, "no", http.StatusNotFound)
return
}
var body map[string]any
b, _ := io.ReadAll(r.Body)
if json.Unmarshal(b, &body) != nil || body["useModelParameters"] != true {
t.Errorf("body %s", b)
}
w.Header().Set("Content-Type", "application/json")
io.WriteString(w, `{"models":[
{"name":"gpt-5.6-luna","clientDisplayName":"GPT-5.6 Luna","supportsNonMaxMode":false,"variants":[
{"displayName":"Low","isMaxMode":true,"legacySlug":"gpt-5.6-luna-low"},
{"displayName":"High","isMaxMode":true,"legacySlug":"gpt-5.6-luna-high"}]},
{"name":"composer-2.5","clientDisplayName":"Composer 2.5","variants":[{"legacySlug":"composer-2.5"}]},
{"name":"glm-5.3","clientDisplayName":"GLM-5.3","contextTokenLimit":200000,"variants":[{"displayName":""}]},
{"name":"glm-5.3-flash","clientDisplayName":"GLM-5.3 Flash"},
{"name":"secret","clientDisplayName":"Secret","isHidden":true},
{"name":"tab","onlySupportsCmdK":true},
{"name":"chat","isChatOnly":true},
{"name":"noagent","supportsAgent":false},
{"name":"claude-4.5-haiku","clientDisplayName":"Haiku 4.5"}]}`)
}))
defer srv.Close()
old := cursorBase
cursorBase = srv.URL
defer func() { cursorBase = old }()
have := []catalog.Model{{ID: "gpt-5.6-luna-low"}, {ID: "composer-2.5"}}
got := cursorPickerModels(context.Background(), "tok", have)
want := []catalog.Model{
{ID: "glm-5.3", Name: "GLM-5.3", Context: 200000},
{ID: "glm-5.3-flash", Name: "GLM-5.3 Flash", Context: cursorContext("glm-5.3-flash", "GLM-5.3 Flash")},
}
if len(got) != len(want) {
t.Fatalf("got %+v, want %+v", got, want)
}
for i := range want {
if got[i].ID != want[i].ID || got[i].Name != want[i].Name || got[i].Context != want[i].Context {
t.Errorf("model %d: got %+v, want %+v", i, got[i], want[i])
}
}
// a picker Cursor can't give adds nothing
cursorBase = srv.URL + "/down"
if got := cursorPickerModels(context.Background(), "tok", have); len(got) != 0 {
t.Errorf("picker down: got %+v", got)
}
}