agent: WorkBuddy's magpie models pointed at another machine's magpie stay there through a sync (悠悠哥 on Discord: 这个问题workbuddy也会有) — as v0.1.891 did for ZCode: a sync rewrote every magpie entry in ~/.workbuddy/models.json to this machine's gateway and key, so models the user had moved to the magpie on a NAS went back to the local one. A sync now keeps the url and apiKey of a magpie entry on another machine (onAnotherMachine) for all of magpie's entries; one on this machine's loopback follows the gateway as before. TestWorkBuddyKeepsRemoteAddress fails on the old code (url http://127.0.0.1:3425/…, key magpie-workbuddy). go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass.

This commit is contained in:
yetone committed 2026-10-05 01:04:07 +08:00
1 parent fe2603ff4f
commit 5daba301ca
2 files changed
+81 -1

No files matched your search

+15 -1
View File
@@ -94,6 +94,8 @@ type workbuddyEntry struct {
ID string `json:"id"`
Vendor string `json:"vendor"`
Disabled *bool `json:"disabled"`
URL string `json:"url"`
APIKey string `json:"apiKey"`
}
func workbuddyMine(raw json.RawMessage) (workbuddyEntry, bool) {
@@ -109,7 +111,9 @@ func workbuddyWired(path string) bool {
// workbuddyWrite puts magpie's models into models.json (on) or takes them
// out, leaving every other entry and key as WorkBuddy wrote it. A model
// turned off in WorkBuddy stays off.
// turned off in WorkBuddy stays off, and models the user pointed at a magpie
// on another machine (a NAS's) stay there with its key, as ZCode's do
// (zcodeAddress): a sync brings the models up to date, not the address.
func workbuddyWrite(path string, on bool) error {
d, err := workbuddyRead(path)
if err != nil {
@@ -118,12 +122,16 @@ func workbuddyWrite(path string, on bool) error {
var kept []json.RawMessage
var ours []string
off := map[string]bool{}
var remote, remoteKey string
at := -1 // where magpie's were, which they keep
for _, raw := range d.models {
if e, ok := workbuddyMine(raw); ok {
if at < 0 {
at = len(kept)
}
if remote == "" && onAnotherMachine(e.URL) {
remote, remoteKey = e.URL, e.APIKey
}
ours = append(ours, e.ID)
if e.Disabled != nil && *e.Disabled {
off[e.ID] = true
@@ -143,6 +151,12 @@ func workbuddyWrite(path string, on bool) error {
if off[m.ID] {
e["disabled"] = true
}
if remote != "" {
e["url"] = remote
if remoteKey != "" {
e["apiKey"] = remoteKey
}
}
b, err := json.Marshal(e)
if err != nil {
return err
+66
View File
@@ -123,3 +123,69 @@ func TestWorkBuddyEfforts(t *testing.T) {
t.Fatalf("%v", e)
}
}
// WorkBuddy pointed at a magpie on another machine stays there through a
// sync, with that magpie's key (悠悠哥 on Discord: models moved to the
// magpie on a NAS were put back on this machine's), while one on this
// machine's loopback follows the gateway.
func TestWorkBuddyKeepsRemoteAddress(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
t.Setenv("USERPROFILE", home)
t.Setenv("XDG_CONFIG_HOME", filepath.Join(home, ".config"))
t.Setenv("XDG_CACHE_HOME", filepath.Join(home, ".cache"))
t.Setenv("WORKBUDDY_CONFIG_DIR", "")
if err := provider.Save(provider.Provider{ID: "deepseek", Name: "DeepSeek", Chat: "https://api.deepseek.com/v1", Key: "k", Models: []string{"pro", "flash"}}); err != nil {
t.Fatal(err)
}
path := filepath.Join(home, ".workbuddy", "models.json")
os.MkdirAll(filepath.Dir(path), 0o755)
a := workbuddy(home)
if err := a.Field("provider").Set(magpieID); err != nil {
t.Fatal(err)
}
read := func() []map[string]any {
t.Helper()
var ms []map[string]any
b, _ := os.ReadFile(path)
if err := json.Unmarshal(b, &ms); err != nil {
t.Fatalf("%v\n%s", err, b)
}
return ms
}
point := func(url, key string) {
t.Helper()
ms := read()
for _, m := range ms {
m["url"], m["apiKey"] = url, key
}
b, _ := json.Marshal(ms)
os.WriteFile(path, b, 0o600)
}
const nas = "http://192.168.1.20:3425/v1/chat/completions"
point(nas, "nas-key")
if err := a.Sync(); err != nil {
t.Fatal(err)
}
ms := read()
if len(ms) != 2 {
t.Fatalf("models: %v", ms)
}
for _, m := range ms {
if m["url"] != nas || m["apiKey"] != "nas-key" {
t.Fatalf("NAS address not kept: %v", m)
}
}
// an address on this machine is magpie's own and follows the gateway
point("http://localhost:9999/v1/chat/completions", "old")
if err := a.Sync(); err != nil {
t.Fatal(err)
}
for _, m := range read() {
if m["url"] != gatewayV1()+"/chat/completions" || m["apiKey"] != "magpie-workbuddy" {
t.Fatalf("local address not followed: %v", m)
}
}
}