Snow CLI (npm snow-ai, MIT, MayDay-wpf/snow-cli) keeps one profile per file under ~/.snow/profiles (or $SNOW_CONFIG_DIR), names the active one in active-profile.json, and copies it over config.json at every start, headless `snow --ask` included. Each profile is the whole snowcfg: base URL, key, request method and models. Snow App (MayDay-wpf/snow-app) reads ~/.snow/profiles/*.json when "Sync Snow CLI API config" is pressed. magpie writes profiles/magpie.json from the profile the user was on (their settings kept, Snow's OAuth sign-in left out): baseUrlMode base at the gateway's /v1, requestMethod chat, the agent's key, the model as advancedModel and basicModel, and the catalog's window and output (200000 and 64000 when not known, the output cut to the window). It makes that profile active and copies it to config.json. The profile the user was on, whether there was an active-profile.json at all, and a magpie.json of their own are stashed; Disconnect, `magpie snow default`, or picking a model of one of the user's profiles puts those back. A Snow from before profiles (config.json alone) gets the default.json Snow itself would make, so its next start doesn't take magpie's config for the user's. Check reports a base URL, key or request method moved off magpie's; Sync rewrites the profile on a port move. A WSL distro's ~/.snow is found and written the same way. Registered: agents.go, the WSL kinds, SNOW_CONFIG_DIR in agentenv, the npm update spec (snow-ai), the icon (Snow App's own, trimmed to 96px), README, docs/reference.md, docs/subsystems/agent-wiring.md, the site's agent list and start.html (en, zh, ja). Run: - go test -tags nogui ./... in a scratch HOME: 44 packages ok. New: TestSnow, TestSnowOwnProfile, TestSnowNoProfiles, TestSnowUsersMagpieProfile, TestSnowCheckSync, TestAgentSnowDefault; snow added to TestOwnProviderNamedAsMagpies, the WSL more-agents tests and TestMaxTokensWithinContextWindow. All fail before this commit (no agent "snow"). - go vet -tags nogui for darwin, linux and windows; gofmt -l clean. - Real Snow CLI 0.9.2 in a sandbox HOME against a sandbox magpie (`magpie serve` on 127.0.0.1:3571, a fake OpenAI upstream on 3561): `magpie snow fake/pro` made the magpie profile active, `snow --ask` answered through the gateway (POST /v1/chat/completions, model pro, logged as agent snow), and `magpie snow default` left profiles, active-profile.json and config.json byte-identical to before. - GUI: agent-layout, agent-connect, agent-models-picker, agent-field-names and models-add-and-icons in Chromium and WebKit; a Snow CLI row checked at 520-960px in en, zh, zh-TW, ja and de in both engines. No new GUI strings.
66 lines
1.8 KiB
Go
66 lines
1.8 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// `magpie snow a/m` puts Snow CLI on a magpie profile and makes it the
|
|
// active one; `magpie snow default` puts back the profile the user was on,
|
|
// its files as they were.
|
|
func TestAgentSnowDefault(t *testing.T) {
|
|
groupsHome(t)
|
|
t.Setenv("SNOW_CONFIG_DIR", "")
|
|
dir := filepath.Join(os.Getenv("HOME"), ".snow")
|
|
os.MkdirAll(filepath.Join(dir, "profiles"), 0o755)
|
|
own := `{
|
|
"snowcfg": {
|
|
"baseUrl": "https://idealab.example.com/v1",
|
|
"apiKey": "team-key",
|
|
"requestMethod": "chat",
|
|
"advancedModel": "glm-5",
|
|
"basicModel": "glm-5"
|
|
}
|
|
}`
|
|
active := "{\n \"activeProfile\": \"default\"\n}"
|
|
files := map[string]string{
|
|
"profiles/default.json": own,
|
|
"config.json": own,
|
|
"active-profile.json": active,
|
|
}
|
|
for f, s := range files {
|
|
if err := os.WriteFile(filepath.Join(dir, f), []byte(s), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
read := func(f string) string {
|
|
b, _ := os.ReadFile(filepath.Join(dir, f))
|
|
return string(b)
|
|
}
|
|
if err := run([]string{"snow", "a/m"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
s := read("profiles/magpie.json")
|
|
for _, want := range []string{`"advancedModel": "a/m"`, `"baseUrlMode": "base"`, `"requestMethod": "chat"`, `/v1"`} {
|
|
if !strings.Contains(s, want) {
|
|
t.Fatalf("not wired (%s missing):\n%s", want, s)
|
|
}
|
|
}
|
|
if !strings.Contains(read("active-profile.json"), `"magpie"`) || read("config.json") != s {
|
|
t.Fatalf("magpie's profile isn't the active one:\n%s\n%s", read("active-profile.json"), read("config.json"))
|
|
}
|
|
if err := run([]string{"snow", "default"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for f, want := range files {
|
|
if got := read(f); got != want {
|
|
t.Errorf("%s not put back:\n%s", f, got)
|
|
}
|
|
}
|
|
if _, err := os.Stat(filepath.Join(dir, "profiles", "magpie.json")); !os.IsNotExist(err) {
|
|
t.Error("magpie.json left")
|
|
}
|
|
}
|