107 lines
4.2 KiB
Go
107 lines
4.2 KiB
Go
package agent
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/yetone/magpie/internal/edit"
|
|
)
|
|
|
|
// CC Switch's Codex config, as it writes it: its "custom" table, one of
|
|
// its older versions' named by a profile, and a table of the user's own.
|
|
const ccSwitchCodex = "model_provider = \"custom\"\nmodel = \"gpt-5.4\"\nmodel_reasoning_effort = \"high\"\n\n" +
|
|
"[model_providers.custom]\nname = \"custom\"\nbase_url = \"https://relay.example/v1\"\nwire_api = \"responses\"\nrequires_openai_auth = true\nexperimental_bearer_token = \"sk-relay\"\n\n" +
|
|
"[model_providers.cc-switch-2]\nname = \"old\"\nbase_url = \"https://old.example/v1\"\n\n" +
|
|
"[model_providers.mine]\nname = \"mine\"\nbase_url = \"https://mine.example/v1\"\n\n" +
|
|
"[profiles.work]\nmodel_provider = \"cc-switch-2\"\n"
|
|
|
|
// A Codex thread keeps the provider it was started on, and CC Switch puts
|
|
// every third-party one on its "custom" table: reopened after magpie took
|
|
// Codex over, it still went to the relay, a magpie model picked in it
|
|
// too, and the relay said the model wasn't found. While a magpie model is
|
|
// on, CC Switch's tables go through magpie too, and get their own base URL
|
|
// back when Codex steps off magpie; a profile's table and the user's own
|
|
// stay as they are.
|
|
func TestCodexTakesCCSwitchTables(t *testing.T) {
|
|
for _, auth := range []string{`{"tokens":{"access_token":"x","id_token":"x.e30.x"}}`, ""} {
|
|
home, read := codexHome(t, auth, ccSwitchCodex)
|
|
path := filepath.Join(home, ".codex", "config.toml")
|
|
cx := codex(home)
|
|
table := func(id string) map[string]string {
|
|
tb, err := edit.GetTOMLTable(path, "model_providers."+id)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return tb
|
|
}
|
|
v1 := here(home).v1()
|
|
if err := cx.Fields[0].Set("fake/m1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if c := table("custom"); c["base_url"] != v1 || c["experimental_bearer_token"] != "sk-relay" || c["requires_openai_auth"] != "true" {
|
|
t.Fatalf("auth %q: custom not through magpie:\n%s", auth, read())
|
|
}
|
|
if table("cc-switch-2")["base_url"] != "https://old.example/v1" || table("mine")["base_url"] != "https://mine.example/v1" {
|
|
t.Fatalf("auth %q: other tables changed:\n%s", auth, read())
|
|
}
|
|
if d := cx.Check(); d != "" {
|
|
t.Fatalf("auth %q: check: %s", auth, d)
|
|
}
|
|
// CC Switch writes its table again: the row says so, and magpie's
|
|
// next sync takes it over again
|
|
if err := edit.SetTOMLKey(path, "model_providers.custom", "base_url", "https://relay2.example/v1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if d := cx.Check(); !strings.Contains(d, "[model_providers.custom]") || !strings.Contains(d, "relay2.example") {
|
|
t.Fatalf("auth %q: check: %q", auth, d)
|
|
}
|
|
if err := cx.Sync(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if table("custom")["base_url"] != v1 || cx.Check() != "" {
|
|
t.Fatalf("auth %q: sync:\n%s", auth, read())
|
|
}
|
|
// one of Codex's own models: the table's own base URL is back
|
|
if err := cx.Fields[0].Set("gpt-5.4"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if table("custom")["base_url"] != "https://relay2.example/v1" {
|
|
t.Fatalf("auth %q: own model:\n%s", auth, read())
|
|
}
|
|
// and a reset gives it back too
|
|
if err := cx.Fields[0].Set("fake/m1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := cx.Fields[0].Set(""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if table("custom")["base_url"] != "https://relay2.example/v1" {
|
|
t.Fatalf("auth %q: reset:\n%s", auth, read())
|
|
}
|
|
if _, ok := stashLoad()[here(home).key("codex.tables")]; ok {
|
|
t.Errorf("auth %q: stash left", auth)
|
|
}
|
|
}
|
|
}
|
|
|
|
// A CC Switch table the user pointed at magpie by hand stays so when Codex
|
|
// steps off magpie: magpie gives back only what it took.
|
|
func TestCodexKeepsHandPointedCCSwitchTable(t *testing.T) {
|
|
home, read := codexHome(t, `{"tokens":{"access_token":"x","id_token":"x.e30.x"}}`, "")
|
|
v1 := here(home).v1()
|
|
os.WriteFile(filepath.Join(home, ".codex", "config.toml"),
|
|
[]byte("[model_providers.custom]\nname = \"custom\"\nbase_url = \""+v1+"\"\nwire_api = \"responses\"\n"), 0o644)
|
|
cx := codex(home)
|
|
if err := cx.Fields[0].Set("fake/m1"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := cx.Fields[0].Set(""); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(read(), `base_url = "`+v1+`"`) {
|
|
t.Fatalf("\n%s", read())
|
|
}
|
|
}
|