From 2cdae80a101531a9d25cc9e684e35236f1a58e52 Mon Sep 17 00:00:00 2001 From: yetone Date: Thu, 8 Oct 2026 20:24:56 +0800 Subject: [PATCH] stats: the day's event no longer names an omp profile or a model the user named; an omp profile goes as `omp`, and on a key's provider a model id models.dev doesn't list (an Ollama model, a fine-tune with the user's organisation in it) goes as `/other` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 169c23c1 cut only `@wsl:` from agent ids, and 78d90571 (four minutes earlier) made each omp profile an agent `omp#`, so the profile name went to PostHog. modelLabel sent `/` for any model on a preset's provider, and on Ollama, LM Studio or a fine-tune that id is the user's own text. docs/reference.md promised "No names". Model ids on subscriptions and plugins are the vendor's and are unchanged; known models on a key's provider still go by id (deepseek/deepseek-v4). Red before: with the old usage.go, TestAgentLabel fails ("omp#acme-secret", want "omp") and TestModelLabelKeepsTheUsersOwnModelIDs fails ("openai/ft:gpt-4o:acme-corp::abc123", want "openai/other"; "ollama/acme-internal-llm", want "ollama/other"); both pass with it. Run in docker golang:1.26.8 (this Mac's syspolicyd is pegged and new test binaries hang before start): gofmt -l, go vet -tags nogui on stats/agent/catalog, GOOS=windows go build, go build -tags nogui, and go test -tags nogui ./... — all pass except internal/agent's aside chmod-0500 tests, which root ignores; internal/agent passes as uid 1000. --- docs/reference.md | 9 ++++-- internal/stats/stats_test.go | 53 ++++++++++++++++++++++++++++++++++++ internal/stats/usage.go | 19 +++++++++++-- 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/docs/reference.md b/docs/reference.md index a9b3a070..3f28deb3 100644 --- a/docs/reference.md +++ b/docs/reference.md @@ -1845,13 +1845,16 @@ and architecture. With it goes what magpie is used with, so we know which agents, providers and models to look after first, by magpie's own ids only: -- the agents connected to magpie (`claude`, `codex`); +- the agents connected to magpie (`claude`, `codex`); an omp profile is + only `omp`; - the providers that are on: a preset's id (`deepseek`), a subscription's (`codex`, `copilot`), a community plugin's (`plugin:kiro`); a provider you added yourself is only `custom`, another plugin only `plugin`; - the models the connected agents are set to, as the provider's id and the - vendor's model id (`deepseek/deepseek-v4`); one on a provider of your own - is only `custom`, a routing group only `group`; + vendor's model id (`deepseek/deepseek-v4`); on a key's provider, a model + id that [models.dev](https://models.dev) doesn't list (a local model, a + fine-tune) is only `/other`; one on a provider of your own is + only `custom`, a routing group only `group`; - how many of each, and how many routing groups you have. No names, base URLs, accounts, keys, prompts or usage go. Turn that part off diff --git a/internal/stats/stats_test.go b/internal/stats/stats_test.go index 47d47cae..512bb649 100644 --- a/internal/stats/stats_test.go +++ b/internal/stats/stats_test.go @@ -5,10 +5,13 @@ import ( "encoding/json" "net/http" "net/http/httptest" + "os" + "path/filepath" "strings" "testing" "time" + "github.com/yetone/magpie/internal/catalog" "github.com/yetone/magpie/internal/provider" "github.com/yetone/magpie/internal/settings" ) @@ -102,3 +105,53 @@ func TestProviderLabel(t *testing.T) { } } } + +// Nothing the user named goes as an agent: an omp profile, a WSL distro. +func TestAgentLabel(t *testing.T) { + for id, want := range map[string]string{ + "claude": "claude", + "claude@wsl:Ubuntu": "claude", + "omp#acme-secret": "omp", + "omp#acme-secret@wsl:Work": "omp", + } { + if got := agentLabel(id); got != want { + t.Errorf("%s: %q, want %q", id, got, want) + } + } +} + +// A model on a key's provider goes by its id only when models.dev knows +// it: one the user named (an Ollama model, a fine-tune naming their +// organisation) is "other". +func TestModelLabelKeepsTheUsersOwnModelIDs(t *testing.T) { + cache := map[string]any{"deepseek": map[string]any{"id": "deepseek", "models": map[string]any{ + "deepseek-v4": map[string]any{"id": "deepseek-v4", "limit": map[string]any{"context": 128000}}, + }}} + b, _ := json.Marshal(cache) + if err := os.MkdirAll(filepath.Dir(catalog.CachePath()), 0o700); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(catalog.CachePath(), b, 0o600); err != nil { + t.Fatal(err) + } + catalog.Reset() + t.Cleanup(func() { os.Remove(catalog.CachePath()); catalog.Reset() }) + for _, p := range []provider.Provider{ + {ID: "my-deepseek", Name: "DS", Preset: "deepseek", Chat: "https://api.deepseek.com/v1", Key: "sk-x", Models: []string{"deepseek-v4"}}, + {ID: "my-openai", Name: "OA", Preset: "openai", Chat: "https://api.openai.com/v1", Key: "sk-y", Models: []string{"ft:gpt-4o:acme-corp::abc123"}}, + {ID: "my-ollama", Name: "Local", Preset: "ollama", Chat: "http://127.0.0.1:11434/v1", Models: []string{"acme-internal-llm"}}, + } { + if err := provider.Save(p); err != nil { + t.Fatal(err) + } + } + for ref, want := range map[string]string{ + "my-deepseek/deepseek-v4": "deepseek/deepseek-v4", + "my-openai/ft:gpt-4o:acme-corp::abc123": "openai/other", + "my-ollama/acme-internal-llm": "ollama/other", + } { + if got := modelLabel(ref); got != want { + t.Errorf("%s: %q, want %q", ref, got, want) + } + } +} diff --git a/internal/stats/usage.go b/internal/stats/usage.go index bcd3e317..89fda879 100644 --- a/internal/stats/usage.go +++ b/internal/stats/usage.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/yetone/magpie/internal/agent" + "github.com/yetone/magpie/internal/catalog" "github.com/yetone/magpie/internal/provider" ) @@ -31,8 +32,7 @@ func readUsage() Usage { if !a.Wired() { continue } - id, _, _ := strings.Cut(a.ID, "@wsl:") - u.Agents = with(u.Agents, id) + u.Agents = with(u.Agents, agentLabel(a.ID)) for _, ref := range a.Models() { u.Models = with(u.Models, modelLabel(ref)) } @@ -75,9 +75,21 @@ func providerLabel(p provider.Provider) string { return "custom" } +// agentLabel is an agent as stats name it: its built-in id, without the +// WSL distro or the omp profile (omp#) the user named. +func agentLabel(id string) string { + id, _, _ = strings.Cut(id, "@wsl:") + id, _, _ = strings.Cut(id, "#") + return id +} + // modelLabel is an agent's model as stats name it: the provider's label // and the vendor's model id, "group" for a routing group, and the label // alone for a provider of the user's own; "" for one magpie can't find. +// On a key's provider the model id is the user's to type (an Ollama +// model they named, a fine-tune with their organisation in it), so it +// goes only when models.dev knows it, else as "other"; a subscription's +// or plugin's ids are its vendor's. func modelLabel(ref string) string { if strings.HasPrefix(ref, provider.GroupPrefix) { return "group" @@ -90,5 +102,8 @@ func modelLabel(ref string) string { if l == "custom" || l == "plugin" { return l } + if p.Account == nil && !p.IsPlugin() && !catalog.Knows(m) { + return l + "/other" + } return l + "/" + m }