From 63f83bf1e12bee2907ca086ae40daaed2d6fae63 Mon Sep 17 00:00:00 2001 From: yetone Date: Mon, 5 Oct 2026 00:51:57 +0800 Subject: [PATCH] =?UTF-8?q?agent:=20a=20ZCode=20pointed=20at=20another=20m?= =?UTF-8?q?achine's=20magpie=20in=20either=20of=20its=20files=20stays=20th?= =?UTF-8?q?ere=20in=20both=20(=E6=82=A0=E6=82=A0=E5=93=A5=20on=20Discord:?= =?UTF-8?q?=20ZCode=20wired=20to=20the=20magpie=20on=20a=20NAS=20kept=20be?= =?UTF-8?q?ing=20switched=20back=20to=20the=20local=20one)=20=E2=80=94=20v?= =?UTF-8?q?0.1.812=20kept=20a=20remote=20address=20per=20file=20only,=20bu?= =?UTF-8?q?t=20ZCode's=20own=20settings=20write=20provider=5Fconfig.json?= =?UTF-8?q?=20alone,=20so=20a=20sync=20rewrote=20config.json=20to=20this?= =?UTF-8?q?=20machine's=20gateway=20and=20ZCode=20could=20take=20the=20pro?= =?UTF-8?q?vider=20back=20from=20it.=20A=20sync=20now=20reads=20magpie's?= =?UTF-8?q?=20provider=20in=20both=20files=20(zcodeKept):=20an=20address?= =?UTF-8?q?=20on=20another=20machine=20in=20either=20one=20is=20written=20?= =?UTF-8?q?to=20both,=20with=20its=20key;=20otherwise=20the=20gateway's.?= =?UTF-8?q?=20TestZCodeKeepsRemoteAddress=20edits=20each=20file=20alone=20?= =?UTF-8?q?to=20a=20NAS=20address=20and=20syncs;=20it=20fails=20on=20the?= =?UTF-8?q?=20old=20code=20(config=20http://127.0.0.1:3425,=20rules=20the?= =?UTF-8?q?=20NAS).=20Check=20chain=20under=20a=20temp=20HOME=20passes.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/agent/zcode.go | 47 +++++++++++++++++++++++++++++------- internal/agent/zcode_test.go | 24 ++++++++++++++++++ 2 files changed, 62 insertions(+), 9 deletions(-) diff --git a/internal/agent/zcode.go b/internal/agent/zcode.go index b013cf7c..2553703e 100644 --- a/internal/agent/zcode.go +++ b/internal/agent/zcode.go @@ -134,9 +134,7 @@ func zcodeProviderJSON(path string, keep bool) any { } base, token := gateway.URL(), gateway.Token if keep { - was, _ := edit.GetJSON(path, "provider."+magpieID+".options.baseURL") - wasKey, _ := edit.GetJSON(path, "provider."+magpieID+".options.apiKey") - base, token = zcodeAddress(was, wasKey) + base, token = zcodeKept(filepath.Dir(path)) } return map[string]any{"name": "magpie", "kind": "anthropic", "enabled": on, "source": "custom", "options": map[string]any{"apiKey": token, "baseURL": base}, "models": ms} @@ -157,6 +155,42 @@ func zcodeAddress(was, wasKey string) (string, string) { return was, wasKey } +// zcodeKept is the address a sync gives magpie's provider in both of +// ZCode's files in dir: one on another machine found in either file, so an +// edit ZCode made to one of them is carried to the other (ZCode's own +// settings write provider_config.json, and a config.json left on this +// machine's magpie took the provider back there), else the gateway's. +func zcodeKept(dir string) (string, string) { + var r struct { + Config struct { + ProviderConfigRules struct { + ProviderRules []struct { + ProviderID string `json:"providerId"` + Config struct { + Access struct { + APIKey string `json:"apiKey"` + } `json:"access"` + API struct { + BaseURL string `json:"baseUrl"` + } `json:"api"` + } `json:"config"` + } `json:"providerRules"` + } `json:"providerConfigRules"` + } `json:"config"` + } + b, _ := os.ReadFile(filepath.Join(dir, "provider_config.json")) + json.Unmarshal(b, &r) + for _, p := range r.Config.ProviderConfigRules.ProviderRules { + if p.ProviderID == magpieID && onAnotherMachine(p.Config.API.BaseURL) { + return zcodeAddress(p.Config.API.BaseURL, p.Config.Access.APIKey) + } + } + path := filepath.Join(dir, "config.json") + was, _ := edit.GetJSON(path, "provider."+magpieID+".options.baseURL") + wasKey, _ := edit.GetJSON(path, "provider."+magpieID+".options.apiKey") + return zcodeAddress(was, wasKey) +} + // onAnotherMachine says base is an http(s) address whose host isn't this // machine's loopback. func onAnotherMachine(base string) bool { @@ -314,12 +348,7 @@ func zcodeRules(path string, on, keep bool) error { } base, token := gateway.URL(), gateway.Token if keep { - c, _ := old["config"].(map[string]any) - access, _ := c["access"].(map[string]any) - api, _ := c["api"].(map[string]any) - was, _ := api["baseUrl"].(string) - wasKey, _ := access["apiKey"].(string) - base, token = zcodeAddress(was, wasKey) + base, token = zcodeKept(filepath.Dir(path)) } rule := map[string]any{"providerId": magpieID, "providerName": "magpie", "enabled": true, "config": map[string]any{ diff --git a/internal/agent/zcode_test.go b/internal/agent/zcode_test.go index a9173358..23483685 100644 --- a/internal/agent/zcode_test.go +++ b/internal/agent/zcode_test.go @@ -359,6 +359,30 @@ func TestZCodeKeepsRemoteAddress(t *testing.T) { t.Fatalf("connecting in magpie kept the NAS address: config %s %s, rules %s %s", b, k, rb, rk) } + // ZCode's own settings change one file only (Discord, 悠悠哥: the NAS + // address kept going back to this machine's magpie): a sync carries the + // NAS address to the other one rather than taking it back + only := func(file, base, key string) { + t.Helper() + was, wasKey, _, _ := addr() + b, _ := os.ReadFile(file) + s := strings.ReplaceAll(string(b), was, base) + s = strings.ReplaceAll(s, `"apiKey": "`+wasKey+`"`, `"apiKey": "`+key+`"`) + os.WriteFile(file, []byte(strings.ReplaceAll(s, `"apiKey":"`+wasKey+`"`, `"apiKey":"`+key+`"`)), 0o644) + } + for _, file := range []string{rules, path} { + if err := a.Fields[0].Set(magpieID); err != nil { + t.Fatal(err) + } + only(file, "http://10.0.0.8:3425", "nas-key") + if err := a.Sync(); err != nil { + t.Fatal(err) + } + if b, k, rb, rk := addr(); b != "http://10.0.0.8:3425" || k != "nas-key" || rb != b || rk != k { + t.Fatalf("a NAS address in %s alone was taken back: config %s %s, rules %s %s", filepath.Base(file), b, k, rb, rk) + } + } + for base, want := range map[string]bool{"http://192.168.1.20:3425": true, "https://nas.lan": true, "http://127.0.0.1:3425": false, "http://localhost:3425": false, "http://[::1]:3425": false, "http://0.0.0.0:3425": false, "": false, "nas:3425": false} { if onAnotherMachine(base) != want {