Files
magpie/internal/agent
yetone 54c3cb06fc agent: the default thinking effort set on one of magpie's models in WorkBuddy stays through a sync, as it does in CodeBuddy Code, ZCode, Kimi Code and MiniMax Code (悠悠哥 on Discord: 供应商能设置模型默认的思考强度吗,我的workbuddy每次手动设置了思考强度,还是会被更新覆盖掉)
WorkBuddy's Settings > Models saves an edited custom model whole into
~/.workbuddy/models.json: reasoning.defaultEffort (absent for its Auto), and
the vendor of the provider it matches, which for magpie's entries is the
"Custom" provider's (WorkBuddy 5.x app.asar: inferProviderIdFromLocalCustomModel,
the form's save in ui-docs-viewer). buddyWrite knew its entries by vendor
"magpie" only, so a sync kept the edited entry as the user's and added
magpie's own with the same id and magpie's default effort; one set by hand
under vendor magpie was simply rewritten.

buddyWrite (WorkBuddy and CodeBuddy Code) now also knows magpie's entries by
their key (magpie-<agent>, or a NAS magpie's key already on its entries),
and keeps each model's defaultEffort (or the older reasoning.effort) while
the model still offers that level; WorkBuddy's Auto stays Auto. A new model
gets magpie's default; a model magpie no longer has is taken out, the edited
one included. The same rule (keptEffort) keeps a hand-set default in ZCode's
config.json (defaultVariant), Kimi Code's config.toml (default_effort) and
MiniMax Code's config.yaml (thinking.defaultEffort), which a sync rewrote too.
The composer's own effort pick is WorkBuddy's localStorage
(cb-effort:by-model), which magpie never touched.

Verified: kept_effort_test.go (TestWorkBuddy/CodeBuddy/ZCode/Kimi/MiniMax
KeepsTheUsersDefault*) fail on the old writers, WorkBuddy's with
"think/wide twice" and the rest with magpie's default back; pass with this,
-race -count=3. go test -tags nogui ./... green under a temp HOME; go vet,
GOOS=linux and GOOS=windows builds. Not tried in the real WorkBuddy app: the
fixture follows its save code, not a file it wrote.
2026-10-07 01:44:03 +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
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
agent: JetBrains Air reaches magpie's models through a Magpie ACP agent (OnurBen on Discord: Air's model picker should list magpie and its routing groups, as AI Assistant's OpenAI-compatible provider does) — Air's own agents (Claude Agent, Codex, Gemini CLI, Junie) run on the accounts under Settings | Account | AI Providers, a sign-in or an API key with no base URL to point at magpie (AIR-4541 asks for one); what Air does take is any Agent Client Protocol agent listed in acp.json in its config folder (~/Library/Application Support/JetBrains/Air, $XDG_CONFIG_HOME/JetBrains/Air, %APPDATA%\JetBrains\Air) under agent_servers, and the models an agent reports at session/new are its model menu. The new air agent's model field adds one there, Magpie: OpenCode's ACP server (opencode acp, by its full path when found on PATH or in ~/.opencode/bin, as Air may not have the shell's PATH) with OPENCODE_CONFIG naming magpie-opencode.json beside acp.json, which holds magpie's provider, the model picked as the one a task starts on (and small_model) and enabled_providers [magpie], so the menu lists magpie's models and routing groups only; the user's own acp.json agents are kept, and disconnecting takes out that entry and that file. Sync keeps the provider's models current, Check reports the entry taken out by hand (set again puts it back) or the wiring changed, the notice says to pick Magpie in a new Air task, or to install OpenCode first when there is none; a model that isn't magpie's is refused, as Air's own agents are picked in Air. Icon: Air's wordmark from jetbrains.com; zh strings for the notices; README row. Checked with OpenCode 2.0.20's opencode acp under a sandbox HOME, as Air would start it: session/new's model option lists magpie/group/gpt-6-luna and magpie/openai/gpt-6.1-sol only, current the configured one (OPENCODE_CONFIG, OPENCODE_CONFIG_DIR, OPENCODE_CONFIG_CONTENT and the global config all do). Known gap, OpenCode's: with a provider's key set in the environment it starts with (OPENAI_API_KEY, ANTHROPIC_API_KEY, DEEPSEEK_API_KEY, even a dummy one), 2.0.20's ACP server lists that provider and none of its config's providers, model or enabled_providers, from any config file, project one included; an empty key or a credential in its auth.json doesn't. Not tried in Air itself. TestAirAddsMagpieAgent, TestAirWithoutOpenCode, TestAirCheckAndSync; go vet, builds (darwin nogui, GOOS=windows, GOOS=linux nogui) and go test -tags nogui -count=1 ./internal/agent/ ./internal/gui/ under a temp HOME pass.
2026-10-04 09:02:44 +08:00
agent: Alma is told which of magpie's models reason, so it offers thinking for every Codex model (#730, Magixyne: Alma's magpie provider listed codex/gpt-5.5, gpt-5.6-luna/-sol/-terra and gpt-6-astra with vision and tools only, no reasoning, and no thinking to pick) — magpie put its catalog into Alma with PUT /api/providers/:id/models as ids and names alone, and Alma (0.4.155, checked read-only in its app.asar out/main/index.js) works a model's capabilities out by its id: a models.dev entry (provider:id or bare id), a fuzzy one by substring only at chat time, then heuristics (a gpt-5 id gets vision); magpie's ids (codex/gpt-5.5) aren't models.dev's, so a Codex model came out reasoning false, and its getModels/getProviderModels add reasoningLevels only to a model that reasons. A model whose id models.dev happens to hold (openrouter-style ids) did reason, hence "部分模型". Alma's PUT keeps each availableModels entry's capabilityOverrides as sent (the ones it had when none are), and Lf lays them over what it worked out, in the provider list, the model picker and the chat request (Lt/Mt read capabilityOverrides.reasoning and reasoningLevels). almaModels now sends each model's capabilityOverrides (almaCaps): reasoning true for a model that thinks (Reasoning or levels), reasoningLevels as those of its levels Alma knows (low, medium, high, xhigh, max, Alma's own list for a provider's /models, in its order; none sent for a model with a thinking switch alone), vision when magpie takes its images, contextWindow and maxOutputTokens (maxTokens) when known; a model magpie knows nothing of gets none, so Alma keeps its own. An override the user set in Alma that magpie says nothing of (functionCalling, pricing) is sent back with magpie's laid over it (almaWithOverrides), and almaSameModels also compares magpie's keys, so a provider an older magpie filled is told on the next Sync and one already told isn't written again. The fake Alma in alma_test.go keeps overrides as Alma's handler does. TestAlmaToldReasoning (a gpt-5.5 with xhigh, minimal, low, medium, high, ultra → low, medium, high, xhigh; a switch-only thinker → reasoning alone; glm-4.6 → no reasoning, its window; nothing written when told; an older magpie's provider told again with the user's functionCalling and pricing kept) fails on the old code (gpt-5.5: null) and passes. go vet ./internal/..., go build -tags nogui ./..., GOOS=windows and GOOS=linux builds and go test -tags nogui ./internal/agent/ (its TestMain sandboxes HOME) pass; the full go test under a temp HOME was not run here (the sandbox refused the HOME override). Not tried in the reporter's Alma: magpie writes the overrides on its next sync of Alma's provider, and Alma shows them when its provider page is opened again.
2026-10-04 08:13:58 +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: an agent's own provider named as one of magpie's isn't magpie's, in every agent that spells a model provider/model (the rest of #835) — OpenHanako's own deepseek/deepseek-v4-pro read as magpie's deepseek, and so did a model of any agent's own provider whose name magpie has a provider by: Pi's, Crush's, Hermes's, OpenCode's relay/glm-4.6 with magpie's relay had the row connected on the agent's own model, and Disconnect from magpie put that model back and left the row connected. An agent says how magpie's values are spelled in it (Spelled, replacing #835's Prefixed): magpie/<ref> for Antigravity CLI, Pi, OmO, Aside, Goose, Zed, VS Code, Crush, DeepSeek Harness, Command Code, fx, omp, Hermes, Mister Morph, Kimi Code, Empryo, MiniMax Code, Droid, Qoder, Qoder CN, Grok Build, AtomCode, Cline and OpenHanako, whose every Get spells magpie's so (a sandbox Set of magpie/relay/glm-4.6 read back as that in each); for OpenCode, MiMo Code and OpenChamber also a provider of the config's own that sends to magpie's gateway, as openCodeRef names a model there. A stopped WSL distro's agent keeps its live one's. Left as they are: Claude Code, Claude Desktop, Codex, Gemini CLI, Cursor, Copilot, Devin (magpie's are bare refs there), Muse Code (a model with / is magpie's by design: Meta's have none), Alma (its own are providerId:model), Air (magpie's only). TestOwnProviderNamedAsMagpies (26 agents: own relay/glm-4.6 not connected, Connect, Disconnect puts it back and the row is off) fails on the old code in each; TestOpenCodeGatewayProviderIsMagpies. go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass.
2026-10-05 06:49:45 +08:00
library: an agent whose folder is a file isn't written, and skills reach 13 more agents with one link in ~/.agents/skills for those that share it (neiko on Discord: with DeepSeek Harness not installed the Library kept failing on "open ~/.dsh/AGENTS.md: not a directory" and ~/.dsh/config.yaml; inaction: the skills list is short of the Agents page, Kimi Code has none). An agent counted as there when its folder path existed or its command was on PATH, never asking whether the path was a folder — a file at ~/.dsh, or another dsh, made DeepSeek Harness look installed. Now an agent whose folder is a file (or under one) isn't detected (agent.Taken; Goose's, Cindy's and Claude Desktop's own checks want a folder too), a Library target leaves out each place a file stands in the way of, one with none left isn't listed, and an agent given no MCP server with none of magpie's isn't read. Skills: Kimi Code, Goose and Cindy get ~/.agents/skills (Kimi's ~/.config/agents/skills when there, as Kimi reads it first; never ~/.kimi/skills, which would hide Claude Code's from it); Command Code, Devin, Hermes, Droid, Cline, Qoder, Qoder CN, Grok, WorkBuddy, Hanako and fx their own skills folder; Kimi, Goose and Grok a project's .agents/skills. The shared folder is filled first, and an agent that reads ~/.agents/skills besides its own (Codex, Gemini CLI, OpenCode, Crush, DeepSeek Harness and those above) gets no second link to a skill already there. Tested with new taken_test.go (neiko's two errors without the change) and agent_skills_test.go (skills folders, written once, a shared skill imported for Kimi), in sandbox HOMEs; library-items and shared-skills 24/24 in Chromium and WebKit; go vet, go build (-tags nogui, GOOS=linux, GOOS=windows), go test -tags nogui ./... pass. Not tried with real Kimi Code, Goose or Cindy.
2026-09-30 14:40:41 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
agent, gui: Claude Code taken off magpie by Default goes under Not set up and says Default (EZN7L2C3, #834 on v0.1.920) — picking Default and confirming Use default left the row up among the connected ones while it said Not connected, its model read Pick a model and its list had magpie's models alone. Default takes Claude Code's tiers and subagent model out with magpie's endpoint; Apply recorded only the field picked, so those read as changed outside magpie (replaced drift) and the drift kept the row up. Apply now records every field magpie set before that the change moves too. An agent not connected whose list has models of its own (Claude Code's, asked of Anthropic directly) now says what it is on, its Default or its own model, and lists everything as when connected: Default, its own models, magpie's. TestClaudeDefaultLeavesNoDrift (fails on the old code: drift replaced opus; a tier changed outside magpie is still said to be); claude-default-off.test.cjs (WebKit, en and zh: folded under Not set up, switch off, Default shown, Default current with the direct and via-magpie models listed, no scroll; fails on the old code: Pick a model / 选模型). agent-path-same, agent-leave-magpie, claude-picker-fold, claude-direct, agent-start-pick, model-rate, unlisted-models, agent-connect, agent-field-names, pi-default-note, click-scroll, desktop-model-menu, model-pick, favorite-star, agent-disconnect, agent-layout, gui-ja and gui-de pass on WebKit. go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass.
2026-10-05 06:40:46 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
2026-10-04 20:33:12 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +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: 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
codex: on magpie API, Codex's own model as the default keeps magpie as its provider and magpie's models in its picker (#701, nullburn: Codex 选回原生默认模型后,第三方模型目录消失(已选择 magpie API)) — with Codex's sign-in set to magpie API, picking one of Codex's own models (gpt-6-luna) as its default in the Agents row ran unroute(): model_provider, model_catalog_json, openai_base_url and magpie-models.json all went, so every third-party model left Codex's picker while the row still said magpie API; and choosing magpie API while on Codex's own model wired nothing (login.Set only re-ran set for a magpie model). Now, on magpie API, Codex's own model goes as magpie serves it on the ChatGPT account there (codexOwnViaMagpie: gpt-6-luna -> codex/gpt-6-luna, the entries shown to Codex first), so set() takes the magpie branch and only the default changes; the picker's OpenAI group offers those ids under their own names (Label gpt-6-luna) so the value matches; one magpie doesn't serve (the ChatGPT subscription off in magpie) is refused with a message naming both ways out, the config untouched, rather than quietly unwired; choosing magpie API on Codex's own model wires it at once; Sync wires a config an older magpie left so (#701's: model = "gpt-6-luna", sign-in api). Back on ChatGPT, a codex/… default turns into Codex's own model again, straight to OpenAI as before (codexOwnOf); the ChatGPT sign-in's paths are otherwise unchanged. TestCodexAPIKeepsMagpieOnOwnModel (api on an own model, magpie model then own model again, picker values, refusal, back to ChatGPT) and TestCodexAPISyncWiresOwnModel fail on the old code and pass; TestCodexProviderAlsoSetsBaseURL's api case now expects magpie to stay wired on Codex's own model. End to end in a temp HOME with a copy of a real models_cache.json: api, fake/m1, then gpt-6-luna leaves model = "codex/gpt-6-luna" with model_provider, model_catalog_json and openai_base_url, and codex-cli 0.160.0's codex debug models with CODEX_HOME on that sandbox (gateway ports pointed at :1) lists fake/m1 beside codex/gpt-6-luna and the other codex/ models. go vet, builds (darwin, GOOS=linux, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass. Not tried in the Codex app or with a turn sent through a real ChatGPT account.
2026-10-03 23:40:06 +08:00
agent: Codex on a routing group's model name is still connected, not "switched off it outside magpie" (#750, Windows 11, magpie 0.1.812, Codex 0.160.0: Codex set to group/auto-gpt-6-1-sol in magpie, its config.toml then reading model = "gpt-6.1-sol" with openai_base_url still magpie's gateway, and the Agents page kept saying 在 magpie 之外被从 … 切走了 with 重新接入, coming back a while after each reconnect) — the gateway takes a model's name without a provider in it as the group of that model (provider.GroupFor: gpt-6.1-sol is group/auto-gpt-6-1-sol), so Codex's requests still went to the group; but Drift compared the field with what magpie recorded setting (applied.json) by string, and gpt-6.1-sol is neither that nor one of magpie's models by magpieValue (isMagpie wants a provider/model id, and Codex's options list it as its own or not at all), so it read as "replaced". What writes gpt-6.1-sol into config.toml is not magpie (no agent path writes a group's model name; set writes the group id as picked) and wasn't found — the Codex app persisting its thread's model by its own name is the likely one — which is why it came back after each reapply. Drift now passes over a field whose value and magpie's recorded one reach the same routing group, one by the group's id and one by its model's name (sameGroup, groupNamed: a group/… id as it is, "magpie/" taken off, else GroupFor); Codex's internal wired() and Agent.Wired (through a new Agent.Routed hook, Codex's routed(): openai_base_url or magpie as its provider) count the group's model name as magpie's only when magpie set that group on the field and Codex's config still sends its model to the gateway, so a Codex taken off magpie on gpt-6.1-sol is not connected, and a Codex's own gpt-5.5 that happens to have an auto group is no more magpie's than before (failover's base URL is untouched). Disconnect takes the field off the group's model name as it does off the group's id (back to Codex's default), rather than leaving Codex asking OpenAI for gpt-6.1-sol. Another group's model (gpt-6.1) or one no group has (gpt-5.5) is still "replaced". The reporter's ask to say which setting differs: the drift's detail already names it ("model is …, not … as magpie set it", the base URL or provider table for unwired) in the status line's and the Apply again pill's tooltip; that is left as it is. Tests: TestCodexGroupByItsModelName (two providers serving gpt-6.1-sol and gpt-6.1, signed in with ChatGPT and with an API key: group/auto-gpt-6-1-sol set, then config.toml's model rewritten to gpt-6.1-sol — Wired and no drift; no route to magpie — not wired; gpt-6.1 and gpt-5.5 — replaced) and TestCodexGroupByItsModelNameDisconnect fail on the old code (not wired, drift replaced, gpt-6.1-sol and the base URL left after Disconnect) and pass. go vet, builds (darwin, GOOS=linux, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass. Not tried on Windows or with the reporter's Codex and groups; not checked: what in Codex rewrites the model to gpt-6.1-sol.
2026-10-04 13:11:23 +08:00
agent, gui: Codex left on model_provider = "magpie" with no [model_providers.magpie] loads its config again, and connecting with nothing in magpie says what to do, in the reader's language (Tystem on Discord) — the Codex app said "无法加载 config.toml … Model provider magpie not found", magpie showed Codex as not connected on "deepseek-flash", and its switch answered only "Codex can't be connected to magpie", in English. Codex looks model_provider up in [model_providers.*] as it loads config.toml (codex-rs: "Model provider {id} not found"), so the key without the table keeps it from loading any config, a new thread too, not just an old one. magpie never writes one without the other: it takes model_provider out whenever it steps out as the provider (disconnect, Unwire, a model of Codex's own, Join) and keeps the table so the threads started on magpie still open. That is unchanged, and TestCodexSteppingOutLeavesNoHalfState now covers it. Another tool or a hand edit had taken the table away. Sync, at magpie's start and whenever the catalog changes, now writes the table back whenever the config names magpie as its provider, at the top or in a profile, and has no table, whether Codex is connected or not. Check reports that state too. A config magpie can't parse is still only reported, never written to. A Connect that finds none of magpie's models because no provider or subscription has been added answers agent.NoModelsError, "Add a provider or subscription in magpie first, then connect Codex". /api answers it with code no_models and the agent's name, which app.js says through t() (en/zh/ja/de). docs/reference.md no longer says the table goes with a native model. TestCodexProviderWithoutTable (top and profile: Check says so, Sync writes the table) and TestConnectWithNoModels in internal/agent, TestAgentConnectNoModels in internal/gui, and agent-connect-no-models.test.cjs (WebKit, en/zh/ja/de: the toast in the reader's language, the switch back off, no scroll, no native dialog) are new and fail without the change; the latter's en case passes either way, as the server's message is English. Chromium wouldn't launch on this machine for this test or the existing agent-connect.test.cjs. TestCodexSyncAddsBaseURLToProvider now expects the table added to a hand-made provider that had none. go vet, go build (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui ./... under a temp HOME pass. In the first full run, internal/gui's TestProvidersAnswerWhileListsComeIn and internal/proc's TestUserPath failed under load; both passed alone and in the second full run.
2026-10-05 21:09:13 +08:00
agent, gui: Codex's row has a square for the model it writes its memories with (Yc on Discord) — Codex sums each thread up with gpt-5.6-luna and consolidates its memories with gpt-5.6-terra (medium), whatever model it runs, and nothing in magpie could change that. Codex reads both from config.toml's [memories] extract_model and consolidation_model (codex-rs/config/src/types.rs; the defaults are memory_extraction_preferred_model / memory_consolidation_preferred_model in model-provider). Codex's row now has a memories square beside the subagents' one, opening the app's model picker: a model picked writes both keys, Default removes them (and a [memories] table left empty), the user's other [memories] keys stay. A model of magpie's is offered and taken only while Codex runs through magpie, as for subagents, and is removed when Codex steps out of magpie or is disconnected, since Codex could no longer find it. Unset, its title says what Codex uses. en/zh/ja/de. TestCodexMemoriesModel and TestCodexMemoriesUnwire (temp HOME) fail without the change; codex-memories.test.cjs (WebKit, en and zh: the square and its unset title, no square with nothing to pick, the model picker with Default first, a pick posted and lit, Default posts "", no select, no scroll, no left border) fails without it. subagent-effort, click-scroll, codex-titles, agent-start-pick and desktop-tiers pass in WebKit. go vet, go build (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui ./... under a temp HOME pass.
2026-10-05 19:11:34 +08:00
toml: Codex's config.toml with a multi-line array (notify = [ … ]) is edited right, and an edit that fails leaves every file as it was (#253 kerwinliu00001: "edited TOML is invalid: line 2, column 1: incomplete number", config.toml left with model_provider gone and [model_providers.magpie] added but no model) — the top-level key edits (GetTOMLTop, SetTOMLTop, DelTOMLTop) went line by line with regexes: a new key went after the last line that looked like key = …, which for notify = [ was inside the array; key = value lines inside a multi-line string were read as keys and a line starting with [ as a table; replacing or deleting a multi-line value touched only its first line. They now locate the top-level keys with the TOML parser, as the table edits already did, each with its value's whole range however many lines it takes (parseTOMLFile, the unnamed root table beside the tables); SetTOMLTop finds all its keys in the file as read and writes once. A file the parser refuses is still read line by line, so a broken config keeps showing its model, and writes to it are refused untouched. And a pick is several writes (Codex: drop model_provider, add magpie's provider table, set openai_base_url and model), each checked, so one failing left the earlier ones on disk: edit.Atomically(fn, paths…) puts each file back to its bytes and mode, or removes one it created, when fn fails, and every field set and Sync of Codex (config.toml and magpie-models.json, so Codex in WSL too), Kimi and Grok goes through it, as do Codex's MCP server writes (putCodex, delCodex). Tested in temp dirs and a temp HOME: the reporter's file read, set and deleted directly and through Codex's model field (signed in, with model_provider and model above the array, with magpie as the provider), the array's text kept and the TOML valid, and back to a Codex model; nested arrays, trailing commas, comments in arrays, [x] and a = b in strings, an inline table in an array; """ and ''' strings holding model = … and [table] lines not read as keys, new keys after their closing quotes, one deleted whole; a forced failure of Codex's last write leaving config.toml byte-identical; TestAtomically. They fail on main (the Codex ones with the reporter's error). go vet ./internal/..., go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried against a real ~/.codex, in WSL or in the GUI; multi-line inline tables (TOML 1.1) are refused by the parser and so left untouched with an error.
2026-09-30 09:31:59 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
agent, gui: Codex left on model_provider = "magpie" with no [model_providers.magpie] loads its config again, and connecting with nothing in magpie says what to do, in the reader's language (Tystem on Discord) — the Codex app said "无法加载 config.toml … Model provider magpie not found", magpie showed Codex as not connected on "deepseek-flash", and its switch answered only "Codex can't be connected to magpie", in English. Codex looks model_provider up in [model_providers.*] as it loads config.toml (codex-rs: "Model provider {id} not found"), so the key without the table keeps it from loading any config, a new thread too, not just an old one. magpie never writes one without the other: it takes model_provider out whenever it steps out as the provider (disconnect, Unwire, a model of Codex's own, Join) and keeps the table so the threads started on magpie still open. That is unchanged, and TestCodexSteppingOutLeavesNoHalfState now covers it. Another tool or a hand edit had taken the table away. Sync, at magpie's start and whenever the catalog changes, now writes the table back whenever the config names magpie as its provider, at the top or in a profile, and has no table, whether Codex is connected or not. Check reports that state too. A config magpie can't parse is still only reported, never written to. A Connect that finds none of magpie's models because no provider or subscription has been added answers agent.NoModelsError, "Add a provider or subscription in magpie first, then connect Codex". /api answers it with code no_models and the agent's name, which app.js says through t() (en/zh/ja/de). docs/reference.md no longer says the table goes with a native model. TestCodexProviderWithoutTable (top and profile: Check says so, Sync writes the table) and TestConnectWithNoModels in internal/agent, TestAgentConnectNoModels in internal/gui, and agent-connect-no-models.test.cjs (WebKit, en/zh/ja/de: the toast in the reader's language, the switch back off, no scroll, no native dialog) are new and fail without the change; the latter's en case passes either way, as the server's message is English. Chromium wouldn't launch on this machine for this test or the existing agent-connect.test.cjs. TestCodexSyncAddsBaseURLToProvider now expects the table added to a hand-made provider that had none. go vet, go build (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui ./... under a temp HOME pass. In the first full run, internal/gui's TestProvidersAnswerWhileListsComeIn and internal/proc's TestUserPath failed under load; both passed alone and in the second full run.
2026-10-05 21:09:13 +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
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
agent: 重开 Codex 后生效 goes once Codex is reopened, whatever Codex itself writes to config.toml after, and a Codex daemon of another home isn't counted (#729, Sun1090 on Codex 0.160.0: the Codex row stayed "已接入 · 重开 Codex 后生效" after ChatGPT and magpie were both restarted) — Agent.Stale counted every process matching (^|/)codex( |$) that started over a second before config.toml's or magpie-models.json's mtime, and Codex writes config.toml itself (each project it is opened in gets a [projects."…"] trust_level, a notice seen, the model picked in its app; this Mac's has 10919 project tables), so a Codex reopened after magpie's change was stale again at its first such write, as was one that never missed anything; and the pattern also took the app-server daemons Codex 0.160 leaves running with ppid 1 for another CODEX_HOME (<home>/.codex/packages/app-server-daemon/…/codex app-server --managed-daemon, days old on this Mac). Stale now compares a copy's start with when magpie last changed what the agent reads at start: a digest of it (Codex: model_provider, model_catalog_json, openai_base_url, the [model_providers.magpie] table and magpie-models.json; Claude Code: env and model in settings.json) is kept in the stash with the files' latest write at the time it was first seen, so neither the agent's own writes nor magpie starting again move it; a magpie change (a new list, connecting) still gives a new time and the notice. A process whose command runs from another home's .codex (or .claude) dir is skipped. pgrep/ps sit behind a var (running), ps now giving etime and command. TestCodexStaleOnlyForMagpiesChange (ChatGPT's Codex reopened an hour ago and another home's daemon: 0; Codex trusting a project: 0; magpie's list changed: 1, and 1 again from a fresh Agent) fails on the old logic at both the daemon and Codex's own write, and passes. go vet ./internal/..., builds (darwin -tags nogui, GOOS=linux, GOOS=windows internal/agent) and go test -tags nogui ./internal/agent pass (its TestMain sandboxes HOME; the HOME override itself was refused here). Not tried in the reporter's app: a Codex already flagged clears once it is reopened after this build has read the digest, one more reopen at most after updating.
2026-10-04 07:47:06 +08:00
agent: 重开 Codex 后生效 goes once Codex is reopened, whatever Codex itself writes to config.toml after, and a Codex daemon of another home isn't counted (#729, Sun1090 on Codex 0.160.0: the Codex row stayed "已接入 · 重开 Codex 后生效" after ChatGPT and magpie were both restarted) — Agent.Stale counted every process matching (^|/)codex( |$) that started over a second before config.toml's or magpie-models.json's mtime, and Codex writes config.toml itself (each project it is opened in gets a [projects."…"] trust_level, a notice seen, the model picked in its app; this Mac's has 10919 project tables), so a Codex reopened after magpie's change was stale again at its first such write, as was one that never missed anything; and the pattern also took the app-server daemons Codex 0.160 leaves running with ppid 1 for another CODEX_HOME (<home>/.codex/packages/app-server-daemon/…/codex app-server --managed-daemon, days old on this Mac). Stale now compares a copy's start with when magpie last changed what the agent reads at start: a digest of it (Codex: model_provider, model_catalog_json, openai_base_url, the [model_providers.magpie] table and magpie-models.json; Claude Code: env and model in settings.json) is kept in the stash with the files' latest write at the time it was first seen, so neither the agent's own writes nor magpie starting again move it; a magpie change (a new list, connecting) still gives a new time and the notice. A process whose command runs from another home's .codex (or .claude) dir is skipped. pgrep/ps sit behind a var (running), ps now giving etime and command. TestCodexStaleOnlyForMagpiesChange (ChatGPT's Codex reopened an hour ago and another home's daemon: 0; Codex trusting a project: 0; magpie's list changed: 1, and 1 again from a fresh Agent) fails on the old logic at both the daemon and Codex's own write, and passes. go vet ./internal/..., builds (darwin -tags nogui, GOOS=linux, GOOS=windows internal/agent) and go test -tags nogui ./internal/agent pass (its TestMain sandboxes HOME; the HOME override itself was refused here). Not tried in the reporter's app: a Codex already flagged clears once it is reopened after this build has read the digest, one more reopen at most after updating.
2026-10-04 07:47:06 +08:00
agent: Cursor Private Inference is connected by its row's switch, as other agents are, with no command to run (mamba on Discord: 这个单独搞个启动命令和别的供应商格格不入啊) — its Open configuration's base URL and key are kept in the state.vscdb regular Cursor shares, and are regular Cursor's own override settings too, so magpie still writes nothing of Cursor's. It sets CURSOR_LOCAL_AGENT_BASE_URL (<gateway>/v1) and CURSOR_LOCAL_AGENT_API_KEY (magpie-cursor-local), which only this build reads, for the user: launchctl setenv on the Mac (apps opened from the Dock or Finder from then on have them), HKCU\Environment plus a WM_SETTINGCHANGE on Windows, ~/.config/environment.d/magpie-cursor-local.conf (from the next login) and systemctl --user set-environment on Linux; switched off, it clears them. magpie notes it in cursor-local.env in its config folder, which the row reads as connected, and sets them again whenever it serves the gateway (launchd forgets them at a restart; the port may have changed). The row has the provider field (magpie) and the connect switch; connecting says to quit the app and open it again, and that a base URL in Open configuration still comes first. The launch command stays as the square beside it, for a start from a shell. TestCursorLocalConnects (connect sets them, a serve sets them again, disconnect clears them, off a serve sets nothing) fails on the old code; cursor-local-launch.test.cjs now checks the switch connects it with no command copied (WebKit, en and zh); agy-launch passes. Not tried with the real app (not installed here), and launchctl/the registry are not touched under tests. go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass.
2026-10-05 00:18:22 +08:00
agent: Cursor Private Inference is connected by its row's switch, as other agents are, with no command to run (mamba on Discord: 这个单独搞个启动命令和别的供应商格格不入啊) — its Open configuration's base URL and key are kept in the state.vscdb regular Cursor shares, and are regular Cursor's own override settings too, so magpie still writes nothing of Cursor's. It sets CURSOR_LOCAL_AGENT_BASE_URL (<gateway>/v1) and CURSOR_LOCAL_AGENT_API_KEY (magpie-cursor-local), which only this build reads, for the user: launchctl setenv on the Mac (apps opened from the Dock or Finder from then on have them), HKCU\Environment plus a WM_SETTINGCHANGE on Windows, ~/.config/environment.d/magpie-cursor-local.conf (from the next login) and systemctl --user set-environment on Linux; switched off, it clears them. magpie notes it in cursor-local.env in its config folder, which the row reads as connected, and sets them again whenever it serves the gateway (launchd forgets them at a restart; the port may have changed). The row has the provider field (magpie) and the connect switch; connecting says to quit the app and open it again, and that a base URL in Open configuration still comes first. The launch command stays as the square beside it, for a start from a shell. TestCursorLocalConnects (connect sets them, a serve sets them again, disconnect clears them, off a serve sets nothing) fails on the old code; cursor-local-launch.test.cjs now checks the switch connects it with no command copied (WebKit, en and zh); agy-launch passes. Not tried with the real app (not installed here), and launchctl/the registry are not touched under tests. go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass.
2026-10-05 00:18:22 +08:00
agent: Cursor Private Inference is connected by its row's switch, as other agents are, with no command to run (mamba on Discord: 这个单独搞个启动命令和别的供应商格格不入啊) — its Open configuration's base URL and key are kept in the state.vscdb regular Cursor shares, and are regular Cursor's own override settings too, so magpie still writes nothing of Cursor's. It sets CURSOR_LOCAL_AGENT_BASE_URL (<gateway>/v1) and CURSOR_LOCAL_AGENT_API_KEY (magpie-cursor-local), which only this build reads, for the user: launchctl setenv on the Mac (apps opened from the Dock or Finder from then on have them), HKCU\Environment plus a WM_SETTINGCHANGE on Windows, ~/.config/environment.d/magpie-cursor-local.conf (from the next login) and systemctl --user set-environment on Linux; switched off, it clears them. magpie notes it in cursor-local.env in its config folder, which the row reads as connected, and sets them again whenever it serves the gateway (launchd forgets them at a restart; the port may have changed). The row has the provider field (magpie) and the connect switch; connecting says to quit the app and open it again, and that a base URL in Open configuration still comes first. The launch command stays as the square beside it, for a start from a shell. TestCursorLocalConnects (connect sets them, a serve sets them again, disconnect clears them, off a serve sets nothing) fails on the old code; cursor-local-launch.test.cjs now checks the switch connects it with no command copied (WebKit, en and zh); agy-launch passes. Not tried with the real app (not installed here), and launchctl/the registry are not touched under tests. go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass.
2026-10-05 00:18:22 +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
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
agents: Disconnect from magpie takes out everything magpie wrote into an agent's config and puts back what it had before (Fate on Discord: 移除由Magpie写入的配置,也就是重置功能,这个好像不是很明显。初步体验好像是选择默认就会清除写入的配置吗?希望能有一个更直接的交互动作,来代表移除由Magpie写入的配置。) — there was no one action for it, and picking Default isn't it: Default is the agent as installed, and for Codex, Claude Code and Gemini CLI it also forgets the stash, so the user's own provider or relay (model_provider + its table, ANTHROPIC_BASE_URL/AUTH_TOKEN, GOOGLE_GEMINI_BASE_URL/GEMINI_API_KEY and sign-in) was lost rather than put back. agent.Disconnect reuses each agent's own restore path: a new Agent.Unwire, for those three, runs the unroute their own-model pick already used (codex.go and claude.go have it pulled out of set as unroute; gemini.go's was there) and then forgets the stash, and every other field magpie set — each one reading a magpie value, or the value applied.json recorded and Unwire left — is set to "" through its own Set, which for every other agent unstashes what it had. applied.json forgets the agent (Keep), so no drift says it was switched off magpie. Agent.Wired (magpie or a magpie model in any field) goes to the GUI as agentJSON.wired; an agent magpie isn't in is left byte for byte. POST /api/agents/disconnect/{id} runs it under edit.Atomically as Sync and the fields' Sets are.
2026-10-03 02:42:09 +08:00
agents: Factory's Droid CLI is an agent magpie sets up (#242 tasselx) — droid keeps its settings in ~/.factory/settings.json ($FACTORY_HOME_OVERRIDE/.factory when set), its BYOK models the customModels array ({model, displayName, baseUrl, apiKey, provider "anthropic" | "openai" (Responses) | "generic-chat-completion-api", maxOutputTokens, noImageSupport …}), picked as "custom:<id>". Picking a catalog model through magpie appends one entry per catalog model after the user's own (so their ids never move), each with an explicit id "custom:magpie/<provider>/<model>", the catalog's label as displayName, the gateway and token magpie, its context (maxContextLimit) and output when known, noImageSupport always written (droid takes a Chat Completions model as blind otherwise), and the API its provider speaks natively so the gateway relays it as it is: Responses → "openai" at /v1, Messages → "anthropic" at the gateway root (Anthropic's SDK adds /v1), anything else "generic-chat-completion-api" at /v1; and sets sessionDefaultSettings.model. The model shows in magpie as magpie/<ref>; the user's sessionDefaultSettings.model is stashed and put back on reset (a top-level "model", the docs' spelling, is left alone and is what droid falls back to), magpie's entries go and an emptied customModels or sessionDefaultSettings with them; everything else in the file, the user's entries included, is kept byte for byte. The picker offers the user's own custom models by the id droid gives them (its "id", else the displayName with whitespace as dashes and a count of the same name before it), including the legacy ~/.factory/config.json custom_models, which magpie never writes. Sync rewrites magpie's entries as providers change; Check reports a missing entry or a changed baseUrl/apiKey; its requests are Droid's in usage (User-Agent factory-cli/<version>). Icon is Factory's own favicon glyph (factory.ai/favicon.svg); lobehub has none. From the docs: docs.factory.ai/cli/byok/overview (customModels fields, the three providers, config.json legacy snake_case merged under settings.json), /cli/configuration/settings (model, sessionDefaultSettings.*), /droid-exec/overview (custom:<Display-Name>-<index>). Verified by reading the shipped droid 0.229.0 bundle (@factory/cli-linux-x64, unpacked, never installed or run): the zod schema of an entry (also id, index, maxContextLimit, enableThinking, reasoningEffort, bedrock-converse), ids as custom:${displayName.trim().replace(/\s+/g,"-")}-${n} with n counting equal names, an entry's own id winning, the lookup by id, top-level model/reasoningEffort/specModeModel moved into sessionDefaultSettings only when unset there, getModel reading sessionDefaultSettings.model, noImageSupport defaulting by provider, FACTORY_HOME_OVERRIDE, and BYOK requests carrying factory-cli/<version>. Tested in a sandbox HOME (internal/agent/droid_test.go): set/sync/reset on a settings.json as droid leaves it with a Groq BYOK model (its entry byte-identical, the file restored exactly), each protocol's provider and baseUrl, a moved baseUrl caught by Check and healed by Sync, picking the user's own model while on magpie's, no file at all, a top-level model, FACTORY_HOME_OVERRIDE and legacy config.json ids (custom:Local-Qwen-0/-1) offered and never written. go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass (TestClaudeSignedOut and TestClaudeAccountNamedAsItsLogin flaked under load and pass alone). Not tried with a real droid: whether droid's /model lists the entries, that it reaches the gateway on each protocol, and how it sends thinking for a custom model (magpie sets no reasoningEffort/enableThinking) are unverified.
2026-09-30 02:35:59 +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
models: reasoning levels are borrowed again for models Azure also hosts, and a routing group keeps its members' levels when one thinks with none to pick from (ARNO on Discord: routing group在接入harness的时候,没有设置reasoning_efforts。我发现是之前很多能自动推导reasoning_efforts列表的模型现在都推导失败了) — the Azure OpenAI preset (c35471cf, Catalog "azure, openai") was taken for a maker, so models.dev's azure list was the maker's word on every model it hosts: Kimi K2.5, DeepSeek V3.2 and R1, Grok 4.20/4.1 Fast Reasoning, listed there with no levels, took none on a relay or custom provider (and the gateway capped them at high as levelless), where the providers listing any give low…high, none/high and the rest. Azure is now marked Hosts, as Groq and Ollama Cloud are; its own provider still takes its own list's word. And groupEntries narrowed a group to the levels every member has, so one member that thinks with no levels (a thinking switch, a Claude 4.5 with a budget alone, OpenRouter's qwen3.8-omni-flash) left the group none and dsh's route wrote it without reasoningEfforts; such a member is now skipped as an unknown one is, since the gateway sends it the effort asked, no more than high (fitFor). The same Entry.Efforts feeds dsh, Codex's catalog, Pi and OpenCode. On a copy of the owner's config and models.dev cache: no plain model loses levels; group/auto-claude-haiku-4-5 and -sonnet-4-5 get low/medium/high/max again (they had them on 09-30), group/auto-qwen3-8-omni-flash none/low/medium/xhigh; across models.dev, the 34 ids Azure emptied (kimi-k2.5, deepseek-v3.2, deepseek-r1, grok-4-20-reasoning …) borrow again. TestHostListIsNoMakersWord (provider) and TestDshGroupHasItsMembersLevels (agent: the group's dsh entry has reasoningEfforts and the thinking field offers low/high/max) fail on the old code. go vet, builds (darwin, GOOS=linux, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass.
2026-10-03 18:17:11 +08:00
agent: an agent's own provider named as one of magpie's isn't magpie's, in every agent that spells a model provider/model (the rest of #835) — OpenHanako's own deepseek/deepseek-v4-pro read as magpie's deepseek, and so did a model of any agent's own provider whose name magpie has a provider by: Pi's, Crush's, Hermes's, OpenCode's relay/glm-4.6 with magpie's relay had the row connected on the agent's own model, and Disconnect from magpie put that model back and left the row connected. An agent says how magpie's values are spelled in it (Spelled, replacing #835's Prefixed): magpie/<ref> for Antigravity CLI, Pi, OmO, Aside, Goose, Zed, VS Code, Crush, DeepSeek Harness, Command Code, fx, omp, Hermes, Mister Morph, Kimi Code, Empryo, MiniMax Code, Droid, Qoder, Qoder CN, Grok Build, AtomCode, Cline and OpenHanako, whose every Get spells magpie's so (a sandbox Set of magpie/relay/glm-4.6 read back as that in each); for OpenCode, MiMo Code and OpenChamber also a provider of the config's own that sends to magpie's gateway, as openCodeRef names a model there. A stopped WSL distro's agent keeps its live one's. Left as they are: Claude Code, Claude Desktop, Codex, Gemini CLI, Cursor, Copilot, Devin (magpie's are bare refs there), Muse Code (a model with / is magpie's by design: Meta's have none), Alma (its own are providerId:model), Air (magpie's only). TestOwnProviderNamedAsMagpies (26 agents: own relay/glm-4.6 not connected, Connect, Disconnect puts it back and the row is off) fails on the old code in each; TestOpenCodeGatewayProviderIsMagpies. go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass.
2026-10-05 06:49:45 +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
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
goose: the model is read and written in the layout Goose's config is in, active_provider and the providers map as well as GOOSE_PROVIDER/GOOSE_MODEL (a follow-up to #987: the reporter's Goose 1.53 has active_provider: magpie and its model in providers.magpie.model) — Goose 1.53 reads active_provider before GOOSE_PROVIDER and the active entry's model before GOOSE_MODEL (get_active_provider/get_active_model, crates/goose/src/config/providers.rs at v1.53.0), and on every write migrates the flat keys into the map and, once a map is there, deletes them (migrate_provider_config/cleanup_legacy_provider_keys, config/migrations.rs; load_write_config, config/base.rs). magpie read and wrote only the flat keys: on a migrated config it showed no model, its Check and the restart notice never saw magpie in use, and a model picked in magpie went beside a map goose read first, so goose kept its own and deleted magpie's at its next write. Now a config with a providers map or active_provider is written as goose's set_active_provider writes it (active_provider, providers.<id>: enabled, model, configured), other providers' entries and the user's other keys and comments kept, stale flat keys removed; an old config keeps the flat keys, which an older goose reads and a newer migrates. Taking Goose off magpie clears active_provider and the flat keys as goose's clear_active_provider does, and drops magpie's own entry with its custom provider. TestGooseModelInEitherLayout (the reporter's layout with another provider; switching to a native model, to magpie's and back off; a stale flat key beside the map; the old layout left old) fails on the old code ("model = \"\", want magpie/zhipu/glm-5.3") and passes; go test ./internal/agent/ ./internal/edit/, -race -count=5 on the Goose/pick/effort tests, go vet (darwin, windows) and darwin/linux(nogui)/windows builds pass. Not tried with a real Goose Desktop.
2026-10-06 14:53:46 +08:00
goose: the model is read and written in the layout Goose's config is in, active_provider and the providers map as well as GOOSE_PROVIDER/GOOSE_MODEL (a follow-up to #987: the reporter's Goose 1.53 has active_provider: magpie and its model in providers.magpie.model) — Goose 1.53 reads active_provider before GOOSE_PROVIDER and the active entry's model before GOOSE_MODEL (get_active_provider/get_active_model, crates/goose/src/config/providers.rs at v1.53.0), and on every write migrates the flat keys into the map and, once a map is there, deletes them (migrate_provider_config/cleanup_legacy_provider_keys, config/migrations.rs; load_write_config, config/base.rs). magpie read and wrote only the flat keys: on a migrated config it showed no model, its Check and the restart notice never saw magpie in use, and a model picked in magpie went beside a map goose read first, so goose kept its own and deleted magpie's at its next write. Now a config with a providers map or active_provider is written as goose's set_active_provider writes it (active_provider, providers.<id>: enabled, model, configured), other providers' entries and the user's other keys and comments kept, stale flat keys removed; an old config keeps the flat keys, which an older goose reads and a newer migrates. Taking Goose off magpie clears active_provider and the flat keys as goose's clear_active_provider does, and drops magpie's own entry with its custom provider. TestGooseModelInEitherLayout (the reporter's layout with another provider; switching to a native model, to magpie's and back off; a stale flat key beside the map; the old layout left old) fails on the old code ("model = \"\", want magpie/zhipu/glm-5.3") and passes; go test ./internal/agent/ ./internal/edit/, -race -count=5 on the Goose/pick/effort tests, go vet (darwin, windows) and darwin/linux(nogui)/windows builds pass. Not tried with a real Goose Desktop.
2026-10-06 14:53:46 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
agents: Pi's model picker lists the models of its openai-codex sign-in from Pi's own registry, and its Default says it lets Pi pick (#709) — Pi's native options came from models.dev by provider id, and models.dev has no openai-codex (Pi's "OpenAI Codex (legacy)" ChatGPT sign-in), so a Pi signed in to both openai and openai-codex was offered openai/… only. Pi's (and OmO's) own options now come first from the model registry in the package Pi was installed from: the pi command on PATH leads to @earendil-works/pi-coding-agent, and pi-ai's dist/providers/data/<provider>.json (Pi 1.0) is read as is, in its order, chat models only (no gpt-image-2), memoized by the file's stamp — the list Pi's /model offers, which moves with every Pi update. A provider the registry doesn't have keeps models.dev's list; openai-codex with no registry in reach falls back to Codex CLI's models_cache.json (the same ChatGPT backend); models.dev's openai list isn't mapped onto it. The rows are openai-codex/<model> under "OpenAI Codex" with OpenAI's logo, a row each beside openai/<model> of the same name; picking one writes defaultProvider=openai-codex, defaultModel=<model> as before. omp shared the gap for its current model's provider (ownOptions): it now reads omp's own catalog (@oh-my-pi/pi-catalog src/models.json, non-chat kinds left out); omp's signed-in providers that aren't the current one are still #341's. Default in Pi's and OmO's model picker now says "clears the default model; Pi picks one on its own" (zh 清除显式默认模型,由 Pi 自动选择; no ja table exists), other agents' still say what they ship with. TestPiOffersItsOwnOpenAICodexModels (a fake npm-linked Pi 1.0 install, temp HOME and PI_CODING_AGENT_DIR, auth.json with openai and openai-codex oauth test metadata), TestPiOpenAICodexWithoutItsRegistry and TestOmpOffersItsOwnOpenAICodexModels fail on the old code (no openai-codex rows) and pass; pi-default-note.test.cjs (webkit, en/zh) fails on the old app.js and passes; agent-disconnect, agent-models and agent-model-groups GUI tests pass. Read-only against this machine's real installs: Pi 1.0.0 gives openai-codex 9 models and openai 44, omp's catalog openai-codex 8. go vet, builds (darwin, GOOS=linux, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass but TestProvidersAnswerWhileListsComeIn, TestClaudeSignedOut, TestClaudeAccountNamedAsItsLogin and TestClaudeIdentityServedWhileAsked, timing tests that pass alone. Not tried in the GUI with real Pi sign-ins, nor with a Pi older than 1.0 (no data folder: models.dev and Codex CLI's list as before) or a Windows npm shim.
2026-10-04 01:53:58 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
agent, gui: an agent whose CLI is gone while its settings are left says so, and Install another agent offers it again (evilgaoshu, #843: 卸载了 DeepSeek Harness,但 ~/.dsh 还在,Agents 页面依然把它当作已安装列出来,也不会出现在 Install another agent 里) — an agent was here when its config or folder was, so dsh, uninstalled with ~/.dsh kept, was listed as installed, and Install another agent left out every agent listed. Agent.CLIMissing: its folder or config is here, its CLI isn't, neither on PATH nor where users' tools go (proc.FindTool, as #839's Claude Code is found on Windows); only for an agent that is its CLI and has an install command magpie knows, not one whose folder an app or editor extension keeps too (Codex, Claude Code, Gemini CLI, OpenCode, Cline, Goose), nor a WSL one. Its row stays, settings kept and nothing deleted, with "CLI not found" where its version goes (its tooltip names the folder and points to the install command), and Install another agent lists it, marked "CLI not found" under its name. dsh now has its npm package, @deepseek-ai/dsh, so it is offered with npm install -g @deepseek-ai/dsh, and its version and updates show like the other CLIs'. zh, ja, de strings. TestCLIMissing (dsh with ~/.dsh and no dsh is missing and offered; codex's folder, an agent not here, a WSL one aren't; dsh in ~/.local/bin off PATH isn't) fails on the old code; agent-cli-missing.test.cjs (WebKit, en and zh: the row's note, its height kept, Install another agent lists it with its command) fails on the old code. agent-update-all, agent-layout, agent-start-pick, click-scroll, gui-ja, gui-de and import-row pass on WebKit. go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass.
2026-10-05 09:25:01 +08:00
agent, gui: an agent whose CLI is gone while its settings are left says so, and Install another agent offers it again (evilgaoshu, #843: 卸载了 DeepSeek Harness,但 ~/.dsh 还在,Agents 页面依然把它当作已安装列出来,也不会出现在 Install another agent 里) — an agent was here when its config or folder was, so dsh, uninstalled with ~/.dsh kept, was listed as installed, and Install another agent left out every agent listed. Agent.CLIMissing: its folder or config is here, its CLI isn't, neither on PATH nor where users' tools go (proc.FindTool, as #839's Claude Code is found on Windows); only for an agent that is its CLI and has an install command magpie knows, not one whose folder an app or editor extension keeps too (Codex, Claude Code, Gemini CLI, OpenCode, Cline, Goose), nor a WSL one. Its row stays, settings kept and nothing deleted, with "CLI not found" where its version goes (its tooltip names the folder and points to the install command), and Install another agent lists it, marked "CLI not found" under its name. dsh now has its npm package, @deepseek-ai/dsh, so it is offered with npm install -g @deepseek-ai/dsh, and its version and updates show like the other CLIs'. zh, ja, de strings. TestCLIMissing (dsh with ~/.dsh and no dsh is missing and offered; codex's folder, an agent not here, a WSL one aren't; dsh in ~/.local/bin off PATH isn't) fails on the old code; agent-cli-missing.test.cjs (WebKit, en and zh: the row's note, its height kept, Install another agent lists it with its command) fails on the old code. agent-update-all, agent-layout, agent-start-pick, click-scroll, gui-ja, gui-de and import-row pass on WebKit. go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass.
2026-10-05 09:25:01 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
provider: Antigravity's models at several levels are one model with those levels (#150: 统一 Antigravity 模型变体与客户端推理档位的映射) — Antigravity lists gemini-3.7-flash-low, -medium and -high as three models, "Gemini 3.7 Flash (Low)" …, so a client picked a level twice: once in the model, once as its reasoning effort, with no telling which won. Now ids that are one id with an effort word after it (-low, -medium, -high, -extra-low, -minimal, -xhigh) are one model, gemini-3.7-flash "Gemini 3.7 Flash", declaring only the levels there are (low,medium,high; Gemini 3.1 Pro low,high), so Codex, Pi and the rest get reasoning levels for it. The level a variant is at is what Antigravity's name says where each name says a different one (gemini-3.5-flash-extra-low is "(Low)", gemini-3.5-flash-low "(Medium)"), else its id's word; a model only named like another (gemini-3-flash-agent, "Gemini 3.5 Flash (High)"; gemini-pro-agent) or with no sibling (gpt-oss-120b-medium) stays as listed. A request asks for the variant the effort picks, an effort it lacks at the nearest level (xhigh is high; medium on low/high is high); with none asked, the id without a level if Antigravity has one, else high — what Gemini 3 does unasked — else the highest. A variant's request carries no thinkingLevel, so the id and the level can't disagree. An old variant id still works: as named with no effort, and moved to the effort asked for. Saved picks and agents set to a variant (antigravity/gemini-3.7-flash-high) are moved to the family, at that level where the agent's own is unset, as Cursor's are. For Gemini 3 models without variants, medium now goes as medium to Flash (which takes minimal/low/medium/high) and still as high to Pro (low/high). Tested against the list an account's fetchAvailableModels gave (sandbox cache)
2026-09-28 20:10:00 +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
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
wsl: OpenCode, Kimi Code, omp and the other CLIs magpie sets up through a file in the home are set up in WSL distros too (#515: on Windows only Codex, Pi, OmO and Claude Code were found in a distro) — fourteen agents join wslKinds, each found by its folder under the distro's $HOME or its command on the distro's own PATH, and listed as <name> · WSL <distro> (opencode@wsl:Ubuntu…): OpenCode (~/.config/opencode, opencode), MiMo Code (~/.config/mimocode, mimo), Kimi Code (~/.kimi-code, kimi; the old kimi-cli's ~/.kimi where that is all there is, found by the command), omp (~/.omp/agent, omp), Crush (~/.config/crush/crush.json, Linux's place, not Windows' LOCALAPPDATA), Hermes Agent (~/.hermes), Grok Build (~/.grok, by its folder alone, as on this machine), Droid (~/.factory), fx (~/.fx, by its folder alone: fx is also the JSON viewer), Command Code (~/.commandcode), MiniMax Code's mcode (~/.minimax), Muse Code (~/.config/muse), Qoder and Qoder CN (~/.qoder, ~/.qoder-cn). Each is its host constructor at a place (opencodeIn, kimiIn, ompIn, crushIn, hermesIn, grokIn, droidIn, fxIn, commandCodeIn, miniMaxIn, museIn, qoderIn/qoderCNIn; the host's opencode(home, cfg) and the rest wrap them), so it writes the same keys and schema as on this machine, but the gateway as the distro reaches it (place.gw/v1: 127.0.0.1 when mirrored, Windows' address under NAT) in its provider, its Check and its Sync, and its folder at the default, as the distro's variables (OPENCODE_CONFIG_DIR, KIMI_CODE_HOME, HERMES_HOME, FACTORY_HOME_OVERRIDE, MINIMAX_DATA_DIR, QODER_CONFIG_DIR…) aren't read (place.getenv is "" there); OpenChamber, a Windows app, isn't looked at for a distro's OpenCode, and omp there, whose version isn't known, gets xhigh rather than a max an older omp refuses. Their notices are the restart advice of their own, as for Codex. A stopped distro's agent is built without looking at its files (place.cold: exists/isDir are false, so the defaults are taken), its options read none (wslOwnAsleep, kimiOwnOptions/ompOwnOptions/miniMaxOwnOptions without a file), and a pick, once the distro is started, builds the agent again warm, so it writes the file the agent reads — an opencode.jsonc already there, ~/.kimi for kimi-cli — not the default. Left out: Gemini CLI and Antigravity (a key lent through .env, a launch command), dsh (profiles and .env), Devin (no gateway; its model list from the devin command on this machine), Goose (no magpie routing; its name is pressly's goose too), Cursor and Copilot (no magpie routing), and the apps (Cline, Hanako, WorkBuddy, ZCode, Claude Desktop, OpenChamber, Alma, Cindy); and the library's skills, MCP and instructions for the new WSL agents, which wslTargetOf still gives only Claude Code, Codex, Pi and OmO. Nothing ran on Windows or in a real WSL. wsl_more_test.go, on fake distro roots under temp dirs with the host's variables pointed elsewhere: TestWSLProbeFindsMoreAgents (each folder and command in the probe, none for grok and fx, kimi-cli by its command), TestWSLMoreAgentsDiscovered (all fourteen listed, no command, UA or aliases), TestWSLMoreAgentsPick (each agent, mirrored and NAT: its file in the distro names the distro's gateway, no 127.0.0.1 under NAT, Check passes, Sync keeps it, the notice; this machine's home and the folders its variables name untouched), TestWSLMoreAgentsStopped (nothing asked nor opened, the last value shown, options, a pick starts the distro and writes there) fail without the change; TestWSLStoppedPickFindsItsFiles fails without the warm rebuild (the pick wrote a second opencode.json beside the .jsonc). go vet ./internal/..., go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build and vet ./internal/..., GOOS=windows go test -c ./internal/agent/ ./internal/library/, and go test -tags nogui -count=1 ./... under a temp HOME pass (TestFXInState failed once on its TempDir cleanup race, passes on the rerun; untouched).
2026-10-02 14:16:38 +08:00
agents: Pi's model picker lists the models of its openai-codex sign-in from Pi's own registry, and its Default says it lets Pi pick (#709) — Pi's native options came from models.dev by provider id, and models.dev has no openai-codex (Pi's "OpenAI Codex (legacy)" ChatGPT sign-in), so a Pi signed in to both openai and openai-codex was offered openai/… only. Pi's (and OmO's) own options now come first from the model registry in the package Pi was installed from: the pi command on PATH leads to @earendil-works/pi-coding-agent, and pi-ai's dist/providers/data/<provider>.json (Pi 1.0) is read as is, in its order, chat models only (no gpt-image-2), memoized by the file's stamp — the list Pi's /model offers, which moves with every Pi update. A provider the registry doesn't have keeps models.dev's list; openai-codex with no registry in reach falls back to Codex CLI's models_cache.json (the same ChatGPT backend); models.dev's openai list isn't mapped onto it. The rows are openai-codex/<model> under "OpenAI Codex" with OpenAI's logo, a row each beside openai/<model> of the same name; picking one writes defaultProvider=openai-codex, defaultModel=<model> as before. omp shared the gap for its current model's provider (ownOptions): it now reads omp's own catalog (@oh-my-pi/pi-catalog src/models.json, non-chat kinds left out); omp's signed-in providers that aren't the current one are still #341's. Default in Pi's and OmO's model picker now says "clears the default model; Pi picks one on its own" (zh 清除显式默认模型,由 Pi 自动选择; no ja table exists), other agents' still say what they ship with. TestPiOffersItsOwnOpenAICodexModels (a fake npm-linked Pi 1.0 install, temp HOME and PI_CODING_AGENT_DIR, auth.json with openai and openai-codex oauth test metadata), TestPiOpenAICodexWithoutItsRegistry and TestOmpOffersItsOwnOpenAICodexModels fail on the old code (no openai-codex rows) and pass; pi-default-note.test.cjs (webkit, en/zh) fails on the old app.js and passes; agent-disconnect, agent-models and agent-model-groups GUI tests pass. Read-only against this machine's real installs: Pi 1.0.0 gives openai-codex 9 models and openai 44, omp's catalog openai-codex 8. go vet, builds (darwin, GOOS=linux, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass but TestProvidersAnswerWhileListsComeIn, TestClaudeSignedOut, TestClaudeAccountNamedAsItsLogin and TestClaudeIdentityServedWhileAsked, timing tests that pass alone. Not tried in the GUI with real Pi sign-ins, nor with a Pi older than 1.0 (no data folder: models.dev and Codex CLI's list as before) or a Windows npm shim.
2026-10-04 01:53:58 +08:00
agent: an omp in WSL under NAT gets the gateway's network key, and one bun installed is found and asked its version (whqtian on Discord: a WSL omp connected only once auth: none was swapped for the key by hand, and Kimi K3's max still read xhigh) — a distro not in mirrored networking reaches the gateway at Windows' address (172.23.80.1), where a request without a named key is turned away, yet magpie wrote auth: none there too. Its models.yml now carries the key the gateway is shared on the network with (access.LANSecret: the default LAN key, "" while nothing is shared or it is off) in place of auth: none; an omp on loopback stays keyless. The probe asked omp its version only when sh -l found it on PATH, but bun's and nvm's installers put theirs on PATH in ~/.bashrc, which sh -l doesn't read: the version stayed unknown and max was offered as xhigh, as for an omp older than 16.4.0. It now also looks in ~/.bun/bin, ~/.local/bin, ~/.npm-global/bin, ~/.volta/bin, pnpm's, nvm's, mise's and asdf's folders, and runs --version with the command's folder on PATH, where bun's #!/usr/bin/env bun finds bun. TestOmpKeyBeyondLoopback (NAT address shared or not, loopback, localhost) and TestWSLProbeFindsBunOmp (the probe script run with a bun-installed omp off PATH; fails on the old script: no bin, no version). go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass but for TestSavedButSignedOutClaudeServed, which timed out once under load and passes 3 of 3 alone.
2026-10-05 14:40:49 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
agent: an omp in WSL under NAT gets the gateway's network key, and one bun installed is found and asked its version (whqtian on Discord: a WSL omp connected only once auth: none was swapped for the key by hand, and Kimi K3's max still read xhigh) — a distro not in mirrored networking reaches the gateway at Windows' address (172.23.80.1), where a request without a named key is turned away, yet magpie wrote auth: none there too. Its models.yml now carries the key the gateway is shared on the network with (access.LANSecret: the default LAN key, "" while nothing is shared or it is off) in place of auth: none; an omp on loopback stays keyless. The probe asked omp its version only when sh -l found it on PATH, but bun's and nvm's installers put theirs on PATH in ~/.bashrc, which sh -l doesn't read: the version stayed unknown and max was offered as xhigh, as for an omp older than 16.4.0. It now also looks in ~/.bun/bin, ~/.local/bin, ~/.npm-global/bin, ~/.volta/bin, pnpm's, nvm's, mise's and asdf's folders, and runs --version with the command's folder on PATH, where bun's #!/usr/bin/env bun finds bun. TestOmpKeyBeyondLoopback (NAT address shared or not, loopback, localhost) and TestWSLProbeFindsBunOmp (the probe script run with a bun-installed omp off PATH; fails on the old script: no bin, no version). go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass but for TestSavedButSignedOutClaudeServed, which timed out once under load and passes 3 of 3 alone.
2026-10-05 14:40:49 +08:00
agent: an omp in WSL under NAT gets the gateway's network key, and one bun installed is found and asked its version (whqtian on Discord: a WSL omp connected only once auth: none was swapped for the key by hand, and Kimi K3's max still read xhigh) — a distro not in mirrored networking reaches the gateway at Windows' address (172.23.80.1), where a request without a named key is turned away, yet magpie wrote auth: none there too. Its models.yml now carries the key the gateway is shared on the network with (access.LANSecret: the default LAN key, "" while nothing is shared or it is off) in place of auth: none; an omp on loopback stays keyless. The probe asked omp its version only when sh -l found it on PATH, but bun's and nvm's installers put theirs on PATH in ~/.bashrc, which sh -l doesn't read: the version stayed unknown and max was offered as xhigh, as for an omp older than 16.4.0. It now also looks in ~/.bun/bin, ~/.local/bin, ~/.npm-global/bin, ~/.volta/bin, pnpm's, nvm's, mise's and asdf's folders, and runs --version with the command's folder on PATH, where bun's #!/usr/bin/env bun finds bun. TestOmpKeyBeyondLoopback (NAT address shared or not, loopback, localhost) and TestWSLProbeFindsBunOmp (the probe script run with a bun-installed omp off PATH; fails on the old script: no bin, no version). go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass but for TestSavedButSignedOutClaudeServed, which timed out once under load and passes 3 of 3 alone.
2026-10-05 14:40:49 +08:00
agent: the disconnect preview right on Windows, and the Codex panel says what connecting does (owner: 去 Windows 测试机上测一下 / 是不是需要界面上解释一下现在的逻辑) — on the Windows test box Claude Code's and OpenCode's disconnect previews were empty though both were connected. Claude: the dry run's temporary home has no ~/.codex/auth.json, so a codex/… model wasn't magpie's there; the magpie asking now writes the providers it has on into that home and the dry run takes their models as magpie's (TestDryRunKnowsTheAskersProviders). OpenCode: magpie/codex/gpt-6.1-sol, a model its copy of magpie's list didn't have yet, read as not connected and Disconnect left it on magpie; a magpie/… value whose model magpie routes is magpie's (TestOpenCodeOnAModelNotInItsList). The preview pairs a line going back only with one as deep (Claude's model, not a modelPicker row) and doesn't mask …_TOKENS counts. The Codex panel, joined: 「重开 Codex 后,/model 里自己的模型照旧,magpie 的模型也在里面。」, and 新会话默认 says 「和 Codex 的 /model 是同一个选择,在哪边改都行」 rather than 「不设就用 Codex 自己上次的选择」 beside a value (/api/state: joined). On Windows (sandbox USERPROFILE/APPDATA, real accounts): previews for Claude, OpenCode, Codex and Gemini; disconnecting all four restored them (Claude back to opus, Gemini to Google sign-in, Codex keeps its [model_providers.magpie] by design), real ~/.claude untouched; real Claude Code requests via yylx/claude-opus-5-5 and codex/gpt-5.5 answered. The new tests fail on the old code. go vet, builds (darwin, GOOS=linux, GOOS=windows), go test -tags nogui -count=1 ./... under a temp HOME and the 34 agent GUI tests pass but cli-update, menu-scroll and old-webkit, which fail on main too.
2026-10-04 02:05:10 +08:00
agent: an agent's own provider named as one of magpie's isn't magpie's, in every agent that spells a model provider/model (the rest of #835) — OpenHanako's own deepseek/deepseek-v4-pro read as magpie's deepseek, and so did a model of any agent's own provider whose name magpie has a provider by: Pi's, Crush's, Hermes's, OpenCode's relay/glm-4.6 with magpie's relay had the row connected on the agent's own model, and Disconnect from magpie put that model back and left the row connected. An agent says how magpie's values are spelled in it (Spelled, replacing #835's Prefixed): magpie/<ref> for Antigravity CLI, Pi, OmO, Aside, Goose, Zed, VS Code, Crush, DeepSeek Harness, Command Code, fx, omp, Hermes, Mister Morph, Kimi Code, Empryo, MiniMax Code, Droid, Qoder, Qoder CN, Grok Build, AtomCode, Cline and OpenHanako, whose every Get spells magpie's so (a sandbox Set of magpie/relay/glm-4.6 read back as that in each); for OpenCode, MiMo Code and OpenChamber also a provider of the config's own that sends to magpie's gateway, as openCodeRef names a model there. A stopped WSL distro's agent keeps its live one's. Left as they are: Claude Code, Claude Desktop, Codex, Gemini CLI, Cursor, Copilot, Devin (magpie's are bare refs there), Muse Code (a model with / is magpie's by design: Meta's have none), Alma (its own are providerId:model), Air (magpie's only). TestOwnProviderNamedAsMagpies (26 agents: own relay/glm-4.6 not connected, Connect, Disconnect puts it back and the row is off) fails on the old code in each; TestOpenCodeGatewayProviderIsMagpies. go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass.
2026-10-05 06:49:45 +08:00
agent: OpenCode is told a magpie model reasons when it thinks with no levels to pick, or has low, medium and high (#725, Sun1090: OpenCode's tooltip for mimo-v2.6-flash-free · opencode-zen said 推理: 不支持推理, where OpenCode's own Zen says it reasons) — the opencode block magpie writes into opencode.json never set reasoning, and OpenCode 1 (1.18.34, npm's latest) takes a model of a provider models.dev doesn't list (magpie) as reasoning only when the config says so (provider.ts: model.reasoning ?? false). models.dev lists Zen's mimo-v2.6-flash-free reasoning: true with no reasoning_options, so it has no levels, and magpieModels didn't hand agents the entry's Reasoning (the flag #402 added for /v1/models), so nothing could say it thinks. magpieModels now carries Reasoning, and OpenCode's block (and its WSL, mimocode and OpenChamber forms) sets "reasoning": true through openCodeReasons: a model that thinks with no levels, or one whose levels hold low, medium and high. OpenCode 1 adds low, medium and high of its own to a reasoning model's variants (ProviderTransform.variants, merged under the config's), checked under a sandbox HOME with 1.18.34's opencode models magpie --verbose: reasoning true with variants {} lists low, medium, high, and with low and max lists low, medium, high, max. So a model with other levels (deepseek-v4-flash-free's low, high, max) is left unmarked, as before, rather than offered levels it doesn't have; a "disabled" variant would hide them in 1 but OpenCode 2 (OpenChamber's) reads it as a variant of its own. A levelless thinker gets low, medium and high, as under OpenCode's own provider, and the gateway asks a model with a thinking switch alone no more than high (fitFor). OpenCode 2 doesn't read the flag. TestOpenCodeZenModelReasons (Zen's models from a models.dev cache: mimo-v2.6-flash-free and laguna-s-2.1-free marked, deepseek-v4-flash-free and ling-2.6-flash-free not) fails on the old code and passes. go vet, builds (darwin, GOOS=linux, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass. Not tried in the reporter's OpenCode app; OpenCode reads its config at start, so one already open shows it after it is reopened.
2026-10-04 07:21:48 +08:00
agents: Pencil (pen.dev) is an agent magpie sets up, its custom models in ~/.pencil/models.json (徐小小 on Discord: Pencil keeps its custom model file at ~/.pencil/models.json, in Pi's format) — Pencil's settings take a custom provider on OpenAI Completions, OpenAI Responses or Anthropic Messages (docs.pen.dev, Authentication), Pi's openai-completions, openai-responses and anthropic-messages, set for the provider as a whole, and its models.json is Pi's: {"providers":{"<id>":{"name","baseUrl","api","models":[{"id","name","reasoning","input","cost":{input,output,cacheRead,cacheWrite},"contextWindow","maxTokens","compat"}]}}}. The new pencil agent (pencil.go) adds magpie there as the provider "magpie": baseUrl the gateway's /v1, api openai-completions, apiKey magpie-pencil (its User-Agent isn't known, so its requests are told by the key), and every model as Pi's entry — Pi's model loop is now piModelJSON, shared — without a model's own api and baseUrl, which Pi reads but Pencil's own editor never writes, so every model goes to the gateway's Chat endpoint whatever Pencil makes of them; each model carries every field Pencil writes for one, Pi's defaults (128K window, 16K out) where magpie knows none, no cost and an empty compat. The model is picked in Pencil's agent composer, not in a file known to magpie, so its field is "provider", as for WorkBuddy and ZCode: whether magpie's models are in Pencil's picker; the user's other providers, their keys and Pencil's other keys stay, off takes only magpie's out, and the catalog sync rewrites it only where it is. It is found by ~/.pencil (the app's and pen.dev's CLI's) or, on a Mac, Pencil.app / pen.dev.app in /Applications or ~/Applications; not by a command, pencil and pen being common names. After a change it asks for Pencil to be restarted when Pencil is running (and always on Windows, where that can't be told): whether it reloads models.json on its own isn't known. No official icon with a licence that allows it was found, so it has the generic one. Nothing of Pencil's was downloaded or run; whether Pencil reads a model's thinkingLevelMap, a settings file naming a default model, and its paths on Windows and Linux (taken as ~/.pencil, as Node's homedir gives) aren't verified. TestPencilModels (the reporter's file with a key and a key of Pencil's: kept through on, sync and off; magpie's provider decoded strictly as Pencil's format, every model's fields of their types, no per-model api or baseUrl; found only with ~/.pencil; among All()) and TestStateListsPencil (the page's state lists Pencil with its provider field once ~/.pencil is there, not before) fail without the change. go vet ./internal/..., go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui -count=1 ./... under a temp HOME pass (TestClaudeSignedOut failed once on its 5 s wait, passes alone; untouched).
2026-10-02 14:43:06 +08:00
agents: Pencil (pen.dev) is an agent magpie sets up, its custom models in ~/.pencil/models.json (徐小小 on Discord: Pencil keeps its custom model file at ~/.pencil/models.json, in Pi's format) — Pencil's settings take a custom provider on OpenAI Completions, OpenAI Responses or Anthropic Messages (docs.pen.dev, Authentication), Pi's openai-completions, openai-responses and anthropic-messages, set for the provider as a whole, and its models.json is Pi's: {"providers":{"<id>":{"name","baseUrl","api","models":[{"id","name","reasoning","input","cost":{input,output,cacheRead,cacheWrite},"contextWindow","maxTokens","compat"}]}}}. The new pencil agent (pencil.go) adds magpie there as the provider "magpie": baseUrl the gateway's /v1, api openai-completions, apiKey magpie-pencil (its User-Agent isn't known, so its requests are told by the key), and every model as Pi's entry — Pi's model loop is now piModelJSON, shared — without a model's own api and baseUrl, which Pi reads but Pencil's own editor never writes, so every model goes to the gateway's Chat endpoint whatever Pencil makes of them; each model carries every field Pencil writes for one, Pi's defaults (128K window, 16K out) where magpie knows none, no cost and an empty compat. The model is picked in Pencil's agent composer, not in a file known to magpie, so its field is "provider", as for WorkBuddy and ZCode: whether magpie's models are in Pencil's picker; the user's other providers, their keys and Pencil's other keys stay, off takes only magpie's out, and the catalog sync rewrites it only where it is. It is found by ~/.pencil (the app's and pen.dev's CLI's) or, on a Mac, Pencil.app / pen.dev.app in /Applications or ~/Applications; not by a command, pencil and pen being common names. After a change it asks for Pencil to be restarted when Pencil is running (and always on Windows, where that can't be told): whether it reloads models.json on its own isn't known. No official icon with a licence that allows it was found, so it has the generic one. Nothing of Pencil's was downloaded or run; whether Pencil reads a model's thinkingLevelMap, a settings file naming a default model, and its paths on Windows and Linux (taken as ~/.pencil, as Node's homedir gives) aren't verified. TestPencilModels (the reporter's file with a key and a key of Pencil's: kept through on, sync and off; magpie's provider decoded strictly as Pencil's format, every model's fields of their types, no per-model api or baseUrl; found only with ~/.pencil; among All()) and TestStateListsPencil (the page's state lists Pencil with its provider field once ~/.pencil is there, not before) fail without the change. go vet ./internal/..., go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui -count=1 ./... under a temp HOME pass (TestClaudeSignedOut failed once on its 5 s wait, passes alone; untouched).
2026-10-02 14:43:06 +08:00
agents: Pi's model picker lists the models of its openai-codex sign-in from Pi's own registry, and its Default says it lets Pi pick (#709) — Pi's native options came from models.dev by provider id, and models.dev has no openai-codex (Pi's "OpenAI Codex (legacy)" ChatGPT sign-in), so a Pi signed in to both openai and openai-codex was offered openai/… only. Pi's (and OmO's) own options now come first from the model registry in the package Pi was installed from: the pi command on PATH leads to @earendil-works/pi-coding-agent, and pi-ai's dist/providers/data/<provider>.json (Pi 1.0) is read as is, in its order, chat models only (no gpt-image-2), memoized by the file's stamp — the list Pi's /model offers, which moves with every Pi update. A provider the registry doesn't have keeps models.dev's list; openai-codex with no registry in reach falls back to Codex CLI's models_cache.json (the same ChatGPT backend); models.dev's openai list isn't mapped onto it. The rows are openai-codex/<model> under "OpenAI Codex" with OpenAI's logo, a row each beside openai/<model> of the same name; picking one writes defaultProvider=openai-codex, defaultModel=<model> as before. omp shared the gap for its current model's provider (ownOptions): it now reads omp's own catalog (@oh-my-pi/pi-catalog src/models.json, non-chat kinds left out); omp's signed-in providers that aren't the current one are still #341's. Default in Pi's and OmO's model picker now says "clears the default model; Pi picks one on its own" (zh 清除显式默认模型,由 Pi 自动选择; no ja table exists), other agents' still say what they ship with. TestPiOffersItsOwnOpenAICodexModels (a fake npm-linked Pi 1.0 install, temp HOME and PI_CODING_AGENT_DIR, auth.json with openai and openai-codex oauth test metadata), TestPiOpenAICodexWithoutItsRegistry and TestOmpOffersItsOwnOpenAICodexModels fail on the old code (no openai-codex rows) and pass; pi-default-note.test.cjs (webkit, en/zh) fails on the old app.js and passes; agent-disconnect, agent-models and agent-model-groups GUI tests pass. Read-only against this machine's real installs: Pi 1.0.0 gives openai-codex 9 models and openai 44, omp's catalog openai-codex 8. go vet, builds (darwin, GOOS=linux, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass but TestProvidersAnswerWhileListsComeIn, TestClaudeSignedOut, TestClaudeAccountNamedAsItsLogin and TestClaudeIdentityServedWhileAsked, timing tests that pass alone. Not tried in the GUI with real Pi sign-ins, nor with a Pi older than 1.0 (no data folder: models.dev and Codex CLI's list as before) or a Windows npm shim.
2026-10-04 01:53:58 +08:00
pi: magpie's models carry their cost, and a prompt-cache lifetime where Pi's request is relayed as it is (#781, Kenoia: Pi's cacheWarming never warmed a magpie model, "cache lifetime unavailable", and every cost was zero) — Pi weighs warming a model's cache by its cost and promptCache, and magpie's models.json entries had neither. Each entry now has cost (input, output, cacheRead, cacheWrite in USD per million) at what a call costs the user, as the usage pages count it (provider.EffectivePriceIn: the user's own price, else the provider's list price, else its maker's); a group is priced when every member costs the same and none runs in a fast mode, else it is left without. promptCache is declared only where the gateway relays Pi's request as sent, at the short end of what the vendor publishes: a Claude on Anthropic's Messages API {short 300, long 3600} (5 minutes, or an hour with a 1h cache_control), a GPT on OpenAI's Responses API {short 300} (24h retention is only some models'); a Claude subscription, which runs through Claude Code and caches on its own, and other vendors declare none. With a copy of the owner's real config, 109 of 201 entries got a cost (OpenAI API GPTs, OpenRouter, DeepSeek, groups such as auto-gpt-6-sol, auto-claude-opus-5-5, auto-kimi-k3), the OpenAI API's 24 GPTs on openai-responses got promptCache {short 300}, and groups with mixed members (test, semantic) none. TestPiCostAndPromptCache fails on the old code. go vet, builds (darwin, GOOS=linux, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass.
2026-10-04 18:53:41 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +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
gui: the header's refresh reads again what the page shown draws, and no longer looks for a newer magpie (evilgaoshu, #844: 顶部刷新按钮按直觉应该是「刷新当前页面」,检查更新是低频操作,不必占用顶部一个常驻按钮) — the round ↻ refreshed the model lists and checked for an update whatever page was shown. Now on Agents it looks for the agents on this computer again: POST /api/agents/rescan (agent.Rescan forgets the answers kept a while because asking was slow: Cursor Private Inference's apps folder, WSL's distro list and failed probes, Alma's server) and draws the list, Install another agent and the CLI versions afresh, so one just installed or removed, or changed outside magpie, shows at once. On Usage it reads the page now, the allowances too (as its Refresh now); in the panel, Agents rescans, Allowances reads the allowances and Usage the requests; on Providers and every other page it refreshes the model lists as before. Its tooltip says what it reads on the page shown (zh, ja, de strings). A newer magpie is looked for by magpie's own timer and Settings › About's Check, as before. TestRescanLooksAgain (an app installed after magpie looked is found only after the half minute without it) and refresh-page.test.cjs (WebKit, en and zh, window and panel: tooltip per page, Agents rescans and a new agent shows and leaves Install another agent, Usage reads the allowances afresh, Providers syncs, never an update check, no click moves the page) fail on the old code; sync-update.test.cjs, which asserted the old update check, is replaced by it. sync-spin, update-hide, update-check, click-scroll, gui-ja, gui-de, usage-card-refresh and agent-update-all pass on WebKit. go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass.
2026-10-05 09:26:30 +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
gateway: every full id of a Claude family Claude Code names goes to its tier's model, served by a provider of the user's or not (KevinXC on Discord, v0.1.665, T3 Code 0.0.45 over Claude Code 2.1.287: claude-haiku-4-5, claude-opus-5, claude-fable-5 and claude-sonnet-4-6 went to the haiku/opus/fable/sonnet tiers, but claude-fable-5-1, claude-sonnet-5 and claude-sonnet-5-5 went to the Claude account, 429 "requires usage credits" / "weekly limit") — the stand-in (4cbd96a3) was only asked for a model magpie shows no entry for, so a full id a provider of the user's serves bare (the Claude account lists claude-sonnet-5, claude-fable-5-1, …; a found auto-<model> group has it too) went there, while one none listed went to the tier: which tier a model reached depended on what the user's providers happen to list, not on the model. T3 Code names every model by its full id rather than Claude Code's alias, so it hit both. Now an id of the opus, sonnet, haiku or fable family (claudeFamily: claude-<family>-<any version>[-date][1m], and claude-3-5-sonnet-… alike, so a release magpie has never heard of is one too) from Claude Code routed through magpie goes to the model its tier is set to before groups or providers are looked at, count_tokens counting it there too. Kept as asked: a provider's "anth/claude-…", another agent's request, Claude Code not routed through magpie (StandIn says nothing), a routing group of the user's own named by the id (one magpie found, auto-…, was never picked for it), and the main model when Claude Code's ANTHROPIC_MODEL is that very id. A tier at an effort of its own (#536, "fake/sol:high[1m]") now reaches its model at that level through a stand-in too, where it was looked up whole and refused. TestClaudeTierStandInByFamily (claude-haiku-4-5, -20251001, claude-haiku-5, claude-opus-5, -5-5, -5-5[1m], claude-opus-6, claude-fable-5, -5-1, -5-1[1m], claude-sonnet-4-6, -5, -5-5, -5-5-20261001, claude-3-5-sonnet-20241022 through /v1/messages, beside a provider serving seven of them bare) fails without the change for the nine served ones; TestClaudeStandIn gains the families and the main model. go vet ./internal/..., go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui -count=1 ./... under a temp HOME pass (TestDevinSignedInOnlyInMagpie, a known flake, aside).
2026-10-02 23:50:42 +08:00
models: Provider in model names has a third way, a name the user gave used just as they wrote it (#92 marsxxl: v0.1.591 的 Codex 下拉里自定义名称又带上了 · WorkBuddy / · Claude Code) — 559ce021 (#203) had a custom name keep " · <provider>" after it like any other, so "Opus 5.5" read "Opus 5.5 · Claude Code" in every list Labels feeds (Codex's model_catalog_json and the gateway's Codex /models, Pi's, OpenCode's, ZCode's, OMP's, Muse's), while #92 had been promised the name as written. Both are kept: the setting is now Off / Not on names I set (自定义名称不带供应商) / On. On stays the default and keeps #203's behaviour, so nobody's list changes unasked; own leaves a name the user gave as it is and a vendor's name with its provider's; off is #335's plain names. Stored as plainOwnNames beside plainNames, so a settings.json of before reads as it did (plainNames: true is off). POST /api/settings/plain-names takes mode on|own|off (a body of on alone still works), magpie model suffix on|own|off, a Settings save keeps it, and /v1/models' magpie_label now follows the setting through Labels as the agents' lists do. The row's hint is one line that fits (en, zh), and its zh name says 供应商 as the rest of the app. Prompts and headers are unchanged. TestSuffixMode, TestSuffixModesReachAgentFiles (Codex model_catalog_json and Pi models.json), TestModelsListSuffixModes (/v1/models magpie_label) and model-suffix-own.test.cjs (Chromium and WebKit, en and zh) fail without the change; TestModelName and TestModelNameAndLevelsReachAgentFiles keep #203's assertions. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestConfiguredModelsAdvertiseImageInput load-flaky, passes alone); plain-names, click-scroll, old-webkit pass.
2026-10-01 23:20:57 +08:00
perf: magpie opens and shows the Agents page in a fraction of the time it took (Junjie Zhou on Discord: 8 个 agent 30 个 provider … 每次我打开的时候都会很慢,要好几秒。setting 页面秒进后 我切换到 agent 就有问题) — at start, writing the agents' model lists (agent.SyncCatalog) built every provider's catalog thousands of times with nothing held, each build reading migrations.json, settings and groups again: 6000+ file reads and ~8.5s of CPU in the first 8s with the owner's 30-odd providers, all competing with the first /api/state and the Agents page. Now SyncCatalog, magpieModels and main's start-up moves run under provider.Hold, migrations, groups, settings and a provider's fetched models are held for a second like the rest, and filememo.Hold lets a GET /api/* not stat a file it confirmed unchanged within the last second (any magpie write, Changed() or a recent mtime still reads it again). A big ~/.codex/config.toml parsed in quadratic time (the TOML parser's Shape counts newlines from the start for every key): a 3 MB one took 5.4s, now 0.04s (tomlShaper). theInstalled reads through edit.Read's memo. Measured with a copy of the owner's magpie config and agent configs under a sandbox HOME, the real server in WebKit: CPU in the first 8s 8.59s → 0.39s, page up 475 → 75ms, Agents rows drawn 775 → 325ms after start; the agents' written model files are unchanged (pi byte for byte, opencode the same models). TestTOMLShaperMatchesParser, TestTOMLBigFileParsesInLinearTime (fails on the old code), TestHold (filememo), TestHoldReadsMigrationsOnce. go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui ./... under a temp HOME pass.
2026-10-05 03:02:40 +08:00
test: every package's tests pass on Windows, and none writes outside its sandbox (the user: 把 Windows 上那几个失败的测试修掉) — on a Windows box the suite failed in most packages, and the root package hung for 25 minutes. Tests set HOME, which os.UserHomeDir ignores on Windows (it reads USERPROFILE), so they read and wrote the runner's own home; each now sets USERPROFILE beside HOME, and Devin's, Goose's, Crush's and Claude Desktop's tests set APPDATA/LOCALAPPDATA, where those keep their files there. said() read the command's output only once it returned, and a pipe holds a few KB on Windows, so magpie model --help blocked forever; it reads while the command writes. Unix permission bits (the gateway key store's 0600 too), exec bits and symlinks Windows lacks are checked only off Windows; TOML strings hold Windows paths as literal strings, JSON as marshalled ones; a URL's path is compared as one. The provider and usage packages run in a home of their own (TestMain, as the gateway's already does), since a CLI's identity kept by a refresh still going when its test ended landed in the runner's ~/.config/magpie — and on a Mac in the user's own. Two product fixes came out of it: imagemcp took a file:///C:/… root or image for the path /C:/…, which doesn't exist on Windows, and now makes a Windows path of it (a host for a UNC share); and session discovery could keep a new Cowork session hidden on Linux, where a folder's mtime is a kernel tick and its size doesn't change, so an entry added within the tick of the last listing left both as they were — a listing made within 2s of its folder's last change is read again, as git does for racy files. TestFilePath and TestRacyDirectoryListedAgain fail without the change. On Windows 11 every package passes (32 of 32) and a run of each package in a fresh home leaves nothing in home, APPDATA or LOCALAPPDATA; on Linux (WSL) and macOS go test -tags nogui ./... passes. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:15:07 +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
agents: each agent's CLI shows its version and updates in one click (#202 JoeyMa-zh: Agents 页面增加"更新 CLI"功能 — 检查各 agent CLI 的版本并一键更新) — the Agents page now puts each CLI's installed version after its name (read with <cli> --version, 10s timeout, no stdin) and, when a newer one is out and magpie can tell how it was installed, a small "Update to x.y.z" pill. How it was installed comes from the resolved binary: the vendor's own installer first (Claude Code's ~/.local/share/claude/versions → claude update, Codex standalone → codex update, ~/.opencode/bin → opencode upgrade), then a global node_modules (bun, pnpm, else npm, run as npm install -g --prefix <prefix> pkg@latest with that prefix's npm, and only where the prefix is writable), then a Homebrew formula or cask allowlisted per agent (brew upgrade [--cask]); anything else shows the version alone, with no button. The latest comes from the npm registry or brew info --json=v2 (no auto-update), cached 6h (15min after a failure); installed versions are cached by the binary's path, size and mtime. GET /api/agents/cli waits at most 3s and says pending, and the page asks again; POST /api/agents/cli/{id} runs the update (one at a time per agent, 10min cap), reads the version again and says so if it did not change, or gives the command's last lines when it fails. The pill goes busy in place and the page never scrolls; not in the tray panel. zh strings added. Tested with a new internal/agent/cliupdate_test.go (version order and parsing; npm/bun/pnpm/brew formula and cask/native installs, a read-only prefix, a local node_modules and unknown binaries in a fake PATH; an update against a fake registry and updater) and a new internal/gui/tests/cli-update.test.cjs in Chromium and WebKit (versions, pills only where magpie can update, row heights, an update with the view scrolled, a failing one, zh). No real update was run. go build (nogui, GOOS=windows, GOOS=linux), go test -tags nogui ./... and the GUI tests pass
2026-09-29 17:56:43 +08:00
agents: each agent's CLI shows its version and updates in one click (#202 JoeyMa-zh: Agents 页面增加"更新 CLI"功能 — 检查各 agent CLI 的版本并一键更新) — the Agents page now puts each CLI's installed version after its name (read with <cli> --version, 10s timeout, no stdin) and, when a newer one is out and magpie can tell how it was installed, a small "Update to x.y.z" pill. How it was installed comes from the resolved binary: the vendor's own installer first (Claude Code's ~/.local/share/claude/versions → claude update, Codex standalone → codex update, ~/.opencode/bin → opencode upgrade), then a global node_modules (bun, pnpm, else npm, run as npm install -g --prefix <prefix> pkg@latest with that prefix's npm, and only where the prefix is writable), then a Homebrew formula or cask allowlisted per agent (brew upgrade [--cask]); anything else shows the version alone, with no button. The latest comes from the npm registry or brew info --json=v2 (no auto-update), cached 6h (15min after a failure); installed versions are cached by the binary's path, size and mtime. GET /api/agents/cli waits at most 3s and says pending, and the page asks again; POST /api/agents/cli/{id} runs the update (one at a time per agent, 10min cap), reads the version again and says so if it did not change, or gives the command's last lines when it fails. The pill goes busy in place and the page never scrolls; not in the tray panel. zh strings added. Tested with a new internal/agent/cliupdate_test.go (version order and parsing; npm/bun/pnpm/brew formula and cask/native installs, a read-only prefix, a local node_modules and unknown binaries in a fake PATH; an update against a fake registry and updater) and a new internal/gui/tests/cli-update.test.cjs in Chromium and WebKit (versions, pills only where magpie can update, row heights, an update with the view scrolled, a failing one, zh). No real update was run. go build (nogui, GOOS=windows, GOOS=linux), go test -tags nogui ./... and the GUI tests pass
2026-09-29 17:56:43 +08:00
agent: an omp in WSL under NAT gets the gateway's network key, and one bun installed is found and asked its version (whqtian on Discord: a WSL omp connected only once auth: none was swapped for the key by hand, and Kimi K3's max still read xhigh) — a distro not in mirrored networking reaches the gateway at Windows' address (172.23.80.1), where a request without a named key is turned away, yet magpie wrote auth: none there too. Its models.yml now carries the key the gateway is shared on the network with (access.LANSecret: the default LAN key, "" while nothing is shared or it is off) in place of auth: none; an omp on loopback stays keyless. The probe asked omp its version only when sh -l found it on PATH, but bun's and nvm's installers put theirs on PATH in ~/.bashrc, which sh -l doesn't read: the version stayed unknown and max was offered as xhigh, as for an omp older than 16.4.0. It now also looks in ~/.bun/bin, ~/.local/bin, ~/.npm-global/bin, ~/.volta/bin, pnpm's, nvm's, mise's and asdf's folders, and runs --version with the command's folder on PATH, where bun's #!/usr/bin/env bun finds bun. TestOmpKeyBeyondLoopback (NAT address shared or not, loopback, localhost) and TestWSLProbeFindsBunOmp (the probe script run with a bun-installed omp off PATH; fails on the old script: no bin, no version). go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass but for TestSavedButSignedOutClaudeServed, which timed out once under load and passes 3 of 3 alone.
2026-10-05 14:40:49 +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
agent: an omp in WSL under NAT gets the gateway's network key, and one bun installed is found and asked its version (whqtian on Discord: a WSL omp connected only once auth: none was swapped for the key by hand, and Kimi K3's max still read xhigh) — a distro not in mirrored networking reaches the gateway at Windows' address (172.23.80.1), where a request without a named key is turned away, yet magpie wrote auth: none there too. Its models.yml now carries the key the gateway is shared on the network with (access.LANSecret: the default LAN key, "" while nothing is shared or it is off) in place of auth: none; an omp on loopback stays keyless. The probe asked omp its version only when sh -l found it on PATH, but bun's and nvm's installers put theirs on PATH in ~/.bashrc, which sh -l doesn't read: the version stayed unknown and max was offered as xhigh, as for an omp older than 16.4.0. It now also looks in ~/.bun/bin, ~/.local/bin, ~/.npm-global/bin, ~/.volta/bin, pnpm's, nvm's, mise's and asdf's folders, and runs --version with the command's folder on PATH, where bun's #!/usr/bin/env bun finds bun. TestOmpKeyBeyondLoopback (NAT address shared or not, loopback, localhost) and TestWSLProbeFindsBunOmp (the probe script run with a bun-installed omp off PATH; fails on the old script: no bin, no version). go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass but for TestSavedButSignedOutClaudeServed, which timed out once under load and passes 3 of 3 alone.
2026-10-05 14:40:49 +08:00
sessions: the Sessions page and local usage read the agents in WSL too, and resume one there through wsl.exe (lgtm on Discord: magpie can't detect the session lists of agents inside WSL?) — on Windows magpie already finds the WSL distros an agent is set up in (internal/agent's wslDistros, the distro user's home as \\wsl.localhost\<distro>\home\<user>), but the session reader only looked at this computer's own ~/.claude, ~/.codex and ~/.pi. Now internal/agent hands those homes to the sessions package (sessions.WSLHomes, set in init, no second discovery), and the sessions of Claude Code, Codex and Pi in each distro are listed beside this computer's, with Session.WSL naming the distro: a "WSL <distro>" badge on the Sessions page's rows and the management page, a WSL line in the details, " · WSL <distro>" in the API's name. Resume runs in the distro: wsl.exe -d '<distro>' --cd '<cwd>' -e sh -lc 'exec ${SHELL:-sh} -lic ''claude --resume <id>''' (the user's own shell, so the agent's PATH is there; no double quotes, which PowerShell 5.1 mangles). Their calls count in local usage (callFiles). Reading a distro over \\wsl.localhost is slow and opening a file in a stopped distro starts it, so the files are listed in the background, at most every 30 s, the listing kept in sessions-wsl.json; the page waits for it only the first time ever (up to 3 s); a stopped distro's sessions stay listed as last read and nothing in it is opened (the parse cache and call shards keep them). magpie doesn't delete a session in WSL: the checkbox and Delete are off for them, with a note to delete them there, and sessions.Delete refuses. OpenCode in WSL isn't read (its SQLite over \\wsl.localhost isn't reliable). zh strings added. TestWSLSessionsListed, TestWSLStoppedDistroKept and TestWSLNoneWithoutHomes (internal/sessions) and TestWSLSessionsOfTheDistro (internal/agent, FakeWSL: a Claude Code session in a fake Ubuntu is listed with its distro and the wsl.exe resume line) fail on the old code and pass. go vet, builds (darwin, GOOS=linux, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass. Not tried on a real WSL with agent sessions: the Windows test box's distros have no Claude Code, Codex or Pi sessions; the resume line wasn't run in PowerShell, and the pages weren't opened in a browser.
2026-10-03 23:55:18 +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
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