provider: Command Code's refusal of a Go plan's key says where the key works (#969, pan17) — a Go key added as the Command Code API-key provider (the preset, on api.commandcode.ai/provider) can never be served: Command Code's Provider API answers every request "Your Go plan doesn't include API access. Upgrade to Provider or higher …". APIError now adds that a Go key works through the Command Code plugin (Plugins › Command Code, signed in with the key), which asks as Command Code's CLI does. TestAPIErrorShapes and the new TestCommandCodeGoKeySaysWhereItWorks (chat, messages and responses through the gateway) fail without it and pass; go test provider/gateway/plugin/gui, vet, linux/windows builds pass.

This commit is contained in:
yetone committed 2026-10-06 12:44:17 +08:00
1 parent daeb108b4e
commit 963a8d8f59
3 files changed
+59

No files matched your search

@@ -0,0 +1,41 @@
package gateway
import (
"io"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/yetone/magpie/internal/provider"
)
// A Go plan's key added as a Command Code API-key provider is refused by
// the Provider API (#969); the error the agent sees says where the key
// works, on every protocol the preset serves.
func TestCommandCodeGoKeySaysWhereItWorks(t *testing.T) {
t.Setenv("XDG_CONFIG_HOME", t.TempDir())
t.Setenv("XDG_CACHE_HOME", t.TempDir())
up := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
io.Copy(io.Discard, r.Body)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(403)
io.WriteString(w, `{"error":{"type":"forbidden","message":"Your Go plan doesn't include API access. Upgrade to Provider or higher at https://commandcode.ai/billing to use these endpoints."}}`)
}))
defer up.Close()
if err := provider.Save(provider.Provider{ID: "commandcode", Name: "Command Code", Key: "k", Models: []string{"m1"},
Chat: up.URL + "/provider/v1", Responses: up.URL + "/provider/v1", Anthropic: up.URL + "/provider"}); err != nil {
t.Fatal(err)
}
for _, q := range []struct{ path, body string }{
{"/v1/chat/completions", `{"model":"commandcode/m1","messages":[{"role":"user","content":"hi"}]}`},
{"/v1/messages", `{"model":"commandcode/m1","max_tokens":64,"messages":[{"role":"user","content":"hi"}]}`},
{"/v1/responses", `{"model":"commandcode/m1","input":"hi"}`},
} {
forgetRouting()
code, body := post(t, q.path, q.body)
if code < 400 || !strings.Contains(body, "Go plan doesn't include API access") || !strings.Contains(body, "Plugins › Command Code") {
t.Errorf("%s: %d %s", q.path, code, body)
}
}
}
+5
View File
@@ -514,6 +514,11 @@ func TestAPIErrorShapes(t *testing.T) {
if got := APIError(nil, "400 Bad Request"); got != "400 Bad Request" {
t.Fatal(got)
}
// Command Code's refusal of a Go plan's key says where it works (#969)
goKey := `{"error":{"type":"forbidden","message":"Your Go plan doesn't include API access. Upgrade to Provider or higher at https://commandcode.ai/billing to use these endpoints."}}`
if got := APIError([]byte(goKey), "403 Forbidden"); got != "Your Go plan doesn't include API access. Upgrade to Provider or higher at https://commandcode.ai/billing to use these endpoints. — "+CommandCodeGoHint {
t.Fatal(got)
}
}
// A backend that only streams is tested with a streamed request: WorkBuddy
+13
View File
@@ -510,9 +510,22 @@ func APIError(b []byte, fallback string) string {
if link, ok := Verification(b); ok {
return VerifyMessage(apiError(b, fallback), link)
}
if cmdGoNoAPI.Match(b) {
return apiError(b, fallback) + " — " + CommandCodeGoHint
}
return apiError(b, fallback)
}
// cmdGoNoAPI is Command Code's Provider API refusing a Go plan's key:
// "Your Go plan doesn't include API access. Upgrade to Provider or higher
// …" (#969). Go's key is only taken where Command Code's CLI asks, which
// the Command Code plugin does; an API-key provider (the "commandcode"
// preset) never can.
var cmdGoNoAPI = regexp.MustCompile(`(?i)\bGo plan doesn.t include API access`)
// CommandCodeGoHint says where a Go plan's key works.
const CommandCodeGoHint = "a Go plan's key works in magpie through the Command Code plugin (Plugins › Command Code, then sign in with the key), which asks Command Code as its CLI does; a Command Code API-key provider can't use it"
// verifyWords is a refusal asking for the account to be verified, put in
// words rather than as VALIDATION_REQUIRED — or already by VerifyMessage.
var verifyWords = regexp.MustCompile(`(?i)verify your account|account verification required|` + verifyAdvice)