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 {