Files
magpie/internal/agent
yetone 84d45e6b8e agent tests: Claude Code's haiku tier follows Claude Haiku 5.5 where a provider serves it beside Haiku 4.5 (Discord: using Haiku 5.5)
magpie keeps no list of Anthropic's models: the Claude subscription's list
is models.dev's "anthropic" provider (catalog.Provider, cached and
refetched daily), other providers' come from their own /v1/models, and the
code that knows Claude models (claudeLight, claudeEffortsFor,
claudeReadsTop, the gateway's adaptiveOnly) reads versions, not ids. So
claude-haiku-5-5 needs no entry: once a provider lists it, claudeLight
picks it over claude-haiku-4-5 and its dated id, and Claude Code is sent
every effort level for it, read from modelSettings only.

TestClaudeLightHaiku55 holds that, on an Anthropic-style provider and on a
router's dotted ids (anthropic/claude-haiku-5.5, as Vercel lists it). With
claudeLight's newest-first compare reversed it fails: claudeLight
("anth/claude-opus-5-5") = "anth/claude-haiku-4-5", want
"anth/claude-haiku-5-5". go vet -tags nogui and go test -tags nogui
./internal/agent pass under a temp HOME.

Not added: models.dev's anthropic provider doesn't list claude-haiku-5-5
yet (only Vercel's gateway does, released 2026-10-07), so the Claude
subscription won't offer it until models.dev does. No Bedrock id was given
or listed, so the Bedrock preset is unchanged. Not tried with a real
account.
2026-10-08 05:00:55 +08:00
..
gateway: a request a proxy or tunnel on this computer forwards to loopback is answered as one from another machine, and needs the gateway key (#1022, znjhahaha: asked for a Cloudflare Tunnel in magpie, with the gateway key checked for requests through it) — local() was the request's address alone, so cloudflared, ngrok, Tailscale serve or funnel, frp's HTTP proxy, or a Caddy or nginx here, all reaching 127.0.0.1:3425 for clients anywhere, were taken for this computer's agents: whoever had the tunnel's address used the user's subscriptions with any token, read /v1/magpie/quotas (the accounts and their balances) and the remote cards, and their usage was counted as local, all without sharing on. reference.md said a proxy here had to sign its clients in itself; a quick tunnel signs in nobody. A request on loopback carrying a forwarding header (Forwarded, X-Forwarded-For, X-Real-IP, Cf-Connecting-IP, True-Client-IP, Tailscale-User-Login), which no agent sends, is now proxied, and local() is false for it, so every check built on local() takes it as from the network: lanGuard refuses it while magpie isn't shared, saying it came through a proxy or tunnel and that Settings → Share on local network and a gateway key let it in; shared, it needs an enabled gateway key and is then sharedWith, as a LAN client is, for the model APIs, quotas, remote cards, concurrency, session route and MCP sign-ins; the Omarchy theme and the Codex title link stay this machine's only, and its usage is no longer marked local. A gateway MAGPIE_ADDR opens to the network stays open to a tunnel as to anyone; one MAGPIE_ADDR keeps on loopback is closed to it. MAGPIE_TRUST_PROXY=1 says a proxy here signs its clients in itself and keeps what it forwards local, as before (listed in agentenv_test's notAnAgent). A tunnel forwarding bare TCP (frp tcp, ssh -R, socat) adds no header and can't be told from an agent: reference.md says to point one at the LAN address with sharing on. Running cloudflared from magpie with a pasted Tunnel Token is not done here: magpie would have to download or run a program it doesn't ship; reference.md says how to serve magpie through a Cloudflare Tunnel today. TestProxiedLoopbackNeedsTheKey (from 127.0.0.1 with cloudflared's, ngrok's, nginx's, RFC 7239's, Akamai's and Tailscale serve's headers: refused unshared, 401 shared without a key, with magpie's token or a wrong key, let in with the key under its identity, a disabled key refused; an agent on loopback let in with any token; MAGPIE_TRUST_PROXY; MAGPIE_ADDR on loopback and open) and TestProxiedLoopbackRoutes (quotas, quotas history, models, Omarchy and /mcp through a tunnel, unshared and shared, with and without the key) fail on main (200 for every tunnel unshared) and pass -race -count=10 with TestLANGuard, TestQuotasOverLAN, TestManagedLANGuard and TestExplicitOpenGatewayAcceptsAllRemoteTokens; go test -race -tags nogui ./internal/gateway (579 s, under -timeout 30m) and go test -tags nogui ./internal/... under a temp HOME pass; go vet (darwin, windows), gofmt -l, linux and windows (nogui) builds pass. No GUI change. Not tried with a real cloudflared (not installed here); its Cf-Connecting-IP and X-Forwarded-For are what Cloudflare documents it sends.
2026-10-06 20:35:18 +08:00
…
…
…
…
…
agent: CodeBuddy Code (Tencent's CLI, codebuddy/cbc, the China edition too) is an agent that uses magpie's models (#980, yujianbinm) — the CLI (npm @tencent-ai/codebuddy-code 2.161.4, one package for codebuddy.ai and codebuddy.cn, CODEBUDDY_INTERNET_ENVIRONMENT=internal) takes models of one's own from ~/.codebuddy/models.json ($CODEBUDDY_CONFIG_DIR), the format WorkBuddy reads, hot-reloaded, and starts a session on settings.json's "model". magpie now writes its models there as WorkBuddy's are written (vendor magpie, key magpie-codebuddy, url the gateway's /v1/chat/completions), keeping the user's own entries, their order, a model turned off and availableModels (magpie's ids added when the list is there), and sets "model" to the pick, the user's other settings kept; one of CodeBuddy's own models, or default, takes magpie's models out again. A new models.json is {"models":[…]} as CodeBuddy's docs give it. workbuddyWrite becomes buddyWrite(agent), the same writer for both. CODEBUDDY_CONFIG_DIR joins agentenv.Vars; cliupdate knows the npm package. TestCodeBuddyCode (user's model, availableModels and settings kept; magpie pick; sync; back to own; default) and TestCodeBuddyCodeNewFile fail without the agent ("no codebuddy agent") and pass; -race -count=5 on the CodeBuddy/WorkBuddy tests. End to end, the real CLI 2.161.4 under a temp HOME with CODEBUDDY_INTERNET_ENVIRONMENT=internal and no CodeBuddy sign-in: magpie codebuddy magpie/mock/pro against a sandbox gateway on 3462, then codebuddy -p with no --model, answered through the gateway from a mock upstream, and magpie's usage counted it under CodeBuddy Code (the CLI sends "CLI/2.161.4 CodeBuddy/2.161.4", so it is told by its key); magpie codebuddy default took it out. A bare-list models.json is read by the CLI too. Not tried with a real CodeBuddy account or a real model vendor. go test ./internal/agent/ ./internal/agentenv/ ./internal/usage/ ., go vet, darwin, linux (nogui) and windows builds pass.
2026-10-06 15:32:23 +08:00
agent: CodeBuddy Code (Tencent's CLI, codebuddy/cbc, the China edition too) is an agent that uses magpie's models (#980, yujianbinm) — the CLI (npm @tencent-ai/codebuddy-code 2.161.4, one package for codebuddy.ai and codebuddy.cn, CODEBUDDY_INTERNET_ENVIRONMENT=internal) takes models of one's own from ~/.codebuddy/models.json ($CODEBUDDY_CONFIG_DIR), the format WorkBuddy reads, hot-reloaded, and starts a session on settings.json's "model". magpie now writes its models there as WorkBuddy's are written (vendor magpie, key magpie-codebuddy, url the gateway's /v1/chat/completions), keeping the user's own entries, their order, a model turned off and availableModels (magpie's ids added when the list is there), and sets "model" to the pick, the user's other settings kept; one of CodeBuddy's own models, or default, takes magpie's models out again. A new models.json is {"models":[…]} as CodeBuddy's docs give it. workbuddyWrite becomes buddyWrite(agent), the same writer for both. CODEBUDDY_CONFIG_DIR joins agentenv.Vars; cliupdate knows the npm package. TestCodeBuddyCode (user's model, availableModels and settings kept; magpie pick; sync; back to own; default) and TestCodeBuddyCodeNewFile fail without the agent ("no codebuddy agent") and pass; -race -count=5 on the CodeBuddy/WorkBuddy tests. End to end, the real CLI 2.161.4 under a temp HOME with CODEBUDDY_INTERNET_ENVIRONMENT=internal and no CodeBuddy sign-in: magpie codebuddy magpie/mock/pro against a sandbox gateway on 3462, then codebuddy -p with no --model, answered through the gateway from a mock upstream, and magpie's usage counted it under CodeBuddy Code (the CLI sends "CLI/2.161.4 CodeBuddy/2.161.4", so it is told by its key); magpie codebuddy default took it out. A bare-list models.json is read by the CLI too. Not tried with a real CodeBuddy account or a real model vendor. go test ./internal/agent/ ./internal/agentenv/ ./internal/usage/ ., go vet, darwin, linux (nogui) and windows builds pass.
2026-10-06 15:32:23 +08:00
agent, gui: an agent connected by its config to an address where nothing answers is told, not shown connected (#1013, cjyrainbow: Codex Desktop's WSL environment reads Windows' ~/.codex/config.toml, whose openai_base_url and [model_providers.magpie].base_url the reporter pointed at Windows as WSL sees it, forwarded to 127.0.0.1:3425 by a portproxy of their own; after a reboot the portproxy listened no more and the Agents page still said Codex was connected) — Drift looked only at the config, which was right. Now an agent pointed at an address off loopback (this machine's Codex at an address the user kept, #816, through Agent.reach; every WSL twin under NAT, at Windows as the distro sees it, through Agent.Gateway) has that address tried from here (reach.go: GET /v1/models, any HTTP status an answer, 2 s timeout, in the background, at most every 20 s per address, never waited for), and one that doesn't answer while the gateway answers on loopback is a new drift, "unreachable", with Addr and the advice in Detail: under WSL (or on Windows) magpie with Settings › Share on local network on, or the user's netsh interface portproxy, which may need setting up again after a restart; Windows' firewall allowing the port for the WSL network; on Windows 11, networkingMode=mirrored; elsewhere, the forward to start again or gateway.URL() to point at. An answer not had yet, and a gateway down on loopback too, are no drift. The config is never changed for it, except where the address is one a WSL distro reached Windows at before (distro.Was, the last 4 kept in wsl.json as a re-probe finds Gateway changed) and the distro reaches Windows at another now: Drift's Move names that one, and Reapply moves the config there (Agent.move; Codex's codexMoveGateway rewrites openai_base_url and magpie's own provider's base_url, only where they begin with the old address). An address no distro was seen at is the user's own and is never offered a move. In the GUI the row's line says "{agent} is set up, but nothing answers at the address it reaches magpie by" in red with the advice as its tooltip, and its pill is "How to fix" (an i, not the reapply arrow), which opens the advice in a dialog (too long for the status line; it wraps and can be copied) and sets nothing — or "Use <address>" (the existing "Use {url}" string) when there is a Move, which reapplies; two new t() strings with zh, ja and de. The probe runs from Windows, not from inside WSL, so a firewall keeping WSL out isn't seen; the advice names it. TestKeptAddressNotAnswering (the reporter's case: Codex at 172.28.96.1, unreachable with the address and loopback in the detail; no drift once it answers, none with the gateway down too), TestKeptAddressProbeNeverWaitedFor, TestKeptAddressMovedWithWSL (Move from a Was address, Reapply rewrites both URLs, Check empty and no drift after; a 10.0.0.7 address is told but never moved) and TestWSLAgentAddressNotAnswering (Codex in a NAT distro told, with Share on local network, portproxy and firewall; a mirrored one never probed) fail without the Drift change and pass; TestLoopbackNotProbed, TestReachProbe (httptest: a 401 is an answer, a closed port none) and TestWSLWas pass. TestMain stubs reachProbe so no test dials out. -race -count=10 on them; go test -tags nogui ./internal/... under a temp HOME, go vet (darwin, windows), gofmt -l, linux and windows (nogui) builds pass. agent-unreachable.test.cjs (the window at 560px and the tray panel at 440px: the red line and tooltip, How to fix's dialog posting nothing, Use <address> posting the reapply, no sideways scroll) fails on main and passes on Chromium and WebKit in en, zh, ja and de; agent-connect, agent-layout, agent-field-names, aside-native, gui-de, gui-ja and i18n-keys pass on both. Not tried on a real WSL NAT setup (the Windows test box didn't answer ssh). docs/subsystems/agent-wiring.md says it.
2026-10-06 19:17:55 +08:00
agent, gateway: Cursor Private Inference's row has an effort, which magpie's gateway asks its requests for (#1003, gjf7) — other agents' rows pick a reasoning effort that magpie writes into their config, but Cursor Private Inference reads only its base URL and key from the environment, and its app offers no Reasoning control for most of magpie's models, so there was no way to set one short of a routing group with a member fixed at a level, which the reporter used as a workaround. Its row now has an effort field like the others': the default (as Cursor asks) first, then every level the models it lists have (cursorLocalEfforts: their levels in MemberEfforts order, low/medium/high where a model reasons with levels unknown, none at all when nothing it lists reasons or it isn't connected). The pick is kept in magpie, settings' agentEfforts by agent (provider.AgentEffort / SetAgentEffort, a level of MemberEfforts or "" for none), and the gateway's candidate loop asks a cursor-local request for it with withFixedEffort, fitted to the model's levels and bounded by a group's, on a model that reasons (the new Provider.Thinks: levels, its list's Reasoning, or models.dev's). Precedence: a group member's fixed effort, then a :effort suffix, then a routing rule's turn pick, then the agent's pick, then the request's own; the pick wins over a level Cursor sent, as Cursor sends its own default as often as a choice, and Default hands the choice back to Cursor. A model that doesn't reason and every other agent's requests go as they came. The Settings page's save carries agentEfforts over as it does fastPicks (TestSettingsSaveKeepsWhatItDoesNotSend's fixture names it). In the window the field sits under "Settings" rather than "New sessions" for this agent alone, as it applies to every request from then on, not to what a session starts on; no new t() strings (Settings, effort and default are translated in zh, ja and de already). TestAgentEffortOnCursorLocal (Chat and Responses with and without a level of their own, Claude on Messages made to think, OpenCode's request untouched, a non-reasoning model untouched, a member fixed at low kept, the pick taken off) fails without the gateway change and passes; TestCursorLocalEffort covers the options (none with no reasoning model, the union of levels, the low/medium/high fallback, none while disconnected), Apply and a bad level refused; both pass -race (-count=20 gateway, -count=10 agent). cursor-local-effort.test.cjs (the window at 560px and the tray panel at 440px: the field under Settings, the slider's five stops with Default first, a pick posting the field, no sideways scroll) passes on Chromium and WebKit in en, zh, ja and de; claude-effort, subagent-effort, agent-field-names, agent-connect, agent-layout, agent-tweak-fold, agent-models, cursor-local-launch and i18n pass on both. go test -tags nogui ./internal/..., go vet, gofmt -l, linux (nogui) and windows builds pass. Not tried with the real Cursor Private Inference: whether it sends a reasoning level of its own on models it shows a Reasoning control for is unverified, which the precedence makes moot. docs/subsystems/gateway-routing.md and agent-wiring.md say it.
2026-10-06 17:29:28 +08:00
agent, gateway: Cursor Private Inference's row has an effort, which magpie's gateway asks its requests for (#1003, gjf7) — other agents' rows pick a reasoning effort that magpie writes into their config, but Cursor Private Inference reads only its base URL and key from the environment, and its app offers no Reasoning control for most of magpie's models, so there was no way to set one short of a routing group with a member fixed at a level, which the reporter used as a workaround. Its row now has an effort field like the others': the default (as Cursor asks) first, then every level the models it lists have (cursorLocalEfforts: their levels in MemberEfforts order, low/medium/high where a model reasons with levels unknown, none at all when nothing it lists reasons or it isn't connected). The pick is kept in magpie, settings' agentEfforts by agent (provider.AgentEffort / SetAgentEffort, a level of MemberEfforts or "" for none), and the gateway's candidate loop asks a cursor-local request for it with withFixedEffort, fitted to the model's levels and bounded by a group's, on a model that reasons (the new Provider.Thinks: levels, its list's Reasoning, or models.dev's). Precedence: a group member's fixed effort, then a :effort suffix, then a routing rule's turn pick, then the agent's pick, then the request's own; the pick wins over a level Cursor sent, as Cursor sends its own default as often as a choice, and Default hands the choice back to Cursor. A model that doesn't reason and every other agent's requests go as they came. The Settings page's save carries agentEfforts over as it does fastPicks (TestSettingsSaveKeepsWhatItDoesNotSend's fixture names it). In the window the field sits under "Settings" rather than "New sessions" for this agent alone, as it applies to every request from then on, not to what a session starts on; no new t() strings (Settings, effort and default are translated in zh, ja and de already). TestAgentEffortOnCursorLocal (Chat and Responses with and without a level of their own, Claude on Messages made to think, OpenCode's request untouched, a non-reasoning model untouched, a member fixed at low kept, the pick taken off) fails without the gateway change and passes; TestCursorLocalEffort covers the options (none with no reasoning model, the union of levels, the low/medium/high fallback, none while disconnected), Apply and a bad level refused; both pass -race (-count=20 gateway, -count=10 agent). cursor-local-effort.test.cjs (the window at 560px and the tray panel at 440px: the field under Settings, the slider's five stops with Default first, a pick posting the field, no sideways scroll) passes on Chromium and WebKit in en, zh, ja and de; claude-effort, subagent-effort, agent-field-names, agent-connect, agent-layout, agent-tweak-fold, agent-models, cursor-local-launch and i18n pass on both. go test -tags nogui ./internal/..., go vet, gofmt -l, linux (nogui) and windows builds pass. Not tried with the real Cursor Private Inference: whether it sends a reasoning level of its own on models it shows a Reasoning control for is unverified, which the precedence makes moot. docs/subsystems/gateway-routing.md and agent-wiring.md say it.
2026-10-06 17:29:28 +08:00
…
…
dsh: the gateway key also goes into dsh's own key store, which the desktop app reads (#969, pan17: in the DeepSeek Harness desktop app every turn failed with llm-pi-ai: no credential for provider route "magpie"; its profile resolves MAGPIE_GATEWAY_KEY, which is not set — store MAGPIE_GATEWAY_KEY through the credentials service (the web Models page writes it) or export it (MISSING_CREDENTIAL), while magpie showed dsh connected) — the route was in the desktop profile (magpie writes every profile; the GUI names only the first, profiles/web, which read as "magpie wrote the npm dsh's config"), but magpie put the key only in ~/.dsh/.env. In dsh 0.2 the .env files are layers the product CLI's boot (dsh-app-boot) loads; dsh-credentials-local resolves inherited environment > $DSH_HOME/.credentials.yaml > project .env > home .env, and "a composition the product CLI did not boot has only the inherited environment as its layer". So the desktop app never saw the key. magpie now also writes refs.MAGPIE_GATEWAY_KEY into ~/.dsh/.credentials.yaml, dsh's own store, which its Models page writes and every dsh reads. Details: a new store is made owner-only, version 1 (dsh refuses a store other users can read); the user's other refs, records and comments are kept; a different key of the user's under magpie's name is left alone (the check already reports it); a store in dsh's pre-release flat layout isn't touched; going back to dsh's own models takes magpie's key out. The check now asks for Apply again when the store lacks the key; a dsh wired by an earlier magpie gets it from the catalog sync magpie runs as it starts. The output of a fresh write and a merge into a store with refs, a grant record and a comment both parse with dsh 0.2.0-rc.2's own parseCredentialsDocument. TestDshDesktopGetsTheKeyFromItsStore (web+desktop profiles as on the reporter's machine) and TestDshStoreOfTheUsersOwn fail without the change and pass; -race -count=5 on the dsh tests. Fixtures that stood for "wired" with .env alone now hold the store too. Not tried with the real desktop app (not installed here; the reporter is on Windows); they're asked to confirm. go test ./internal/agent/, go vet, darwin, linux (nogui) and windows builds pass.
2026-10-06 14:13:53 +08:00
…
gui: a model with a fast mode is sent fast, or not, from its row in the agent's picker (#954, Gyarados4157) — Fast was only a routing group member's (Group.Fast), so a GPT on a ChatGPT account picked straight in Codex or OpenCode could only go fast through a group of one. A model provider.CanFast says has a fast mode (a ChatGPT account's GPT, an OpenAI key's Responses GPT/o-series, Cursor's -fast, Claude Opus on an Anthropic key) now has a bolt beside its star in the agent's picker and in the same picker opened from a provider's row; a click posts /api/agent-fast and switches it for that agent (settings FastPicks, by agent, "<provider>/<model>", moved by a provider rename and kept by the Settings page's save) without changing the pick or closing the picker; a refusal puts it back. The field shows a bolt after a model sent fast. The gateway asks for the vendor's fast mode (service_tier "priority" / speed "fast", as for a group member) on that agent's requests for that entry, every account and key of it, not its fallbacks, another agent's requests or the same model at another provider; the Routing trace marks the try Fast. A routing group is never switched: its members say it. zh/ja/de added. fast-pick (window and 440px panel, en/zh/ja/de, Chromium and WebKit; the bolt only on models with a fast mode, the post, the refusal, the provider row's picker) passes and fails without the fix; TestFastPick (gateway, Chat/Responses/Anthropic in, fails with the gateway hunk off), TestSetFastPick, TestFastPickOptions and the settings-keep test (fails without the carry) pass with -race; i18n-keys, gui-ja, gui-de, favorite-star, agent-models-picker, claude-picker-fold and click-scroll pass; go test ./internal/gui/ ./internal/provider/ ./internal/agent/ ./internal/gateway/ ./internal/settings/ pass.
2026-10-06 11:15:52 +08:00
…
…
…
agent, gui: an agent connected by its config to an address where nothing answers is told, not shown connected (#1013, cjyrainbow: Codex Desktop's WSL environment reads Windows' ~/.codex/config.toml, whose openai_base_url and [model_providers.magpie].base_url the reporter pointed at Windows as WSL sees it, forwarded to 127.0.0.1:3425 by a portproxy of their own; after a reboot the portproxy listened no more and the Agents page still said Codex was connected) — Drift looked only at the config, which was right. Now an agent pointed at an address off loopback (this machine's Codex at an address the user kept, #816, through Agent.reach; every WSL twin under NAT, at Windows as the distro sees it, through Agent.Gateway) has that address tried from here (reach.go: GET /v1/models, any HTTP status an answer, 2 s timeout, in the background, at most every 20 s per address, never waited for), and one that doesn't answer while the gateway answers on loopback is a new drift, "unreachable", with Addr and the advice in Detail: under WSL (or on Windows) magpie with Settings › Share on local network on, or the user's netsh interface portproxy, which may need setting up again after a restart; Windows' firewall allowing the port for the WSL network; on Windows 11, networkingMode=mirrored; elsewhere, the forward to start again or gateway.URL() to point at. An answer not had yet, and a gateway down on loopback too, are no drift. The config is never changed for it, except where the address is one a WSL distro reached Windows at before (distro.Was, the last 4 kept in wsl.json as a re-probe finds Gateway changed) and the distro reaches Windows at another now: Drift's Move names that one, and Reapply moves the config there (Agent.move; Codex's codexMoveGateway rewrites openai_base_url and magpie's own provider's base_url, only where they begin with the old address). An address no distro was seen at is the user's own and is never offered a move. In the GUI the row's line says "{agent} is set up, but nothing answers at the address it reaches magpie by" in red with the advice as its tooltip, and its pill is "How to fix" (an i, not the reapply arrow), which opens the advice in a dialog (too long for the status line; it wraps and can be copied) and sets nothing — or "Use <address>" (the existing "Use {url}" string) when there is a Move, which reapplies; two new t() strings with zh, ja and de. The probe runs from Windows, not from inside WSL, so a firewall keeping WSL out isn't seen; the advice names it. TestKeptAddressNotAnswering (the reporter's case: Codex at 172.28.96.1, unreachable with the address and loopback in the detail; no drift once it answers, none with the gateway down too), TestKeptAddressProbeNeverWaitedFor, TestKeptAddressMovedWithWSL (Move from a Was address, Reapply rewrites both URLs, Check empty and no drift after; a 10.0.0.7 address is told but never moved) and TestWSLAgentAddressNotAnswering (Codex in a NAT distro told, with Share on local network, portproxy and firewall; a mirrored one never probed) fail without the Drift change and pass; TestLoopbackNotProbed, TestReachProbe (httptest: a 401 is an answer, a closed port none) and TestWSLWas pass. TestMain stubs reachProbe so no test dials out. -race -count=10 on them; go test -tags nogui ./internal/... under a temp HOME, go vet (darwin, windows), gofmt -l, linux and windows (nogui) builds pass. agent-unreachable.test.cjs (the window at 560px and the tray panel at 440px: the red line and tooltip, How to fix's dialog posting nothing, Use <address> posting the reapply, no sideways scroll) fails on main and passes on Chromium and WebKit in en, zh, ja and de; agent-connect, agent-layout, agent-field-names, aside-native, gui-de, gui-ja and i18n-keys pass on both. Not tried on a real WSL NAT setup (the Windows test box didn't answer ssh). docs/subsystems/agent-wiring.md says it.
2026-10-06 19:17:55 +08:00
…
…
…
…
…
…
agent, gui: an agent connected by its config to an address where nothing answers is told, not shown connected (#1013, cjyrainbow: Codex Desktop's WSL environment reads Windows' ~/.codex/config.toml, whose openai_base_url and [model_providers.magpie].base_url the reporter pointed at Windows as WSL sees it, forwarded to 127.0.0.1:3425 by a portproxy of their own; after a reboot the portproxy listened no more and the Agents page still said Codex was connected) — Drift looked only at the config, which was right. Now an agent pointed at an address off loopback (this machine's Codex at an address the user kept, #816, through Agent.reach; every WSL twin under NAT, at Windows as the distro sees it, through Agent.Gateway) has that address tried from here (reach.go: GET /v1/models, any HTTP status an answer, 2 s timeout, in the background, at most every 20 s per address, never waited for), and one that doesn't answer while the gateway answers on loopback is a new drift, "unreachable", with Addr and the advice in Detail: under WSL (or on Windows) magpie with Settings › Share on local network on, or the user's netsh interface portproxy, which may need setting up again after a restart; Windows' firewall allowing the port for the WSL network; on Windows 11, networkingMode=mirrored; elsewhere, the forward to start again or gateway.URL() to point at. An answer not had yet, and a gateway down on loopback too, are no drift. The config is never changed for it, except where the address is one a WSL distro reached Windows at before (distro.Was, the last 4 kept in wsl.json as a re-probe finds Gateway changed) and the distro reaches Windows at another now: Drift's Move names that one, and Reapply moves the config there (Agent.move; Codex's codexMoveGateway rewrites openai_base_url and magpie's own provider's base_url, only where they begin with the old address). An address no distro was seen at is the user's own and is never offered a move. In the GUI the row's line says "{agent} is set up, but nothing answers at the address it reaches magpie by" in red with the advice as its tooltip, and its pill is "How to fix" (an i, not the reapply arrow), which opens the advice in a dialog (too long for the status line; it wraps and can be copied) and sets nothing — or "Use <address>" (the existing "Use {url}" string) when there is a Move, which reapplies; two new t() strings with zh, ja and de. The probe runs from Windows, not from inside WSL, so a firewall keeping WSL out isn't seen; the advice names it. TestKeptAddressNotAnswering (the reporter's case: Codex at 172.28.96.1, unreachable with the address and loopback in the detail; no drift once it answers, none with the gateway down too), TestKeptAddressProbeNeverWaitedFor, TestKeptAddressMovedWithWSL (Move from a Was address, Reapply rewrites both URLs, Check empty and no drift after; a 10.0.0.7 address is told but never moved) and TestWSLAgentAddressNotAnswering (Codex in a NAT distro told, with Share on local network, portproxy and firewall; a mirrored one never probed) fail without the Drift change and pass; TestLoopbackNotProbed, TestReachProbe (httptest: a 401 is an answer, a closed port none) and TestWSLWas pass. TestMain stubs reachProbe so no test dials out. -race -count=10 on them; go test -tags nogui ./internal/... under a temp HOME, go vet (darwin, windows), gofmt -l, linux and windows (nogui) builds pass. agent-unreachable.test.cjs (the window at 560px and the tray panel at 440px: the red line and tooltip, How to fix's dialog posting nothing, Use <address> posting the reapply, no sideways scroll) fails on main and passes on Chromium and WebKit in en, zh, ja and de; agent-connect, agent-layout, agent-field-names, aside-native, gui-de, gui-ja and i18n-keys pass on both. Not tried on a real WSL NAT setup (the Windows test box didn't answer ssh). docs/subsystems/agent-wiring.md says it.
2026-10-06 19:17:55 +08:00
agent, gui: an agent connected by its config to an address where nothing answers is told, not shown connected (#1013, cjyrainbow: Codex Desktop's WSL environment reads Windows' ~/.codex/config.toml, whose openai_base_url and [model_providers.magpie].base_url the reporter pointed at Windows as WSL sees it, forwarded to 127.0.0.1:3425 by a portproxy of their own; after a reboot the portproxy listened no more and the Agents page still said Codex was connected) — Drift looked only at the config, which was right. Now an agent pointed at an address off loopback (this machine's Codex at an address the user kept, #816, through Agent.reach; every WSL twin under NAT, at Windows as the distro sees it, through Agent.Gateway) has that address tried from here (reach.go: GET /v1/models, any HTTP status an answer, 2 s timeout, in the background, at most every 20 s per address, never waited for), and one that doesn't answer while the gateway answers on loopback is a new drift, "unreachable", with Addr and the advice in Detail: under WSL (or on Windows) magpie with Settings › Share on local network on, or the user's netsh interface portproxy, which may need setting up again after a restart; Windows' firewall allowing the port for the WSL network; on Windows 11, networkingMode=mirrored; elsewhere, the forward to start again or gateway.URL() to point at. An answer not had yet, and a gateway down on loopback too, are no drift. The config is never changed for it, except where the address is one a WSL distro reached Windows at before (distro.Was, the last 4 kept in wsl.json as a re-probe finds Gateway changed) and the distro reaches Windows at another now: Drift's Move names that one, and Reapply moves the config there (Agent.move; Codex's codexMoveGateway rewrites openai_base_url and magpie's own provider's base_url, only where they begin with the old address). An address no distro was seen at is the user's own and is never offered a move. In the GUI the row's line says "{agent} is set up, but nothing answers at the address it reaches magpie by" in red with the advice as its tooltip, and its pill is "How to fix" (an i, not the reapply arrow), which opens the advice in a dialog (too long for the status line; it wraps and can be copied) and sets nothing — or "Use <address>" (the existing "Use {url}" string) when there is a Move, which reapplies; two new t() strings with zh, ja and de. The probe runs from Windows, not from inside WSL, so a firewall keeping WSL out isn't seen; the advice names it. TestKeptAddressNotAnswering (the reporter's case: Codex at 172.28.96.1, unreachable with the address and loopback in the detail; no drift once it answers, none with the gateway down too), TestKeptAddressProbeNeverWaitedFor, TestKeptAddressMovedWithWSL (Move from a Was address, Reapply rewrites both URLs, Check empty and no drift after; a 10.0.0.7 address is told but never moved) and TestWSLAgentAddressNotAnswering (Codex in a NAT distro told, with Share on local network, portproxy and firewall; a mirrored one never probed) fail without the Drift change and pass; TestLoopbackNotProbed, TestReachProbe (httptest: a 401 is an answer, a closed port none) and TestWSLWas pass. TestMain stubs reachProbe so no test dials out. -race -count=10 on them; go test -tags nogui ./internal/... under a temp HOME, go vet (darwin, windows), gofmt -l, linux and windows (nogui) builds pass. agent-unreachable.test.cjs (the window at 560px and the tray panel at 440px: the red line and tooltip, How to fix's dialog posting nothing, Use <address> posting the reapply, no sideways scroll) fails on main and passes on Chromium and WebKit in en, zh, ja and de; agent-connect, agent-layout, agent-field-names, aside-native, gui-de, gui-ja and i18n-keys pass on both. Not tried on a real WSL NAT setup (the Windows test box didn't answer ssh). docs/subsystems/agent-wiring.md says it.
2026-10-06 19:17:55 +08:00
…
wsl: background work never touches a WSL distro that has stopped since it was last seen running — it booted it again (TJHHHH on Discord: while they were repairing WSL, magpie kept starting it). Detection already listed only running distros, but the running set was kept for a minute (wslListAge), agents built while a distro ran kept its home and read its files from their Get/Sync/Check/Reached/Routed closures later, the sessions listing kept a distro's Running for 30s+ and read its \\wsl.localhost files, and wslrun.Find reused a tool it had found in a distro for a minute and ran wsl.exe -d on it. Any wsl.exe -d or \\wsl.localhost read boots a stopped distro, so a wsl --shutdown was undone within a minute, and the distro, running again, kept it going. Now wsl.exe -l --running -q (it starts nothing; UTF-16 with or without BOM, or UTF-8 under WSL_UTF8) is asked again after 3s, and a distro not in it is not touched: a WSL agent's Get gives the last values seen, Sync/Check/Reached do nothing and Routed/Joined/Beside/Added say no; sessions aren't listed or read from it (wslCold says cold); wslrun.Find (Claude subscription sign-in and usage) doesn't reuse or run a tool there; the Library gives skills to no target in it and its MCP probe says it isn't running. An explicit action still starts it: setting a WSL agent's field, a Set on a running agent, resuming a WSL session. TestWSLStoppedSinceNotOpened (agent, sessions), TestWSLStoppedSinceNoTarget (library) and TestFindStoppedSince (wslrun) fail without the change and pass; TestUp covers the -l --running parse. On the Windows box (10.0.0.132) a test binary that had seen magpie-fedora running ran Values/Check/Reached/wslDistros/wslAgents/sessions.List/wslrun.Find against it for 4 rounds while it was stopped: it stayed Stopped and wsl -l -v was unchanged; wslrun and agent WSL tests pass there. No distro was terminated for the check (magpie-desktop is in use, the stopped ones aren't ours). go test ./... (nogui), -race on the WSL tests, go vet, windows and linux (nogui) builds pass.
2026-10-06 14:25:41 +08:00
…
gui: a model with a fast mode is sent fast, or not, from its row in the agent's picker (#954, Gyarados4157) — Fast was only a routing group member's (Group.Fast), so a GPT on a ChatGPT account picked straight in Codex or OpenCode could only go fast through a group of one. A model provider.CanFast says has a fast mode (a ChatGPT account's GPT, an OpenAI key's Responses GPT/o-series, Cursor's -fast, Claude Opus on an Anthropic key) now has a bolt beside its star in the agent's picker and in the same picker opened from a provider's row; a click posts /api/agent-fast and switches it for that agent (settings FastPicks, by agent, "<provider>/<model>", moved by a provider rename and kept by the Settings page's save) without changing the pick or closing the picker; a refusal puts it back. The field shows a bolt after a model sent fast. The gateway asks for the vendor's fast mode (service_tier "priority" / speed "fast", as for a group member) on that agent's requests for that entry, every account and key of it, not its fallbacks, another agent's requests or the same model at another provider; the Routing trace marks the try Fast. A routing group is never switched: its members say it. zh/ja/de added. fast-pick (window and 440px panel, en/zh/ja/de, Chromium and WebKit; the bolt only on models with a fast mode, the post, the refusal, the provider row's picker) passes and fails without the fix; TestFastPick (gateway, Chat/Responses/Anthropic in, fails with the gateway hunk off), TestSetFastPick, TestFastPickOptions and the settings-keep test (fails without the carry) pass with -race; i18n-keys, gui-ja, gui-de, favorite-star, agent-models-picker, claude-picker-fold and click-scroll pass; go test ./internal/gui/ ./internal/provider/ ./internal/agent/ ./internal/gateway/ ./internal/settings/ pass.
2026-10-06 11:15:52 +08:00
…
…
agent: VSCodium's magpie group is written for the provider its installed Copilot Chat declares, OpenAI Compatible (customoai) on the Marketplace's 0.48.1 (#1014, xybio: VSCodium's Chat picker showed only Auto) — VSCodium has no Copilot Chat of its own, and the last Marketplace Copilot Chat it can install, 0.48.1, declares no Custom Endpoint provider (its contributes.languageModelChatProviders: copilot, copilotcli, claude-code, anthropic, xai, gemini, openrouter, openai, ollama, customoai, azure), so the customendpoint group magpie wrote in chatLanguageModels.json was never read. magpie now reads the package.json of the github.copilot-chat installed under ~/.vscode-oss/extensions (vscodeChatOf: the one extensions.json lists, else the highest github.copilot-chat-<version> folder not in .obsolete) and writes customendpoint when it is declared, customoai when only that is: each model's window as maxInputTokens beside maxOutputTokens (0.48.1 adds them up), and the token as x-api-key, since 0.48.1 drops an Authorization in requestHeaders and its apiKey has to be a ${input:} secret; the gateway already takes a key from x-api-key, past an empty Authorization, so Usage still counts VSCodium. No extension found, or a package.json that can't be read, keeps customendpoint as before; one declaring neither is said in Notice and Check. Writing the group removes magpie's group for the other provider in the default's and each profile's file, and Disconnect removes both; the user's own groups, under either provider, stay. Sync (at magpie's start and on catalog changes) rewrites a group written for the other provider, and Check reports it until then. VS Code and Insiders, whose chat is built in, keep customendpoint unchanged. The Notice says 0.48.1 registers its providers only while signed in to GitHub with a personal Copilot plan (its BYOK registration is gated on the Copilot token's individual/BYOK flag). TestVSCodiumCopilotChatOpenAICompatible (the real 0.48.1 provider list installed in a temp ~/.vscode-oss: Connect writes customoai with x-api-key magpie-vscodium and no Authorization or contextWindow, the user's groups kept, Check empty; a Custom Endpoint group an older magpie wrote is flagged and rewritten by Sync; a Copilot Chat declaring customendpoint switches it back; one declaring neither is reported; Disconnect removes both) and TestVSCodeChatInstalledWithoutExtensionsJSON (folder scan, .obsolete, unreadable package.json) fail on main, which writes customendpoint, and pass; -race -count=10 on the VS Code tests, go test -tags nogui ./internal/..., go vet, gofmt -l, linux and windows (nogui) builds pass. No GUI change. Not tried with a real VSCodium. docs/subsystems/agent-wiring.md and docs/reference.md say it.
2026-10-06 19:09:26 +08:00
agent: VSCodium's magpie group is written for the provider its installed Copilot Chat declares, OpenAI Compatible (customoai) on the Marketplace's 0.48.1 (#1014, xybio: VSCodium's Chat picker showed only Auto) — VSCodium has no Copilot Chat of its own, and the last Marketplace Copilot Chat it can install, 0.48.1, declares no Custom Endpoint provider (its contributes.languageModelChatProviders: copilot, copilotcli, claude-code, anthropic, xai, gemini, openrouter, openai, ollama, customoai, azure), so the customendpoint group magpie wrote in chatLanguageModels.json was never read. magpie now reads the package.json of the github.copilot-chat installed under ~/.vscode-oss/extensions (vscodeChatOf: the one extensions.json lists, else the highest github.copilot-chat-<version> folder not in .obsolete) and writes customendpoint when it is declared, customoai when only that is: each model's window as maxInputTokens beside maxOutputTokens (0.48.1 adds them up), and the token as x-api-key, since 0.48.1 drops an Authorization in requestHeaders and its apiKey has to be a ${input:} secret; the gateway already takes a key from x-api-key, past an empty Authorization, so Usage still counts VSCodium. No extension found, or a package.json that can't be read, keeps customendpoint as before; one declaring neither is said in Notice and Check. Writing the group removes magpie's group for the other provider in the default's and each profile's file, and Disconnect removes both; the user's own groups, under either provider, stay. Sync (at magpie's start and on catalog changes) rewrites a group written for the other provider, and Check reports it until then. VS Code and Insiders, whose chat is built in, keep customendpoint unchanged. The Notice says 0.48.1 registers its providers only while signed in to GitHub with a personal Copilot plan (its BYOK registration is gated on the Copilot token's individual/BYOK flag). TestVSCodiumCopilotChatOpenAICompatible (the real 0.48.1 provider list installed in a temp ~/.vscode-oss: Connect writes customoai with x-api-key magpie-vscodium and no Authorization or contextWindow, the user's groups kept, Check empty; a Custom Endpoint group an older magpie wrote is flagged and rewritten by Sync; a Copilot Chat declaring customendpoint switches it back; one declaring neither is reported; Disconnect removes both) and TestVSCodeChatInstalledWithoutExtensionsJSON (folder scan, .obsolete, unreadable package.json) fail on main, which writes customendpoint, and pass; -race -count=10 on the VS Code tests, go test -tags nogui ./internal/..., go vet, gofmt -l, linux and windows (nogui) builds pass. No GUI change. Not tried with a real VSCodium. docs/subsystems/agent-wiring.md and docs/reference.md say it.
2026-10-06 19:09:26 +08:00
agent: CodeBuddy Code (Tencent's CLI, codebuddy/cbc, the China edition too) is an agent that uses magpie's models (#980, yujianbinm) — the CLI (npm @tencent-ai/codebuddy-code 2.161.4, one package for codebuddy.ai and codebuddy.cn, CODEBUDDY_INTERNET_ENVIRONMENT=internal) takes models of one's own from ~/.codebuddy/models.json ($CODEBUDDY_CONFIG_DIR), the format WorkBuddy reads, hot-reloaded, and starts a session on settings.json's "model". magpie now writes its models there as WorkBuddy's are written (vendor magpie, key magpie-codebuddy, url the gateway's /v1/chat/completions), keeping the user's own entries, their order, a model turned off and availableModels (magpie's ids added when the list is there), and sets "model" to the pick, the user's other settings kept; one of CodeBuddy's own models, or default, takes magpie's models out again. A new models.json is {"models":[…]} as CodeBuddy's docs give it. workbuddyWrite becomes buddyWrite(agent), the same writer for both. CODEBUDDY_CONFIG_DIR joins agentenv.Vars; cliupdate knows the npm package. TestCodeBuddyCode (user's model, availableModels and settings kept; magpie pick; sync; back to own; default) and TestCodeBuddyCodeNewFile fail without the agent ("no codebuddy agent") and pass; -race -count=5 on the CodeBuddy/WorkBuddy tests. End to end, the real CLI 2.161.4 under a temp HOME with CODEBUDDY_INTERNET_ENVIRONMENT=internal and no CodeBuddy sign-in: magpie codebuddy magpie/mock/pro against a sandbox gateway on 3462, then codebuddy -p with no --model, answered through the gateway from a mock upstream, and magpie's usage counted it under CodeBuddy Code (the CLI sends "CLI/2.161.4 CodeBuddy/2.161.4", so it is told by its key); magpie codebuddy default took it out. A bare-list models.json is read by the CLI too. Not tried with a real CodeBuddy account or a real model vendor. go test ./internal/agent/ ./internal/agentenv/ ./internal/usage/ ., go vet, darwin, linux (nogui) and windows builds pass.
2026-10-06 15:32:23 +08:00
wsl: background work never touches a WSL distro that has stopped since it was last seen running — it booted it again (TJHHHH on Discord: while they were repairing WSL, magpie kept starting it). Detection already listed only running distros, but the running set was kept for a minute (wslListAge), agents built while a distro ran kept its home and read its files from their Get/Sync/Check/Reached/Routed closures later, the sessions listing kept a distro's Running for 30s+ and read its \\wsl.localhost files, and wslrun.Find reused a tool it had found in a distro for a minute and ran wsl.exe -d on it. Any wsl.exe -d or \\wsl.localhost read boots a stopped distro, so a wsl --shutdown was undone within a minute, and the distro, running again, kept it going. Now wsl.exe -l --running -q (it starts nothing; UTF-16 with or without BOM, or UTF-8 under WSL_UTF8) is asked again after 3s, and a distro not in it is not touched: a WSL agent's Get gives the last values seen, Sync/Check/Reached do nothing and Routed/Joined/Beside/Added say no; sessions aren't listed or read from it (wslCold says cold); wslrun.Find (Claude subscription sign-in and usage) doesn't reuse or run a tool there; the Library gives skills to no target in it and its MCP probe says it isn't running. An explicit action still starts it: setting a WSL agent's field, a Set on a running agent, resuming a WSL session. TestWSLStoppedSinceNotOpened (agent, sessions), TestWSLStoppedSinceNoTarget (library) and TestFindStoppedSince (wslrun) fail without the change and pass; TestUp covers the -l --running parse. On the Windows box (10.0.0.132) a test binary that had seen magpie-fedora running ran Values/Check/Reached/wslDistros/wslAgents/sessions.List/wslrun.Find against it for 4 rounds while it was stopped: it stayed Stopped and wsl -l -v was unchanged; wslrun and agent WSL tests pass there. No distro was terminated for the check (magpie-desktop is in use, the stopped ones aren't ours). go test ./... (nogui), -race on the WSL tests, go vet, windows and linux (nogui) builds pass.
2026-10-06 14:25:41 +08:00
wsl: background work never touches a WSL distro that has stopped since it was last seen running — it booted it again (TJHHHH on Discord: while they were repairing WSL, magpie kept starting it). Detection already listed only running distros, but the running set was kept for a minute (wslListAge), agents built while a distro ran kept its home and read its files from their Get/Sync/Check/Reached/Routed closures later, the sessions listing kept a distro's Running for 30s+ and read its \\wsl.localhost files, and wslrun.Find reused a tool it had found in a distro for a minute and ran wsl.exe -d on it. Any wsl.exe -d or \\wsl.localhost read boots a stopped distro, so a wsl --shutdown was undone within a minute, and the distro, running again, kept it going. Now wsl.exe -l --running -q (it starts nothing; UTF-16 with or without BOM, or UTF-8 under WSL_UTF8) is asked again after 3s, and a distro not in it is not touched: a WSL agent's Get gives the last values seen, Sync/Check/Reached do nothing and Routed/Joined/Beside/Added say no; sessions aren't listed or read from it (wslCold says cold); wslrun.Find (Claude subscription sign-in and usage) doesn't reuse or run a tool there; the Library gives skills to no target in it and its MCP probe says it isn't running. An explicit action still starts it: setting a WSL agent's field, a Set on a running agent, resuming a WSL session. TestWSLStoppedSinceNotOpened (agent, sessions), TestWSLStoppedSinceNoTarget (library) and TestFindStoppedSince (wslrun) fail without the change and pass; TestUp covers the -l --running parse. On the Windows box (10.0.0.132) a test binary that had seen magpie-fedora running ran Values/Check/Reached/wslDistros/wslAgents/sessions.List/wslrun.Find against it for 4 rounds while it was stopped: it stayed Stopped and wsl -l -v was unchanged; wslrun and agent WSL tests pass there. No distro was terminated for the check (magpie-desktop is in use, the stopped ones aren't ours). go test ./... (nogui), -race on the WSL tests, go vet, windows and linux (nogui) builds pass.
2026-10-06 14:25:41 +08:00
wsl: background work never touches a WSL distro that has stopped since it was last seen running — it booted it again (TJHHHH on Discord: while they were repairing WSL, magpie kept starting it). Detection already listed only running distros, but the running set was kept for a minute (wslListAge), agents built while a distro ran kept its home and read its files from their Get/Sync/Check/Reached/Routed closures later, the sessions listing kept a distro's Running for 30s+ and read its \\wsl.localhost files, and wslrun.Find reused a tool it had found in a distro for a minute and ran wsl.exe -d on it. Any wsl.exe -d or \\wsl.localhost read boots a stopped distro, so a wsl --shutdown was undone within a minute, and the distro, running again, kept it going. Now wsl.exe -l --running -q (it starts nothing; UTF-16 with or without BOM, or UTF-8 under WSL_UTF8) is asked again after 3s, and a distro not in it is not touched: a WSL agent's Get gives the last values seen, Sync/Check/Reached do nothing and Routed/Joined/Beside/Added say no; sessions aren't listed or read from it (wslCold says cold); wslrun.Find (Claude subscription sign-in and usage) doesn't reuse or run a tool there; the Library gives skills to no target in it and its MCP probe says it isn't running. An explicit action still starts it: setting a WSL agent's field, a Set on a running agent, resuming a WSL session. TestWSLStoppedSinceNotOpened (agent, sessions), TestWSLStoppedSinceNoTarget (library) and TestFindStoppedSince (wslrun) fail without the change and pass; TestUp covers the -l --running parse. On the Windows box (10.0.0.132) a test binary that had seen magpie-fedora running ran Values/Check/Reached/wslDistros/wslAgents/sessions.List/wslrun.Find against it for 4 rounds while it was stopped: it stayed Stopped and wsl -l -v was unchanged; wslrun and agent WSL tests pass there. No distro was terminated for the check (magpie-desktop is in use, the stopped ones aren't ours). go test ./... (nogui), -race on the WSL tests, go vet, windows and linux (nogui) builds pass.
2026-10-06 14:25:41 +08:00