yetone
5df609e525
usage: an Antigravity account shows each group of models' 5-hour and weekly allowance, one row a group (a user on Discord: 这里显示5h 和一周剩余比较好吧,现在是只显示5h,这3个模型都是一样的,没必要分开…多加个7day 条就好) — fetchAvailableModels gives each model only its 5-hour figure, the same for every model drawing on one quota, so the Usage page, the panel and the account rows showed a figure a family (Gemini, Claude, GPT-OSS) and no week. Antigravity's retrieveUserQuotaSummary reports the quota a group ("Gemini Models"; "Claude and GPT models", Claude and GPT-OSS sharing one), each with a 5h and a weekly bucket; magpie now reads it beside the models' (best-effort: without it the windows are as before) and adds each group's windows, named "5 hours" and "7 days" with their pool (Gemini, Claude & GPT), each model's window naming its pool. The Usage page shows Gemini · 5 hours, Gemini · 7 days, Claude & GPT · 5 hours, Claude & GPT · 7 days, the pool's models in each tooltip; the panel four rings (Gemini 5h/7d, Claude 5h/7d); the account rows each pool with its 5h and 7d meters; the TUI the pools' windows in place of the models'. "Every model" lists the models' own windows. The pools' windows are aside for routing, which reads the models' as before; the tray's text is unchanged. TestAntigravityQuotaPools and quota-pools.test.cjs (Chromium, WebKit; en, zh) fail without the change; quota-families, click-scroll, old-webkit, tray-usages, panel-usage pass. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-02 07:03:17 +08:00
..
provider: a Command Code Go account lists the models Command Code has for Go, not ten (01huadalang on Discord: command 账号登录只有十个模型,正确的应该是几十个) — for Go, magpie never asked for a list and showed a table of 10, on the word that Command Code has none; its Provider API's list answers without a key (86 models), and its CLI (1.73.0) offers Go every model its picker shows but the premium ones and those it blocks for Go. A Go account now fetches that list without its key, less the 30 refused, and saves it (56 today); the table, the CLI's whole Go set (57), stands in until then or when the fetch fails. Requests still go to /alpha/generate. TestCommandCodeGoModels fails without the change (10 models). go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./internal/provider pass.
2026-10-01 06:15:04 +08:00
providers: each account of a subscription, and each key, can be kept for some of the provider's models only (#474: 增加账号级别的模型选项, a low-quota but verified account kept for the cheap models) — every account or key a provider had served every model it did, so one couldn't be spared for some. An account's or key's row in its provider's editor now has a models badge: a click opens the provider's models as chips, Save keeps the account for those picked, All models gives it every one again; one kept for some says how many, always shown. magpie provider account-models <id> [account|key [models…|all]] does the same and lists them. It is kept in providers.json as accountModels, an account by its name in lower case, a key by its id; one not in it serves every model, as before. The gateway never sends a model to an account or key whose list leaves it out, in every routing mode, in drag order, in a group and as a fallback, and never falls back to it all the same; the trace says it was left out as set to serve other models. When every account or key there is leaves the model out, the request is refused with a 403 saying so and how to change it, not "none of X's models is ready". TestKeyModelsNarrowCandidates, TestAccountModelsNeverChosen, TestAccountModelsCmd and account-models.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; account-models, click-scroll, old-webkit, account-arrange, account-proxy, account-return, routing-account-order, panel-routing, unlisted-models pass.
2026-10-02 05:50:23 +08:00
2026-10-02 03:32:42 +08:00
2026-10-02 03:32:41 +08:00
2026-10-02 03:32:42 +08:00
claude: adding a Claude account is Claude Code's own claude auth login, and magpie never refreshes a Claude sign-in nor asks Anthropic anything with one (the user: 把 magpie 自己的 Claude 登录改成直接用 claude /login,只要体验上没什么差别就改) — magpie traded the sign-in page's code for tokens with Claude Code's OAuth client, asked Anthropic's profile and model list with them, refreshed saved accounts itself (daily keepalive included) and handed a saved account to Claude Code as CLAUDE_CODE_OAUTH_TOKEN. Now Add account runs claude auth login --claudeai in a config directory of magpie's own: the page Claude Code would open comes to magpie's window (Claude Code is given magpie as its BROWSER, which writes the page down and exits), the browser comes back to Claude Code's own listener, and when the browser can't reach this machine the address it ended on, or the code Claude's page shows, is pasted as before and handed to Claude Code. Who signed in is what Claude Code kept (.claude.json, auth status). A saved account in use beside the signed-in one runs Claude Code with CLAUDE_CONFIG_DIR set to its own directory (claude-accounts/ beside magpie's config), its sign-in put there once from logins.json and read back as Claude Code refreshes it; switching to it moves it into Claude Code's own store and removes the directory, as forgetting it does. Claude's models are the catalog's (models.dev), not asked of Anthropic; an imported Claude login is kept as the file has it, and Claude Code refreshes it on first use. Claude Code is required to add a Claude account. TestClaudeSignInByPaste, TestClaudeSignInByPastedAddress, TestClaudeSavedAccountDir (a fake claude CLI, and a server standing in for Anthropic that fails the test if asked) and the reworked sign-in, import and gateway tests fail without the change. With the real Claude Code 2.1.286 in a sandbox directory, its sign-in page (localhost callback) reached magpie's binary and the sign-in waited for the browser; nothing was left behind once it was canceled. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; claude-risk, plugin-signin, signin-callback, signin-link, signin-paste-codex, routing-signin, own-signin-remove, click-scroll, old-webkit pass.
2026-10-01 16:37:07 +08:00
2026-10-02 00:42:48 +08:00
gateway: a conversation stays with the account that answered it across a restart of magpie, and routing goes by each account's last known allowance until the first reading since the start is back (vincentzhang on Discord: in smart routing a restart moved a session to the first account, an update and restart back to the second, and the prompt cache was read by neither) — who answered a conversation last was kept in memory only, so after a restart every conversation was "first" and went to whoever routing put first; and until the accounts' allowances were read again (a first wait of 3s, the read itself up to 30s) none was known, every account counted as unused and the first in order went first, until the reading came back and put the one renewing soonest first again. Who answered is now also kept in affinity.json next to the providers (0600, written atomically, the latest 512 conversations, none older than the 24h a conversation is remembered), read again when a conversation isn't known here and the file changed — after a restart, or written by the magpie handing over. The rules for when a conversation moves are unchanged: within a turn it stays, across turns while the vendor read enough from its cache within the last five minutes, and never to an account resting, all but used up or gone. While the first reading is out, Allowances returns each account's last reading kept in quotas.json, its windows past their reset counted empty. Prompts and headers are unchanged. TestAffinitySurvivesRestart and TestAllowancesBeforeFirstReading fail without the change; TestAffinityFileBounded keeps the file bounded. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestFetchNewLeavesListedPlugins and TestFXInState flake under load on main too, pass alone).
2026-10-01 20:09:25 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
usage: an Antigravity call at a level answered under its model's own name is no swap (#462: gemini-3.8-flash at medium marked Swapped, answered by gemini-3.8-flash) — on an Antigravity account a call at an effort goes out as that level's id (AntigravitySentID: gemini-3.8-flash-medium), and Cloud Code's reply names the family in modelVersion (gemini-3.8-flash), so Swapped compared gemini-3.8-flash-medium with gemini-3.8-flash and the request list and the Routing view tagged the model as swapped for itself. A sent id whose last word is an effort word (provider.EffortFamily: low, medium, high, xhigh, minimal, extra-low, extra-high) now matches a reply naming the id without it; a reply naming another level, or another model, is still a swap. TestLedgerAntigravityReplyNamingTheFamilyIsNoSwap fails without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestClaudeRunEndsWhenTheClientLeaves, a load flake, passes alone).
2026-10-02 02:24:48 +08:00
provider: Azure OpenAI, asked at the user's own resource on its v1 API with the key in api-key, for Codex, Claude Code and chat clients alike, and brought in from other apps instead of left out — Azure OpenAI had no preset, and importing an Azure entry from Alma was skipped with "magpie doesn't support Azure OpenAI yet". A new Azure OpenAI preset (vendor) has no URL of its own: its editor asks for the resource's endpoint in a field above the key, focused first, with https://<resource>.openai.azure.com as the placeholder and a hint on where the portal shows it and that the model ids are the deployments' names (en and zh); adding without one says "Your resource's endpoint is needed" and sends nothing, and Save refuses one without an endpoint too. Whatever is pasted — the bare endpoint, …/openai, …/openai/v1/, a classic deployment URL with its api-version, a *.cognitiveservices.azure.com or *.services.ai.azure.com host, or only the resource's name — is saved as https://<host>/openai/v1 for both chat completions and Responses. magpie uses the v1 GA API rather than the classic /openai/deployments/<name>/…?api-version= paths: the paths match OpenAI's, the body's model is the deployment's name, and no api-version is needed (the reasoning is in internal/provider/azure.go). The key goes in api-key, never as a Bearer, which Azure takes as an Entra ID token; nothing sends Authorization or x-api-key there. Deployments named after GPT/o/codex models go to Responses first, as OpenAI's do, and others to chat completions. Chat bodies ask max_completion_tokens instead of max_tokens and drop thinking/enable_thinking, both in passthrough and in Claude Code's translated requests, and the Test probe asks max_completion_tokens as well. The model list is the resource's deployments (/openai/deployments?api-version=2022-12-01), falling back to /openai/v1/models, with the key in api-key; when neither answers, the error says to type the deployment names in as model ids. Before a list, no catalog models are offered, since a model the resource hasn't deployed would be turned away. An Alma azure entry, and any imported entry at a resource's host, becomes the preset at its v1 base; an Alma azure entry with no endpoint is skipped as "it has no Azure OpenAI endpoint", and one at a non-Azure host (an API Management gateway) keeps its URL and is still signed with api-key. Adds the lobe-icons Azure icon. Tested in Go against fake resources (httptest): TestAzureRoutes checks that Codex /v1/responses, a chat client's /v1/chat/completions and Claude Code's /v1/messages on both a GPT-named and another deployment reach /openai/v1/responses or /openai/v1/chat/completions with api-key set, no Authorization or x-api-key, the deployment name as the model, max_completion_tokens and no thinking; TestAzureBase covers each pasted form and the hosts that aren't resources; TestAzurePresetSaved covers the endpoint required, both URLs on the v1 base, api-key-only headers, Native, the probe's URL and body, and nothing available before a list; TestAzureModels covers deployments first, the v1 fallback and a refused key's message; TestImportAzure covers Alma rows with an endpoint, with a bare resource name and with none, plus a classic URL from another app. azure-endpoint.test.cjs, in Chromium and WebKit, en and zh, checks the field, placeholder, hint and focus, the warning without an endpoint with nothing sent and the page not scrolled, the endpoint sent as chat and responses with the key, and that OpenAI's editor has no such field. add-sheet and old-webkit pass. go build -tags nogui (and GOOS=linux, GOOS=windows), go vet and go test -tags nogui ./... pass (TestClaudeAccountNamedAsItsLogin failed under load and passes alone). Not tried against a real Azure resource: whether a key still lists deployments with api-version 2022-12-01, whether Azure's Responses API accepts every field Codex sends, Claude models on Azure AI Foundry's Anthropic endpoint (not wired), Entra ID tokens, and API Management custom domains beyond keeping their URL. Not tried in the real Wails window.
2026-09-30 02:17:15 +08:00
provider: Azure OpenAI, asked at the user's own resource on its v1 API with the key in api-key, for Codex, Claude Code and chat clients alike, and brought in from other apps instead of left out — Azure OpenAI had no preset, and importing an Azure entry from Alma was skipped with "magpie doesn't support Azure OpenAI yet". A new Azure OpenAI preset (vendor) has no URL of its own: its editor asks for the resource's endpoint in a field above the key, focused first, with https://<resource>.openai.azure.com as the placeholder and a hint on where the portal shows it and that the model ids are the deployments' names (en and zh); adding without one says "Your resource's endpoint is needed" and sends nothing, and Save refuses one without an endpoint too. Whatever is pasted — the bare endpoint, …/openai, …/openai/v1/, a classic deployment URL with its api-version, a *.cognitiveservices.azure.com or *.services.ai.azure.com host, or only the resource's name — is saved as https://<host>/openai/v1 for both chat completions and Responses. magpie uses the v1 GA API rather than the classic /openai/deployments/<name>/…?api-version= paths: the paths match OpenAI's, the body's model is the deployment's name, and no api-version is needed (the reasoning is in internal/provider/azure.go). The key goes in api-key, never as a Bearer, which Azure takes as an Entra ID token; nothing sends Authorization or x-api-key there. Deployments named after GPT/o/codex models go to Responses first, as OpenAI's do, and others to chat completions. Chat bodies ask max_completion_tokens instead of max_tokens and drop thinking/enable_thinking, both in passthrough and in Claude Code's translated requests, and the Test probe asks max_completion_tokens as well. The model list is the resource's deployments (/openai/deployments?api-version=2022-12-01), falling back to /openai/v1/models, with the key in api-key; when neither answers, the error says to type the deployment names in as model ids. Before a list, no catalog models are offered, since a model the resource hasn't deployed would be turned away. An Alma azure entry, and any imported entry at a resource's host, becomes the preset at its v1 base; an Alma azure entry with no endpoint is skipped as "it has no Azure OpenAI endpoint", and one at a non-Azure host (an API Management gateway) keeps its URL and is still signed with api-key. Adds the lobe-icons Azure icon. Tested in Go against fake resources (httptest): TestAzureRoutes checks that Codex /v1/responses, a chat client's /v1/chat/completions and Claude Code's /v1/messages on both a GPT-named and another deployment reach /openai/v1/responses or /openai/v1/chat/completions with api-key set, no Authorization or x-api-key, the deployment name as the model, max_completion_tokens and no thinking; TestAzureBase covers each pasted form and the hosts that aren't resources; TestAzurePresetSaved covers the endpoint required, both URLs on the v1 base, api-key-only headers, Native, the probe's URL and body, and nothing available before a list; TestAzureModels covers deployments first, the v1 fallback and a refused key's message; TestImportAzure covers Alma rows with an endpoint, with a bare resource name and with none, plus a classic URL from another app. azure-endpoint.test.cjs, in Chromium and WebKit, en and zh, checks the field, placeholder, hint and focus, the warning without an endpoint with nothing sent and the page not scrolled, the endpoint sent as chat and responses with the key, and that OpenAI's editor has no such field. add-sheet and old-webkit pass. go build -tags nogui (and GOOS=linux, GOOS=windows), go vet and go test -tags nogui ./... pass (TestClaudeAccountNamedAsItsLogin failed under load and passes alone). Not tried against a real Azure resource: whether a key still lists deployments with api-version 2022-12-01, whether Azure's Responses API accepts every field Codex sends, Claude models on Azure AI Foundry's Anthropic endpoint (not wired), Entra ID tokens, and API Management custom domains beyond keeping their URL. Not tried in the real Wails window.
2026-09-30 02:17:15 +08:00
provider: a providers.json that can't be read is said where the providers are listed, never backed up or synced as none, and is replaced through a rename (PR #415's review) — #415 made edits refuse a file they couldn't read or decode, but every read for the user still took it as empty: magpie providers said "no providers yet", magpie models "no models yet", the Providers page opened the Add sheet as for a first use, and backup.Collect, so an export and a WebDAV/S3 sync, carried it as no providers, which another computer's Mirror would then take as every provider removed. magpie providers and magpie models now list what is left (the signed-in accounts) and end in the error, the TUI says it over its list, and the Providers page shows a "Your providers file can't be read" box (无法读取供应商配置文件) over the list with magpie's reason and no Add sheet; start-up, the gateway and the catalog still go on with it as empty. Stored and StoredGroups return the read error, so a backup and a sync stop on it with nothing pushed. The error, for reads and refused writes alike, names the file, says magpie left it unchanged and to fix it or move it aside (errors.Is ErrUnreadable). store writes through writePrivate, a 0600 temp file renamed over it (steady.Rename waits out a Windows reader holding it, a symlink keeps its target), instead of os.WriteFile's truncate-then-write, and the read goes through steady.ReadFile. TestFileErrorSaysUnreadable, TestWriteErrorsSayLeftUnchanged, TestStoredRefusesUnreadable, TestStoreReplacesAtomically, TestSyncStopsOnUnreadableProviders, TestProvidersCmdSaysUnreadable and provider-file-error.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; provider-file-error, click-scroll, old-webkit, providers-off-fold, add-sheet pass.
2026-10-01 19:45:24 +08:00
provider: a providers.json that can't be read is said where the providers are listed, never backed up or synced as none, and is replaced through a rename (PR #415's review) — #415 made edits refuse a file they couldn't read or decode, but every read for the user still took it as empty: magpie providers said "no providers yet", magpie models "no models yet", the Providers page opened the Add sheet as for a first use, and backup.Collect, so an export and a WebDAV/S3 sync, carried it as no providers, which another computer's Mirror would then take as every provider removed. magpie providers and magpie models now list what is left (the signed-in accounts) and end in the error, the TUI says it over its list, and the Providers page shows a "Your providers file can't be read" box (无法读取供应商配置文件) over the list with magpie's reason and no Add sheet; start-up, the gateway and the catalog still go on with it as empty. Stored and StoredGroups return the read error, so a backup and a sync stop on it with nothing pushed. The error, for reads and refused writes alike, names the file, says magpie left it unchanged and to fix it or move it aside (errors.Is ErrUnreadable). store writes through writePrivate, a 0600 temp file renamed over it (steady.Rename waits out a Windows reader holding it, a symlink keeps its target), instead of os.WriteFile's truncate-then-write, and the read goes through steady.ReadFile. TestFileErrorSaysUnreadable, TestWriteErrorsSayLeftUnchanged, TestStoredRefusesUnreadable, TestStoreReplacesAtomically, TestSyncStopsOnUnreadableProviders, TestProvidersCmdSaysUnreadable and provider-file-error.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; provider-file-error, click-scroll, old-webkit, providers-off-fold, add-sheet pass.
2026-10-01 19:45:24 +08:00
usage: a custom balance's card says when it was read, shows each of its amounts on a line of its own and a percent as a meter (#420 by emo172: 余额卡片显示读取时间、百分比进度条) — a balance read from a provider's own Balance URL showed one line, "Balance $2.00 · Today $2.50 · Used 90%", and nothing said how old it was. magpie now hands the card the amounts the user's expression names, each with its label, and a "%" one's share; the Usage page shows each on a line of its own, the user's label quiet and the first amount the larger, "Balance" only where no label was given, and a percent as the quota meter, amber from 90%. Every card that was read says so, "Updated 3 minutes ago" (3分钟前更新), and one standing in for a reading that failed just now says "As of … — couldn't be read just now" (截至 …,暂时无法获取最新用量), allowance cards too. The menu bar panel's Balances show the same amounts and meter and an amber "As of" (截至), and the tray's tooltip adds "as of …, couldn't be read just now". One amount alone reads as it did, and the balance line, the CLI and the expression syntax are unchanged. No balance URL, path or site is added: /api/usage/token and unlimited_quota are one kind of relay's and stay the user's to write. TestBalanceParts, TestTrayUsageText and balance-parts.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; balance-parts, click-scroll, old-webkit, quota-families, panel-usage, tray-usages, balance-fix, usage-refresh, currency, claude-usage-asked pass.
2026-10-01 19:44:44 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
usage: a custom balance's card says when it was read, shows each of its amounts on a line of its own and a percent as a meter (#420 by emo172: 余额卡片显示读取时间、百分比进度条) — a balance read from a provider's own Balance URL showed one line, "Balance $2.00 · Today $2.50 · Used 90%", and nothing said how old it was. magpie now hands the card the amounts the user's expression names, each with its label, and a "%" one's share; the Usage page shows each on a line of its own, the user's label quiet and the first amount the larger, "Balance" only where no label was given, and a percent as the quota meter, amber from 90%. Every card that was read says so, "Updated 3 minutes ago" (3分钟前更新), and one standing in for a reading that failed just now says "As of … — couldn't be read just now" (截至 …,暂时无法获取最新用量), allowance cards too. The menu bar panel's Balances show the same amounts and meter and an amber "As of" (截至), and the tray's tooltip adds "as of …, couldn't be read just now". One amount alone reads as it did, and the balance line, the CLI and the expression syntax are unchanged. No balance URL, path or site is added: /api/usage/token and unlimited_quota are one kind of relay's and stay the user's to write. TestBalanceParts, TestTrayUsageText and balance-parts.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; balance-parts, click-scroll, old-webkit, quota-families, panel-usage, tray-usages, balance-fix, usage-refresh, currency, claude-usage-asked pass.
2026-10-01 19:44:44 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
claude: the Claude accounts saved in magpie are served while Claude Code is logged out, and none is dropped (StringKe on Discord: CC(API) -> Magpie -> CC Subscription, and as soon as I /logout in Claude Code all six accounts I manage in magpie disappear) — magpie served its saved Claude accounts only beside the one Claude Code was signed in to: claudeAccount gave no provider without Claude Code's own credentials (or with claude auth status saying no one is signed in), so the gateway had no Claude account at all and the page said the saved ones "are only offered beside the account it is signed in to". Claude Code itself tells the user to log out: with magpie's ANTHROPIC_AUTH_TOKEN beside a claude.ai sign-in it warns "ANTHROPIC_AUTH_TOKEN overriding Claude subscription login · unset it or /logout to sign it out". magpie keeps every account's sign-in in logins.json, so a logout now signs none of them out of magpie: the account seen last (the one Claude Code was signed in to until then, which magpie saw every 30s) stands in its place, run in a config directory of its own as the others on are, listed on, and it can be paused behind another as Claude Code's own could; the others on are served behind it, the Usage page reads it as a saved account, and the saved-but-signed-out notice is no longer given for Claude. An account whose saved sign-in is unreadable is listed as signed out ("its sign-in is gone; sign in again"), never dropped, and isn't picked to stand in while another has one. An account signed in in magpie while Claude Code is logged out and magpie has Claude accounts no longer signs Claude Code back in (which only brought back its warning); it is magpie's alone, on, and the one served first till then stays on behind it. Prompts, identity lines and headers are unchanged; magpie still never refreshes a Claude sign-in nor asks Anthropic anything itself. TestClaudeAccountsOutliveLogout, TestClaudeSignInWhileLoggedOut and TestSavedButSignedOutClaudeServed fail without the change; TestSavedButSignedOutCanBeRemoved now removes the account from the list. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestFetchNewLeavesListedPlugins, a bun plugin test, failed once under load and passes alone and in a rerun of the package).
2026-10-01 20:13:58 +08:00
claude: an account's usage keeps itself up to date again, every ten minutes, through Claude Code (the user: 既然 Magpie 不再发任何的 Claude 请求了,轮询可以再加上,只是别那么频繁) — since v0.1.558 the usage was only read when Usage was opened or Refresh pressed, so the figures left open, in the menu bar and for routing went stale. The account Claude Code is signed in to now has its /usage run again by itself once its last reading is ten minutes old (an ask still reads at once, no more than once in 30s); magpie still never asks Anthropic, and a saved account is still never read. A failed run says why until the next one rather than "not read yet". TestClaudeWindowsAsked fails without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; claude-usage-asked, tray-usages, click-scroll, old-webkit pass.
2026-10-01 15:16:34 +08:00
provider: a Claude account's Fable week is read and routed on (#139) — /api/oauth/usage gives a week's allowance per model only in its limits[] array, which readClaudeWindows didn't parse, so magpie accounts, magpie quota and the app never showed Fable's, often the first to run out on Max, and routing went on sending Fable requests to an account whose Fable week was used up. Each weekly_scoped item with a scope.model.display_name is now a window "7 days · <name>", counted in percent, renewing at resets_at, a week long and counting only its model (the name lowercased, spaces and dots as dashes, so "Fable" counts every claude-fable-*), which Allowance.For and Full already weigh against that model alone, as they do the Opus and Sonnet weeks; one without a scope (seven_day again) or one for a model seven_day_opus/seven_day_sonnet already told is left out. Claude Code's rate_limit_event names the same window seven_day_overage_included, its "Fable limit" (in 2.1.283's bundle, for its allowlist Fable, Fable 5, Fable 5.1); claudeKinds takes it too, so the Fable week stays known while the usage endpoint turns magpie away. Reported by Cyb3rN8
2026-09-28 17:12:12 +08:00
claude: the Claude accounts saved in magpie are served while Claude Code is logged out, and none is dropped (StringKe on Discord: CC(API) -> Magpie -> CC Subscription, and as soon as I /logout in Claude Code all six accounts I manage in magpie disappear) — magpie served its saved Claude accounts only beside the one Claude Code was signed in to: claudeAccount gave no provider without Claude Code's own credentials (or with claude auth status saying no one is signed in), so the gateway had no Claude account at all and the page said the saved ones "are only offered beside the account it is signed in to". Claude Code itself tells the user to log out: with magpie's ANTHROPIC_AUTH_TOKEN beside a claude.ai sign-in it warns "ANTHROPIC_AUTH_TOKEN overriding Claude subscription login · unset it or /logout to sign it out". magpie keeps every account's sign-in in logins.json, so a logout now signs none of them out of magpie: the account seen last (the one Claude Code was signed in to until then, which magpie saw every 30s) stands in its place, run in a config directory of its own as the others on are, listed on, and it can be paused behind another as Claude Code's own could; the others on are served behind it, the Usage page reads it as a saved account, and the saved-but-signed-out notice is no longer given for Claude. An account whose saved sign-in is unreadable is listed as signed out ("its sign-in is gone; sign in again"), never dropped, and isn't picked to stand in while another has one. An account signed in in magpie while Claude Code is logged out and magpie has Claude accounts no longer signs Claude Code back in (which only brought back its warning); it is magpie's alone, on, and the one served first till then stays on behind it. Prompts, identity lines and headers are unchanged; magpie still never refreshes a Claude sign-in nor asks Anthropic anything itself. TestClaudeAccountsOutliveLogout, TestClaudeSignInWhileLoggedOut and TestSavedButSignedOutClaudeServed fail without the change; TestSavedButSignedOutCanBeRemoved now removes the account from the list. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestFetchNewLeavesListedPlugins, a bun plugin test, failed once under load and passes alone and in a rerun of the package).
2026-10-01 20:13:58 +08:00
claude: nothing is sent to Anthropic in Claude Code's name any more, and a Claude account's model test runs Claude Code (the user: 先把伪装代码删掉,测试模型改走 CLI) — claude_cloak.go made magpie's own requests on a Claude sign-in look like Claude Code's (its User-Agent, session and device ids, Stainless headers, betas, a billing header with a fingerprint and xxHash in the body). Generations already ran Claude Code through the bridge; the cloak was left driving the provider test (a direct /v1/messages "hi") and the model list. It is gone: a Claude account's direct requests are refused unsigned, the model test has Claude Code answer "hi" at the model tested (the warm-up's run, --model the one tested, a saved account's sign-in as CLAUDE_CODE_OAUTH_TOKEN), and the model list says it is magpie (User-Agent magpie, only the oauth beta). TestClaudeTestRunsThroughClaudeCode and TestClaudeTestRunsClaudeCode fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 11:12:27 +08:00
claude: adding a Claude account is Claude Code's own claude auth login, and magpie never refreshes a Claude sign-in nor asks Anthropic anything with one (the user: 把 magpie 自己的 Claude 登录改成直接用 claude /login,只要体验上没什么差别就改) — magpie traded the sign-in page's code for tokens with Claude Code's OAuth client, asked Anthropic's profile and model list with them, refreshed saved accounts itself (daily keepalive included) and handed a saved account to Claude Code as CLAUDE_CODE_OAUTH_TOKEN. Now Add account runs claude auth login --claudeai in a config directory of magpie's own: the page Claude Code would open comes to magpie's window (Claude Code is given magpie as its BROWSER, which writes the page down and exits), the browser comes back to Claude Code's own listener, and when the browser can't reach this machine the address it ended on, or the code Claude's page shows, is pasted as before and handed to Claude Code. Who signed in is what Claude Code kept (.claude.json, auth status). A saved account in use beside the signed-in one runs Claude Code with CLAUDE_CONFIG_DIR set to its own directory (claude-accounts/ beside magpie's config), its sign-in put there once from logins.json and read back as Claude Code refreshes it; switching to it moves it into Claude Code's own store and removes the directory, as forgetting it does. Claude's models are the catalog's (models.dev), not asked of Anthropic; an imported Claude login is kept as the file has it, and Claude Code refreshes it on first use. Claude Code is required to add a Claude account. TestClaudeSignInByPaste, TestClaudeSignInByPastedAddress, TestClaudeSavedAccountDir (a fake claude CLI, and a server standing in for Anthropic that fails the test if asked) and the reworked sign-in, import and gateway tests fail without the change. With the real Claude Code 2.1.286 in a sandbox directory, its sign-in page (localhost callback) reached magpie's binary and the sign-in waited for the browser; nothing was left behind once it was canceled. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; claude-risk, plugin-signin, signin-callback, signin-link, signin-paste-codex, routing-signin, own-signin-remove, click-scroll, old-webkit pass.
2026-10-01 16:37:07 +08:00
claude: magpie no longer asks Anthropic for a Claude account's usage, and adding a Claude account warns of a ban (the user: 不要伪造任何的 Claude 请求,能否通过 claude cli 获取 / 我害怕被封; 添加账号时要像其他的 Subscription Provider 一样显示风险提示) — the usage was read by magpie itself calling Anthropic's /api/oauth/usage with the account's token, on a timer, for every saved account, and Claude's usage-limit resets (cedar_ember) were listed, spent and auto-spent the same way. Now the usage is what Claude Code's own /usage prints (claude -p /usage, a command Claude Code answers itself without asking a model), run only when Usage is opened or Refresh pressed (GUI, magpie quota, accounts, TUI), for the account Claude Code is signed in to, at most once in 30s; a saved account shows only what Claude Code reported while using it, or the last reading kept. The Claude resets, Auto-use and their settings are gone (Codex's stay). Session jsonl files hold no usage figures, so they aren't read. Starting a Claude sign-in or import (GUI and CLI) first says Anthropic may suspend or ban the account and that it is at the user's own risk. TestClaudeWindowsAsked, TestParseClaudeUsage, TestClaudeUsageRunsClaudeCode, claude-usage-asked.test.cjs and claude-risk.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; routing-auto-reset, codex-auto-reset, quota-families, tray-usages, click-scroll, old-webkit, plugin-signin, usage-alert, usage-ledger pass.
2026-10-01 12:38:25 +08:00
2026-10-02 00:42:48 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
2026-10-01 23:39:33 +08:00
2026-09-29 10:50:39 +08:00
claude: adding a Claude account is Claude Code's own claude auth login, and magpie never refreshes a Claude sign-in nor asks Anthropic anything with one (the user: 把 magpie 自己的 Claude 登录改成直接用 claude /login,只要体验上没什么差别就改) — magpie traded the sign-in page's code for tokens with Claude Code's OAuth client, asked Anthropic's profile and model list with them, refreshed saved accounts itself (daily keepalive included) and handed a saved account to Claude Code as CLAUDE_CODE_OAUTH_TOKEN. Now Add account runs claude auth login --claudeai in a config directory of magpie's own: the page Claude Code would open comes to magpie's window (Claude Code is given magpie as its BROWSER, which writes the page down and exits), the browser comes back to Claude Code's own listener, and when the browser can't reach this machine the address it ended on, or the code Claude's page shows, is pasted as before and handed to Claude Code. Who signed in is what Claude Code kept (.claude.json, auth status). A saved account in use beside the signed-in one runs Claude Code with CLAUDE_CONFIG_DIR set to its own directory (claude-accounts/ beside magpie's config), its sign-in put there once from logins.json and read back as Claude Code refreshes it; switching to it moves it into Claude Code's own store and removes the directory, as forgetting it does. Claude's models are the catalog's (models.dev), not asked of Anthropic; an imported Claude login is kept as the file has it, and Claude Code refreshes it on first use. Claude Code is required to add a Claude account. TestClaudeSignInByPaste, TestClaudeSignInByPastedAddress, TestClaudeSavedAccountDir (a fake claude CLI, and a server standing in for Anthropic that fails the test if asked) and the reworked sign-in, import and gateway tests fail without the change. With the real Claude Code 2.1.286 in a sandbox directory, its sign-in page (localhost callback) reached magpie's binary and the sign-in waited for the browser; nothing was left behind once it was canceled. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; claude-risk, plugin-signin, signin-callback, signin-link, signin-paste-codex, routing-signin, own-signin-remove, click-scroll, old-webkit pass.
2026-10-01 16:37:07 +08:00
provider: Cursor stays listed when cursor-agent can't say who is signed in (cataglyphis: 供应商选型中间歇无法显示 cursor,导致路由里不能正常路由到 cursor 的模型) — who Cursor's account is comes from cursor-agent about --format json, asked again behind the served answer every minute, and any about that failed, ran past its 10s (it asks Cursor's servers), or printed something besides its JSON was taken for nobody signed in: Cursor dropped out of the Providers page and of routing (All() lists the accounts for both), and that was kept on disk, until an ask a minute or more on came back. Now an ask that couldn't tell leaves what was served, on disk too, and is asked again in a minute (cliIdentity's ask returns an error for that); Cursor is taken as signed out only when about says so in its JSON or cursor-agent keeps no token. About's JSON after a line of its own (an update notice) is read too. Devin's ask is as before. Tested with fake cursor-agent scripts in a temp HOME (signed in, update notice, says nobody, fails, no JSON, fails with the token gone) and the cache through a failed ask and a sure sign-out; not tested against a real cursor-agent, and what made reporter's about fail isn't known
2026-09-28 21:02:48 +08:00
provider: Cursor stays listed when cursor-agent can't say who is signed in (cataglyphis: 供应商选型中间歇无法显示 cursor,导致路由里不能正常路由到 cursor 的模型) — who Cursor's account is comes from cursor-agent about --format json, asked again behind the served answer every minute, and any about that failed, ran past its 10s (it asks Cursor's servers), or printed something besides its JSON was taken for nobody signed in: Cursor dropped out of the Providers page and of routing (All() lists the accounts for both), and that was kept on disk, until an ask a minute or more on came back. Now an ask that couldn't tell leaves what was served, on disk too, and is asked again in a minute (cliIdentity's ask returns an error for that); Cursor is taken as signed out only when about says so in its JSON or cursor-agent keeps no token. About's JSON after a line of its own (an update notice) is read too. Devin's ask is as before. Tested with fake cursor-agent scripts in a temp HOME (signed in, update notice, says nobody, fails, no JSON, fails with the token gone) and the cache through a failed ask and a sure sign-out; not tested against a real cursor-agent, and what made reporter's about fail isn't known
2026-09-28 21:02:48 +08:00
2026-09-28 10:28:20 +08:00
usage: a Codex account can spend one of its rate-limit resets by itself once its week is used up (StringKe on Discord: 账号里有 Bank Reset 的重置次数,可以自动使用 — 七天全部用完的时候重置) — off by default, turned on per account with Auto-use beside Use a reset (Usage page, panel) or magpie quota auto-reset <account> on. It fires only when every other account a request could go to is resting, fresh usage shows the weekly window used up (the 5 hours' being full never counts: a reset starts both, and five hours pass on their own), the account holds one, and none was spent by itself this week (kept in codex-autoreset.json across restarts); it spends the one expiring first, lifts the rest and asks once more, and on nothing_to_reset/no_credit/error ChatGPT's own 429 goes to the agent. Both the pooled accounts and Codex's own sign-in are covered; each use shows on the Routing page and in the request log. TestCodexAutoResetOneAccount, TestCodexAutoResetAfterEveryAccount, TestCodexAutoResetNot, TestWeekUsedUp, TestAutoResetKeptPastRestart, codex-auto-reset.test.cjs and routing-auto-reset.test.cjs are new; the gateway and GUI ones fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; click-scroll, old-webkit, tray-usages pass.
2026-09-30 21:35:40 +08:00
claude: magpie no longer asks Anthropic for a Claude account's usage, and adding a Claude account warns of a ban (the user: 不要伪造任何的 Claude 请求,能否通过 claude cli 获取 / 我害怕被封; 添加账号时要像其他的 Subscription Provider 一样显示风险提示) — the usage was read by magpie itself calling Anthropic's /api/oauth/usage with the account's token, on a timer, for every saved account, and Claude's usage-limit resets (cedar_ember) were listed, spent and auto-spent the same way. Now the usage is what Claude Code's own /usage prints (claude -p /usage, a command Claude Code answers itself without asking a model), run only when Usage is opened or Refresh pressed (GUI, magpie quota, accounts, TUI), for the account Claude Code is signed in to, at most once in 30s; a saved account shows only what Claude Code reported while using it, or the last reading kept. The Claude resets, Auto-use and their settings are gone (Codex's stay). Session jsonl files hold no usage figures, so they aren't read. Starting a Claude sign-in or import (GUI and CLI) first says Anthropic may suspend or ban the account and that it is at the user's own risk. TestClaudeWindowsAsked, TestParseClaudeUsage, TestClaudeUsageRunsClaudeCode, claude-usage-asked.test.cjs and claude-risk.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; routing-auto-reset, codex-auto-reset, quota-families, tray-usages, click-scroll, old-webkit, plugin-signin, usage-alert, usage-ledger pass.
2026-10-01 12:38:25 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
2026-09-29 11:59:57 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
2026-10-02 00:42:48 +08:00
2026-10-01 17:42:10 +08:00
codex: a turn relayed through Codex accounts says it is the Codex client it came from, or newer, so a model Codex CLI reaches on its own is no longer refused through magpie (Discord, lantern2077 / TuskerManshu: gpt-6.1-sol through a routing group answered 400 "The 'gpt-6.1-sol' model is not supported when using Codex with a ChatGPT account" while Codex CLI alone could use it) — the ChatGPT backend serves a model only to a client new enough for it. Re-signing a pool turn, codexSign set User-Agent codex_cli_rs/<codexVersion()>, the newest of a constant 0.154.0, ~/.codex/models_cache.json's client_version (written by the Codex before the last update) and codex --version when codex was on PATH, ~/.local/bin or Homebrew's — nvm, mise, fnm, npm prefixes, pnpm and Volta were out of reach, above all in magpie serve — while the client's own version header was relayed: one turn saying two versions, the older in the User-Agent. Now codexSign writes one version in both, never older than the relayed one; the gateway notes the newest version a Codex client (originator or codex… User-Agent) has come with (SawCodexClient) and codexVersion, also asked by the accounts' model lists, takes it; the fallback is 0.159.0; the models cache is read from CODEX_HOME when set; codexExecutable also looks in proc.UserBinDirs() (every Node of nvm, mise and fnm, ~/.npmrc's prefix, pnpm, bun, Volta; %APPDATA%\npm and the like on Windows; codex.cmd/.exe there). Tested with TestCodexPoolSaysTheClientsVersion against a fake backend refusing gpt-6.1-sol below 0.161.0: Codex CLI 0.161.0 through the pool failed on main with codex_cli_rs/0.154.0 and passes; TestCodexVersionSeen (Claude Code's User-Agent ignored, CLI and Desktop versions read, never lowered, the model list asked with it), TestCodexVersion with CODEX_HOME, TestCodexExecutableOffPath (nvm, mise, an .npmrc prefix with PATH /usr/bin:/bin). go vet ./internal/..., go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried against the real backend: the version gating is read from the error and the models cache, not seen on the wire.
2026-09-30 10:06:15 +08:00
codex: a turn relayed through Codex accounts says it is the Codex client it came from, or newer, so a model Codex CLI reaches on its own is no longer refused through magpie (Discord, lantern2077 / TuskerManshu: gpt-6.1-sol through a routing group answered 400 "The 'gpt-6.1-sol' model is not supported when using Codex with a ChatGPT account" while Codex CLI alone could use it) — the ChatGPT backend serves a model only to a client new enough for it. Re-signing a pool turn, codexSign set User-Agent codex_cli_rs/<codexVersion()>, the newest of a constant 0.154.0, ~/.codex/models_cache.json's client_version (written by the Codex before the last update) and codex --version when codex was on PATH, ~/.local/bin or Homebrew's — nvm, mise, fnm, npm prefixes, pnpm and Volta were out of reach, above all in magpie serve — while the client's own version header was relayed: one turn saying two versions, the older in the User-Agent. Now codexSign writes one version in both, never older than the relayed one; the gateway notes the newest version a Codex client (originator or codex… User-Agent) has come with (SawCodexClient) and codexVersion, also asked by the accounts' model lists, takes it; the fallback is 0.159.0; the models cache is read from CODEX_HOME when set; codexExecutable also looks in proc.UserBinDirs() (every Node of nvm, mise and fnm, ~/.npmrc's prefix, pnpm, bun, Volta; %APPDATA%\npm and the like on Windows; codex.cmd/.exe there). Tested with TestCodexPoolSaysTheClientsVersion against a fake backend refusing gpt-6.1-sol below 0.161.0: Codex CLI 0.161.0 through the pool failed on main with codex_cli_rs/0.154.0 and passes; TestCodexVersionSeen (Claude Code's User-Agent ignored, CLI and Desktop versions read, never lowered, the model list asked with it), TestCodexVersion with CODEX_HOME, TestCodexExecutableOffPath (nvm, mise, an .npmrc prefix with PATH /usr/bin:/bin). go vet ./internal/..., go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried against the real backend: the version gating is read from the error and the models cache, not seen on the wire.
2026-09-30 10:06:15 +08:00
2026-09-28 18:22:34 +08:00
claude: magpie no longer asks Anthropic for a Claude account's usage, and adding a Claude account warns of a ban (the user: 不要伪造任何的 Claude 请求,能否通过 claude cli 获取 / 我害怕被封; 添加账号时要像其他的 Subscription Provider 一样显示风险提示) — the usage was read by magpie itself calling Anthropic's /api/oauth/usage with the account's token, on a timer, for every saved account, and Claude's usage-limit resets (cedar_ember) were listed, spent and auto-spent the same way. Now the usage is what Claude Code's own /usage prints (claude -p /usage, a command Claude Code answers itself without asking a model), run only when Usage is opened or Refresh pressed (GUI, magpie quota, accounts, TUI), for the account Claude Code is signed in to, at most once in 30s; a saved account shows only what Claude Code reported while using it, or the last reading kept. The Claude resets, Auto-use and their settings are gone (Codex's stay). Session jsonl files hold no usage figures, so they aren't read. Starting a Claude sign-in or import (GUI and CLI) first says Anthropic may suspend or ban the account and that it is at the user's own risk. TestClaudeWindowsAsked, TestParseClaudeUsage, TestClaudeUsageRunsClaudeCode, claude-usage-asked.test.cjs and claude-risk.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; routing-auto-reset, codex-auto-reset, quota-families, tray-usages, click-scroll, old-webkit, plugin-signin, usage-alert, usage-ledger pass.
2026-10-01 12:38:25 +08:00
accounts: the account made first stays first — magpie signs Codex or Claude Code back in to it once it has room again (#408: 智能路由会自动把所使用账号设为首选) — since #208/#209 magpie signs the agent in to the next ticked account once the one it is on is 98% used, and left it there for good, so the account the user made first lost its place after its first spent window. magpie now keeps the account it moved off (login-returns.json beside logins.json) and signs the agent back in to it once that is below 90% (Smart's low share, so it doesn't flap) and still ticked; a switch the user makes meanwhile, in magpie or the agent, ends that. The Accounts list says it: the stand-in reads "First for now" (暂为首选), its title naming the one it goes back to, and that one "First again once it has room" (额度恢复后切回首选); the Routing note says magpie moves back. TestCodexSwitchedBackWhenItHasRoom and account-return.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; account-return, click-scroll, old-webkit, routing-signin pass.
2026-10-01 17:16:47 +08:00
claude: magpie no longer asks Anthropic for a Claude account's usage, and adding a Claude account warns of a ban (the user: 不要伪造任何的 Claude 请求,能否通过 claude cli 获取 / 我害怕被封; 添加账号时要像其他的 Subscription Provider 一样显示风险提示) — the usage was read by magpie itself calling Anthropic's /api/oauth/usage with the account's token, on a timer, for every saved account, and Claude's usage-limit resets (cedar_ember) were listed, spent and auto-spent the same way. Now the usage is what Claude Code's own /usage prints (claude -p /usage, a command Claude Code answers itself without asking a model), run only when Usage is opened or Refresh pressed (GUI, magpie quota, accounts, TUI), for the account Claude Code is signed in to, at most once in 30s; a saved account shows only what Claude Code reported while using it, or the last reading kept. The Claude resets, Auto-use and their settings are gone (Codex's stay). Session jsonl files hold no usage figures, so they aren't read. Starting a Claude sign-in or import (GUI and CLI) first says Anthropic may suspend or ban the account and that it is at the user's own risk. TestClaudeWindowsAsked, TestParseClaudeUsage, TestClaudeUsageRunsClaudeCode, claude-usage-asked.test.cjs and claude-risk.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; routing-auto-reset, codex-auto-reset, quota-families, tray-usages, click-scroll, old-webkit, plugin-signin, usage-alert, usage-ledger pass.
2026-10-01 12:38:25 +08:00
accounts: the account made first stays first — magpie signs Codex or Claude Code back in to it once it has room again (#408: 智能路由会自动把所使用账号设为首选) — since #208/#209 magpie signs the agent in to the next ticked account once the one it is on is 98% used, and left it there for good, so the account the user made first lost its place after its first spent window. magpie now keeps the account it moved off (login-returns.json beside logins.json) and signs the agent back in to it once that is below 90% (Smart's low share, so it doesn't flap) and still ticked; a switch the user makes meanwhile, in magpie or the agent, ends that. The Accounts list says it: the stand-in reads "First for now" (暂为首选), its title naming the one it goes back to, and that one "First again once it has room" (额度恢复后切回首选); the Routing note says magpie moves back. TestCodexSwitchedBackWhenItHasRoom and account-return.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; account-return, click-scroll, old-webkit, routing-signin pass.
2026-10-01 17:16:47 +08:00
2026-09-29 14:29:06 +08:00
providers: each account of a subscription holding several can go through its own proxy — the provider's, none, or its own address (Discord, gakki: 是否可以为不同的codex账号设置不用的代理,现在是同一个供应商下使用相同的代理) — the per-provider proxy (#237) was one for all of Codex's signed-in accounts. A subscription's entry in providers.json now keeps accountProxies, by the account's name in lower case, each checked by settings.CheckProxy on save (ftp:// refused), addresses trimmed, accounts following the provider's proxy left out. Provider.ProxyChoice picks an account's own proxy, else the provider's, else the global one, so everything that already went through Provider.Via follows the account: gateway turns and fallback across accounts, usage and quota, token refresh, Codex's warm-up, reset and saved accounts' model lists, Claude's warm-up and the *_PROXY of Claude Code runs (ViaLogin / ProxyOfLogin), and Codex's own sign-in relayed as it came (ViaSignedIn). Extra accounts of Copilot, ZCode, Kiro and the like, made afresh without the provider's settings, now read them from providers.json, so they honour the provider's proxy too. A save without accountProxies keeps them; {} clears them. The provider editor, for a subscription with two or more accounts, lists each under the Proxy row: Provider's proxy | Direct | Custom, the address field's room kept so a pick moves nothing; Custom with no address is refused before anything is posted, its field focused without scrolling. en and zh together; no border stripes. Tested with internal/gateway/account_proxy_test.go in a sandbox HOME against fake proxies and a fake ChatGPT backend: three Codex accounts (own proxy, direct, following the provider) each reach the backend their own way in one turn and for usage; clearing an account's proxy sends it through the provider's, clearing the provider's through the global one, direct staying direct; ftp:// refused; TestClaudeAccountProxyEnv covers each Claude account's HTTPS_PROXY. Both fail with the per-account lookup off. account-proxy.test.cjs, Chromium and WebKit, en and zh (new), provider-proxy, click-scroll and old-webkit pass. go vet ./internal/..., go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried against a real proxy, real accounts or the real Wails window; Grok's per-account usage and Kiro's usage on a key still use the provider's proxy.
2026-09-30 04:52:03 +08:00
providers: Command Code's free models are marked free, and providers switched off fold below the ones on (01huadalang on Discord: Space Bunny Alpha 在 Command Code 里是 FREE,magpie 只给 Ling 3.1 Flash 标了免费;已关闭的供应商还占着位置) — magpie marked a model free when the plan said so (m.free) or its id or name said "free"; Command Code's /provider/v1/models says nothing of it, so only ids like inclusionai/ling-3.1-flash:free got 免费. Its CLI (1.73.2) badges eleven models free in its own table (badge:"free"), Space Bunny Alpha and Pixel Canary among them; those are now marked Free on the Go table, on Go's fetched list and on a keyed plan's, so the chips say 免费 with "doesn't use the plan's credits". Neither the CLI nor the API says a discount (no "-99%" anywhere), so none is shown. On the Providers page the providers switched off now sit below the list under a "Turned off (N)" fold (已关闭的供应商), folded at first and remembered per viewer; a click on it moves nothing, and a provider switched off moves under it. TestCommandCodeFreeModels and providers-off-fold.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestClaudeRunEndsWhenTheClientLeaves a load flake, passes alone); providers-off-fold, click-scroll, old-webkit, provider-search, provider-remove, add-sheet, nokey-editor, plain-names, model-test-one pass.
2026-10-01 17:13:34 +08:00
provider: a Command Code Go account lists the models Command Code has for Go, not ten (01huadalang on Discord: command 账号登录只有十个模型,正确的应该是几十个) — for Go, magpie never asked for a list and showed a table of 10, on the word that Command Code has none; its Provider API's list answers without a key (86 models), and its CLI (1.73.0) offers Go every model its picker shows but the premium ones and those it blocks for Go. A Go account now fetches that list without its key, less the 30 refused, and saves it (56 today); the table, the CLI's whole Go set (57), stands in until then or when the fetch fails. Requests still go to /alpha/generate. TestCommandCodeGoModels fails without the change (10 models). go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./internal/provider pass.
2026-10-01 06:15:04 +08:00
provider: a Command Code Go account lists the models Command Code has for Go, not ten (01huadalang on Discord: command 账号登录只有十个模型,正确的应该是几十个) — for Go, magpie never asked for a list and showed a table of 10, on the word that Command Code has none; its Provider API's list answers without a key (86 models), and its CLI (1.73.0) offers Go every model its picker shows but the premium ones and those it blocks for Go. A Go account now fetches that list without its key, less the 30 refused, and saves it (56 today); the table, the CLI's whole Go set (57), stands in until then or when the fetch fails. Requests still go to /alpha/generate. TestCommandCodeGoModels fails without the change (10 models). go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./internal/provider pass.
2026-10-01 06:15:04 +08:00
commandcode: a reply is asked for within Command Code's 200000 tokens, and the agents are told no more (Discord: every Command Code model, free or paid, failed with "Too big: expected number to be <=200000 at params.max_tokens") — magpie passed the client's max_tokens to /alpha/generate as it came, and told the agents each Command Code model's reply limit as models.dev gives it: DeepSeek V4's 384000, MiniMax M3's 512000, Space Bunny Alpha's 524288, Kimi K2.x's 262144, so an agent asking for what it was told had the whole request refused. params.max_tokens is now the asked number within the model's own limit as models.dev gives it and within 200000; less is sent as it was, and none asked is still the CLI's 64000. The Command Code subscription's models are listed to the agents (their configs, /v1/models) with a reply limit of at most 200000, a user's own limit included. Prompts and headers are unchanged. TestCommandCodeGoMaxTokens and TestCommandCodeOutputCapped fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-02 06:58:18 +08:00
commandcode: a reply is asked for within Command Code's 200000 tokens, and the agents are told no more (Discord: every Command Code model, free or paid, failed with "Too big: expected number to be <=200000 at params.max_tokens") — magpie passed the client's max_tokens to /alpha/generate as it came, and told the agents each Command Code model's reply limit as models.dev gives it: DeepSeek V4's 384000, MiniMax M3's 512000, Space Bunny Alpha's 524288, Kimi K2.x's 262144, so an agent asking for what it was told had the whole request refused. params.max_tokens is now the asked number within the model's own limit as models.dev gives it and within 200000; less is sent as it was, and none asked is still the CLI's 64000. The Command Code subscription's models are listed to the agents (their configs, /v1/models) with a reply limit of at most 200000, a user's own limit included. Prompts and headers are unchanged. TestCommandCodeGoMaxTokens and TestCommandCodeOutputCapped fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-02 06:58:18 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
kiro: removing kiro-cli's or the Kiro IDE's own sign-in hides it in magpie, and it shows again when Kiro signs in anew (Discord 碳碳双键: 本机没安装 kiro,但旧的 Kiro 数据还在,magpie 列出一个"Kiro account"(登录已失效,请重新添加此账号),添加新账号并设为首位后,旧的数据无法移除) — magpie reads Kiro's own sign-in from kiro-cli's database or ~/.aws/sso/cache and lists it among the accounts it signed in; Remove on it said "that is kiro-cli's or the Kiro IDE's own sign-in; run kiro-cli logout or sign out in the IDE", which with neither installed left a dead account there for good. The same refusal was shared by every agent whose own sign-in magpie only reads (forgetSideLogin: Kiro, Devin, Grok, Copilot, ZCode, WorkBuddy and WorkBuddy AI, Command Code, Gemini CLI, Antigravity). Now Remove on the agent's own sign-in hides it: logins.json's entry for it keeps a Hidden mark, and it is left out of the account list and so of the gateway's tries (the first and the ones behind it both come from that list); the agent's files are never deleted or written. It shows again when that sign-in changes: for Kiro, by a mark that is a digest of where the sign-in is (kiro-cli's row or the IDE's file) and its refresh token (never the token itself), so a new kiro-cli login or IDE sign-in, to any account, brings it back; for the others, which have no such mark, when it is another account. Removing it while it is first is allowed now, the next account being put first (saved, so it stays first when the own one comes back); removed when it was the only one, the agent has no account left. One of magpie's own accounts is removed with its home as before, and still can't be while it is first. The error and its per-agent sign-out hints are gone. Logins carry own, and the accounts list shows Remove on the agent's own sign-in also while it is first, its title "magpie stops showing and using Kiro's own sign-in; its files are left as they are, and it shows again when Kiro signs in anew" (magpie 不再显示和使用 Kiro 自己的登录;它的文件保持原样,Kiro 重新登录后会再次出现). Tested with a new internal/provider/side_logins_hide_test.go in a sandbox HOME: an expired kiro-cli sign-in ("Kiro account") behind a Google one magpie signed in is removed, stays gone across reads, isn't the account used nor among AlsoOn, kiro-cli's database byte-for-byte and mtime as it was, the refresh token nowhere in magpie's files; a new kiro-cli sign-in brings it back behind the one first; put first and removed, the next is first; one of magpie's removed takes its home and leaves the other's; the only account removed leaves Kiro with none; Grok's CLI sign-in hidden with auth.json untouched, back once it is another account. The agents' tests that expected the refusal (Command Code, Copilot, Devin, Grok, WorkBuddy, ZCode) no longer do. A new internal/gui/tests/own-signin-remove.test.cjs in Chromium and WebKit, en and zh: kiro-cli's sign-in behind another and alone first both have Remove with that title and post login/forget, magpie's first account has none. go build -tags nogui (and GOOS=linux, GOOS=windows), go test -tags nogui ./... and the whole GUI suite (138) pass. Not tried with a real Kiro, kiro-cli or the Kiro IDE.
2026-09-29 23:52:33 +08:00
kiro: removing kiro-cli's or the Kiro IDE's own sign-in hides it in magpie, and it shows again when Kiro signs in anew (Discord 碳碳双键: 本机没安装 kiro,但旧的 Kiro 数据还在,magpie 列出一个"Kiro account"(登录已失效,请重新添加此账号),添加新账号并设为首位后,旧的数据无法移除) — magpie reads Kiro's own sign-in from kiro-cli's database or ~/.aws/sso/cache and lists it among the accounts it signed in; Remove on it said "that is kiro-cli's or the Kiro IDE's own sign-in; run kiro-cli logout or sign out in the IDE", which with neither installed left a dead account there for good. The same refusal was shared by every agent whose own sign-in magpie only reads (forgetSideLogin: Kiro, Devin, Grok, Copilot, ZCode, WorkBuddy and WorkBuddy AI, Command Code, Gemini CLI, Antigravity). Now Remove on the agent's own sign-in hides it: logins.json's entry for it keeps a Hidden mark, and it is left out of the account list and so of the gateway's tries (the first and the ones behind it both come from that list); the agent's files are never deleted or written. It shows again when that sign-in changes: for Kiro, by a mark that is a digest of where the sign-in is (kiro-cli's row or the IDE's file) and its refresh token (never the token itself), so a new kiro-cli login or IDE sign-in, to any account, brings it back; for the others, which have no such mark, when it is another account. Removing it while it is first is allowed now, the next account being put first (saved, so it stays first when the own one comes back); removed when it was the only one, the agent has no account left. One of magpie's own accounts is removed with its home as before, and still can't be while it is first. The error and its per-agent sign-out hints are gone. Logins carry own, and the accounts list shows Remove on the agent's own sign-in also while it is first, its title "magpie stops showing and using Kiro's own sign-in; its files are left as they are, and it shows again when Kiro signs in anew" (magpie 不再显示和使用 Kiro 自己的登录;它的文件保持原样,Kiro 重新登录后会再次出现). Tested with a new internal/provider/side_logins_hide_test.go in a sandbox HOME: an expired kiro-cli sign-in ("Kiro account") behind a Google one magpie signed in is removed, stays gone across reads, isn't the account used nor among AlsoOn, kiro-cli's database byte-for-byte and mtime as it was, the refresh token nowhere in magpie's files; a new kiro-cli sign-in brings it back behind the one first; put first and removed, the next is first; one of magpie's removed takes its home and leaves the other's; the only account removed leaves Kiro with none; Grok's CLI sign-in hidden with auth.json untouched, back once it is another account. The agents' tests that expected the refusal (Command Code, Copilot, Devin, Grok, WorkBuddy, ZCode) no longer do. A new internal/gui/tests/own-signin-remove.test.cjs in Chromium and WebKit, en and zh: kiro-cli's sign-in behind another and alone first both have Remove with that title and post login/forget, magpie's first account has none. go build -tags nogui (and GOOS=linux, GOOS=windows), go test -tags nogui ./... and the whole GUI suite (138) pass. Not tried with a real Kiro, kiro-cli or the Kiro IDE.
2026-09-29 23:52:33 +08:00
copilot: Auto asks its session with the API version VS Code sends, and an account Copilot has no Auto for is told so (#256, CakewthinSUm: "Copilot Auto: 404 Not Found") — signed in from magpie (the editors' sign-in), the POST {api}/models/session went out with no X-GitHub-Api-Version, which VS Code's Copilot Chat puts on every CAPI request (@vscode/copilot-api 0.2.19 _mixinHeaders: 2025-10-01, AutoModels among the types); it now carries 2025-10-01 (the Copilot CLI's sign-in keeps its own 2026-07-01). VS Code's session answer names no selected_model, only available_models, and it takes the first it knows: magpie does the same when none is named. A 404 however asked falls back to the first model the account may pick by hand, sent without a session, for 10 minutes; with none, the error says Copilot doesn't offer Auto to this account. TestCopilotAutoSessionAsVSCode and TestCopilotAutoUnavailable fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-09-30 19:42:44 +08:00
2026-10-01 11:28:41 +08:00
copilot: Auto — Copilot's own pick, the only choice a Student plan has — is listed for every Copilot account and works through magpie, as Copilot's clients do it (#256; Discord, CakeJskSUMM: Copilot Student can only use Auto) — Copilot's /models doesn't list Auto; its clients add it themselves (Copilot CLI 1.0.79: {id:"auto",name:"Auto"}, AUTO_MODEL_ID) and ask POST {api}/models/session with {"auto_mode":{"model_hints":["auto"]}} for a session_token, the selected_model and expires_at, each request then naming that model with the token in Copilot-Session-Token. magpie listed no Auto, failed an account whose list left nothing to pick by hand ("Copilot lists no chat model for this account"), and sent "auto" as a model. Now copilot_auto.go keeps the session per GitHub account, asked again two minutes before it expires; the gateway resolves Auto before choosing the API, so a picked model served only on /responses goes there; a body still naming "auto" (the model test) is rewritten; the endpoints of every model Copilot lists, hidden ones too, are kept for the picked one. A reply to "auto" from another model isn't counted as swapped (Cursor's auto too); the Copilot CLI's picker, which offers auto itself, leaves out the listed one. Tested with fakes in a sandbox HOME: provider/copilot_auto_test.go (a Student-like account whose models are all disabled lists [auto], the session body sent as above, requests carry the picked gpt-5-mini and the token, one session reused, renewed near expiry, an object-shaped selected_model, a refusal reported) and gateway/copilot_auto_test.go (a chat request for copilot/auto goes to /responses as gpt-5-mini with the token, two turns one session; fails without the gateway change); served_test gains the auto cases. go vet ./internal/..., go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried with a real Student account: what its /models returns, whether the plain session request suffices (Auto v2's /models/session/intent is not done), and the body is from VS Code's Copilot Chat, not captured traffic.
2026-09-30 10:17:15 +08:00
windows: the desktop app no longer opens a console window for every command it runs (#54) — it is linked as a GUI program and has no console, so each console CLI it started (devin auth status and models list, devin acp for every Devin turn, claude, codex, cursor-agent and grok probes and runs, grok login) was given a new console by Windows, and a Windows Terminal window with it, some every few seconds while the app sat idle. Every command magpie runs is now made through internal/proc, which starts it with CREATE_NO_WINDOW when magpie has no console of its own: the child gets a console without a window, and its output, which magpie always pipes back, arrives as before. A magpie run in a terminal (magpie serve, the TUI, the desktop app started from one with a command) has one, and its children share it as they did, so Ctrl+C there still reaches them. The relaunch after an update keeps its DETACHED_PROCESS, added to rather than replacing the flags it was made with, and a test fails on any command made with os/exec directly, so a new one can't bring the windows back
2026-09-25 14:04:44 +08:00
2026-10-01 11:28:41 +08:00
2026-10-01 11:28:41 +08:00
providers: smart routing, a Copilot subscription signed in from magpie, and import by app in tabs — Smart, now the default, keeps the first key or account while it has quota to spare and moves to the one with the most left as it runs low; one out of credit sits out half an hour, one out of quota until it says it resets, one rate limited as long as the vendor asks, and one failing a minute, longer each time; Copilot gets a tile of its own that signs in with GitHub's device code (the code shown in magpie), several accounts beside the editors' own; Import from other apps shows a tab per app it reads, each with how many providers it has to bring over
2026-09-24 19:41:34 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
2026-09-29 13:26:16 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
cursor: a sign-in link cursor-agent wrapped over lines is joined whole before it is opened (#261: the page said "This sign-in link is incomplete or has expired" for https://cursor.com/loginDeepControl?, the link cut after its "?") — runCLISignIn took the first https:// run of a line, so a link broken where the terminal wrapped lost everything after the break. A Cursor link without challenge and uuid now takes the lines after it that are only URL characters; one that has them takes only more of its query read with it, not a word printed after it; a link never made whole is used as it was once the wait is over. Grok's link is handed on as printed. Not reproduced with cursor-agent 2025.08.08, 2026.09.23 or 2026.09.28, which print it on one line. Tested with TestCursorSignInJoinsAWrappedLink (a break after ?, over three lines, in and after the uuid, the rest 0.3s later, whole then "Waiting...", never whole; fails without the change) and TestCLISignInFirstLinkAsPrinted.
2026-09-30 11:50:05 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
2026-09-28 12:04:43 +08:00
2026-09-28 12:04:43 +08:00
2026-10-02 00:42:48 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
providers: each provider, a signed-in account like Codex's among them, goes through its own proxy — the one in Settings, none, or its own address (#237 xosi: 目前似乎是全局设置代理的,codex和国模供应商无法单独区分设置代理) — magpie had one proxy, Settings' (or the environment's, or the system's), for every request it made, so Codex, which needs a proxy from China, and a vendor at home, which is slower or refused through one, couldn't both be right. A provider now has a proxy, "" (following the global one, as before and the default), "direct" (none, whatever Settings says) or an http://, https:// or socks5:// address (host:port meaning http), kept as proxy in providers.json only when set, and for an account provider in its picks entry beside its models. It is checked on save by the same rule Settings' proxy is (settings.CheckProxy, now shared), so ftp:// and the like are refused. netproxy.With puts a provider's choice on a request's context and netproxy.Func honours it; netproxy.Dispatch sends such a request through a clone of the transport kept for that proxy alone (at most 32, cleared past that), since a transport shares an HTTP/2 connection by host whatever proxy dialled it; loopback is never proxied. The gateway's client and http.DefaultClient go through Dispatch, and every request made on a provider's behalf carries its choice: the gateway's turns (attempt, forward, draw, decide, the Codex backend), and the model lists, balances, plan and subscription usage, tests, sign-in, Codex's warm-up and reset, while the Claude subscription's and warm-up's CLI runs get the account's proxy in their *_PROXY (netproxy.EnvWith). The provider editor, a key provider's and a signed-in account's alike, has a Proxy row after Fallback: Global proxy | Direct | Custom (全局代理 | 直连 | 自定义), the address field beside the options only for Custom, its room kept otherwise so a pick never changes the centred dialog's height and moves nothing, and a line under it saying what the pick does; Save posts proxy ("" , "direct" or the trimmed address), a save without it keeps the old one, and Custom with no address is refused before anything is posted ("Proxy: type its address, like http://127.0.0.1:7890"). No border stripes; en and zh strings together. Tested with a new internal/gateway/proxy_test.go in a sandbox HOME: with a global proxy set, provider A's turns and model list go through its own fake proxy, B's (direct) straight to the vendor, C's (following) through the global one, none through another, and A set back to following goes through the global one; ftp:// is refused (fails with With neutered). netproxy_test.go's TestWith covers Func, Dispatch's per-proxy transports and EnvWith. A new internal/gui/tests/provider-proxy.test.cjs in Chromium and WebKit, en and zh: a key provider opens on Global proxy with no address, Custom unfilled is refused and nothing posted, a padded socks5 address saved trimmed, Direct saved as "direct" and Global as ""; Codex's account opens on Custom with its address and saves Direct with its models; every pick leaves the option within 1px; no left border. go build -tags nogui (and GOOS=linux, GOOS=windows), go test -tags nogui ./..., provider-proxy, click-scroll, old-webkit, balance-fix and add-sheet pass (click-scroll's WebKit case failed once alongside the others and passes alone, twice). Not tried against a real proxy or the real Wails window.
2026-09-30 02:15:50 +08:00
2026-10-01 12:37:01 +08:00
devin: an account signed in only in magpie works without the Devin CLI signed in, and is listed once (蓝猫 on Discord: every request from Claude Code failed until devin auth login, then the same account showed twice) — the model list that turns a family and effort into the variant Devin takes (claude-sonnet-5-5 + high → claude-sonnet-5-5-high) was asked only of the CLI's own sign-in, so with that signed out or its key refused the bare family id went to Devin and was refused. It is now asked of the signed-in accounts in their own homes, the one in use first, the CLI's own last. And the CLI's own sign-in isn't listed beside a working magpie account of the same user (an old logins.json entry renamed to that user when the CLI signed in again). Tested with a new TestDevinSignedInOnlyInMagpie in a sandbox HOME with a fake devin CLI and exchange server, following 蓝猫's steps: it fails without either change (variant stays claude-sonnet-5-5; dev@example.com listed twice). go vet, go build (-tags nogui, GOOS=linux, GOOS=windows), go test -tags nogui ./... pass (TestUserPath and TestClaudeAccountNamedAsItsLogin flake under load, pass alone). Not tried against the real Devin API.
2026-09-30 14:24:53 +08:00
devin: whether a Devin model takes images is what Devin tells its CLI, for models models.dev doesn't know (#417, HwFee: swe-2 and gpt-6-1-sol were said to take no images) — devin models list says nothing of images and models.dev has no entry for Devin's own ids, so swe-2, gpt-6-1-sol and the like were served as text-only and agents dropped the images. When it reads the list, magpie now also asks Devin's GetCliModelConfigs, the read-only call the CLI's own model picker makes, with the same metadata magpie's chats already send. Each ClientModelConfig's supports_images is put on its variant, and on the family and its tiers when all their variants agree: swe-2, gpt-6-1-sol, claude-sonnet-5-5 and kimi-k3 take images, GLM and DeepSeek don't. A model Devin doesn't name, or a failed call, is left to models.dev as before; a list saved earlier takes what Devin said, and a user's own image setting still wins. No prompt, header, user agent or existing request changes. TestDevinImagesFromModelConfigs fails without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath and the Claude account tests flaked and pass alone).
2026-10-01 19:38:36 +08:00
devin: whether a Devin model takes images is what Devin tells its CLI, for models models.dev doesn't know (#417, HwFee: swe-2 and gpt-6-1-sol were said to take no images) — devin models list says nothing of images and models.dev has no entry for Devin's own ids, so swe-2, gpt-6-1-sol and the like were served as text-only and agents dropped the images. When it reads the list, magpie now also asks Devin's GetCliModelConfigs, the read-only call the CLI's own model picker makes, with the same metadata magpie's chats already send. Each ClientModelConfig's supports_images is put on its variant, and on the family and its tiers when all their variants agree: swe-2, gpt-6-1-sol, claude-sonnet-5-5 and kimi-k3 take images, GLM and DeepSeek don't. A model Devin doesn't name, or a failed call, is left to models.dev as before; a list saved earlier takes what Devin said, and a user's own image setting still wins. No prompt, header, user agent or existing request changes. TestDevinImagesFromModelConfigs fails without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath and the Claude account tests flaked and pass alone).
2026-10-01 19:38:36 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
2026-10-01 12:37:01 +08:00
plugins: built-in Devin shows its usage as the Devin plugin does, and a Grok account whose sign-in has expired no longer stops Grok's move (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样) — the plugin showed a Devin account's day and week quotas, its ACUs and extra balance from GetUserStatus while the built-in showed no usage at all, so routing had no allowance to fail over on until the move; the built-in now reads the same and fills the same windows (1 day, 7 days, ACUs aside), plan end and balance, and a refused key says to sign in again. A move checks each account through the plugin and stopped when one failed; Grok's plugin says an expired sign-in only in words ("Grok's sign-in has expired"), so one dead account kept every Grok account on the built-in. Such an account now moves along untried and unmarked, as a built-in Grok account was never marked; any other failure still stops the move. TestDevinUsage and TestMoveExpiredInWords fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 12:24:45 +08:00
devin: whether a Devin model takes images is what Devin tells its CLI, for models models.dev doesn't know (#417, HwFee: swe-2 and gpt-6-1-sol were said to take no images) — devin models list says nothing of images and models.dev has no entry for Devin's own ids, so swe-2, gpt-6-1-sol and the like were served as text-only and agents dropped the images. When it reads the list, magpie now also asks Devin's GetCliModelConfigs, the read-only call the CLI's own model picker makes, with the same metadata magpie's chats already send. Each ClientModelConfig's supports_images is put on its variant, and on the family and its tiers when all their variants agree: swe-2, gpt-6-1-sol, claude-sonnet-5-5 and kimi-k3 take images, GLM and DeepSeek don't. A model Devin doesn't name, or a failed call, is left to models.dev as before; a list saved earlier takes what Devin said, and a user's own image setting still wins. No prompt, header, user agent or existing request changes. TestDevinImagesFromModelConfigs fails without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath and the Claude account tests flaked and pass alone).
2026-10-01 19:38:36 +08:00
providers: DimAgent's subscription is taken out of magpie (a DimAgent team member on X: dim doesn't allow its subscription used through a proxy, and users doing so get banned or lose their discount) — #226 signed in to DimAgent as its desktop client does and served its models through the gateway. The sign-in, the account provider and its dimagent/<model> models, the quota card, magpie accounts … dimagent and the icon are gone, with internal/dimagent. An account signed in before is left out when logins.json is read and dropped from the file at its next write, so its tokens aren't kept. The pasted-callback field and route stay, generic, with no sign-in using them. Tested with TestDimAgentLoginDropped (fails without the filter); in a sandbox HOME with a DimAgent login left in logins.json, magpie accounts --json lists nothing and magpie accounts add dimagent is refused. signin-callback (fixture renamed), old-webkit and click-scroll pass; go vet, go build (GUI, -tags nogui, GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass (TestUserPath and the Claude/Devin sign-in tests flaked under the full run and pass alone).
2026-09-30 15:33:40 +08:00
signin: Grok and Command Code sign in from magpie in Docker (xugui on Discord: docker版登不上grok和command code) — Grok's sign-in first installs Grok Build with its installer, curl … | bash, and the image has neither bash nor curl, so it stopped at "installing Grok Build failed (exec: "bash": executable file not found)"; the community Grok plugin, beside the built-in rather than moved onto, wasn't given the CLI at all and said "install Grok Build first". Where no shell and curl/wget can run, Grok Build is now installed as its installer does, from the same x.ai/cli (then its storage bucket) address: the stable version, its binary for the platform, checked with --version, linked as ~/.grok/bin/grok and agent, installer = "internal" noted in its config.toml; the plugin's sign-in installs it first too. The device sign-in itself needs nothing back from the browser and was fine. Command Code's Studio posts the key to magpie's 127.0.0.1 port in the background, which a browser outside the container can't reach and no address carries; while it waits, its sign-in now takes an API key made on commandcode.ai/settings/keys and pasted (as Command Code's own CLI offers), checked with whoami and its plan as Studio's was, and a plugin's browser sign-in offers "Use an API key instead", its own api way (the Command Code plugin has one). No identity, header or prompt changes. TestGrokInstallsWithoutShell, TestCommandCodeSignInPastedKey and TestGrokPluginSignInInstallsCLI fail without the change, signin-paste-key.test.cjs too. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; signin-paste-key, signin-paste-codex, plugin-signin, signin-callback, commandcode-risk, plugin-key-hint, signin-link, click-scroll, old-webkit pass.
2026-10-01 22:25:39 +08:00
2026-09-30 10:46:55 +08:00
2026-10-01 11:28:41 +08:00
factory: X-Factory-Org-Id carries Factory's own id for the org, as droid sends it, not WorkOS's, and a refused org is mended once (#242 tasselx: "403 permission_error: Factory: Requested active organization is not accessible by this user") — read again from droid 0.229.0 (still the latest @factory/cli-darwin-arm64): its header builder (Ad) sends X-Factory-Org-Id only from the stored active_organization_id, left off when null; that field is only ever filled with Factory's (Firestore) org ids, whoami's orgId or /api/app/auth/me's memberships, never WorkOS's org_… ids, which go only to WorkOS's refresh; moving a token that names no org into the first of /api/cli/org's workosOrgIds (gt) saves active_organization_id null; routine refresh names no org. magpie sent the WorkOS org id as the header, which Factory looks up as one of its own and refuses. Now factoryCreds keeps Active (activeOrganizationId) from whoami's orgId, asked without an org header, and only it is sent; Org, the WorkOS id, is kept but never sent; logins saved by v0.1.432 have no Active and so send none; refresh names no org. The sign-in checks the JWT's external_org_id then org_id, carries on as droid does when /api/cli/org fails or lists none, and when whoami fails but the token says whose it is. On that 403 an account mends itself once (Account.retry, Provider.Retries/Retry, asked by gateway.forward and by the usage read): an active org sent is dropped and the request goes again without the header; with none sent, the token is put in the first org /api/cli/org lists (droid does this at sign-in, not on a 403). Other 403s and 401s are passed on as they were. Tested in factory_test.go against fake WorkOS and Factory servers that answer droid's way: TestFactoryActiveOrg (a token WorkOS put in org_A keeps fac_A and gets a 200; a v0.1.432-format login sends no header and gets a 200) and TestFactoryOrgRefused (a left active org dropped and retried with no refresh; a left token org refreshed into org_A and retried; the usage read the same; other 403s and 401s not retried) fail on main with the reporter's 403; the existing tests now check whoami and /api/cli/org get no org header and refresh sends no organization_id. go vet ./internal/..., go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried against a real Factory account: that the server reads the header as a Factory org id is from droid's code, not seen on the wire; the gateway's retry is covered only by a provider-level test; accounts with several orgs take the first, with no picker.
2026-09-30 09:34:21 +08:00
2026-10-01 11:28:41 +08:00
2026-09-24 14:04:42 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
2026-09-27 18:52:49 +08:00
test(provider): TestFetchNewLeavesListedPlugins waits for the refresh its sign-in started, and TestFetchNewRetriedSoon puts back what it set — signing in with a key (PluginAPIKey) shows the account, which lists the providers while the host's auth event has them stale, so Cached refreshes them in the background; that refresh could end after the test had set the list's time back, rewriting plugin-providers.json, which read as FetchNew asking the plugins again (failed 3 in 5 run after TestFetchNewRetriedSoon, and now and then after TestFetchNewAccount). plugin.Refreshed waits for those refreshes with the host left running, and the test waits before it sets the time. TestFetchNewRetriedSoon now resets newFetches, newSoonAt, wbTokens and the account caches, after waiting for a FetchNewSoon under way. The pair passes 10 in 10 (and with TestFetchNewAccount 10 in 10); ./internal/provider 3 in 3; go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 21:49:16 +08:00
providers: an account signed in while magpie runs is listed with its vendor's models (#204 uclort: 首次添加 WorkBuddy 模型显示不全,点击刷新后模型全部显示) — a signed-in account's own list was fetched only at start-up, for the accounts there then (and once: a fetch that failed was not tried again). WorkBuddy AI signed in afterwards, in magpie or in WorkBuddy itself, showed magpie's built-in list ("magpie's list · Refresh asks the vendor", 14 models) until Refresh fetched /v3/config's 20-odd. Now provider.FetchNew, which start-up uses in place of its loop, also runs before the providers are listed (providersState, 8s each): each ready account with no fetched list is asked for it, so the first listing after a sign-in is the vendor's. One that fails is asked again after 10 minutes, not on each listing; one fetched is not asked again. Tested with a new TestFetchNewAccount (a fake WorkBuddy /v3/config: nothing asked with no account; a WorkBuddy auth file written while running lists the built-in models, then the vendor's three after FetchNew; not asked again; a 502 asked once over two listings, then again after the retry time). go build -tags nogui (and GOOS=linux, GOOS=windows), go test -tags nogui ./... pass (TestUserPath and three Claude sign-in tests timed out once under load, pass on their own and on a rerun of the package). Not tried in the GUI with a real WorkBuddy account
2026-09-29 18:56:32 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
2026-10-02 00:57:41 +08:00
subscription: Antigravity accounts can be imported from a JSON file (莫: https://github.com/jlcodes99/vscode-antigravity-cockpit 这个开源的里面有 你可以看看) — beside Add account (and as "Import instead…" on the risk note) the Antigravity card takes files or pasted text exported by Antigravity Cockpit (a JSON array of {email, refresh_token}, or refresh tokens one a line), Antigravity Manager (the same array, {accounts:[…]}, or an account file with token{refresh_token, email, project_id}) and CLIProxyAPI (an antigravity auth file, type/email/refresh_token/project_id; another type's is refused). All three sign in with the Antigravity app's own OAuth client, as magpie does, so their refresh tokens are good here. Each account is checked as signing in does: the token refreshed at Google, the email read from userinfo (the file's if that's refused), the project and plan from loadCodeAssist, then kept in logins.json like a signed-in account. A token magpie already has is not sent again (exists); a known email with a new token replaces the old (updated); duplicates in the file, entries with no token and tokens Google refuses are reported per account, Google's bare "Bad Request" explained. POST /api/signin/import; tokens are never logged, shown or returned, and the paste box is masked. Tested against an httptest token/userinfo/Code Assist server in a sandbox HOME
2026-09-29 00:52:09 +08:00
subscription: Antigravity accounts can be imported from a JSON file (莫: https://github.com/jlcodes99/vscode-antigravity-cockpit 这个开源的里面有 你可以看看) — beside Add account (and as "Import instead…" on the risk note) the Antigravity card takes files or pasted text exported by Antigravity Cockpit (a JSON array of {email, refresh_token}, or refresh tokens one a line), Antigravity Manager (the same array, {accounts:[…]}, or an account file with token{refresh_token, email, project_id}) and CLIProxyAPI (an antigravity auth file, type/email/refresh_token/project_id; another type's is refused). All three sign in with the Antigravity app's own OAuth client, as magpie does, so their refresh tokens are good here. Each account is checked as signing in does: the token refreshed at Google, the email read from userinfo (the file's if that's refused), the project and plan from loadCodeAssist, then kept in logins.json like a signed-in account. A token magpie already has is not sent again (exists); a known email with a new token replaces the old (updated); duplicates in the file, entries with no token and tokens Google refuses are reported per account, Google's bare "Bad Request" explained. POST /api/signin/import; tokens are never logged, shown or returned, and the paste box is masked. Tested against an httptest token/userinfo/Code Assist server in a sandbox HOME
2026-09-29 00:52:09 +08:00
usage: an Antigravity account shows each group of models' 5-hour and weekly allowance, one row a group (a user on Discord: 这里显示5h 和一周剩余比较好吧,现在是只显示5h,这3个模型都是一样的,没必要分开…多加个7day 条就好) — fetchAvailableModels gives each model only its 5-hour figure, the same for every model drawing on one quota, so the Usage page, the panel and the account rows showed a figure a family (Gemini, Claude, GPT-OSS) and no week. Antigravity's retrieveUserQuotaSummary reports the quota a group ("Gemini Models"; "Claude and GPT models", Claude and GPT-OSS sharing one), each with a 5h and a weekly bucket; magpie now reads it beside the models' (best-effort: without it the windows are as before) and adds each group's windows, named "5 hours" and "7 days" with their pool (Gemini, Claude & GPT), each model's window naming its pool. The Usage page shows Gemini · 5 hours, Gemini · 7 days, Claude & GPT · 5 hours, Claude & GPT · 7 days, the pool's models in each tooltip; the panel four rings (Gemini 5h/7d, Claude 5h/7d); the account rows each pool with its 5h and 7d meters; the TUI the pools' windows in place of the models'. "Every model" lists the models' own windows. The pools' windows are aside for routing, which reads the models' as before; the tray's text is unchanged. TestAntigravityQuotaPools and quota-pools.test.cjs (Chromium, WebKit; en, zh) fail without the change; quota-families, click-scroll, old-webkit, tray-usages, panel-usage pass. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-02 07:03:17 +08:00
usage: an Antigravity account shows each group of models' 5-hour and weekly allowance, one row a group (a user on Discord: 这里显示5h 和一周剩余比较好吧,现在是只显示5h,这3个模型都是一样的,没必要分开…多加个7day 条就好) — fetchAvailableModels gives each model only its 5-hour figure, the same for every model drawing on one quota, so the Usage page, the panel and the account rows showed a figure a family (Gemini, Claude, GPT-OSS) and no week. Antigravity's retrieveUserQuotaSummary reports the quota a group ("Gemini Models"; "Claude and GPT models", Claude and GPT-OSS sharing one), each with a 5h and a weekly bucket; magpie now reads it beside the models' (best-effort: without it the windows are as before) and adds each group's windows, named "5 hours" and "7 days" with their pool (Gemini, Claude & GPT), each model's window naming its pool. The Usage page shows Gemini · 5 hours, Gemini · 7 days, Claude & GPT · 5 hours, Claude & GPT · 7 days, the pool's models in each tooltip; the panel four rings (Gemini 5h/7d, Claude 5h/7d); the account rows each pool with its 5h and 7d meters; the TUI the pools' windows in place of the models'. "Every model" lists the models' own windows. The pools' windows are aside for routing, which reads the models' as before; the tray's text is unchanged. TestAntigravityQuotaPools and quota-pools.test.cjs (Chromium, WebKit; en, zh) fail without the change; quota-families, click-scroll, old-webkit, tray-usages, panel-usage pass. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-02 07:03:17 +08:00
2026-10-01 04:59:22 +08:00
kiro: removing kiro-cli's or the Kiro IDE's own sign-in hides it in magpie, and it shows again when Kiro signs in anew (Discord 碳碳双键: 本机没安装 kiro,但旧的 Kiro 数据还在,magpie 列出一个"Kiro account"(登录已失效,请重新添加此账号),添加新账号并设为首位后,旧的数据无法移除) — magpie reads Kiro's own sign-in from kiro-cli's database or ~/.aws/sso/cache and lists it among the accounts it signed in; Remove on it said "that is kiro-cli's or the Kiro IDE's own sign-in; run kiro-cli logout or sign out in the IDE", which with neither installed left a dead account there for good. The same refusal was shared by every agent whose own sign-in magpie only reads (forgetSideLogin: Kiro, Devin, Grok, Copilot, ZCode, WorkBuddy and WorkBuddy AI, Command Code, Gemini CLI, Antigravity). Now Remove on the agent's own sign-in hides it: logins.json's entry for it keeps a Hidden mark, and it is left out of the account list and so of the gateway's tries (the first and the ones behind it both come from that list); the agent's files are never deleted or written. It shows again when that sign-in changes: for Kiro, by a mark that is a digest of where the sign-in is (kiro-cli's row or the IDE's file) and its refresh token (never the token itself), so a new kiro-cli login or IDE sign-in, to any account, brings it back; for the others, which have no such mark, when it is another account. Removing it while it is first is allowed now, the next account being put first (saved, so it stays first when the own one comes back); removed when it was the only one, the agent has no account left. One of magpie's own accounts is removed with its home as before, and still can't be while it is first. The error and its per-agent sign-out hints are gone. Logins carry own, and the accounts list shows Remove on the agent's own sign-in also while it is first, its title "magpie stops showing and using Kiro's own sign-in; its files are left as they are, and it shows again when Kiro signs in anew" (magpie 不再显示和使用 Kiro 自己的登录;它的文件保持原样,Kiro 重新登录后会再次出现). Tested with a new internal/provider/side_logins_hide_test.go in a sandbox HOME: an expired kiro-cli sign-in ("Kiro account") behind a Google one magpie signed in is removed, stays gone across reads, isn't the account used nor among AlsoOn, kiro-cli's database byte-for-byte and mtime as it was, the refresh token nowhere in magpie's files; a new kiro-cli sign-in brings it back behind the one first; put first and removed, the next is first; one of magpie's removed takes its home and leaves the other's; the only account removed leaves Kiro with none; Grok's CLI sign-in hidden with auth.json untouched, back once it is another account. The agents' tests that expected the refusal (Command Code, Copilot, Devin, Grok, WorkBuddy, ZCode) no longer do. A new internal/gui/tests/own-signin-remove.test.cjs in Chromium and WebKit, en and zh: kiro-cli's sign-in behind another and alone first both have Remove with that title and post login/forget, magpie's first account has none. go build -tags nogui (and GOOS=linux, GOOS=windows), go test -tags nogui ./... and the whole GUI suite (138) pass. Not tried with a real Kiro, kiro-cli or the Kiro IDE.
2026-09-29 23:52:33 +08:00
signin: Grok and Command Code sign in from magpie in Docker (xugui on Discord: docker版登不上grok和command code) — Grok's sign-in first installs Grok Build with its installer, curl … | bash, and the image has neither bash nor curl, so it stopped at "installing Grok Build failed (exec: "bash": executable file not found)"; the community Grok plugin, beside the built-in rather than moved onto, wasn't given the CLI at all and said "install Grok Build first". Where no shell and curl/wget can run, Grok Build is now installed as its installer does, from the same x.ai/cli (then its storage bucket) address: the stable version, its binary for the platform, checked with --version, linked as ~/.grok/bin/grok and agent, installer = "internal" noted in its config.toml; the plugin's sign-in installs it first too. The device sign-in itself needs nothing back from the browser and was fine. Command Code's Studio posts the key to magpie's 127.0.0.1 port in the background, which a browser outside the container can't reach and no address carries; while it waits, its sign-in now takes an API key made on commandcode.ai/settings/keys and pasted (as Command Code's own CLI offers), checked with whoami and its plan as Studio's was, and a plugin's browser sign-in offers "Use an API key instead", its own api way (the Command Code plugin has one). No identity, header or prompt changes. TestGrokInstallsWithoutShell, TestCommandCodeSignInPastedKey and TestGrokPluginSignInInstallsCLI fail without the change, signin-paste-key.test.cjs too. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; signin-paste-key, signin-paste-codex, plugin-signin, signin-callback, commandcode-risk, plugin-key-hint, signin-link, click-scroll, old-webkit pass.
2026-10-01 22:25:39 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
grok: Codex's sub-agent tools reach a Grok subscription (#404) — Codex groups spawn_agent, wait_agent, send_message and followup_task in its collaboration namespace and set_thread_title in codex_app, and since aa08863d12 a namespace was left out whole, as Grok's backend turns a request away over the type: multi_agent_v2 on Grok had no tools to spawn with. A namespace's functions now go to Grok as functions of their own under the flat name the translation path gives them (collaboration__spawn_agent, flatName, now provider.FlatName), and so do a call to one handed back and a tool_choice naming one; the namespace type itself still never reaches Grok, nor does a freeform tool (apply_patch, or one inside a namespace), and a namespace with no function goes whole. Responses Lite's "functions" namespace stays plain names. On the way back a call Grok makes to a flat name reaches Codex under its own name and namespace with an empty encrypted_function_args, as callTo gives one, streamed (output_item.added/done, response.completed) or not. A ChatGPT account still gets the namespace as Codex sent it. TestGrokGetsNamespacedTools (a fake Grok upstream returning a call to collaboration__spawn_agent), TestGrokBodyFlattensNamespacedCalls and the updated TestGrokBodyLeavesOutCustomTools fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath, a load flake, passes alone).
2026-10-01 16:20:10 +08:00
2026-10-01 04:59:22 +08:00
2026-10-01 04:59:22 +08:00
2026-10-02 00:42:48 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
groups: the groups magpie finds on its own can be switched off, in the Routing view and with magpie group auto off (蓝猫 on Discord: 路由分组会自动创建,可以关闭掉吗) — a model two or more providers serve always became an auto-<model> group, and one could only be removed at a time. A switch right under the routing groups' head, with what it does in words, and magpie group auto [on|off] now keep noAutoGroups in providers.json: off, no found group is listed, catalogued or served, and the groups the user made or changed stay; on, they are back, along with any the user had removed still removed. An agent set to a found group is moved to its model from one provider (the status line and the CLI say which), and a request that still names group/auto-<model> goes to that provider's model rather than failing. Switching off is refused while a group of the user's holds a found group as a member or classifier, so none is left pointing at nothing. TestAutoGroupsOff, TestAutoStandIn, TestAutoGroupsOffHeld, TestFoundGroupOff, TestReseatFoundGroupsOff and TestGroupsFoundSwitch fail without the change; group-found-off.test.cjs (Chromium, WebKit, en, zh), click-scroll and old-webkit pass. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath a load flake, passes alone; TestClaudeSignedOut fails alone on main as well).
2026-10-02 02:24:49 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
routing: a group can name the reasoning levels agents are offered, so one member with few doesn't take the rest from the others (#295) — a group offered only the levels every member has, so deepseek-flash (low/high/max) beside models with medium and xhigh left the group without them. Group.Levels (CLI magpie group set <id> levels=low,medium,high,xhigh, levels= clears; TUI l; GUI group editor's Levels: its models' shared / named) is offered instead in /v1/models, Codex's catalog, Pi and the rest; only levels magpie knows are taken, stored lowest first; a group in a group that names its own offers them for its models; unset is as before. A member without the level asked is sent its nearest, as it already was. The GUI's group save also keeps a family set from the CLI. TestGroupLevelsOverride, TestGroupLevelsReachAgents, TestGroupLevelsNamed (passthrough and translated: medium→high, xhigh→max on the low/high/max member, as asked on the one with all), TestGroupSetLevels and routing-levels.test.cjs (Chromium, WebKit, en/zh) fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath, a known flake under load, passes alone); click-scroll, old-webkit, routing-effort(-row), routing-levels, settings-groups GUI tests pass.
2026-09-30 16:26:37 +08:00
routing: a group's member can be sent in its vendor's fast mode, beside its own reasoning (vs on Discord: a member "gpt-6.1 sol · high · fast") — a member's effort was already its own (#189, "provider/model:effort") but there was no way to ask for speed, so a group could not hold "gpt-6.1-sol at high, priority" next to slower members. A group now lists in fast the members it sends fast, as Members spells them, kept beside Members rather than in their ids so an older version still routes to them, only not fast (checked: HEAD's build on the same providers.json sends the same members at their effort, no tier, and leaves the file as it was). When the gateway sends to such a member it asks in the upstream's own words, only where the model has a fast mode magpie can ask for (provider.CanFast): service_tier "priority" for a ChatGPT account's GPT models and an OpenAI key's GPT/o-series models on its Responses API, Cursor's -fast variant, and speed "fast" with the fast-mode-2026-02-01 beta for Claude Opus 4.8/5/5.5 on an Anthropic key (api.anthropic.com); a relay, Bedrock, a Claude subscription, a model without one, or a provider since moved off those hosts is sent untouched. It is applied in the agent's own API and carried through translation (parseAnthropic now reads speed), so Chat, Responses and Anthropic agents all get it. A translated request for OpenAI's Chat API is still told no tier (TestCursorPluginFast), hence the Responses requirement. The trace marks the try, the order and the group (fast), shown as "fast" beside the reasoning in Requests and the order. Typed, a member is provider/model[:effort]:fast: magpie group add/set models=… takes it, fast=<m1>,… sets them, models-= takes either spelling, and the group lists and shows members as typed with "· fast"; a model with no fast mode, or a group in the group, is refused. The GUI group editor shows a "Standard speed"/"Fast" toggle (标准速度/快速) beside a member's reasoning only for a model that has one, the card reads "· fast" after the reasoning, and fast follows a member's reasoning change and leaves with a removed member; the TUI's group view takes E to step a member's effort and F to toggle fast. Provider renames carry it. TestFastMemberOpenAI, TestFastMemberAnthropic, TestWithFastWire (gateway, per wire format, a fake vendor recording body and anthropic-beta), TestCanFast, TestSaveGroupFast, TestGroupMembersFast, TestGroupMemberEffortAndFast, TestGroupSaveFast and group-member-fast.test.cjs fail without the change. A sandbox magpie (own HOME, gateway on 3966) with providers at http://api.openai.com and http://api.anthropic.com through a local recording proxy sent priority+high to OpenAI and speed fast + the beta to Anthropic from Chat, Responses and Anthropic clients, and nothing extra for Sonnet or a non-fast member. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; group-member-fast, click-scroll, old-webkit, routing-levels, routing-manual, routing-effort, settings-groups pass (Chromium, WebKit, en/zh).
2026-10-01 17:13:34 +08:00
plugins: a plugin's subscription does what a built-in's does, in seven places it didn't (the user: 要保证插件订阅 provider 跟内置的订阅 provider所有逻辑都要一模一样) — an installed plugin's provider id is kept for it signed in or not, as a built-in's is: a provider of the user's own isn't saved on it, renamed onto it or imported as it (freeID gives id-2). A plugin's account whose plan lacks the model is tried after the ones that list it, as a Codex Free account behind a Plus, by the list the plugin told for it. Cursor's plugin has fast mode where the built-in Cursor has it: a model with a -fast one is saved :fast in a group and sent service_tier "priority", one without is refused. Removing a plugin's provider hides it as a built-in's is, its accounts kept and shown again from Hidden or by signing in, rather than signing every account out ("stays signed in" said so already). magpie accounts lists, adds, switches and forgets a plugin's accounts by its provider's id or name. Grok's plugin beside the built-in Grok (grok-plugin) searches by itself as Grok does. A plugin's plan is named as its built-in's ("Cursor Pro", "SuperGrok"), and a plugin's resets are shown but have no Use button or Auto-use, which spent Codex's reset of the same user. TestPluginIDReservedSignedOut, TestPluginAccountLackingTheModelGoesLast, TestCursorPluginGroupFast, TestAccountsOfAPlugin, TestGrokPluginSearchesItself, plugin-plan and codex-auto-reset fail without the change; TestPluginSignIn and TestPluginAccounts now expect a removed plugin hidden. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestClaudeSignedOut failed once under load, passes alone); the gateway, provider and plugin suites and TestAccountsOfAPlugin pass on Windows, the plugin tests on Linux.
2026-10-01 20:26:55 +08:00
groups: the groups magpie finds on its own can be switched off, in the Routing view and with magpie group auto off (蓝猫 on Discord: 路由分组会自动创建,可以关闭掉吗) — a model two or more providers serve always became an auto-<model> group, and one could only be removed at a time. A switch right under the routing groups' head, with what it does in words, and magpie group auto [on|off] now keep noAutoGroups in providers.json: off, no found group is listed, catalogued or served, and the groups the user made or changed stay; on, they are back, along with any the user had removed still removed. An agent set to a found group is moved to its model from one provider (the status line and the CLI say which), and a request that still names group/auto-<model> goes to that provider's model rather than failing. Switching off is refused while a group of the user's holds a found group as a member or classifier, so none is left pointing at nothing. TestAutoGroupsOff, TestAutoStandIn, TestAutoGroupsOffHeld, TestFoundGroupOff, TestReseatFoundGroupsOff and TestGroupsFoundSwitch fail without the change; group-found-off.test.cjs (Chromium, WebKit, en, zh), click-scroll and old-webkit pass. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath a load flake, passes alone; TestClaudeSignedOut fails alone on main as well).
2026-10-02 02:24:49 +08:00
routing: a group can name the reasoning levels agents are offered, so one member with few doesn't take the rest from the others (#295) — a group offered only the levels every member has, so deepseek-flash (low/high/max) beside models with medium and xhigh left the group without them. Group.Levels (CLI magpie group set <id> levels=low,medium,high,xhigh, levels= clears; TUI l; GUI group editor's Levels: its models' shared / named) is offered instead in /v1/models, Codex's catalog, Pi and the rest; only levels magpie knows are taken, stored lowest first; a group in a group that names its own offers them for its models; unset is as before. A member without the level asked is sent its nearest, as it already was. The GUI's group save also keeps a family set from the CLI. TestGroupLevelsOverride, TestGroupLevelsReachAgents, TestGroupLevelsNamed (passthrough and translated: medium→high, xhigh→max on the low/high/max member, as asked on the one with all), TestGroupSetLevels and routing-levels.test.cjs (Chromium, WebKit, en/zh) fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath, a known flake under load, passes alone); click-scroll, old-webkit, routing-effort(-row), routing-levels, settings-groups GUI tests pass.
2026-09-30 16:26:37 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
routing: a group's rule can hold hours of the day (Discord: send DeepSeek's or GLM's peak-price hours to another provider) — a rule takes time: {from, to, days} in this computer's local time, HH:MM to HH:MM; hours that end before they begin run past midnight and belong to the day they begin on (Friday's 22:00–08:00 takes Saturday's early hours), days are optional, and the hours are checked as a turn begins, so a turn that began inside them finishes where it went. The rule reads "time 09:00–18:00 Mon–Fri" on the group and in the trace; the editor types the hours into one pill (从 … 到 …), notes past midnight, marks a time that isn't one and picks days like the agents (every day, weekdays, weekends, or each); magpie group rule add … time=14:00-18:00 days=mon-fri and the TUI's rule line take it too. Older versions ignore the field, and a rule with only hours then matches nothing there. TestRuleTimeMatches and TestRuleTimeWindowAtTurnStart (injected clock) and routing-time.test.cjs fail without the change. A sandbox magpie with two fake vendors sent a request inside the hours to the rule's member and one outside them, or on another day, to the first. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; routing-time, routing-compact, routing-manual, routing-steady, settings-groups, click-scroll, old-webkit pass.
2026-10-01 15:04:16 +08:00
routing: a group's rule can hold hours of the day (Discord: send DeepSeek's or GLM's peak-price hours to another provider) — a rule takes time: {from, to, days} in this computer's local time, HH:MM to HH:MM; hours that end before they begin run past midnight and belong to the day they begin on (Friday's 22:00–08:00 takes Saturday's early hours), days are optional, and the hours are checked as a turn begins, so a turn that began inside them finishes where it went. The rule reads "time 09:00–18:00 Mon–Fri" on the group and in the trace; the editor types the hours into one pill (从 … 到 …), notes past midnight, marks a time that isn't one and picks days like the agents (every day, weekdays, weekends, or each); magpie group rule add … time=14:00-18:00 days=mon-fri and the TUI's rule line take it too. Older versions ignore the field, and a rule with only hours then matches nothing there. TestRuleTimeMatches and TestRuleTimeWindowAtTurnStart (injected clock) and routing-time.test.cjs fail without the change. A sandbox magpie with two fake vendors sent a request inside the hours to the rule's member and one outside them, or on another day, to the first. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; routing-time, routing-compact, routing-manual, routing-steady, settings-groups, click-scroll, old-webkit pass.
2026-10-01 15:04:16 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
provider: Huawei Cloud's MaaS Token Plan is a preset (Lemon: 能否支持华为 codearts 订阅啊) — huaweicloud, Huawei Cloud MaaS: the Token Plan (personal accounts, 西南-贵阳一 only) is spent only at its own endpoints, https://api.modelarts-maas.com/plan/v2 for chat completions (its OpenClaw, Cherry Studio and CodeArts pages, tokenplan-maas-0004/0009/0014) and /plan/anthropic for messages (its Claude Code page, tokenplan-maas-0003); pay-as-you-go MaaS is the other Plan, /openai/v1 (qs-maas-0001, OpenCode page maas-modelarts-0909) and /anthropic (model-call-060). No Responses on either. Its models (glm-5.3, glm-5.1, kimi-k2.6, deepseek-v4.1-flash, deepseek-v4-flash, lowercase as its OpenClaw page has them) are given until a list is fetched; the key is a MaaS API key from console.huaweicloud.com/modelarts/?#/model-studio/authmanage; no usage API is documented (quota is shown in the console's 订阅管理), so none is read. CodeArts (码道) itself isn't a provider: it has no official API, its private endpoints are reverse-engineered, and its own doc has it reach the Token Plan through these same endpoints. Icon is lobehub's huaweicloud-color, as the others are.
2026-09-29 00:22:50 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
2026-10-01 11:42:45 +08:00
2026-09-25 09:36:42 +08:00
2026-09-25 20:11:28 +08:00
plugins: a plugin's subscription does what a built-in's does, in seven places it didn't (the user: 要保证插件订阅 provider 跟内置的订阅 provider所有逻辑都要一模一样) — an installed plugin's provider id is kept for it signed in or not, as a built-in's is: a provider of the user's own isn't saved on it, renamed onto it or imported as it (freeID gives id-2). A plugin's account whose plan lacks the model is tried after the ones that list it, as a Codex Free account behind a Plus, by the list the plugin told for it. Cursor's plugin has fast mode where the built-in Cursor has it: a model with a -fast one is saved :fast in a group and sent service_tier "priority", one without is refused. Removing a plugin's provider hides it as a built-in's is, its accounts kept and shown again from Hidden or by signing in, rather than signing every account out ("stays signed in" said so already). magpie accounts lists, adds, switches and forgets a plugin's accounts by its provider's id or name. Grok's plugin beside the built-in Grok (grok-plugin) searches by itself as Grok does. A plugin's plan is named as its built-in's ("Cursor Pro", "SuperGrok"), and a plugin's resets are shown but have no Use button or Auto-use, which spent Codex's reset of the same user. TestPluginIDReservedSignedOut, TestPluginAccountLackingTheModelGoesLast, TestCursorPluginGroupFast, TestAccountsOfAPlugin, TestGrokPluginSearchesItself, plugin-plan and codex-auto-reset fail without the change; TestPluginSignIn and TestPluginAccounts now expect a removed plugin hidden. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestClaudeSignedOut failed once under load, passes alone); the gateway, provider and plugin suites and TestAccountsOfAPlugin pass on Windows, the plugin tests on Linux.
2026-10-01 20:26:55 +08:00
2026-09-25 20:11:28 +08:00
2026-09-29 23:25:56 +08:00
2026-09-29 23:25:56 +08:00
grok: Grok Build is found on Windows where its installer puts it (#180: the Grok Build installer finished, but magpie can't find it) — magpie looked for ~/.grok/bin/grok, without .exe, and then only at the first grok on PATH, which on Windows may be another (an npm grok.cmd). Now it looks at GROK_BIN_DIR, the grok home's bin and ~/.grok/bin (grok.exe on Windows), then every folder on PATH and on the registry's PATH, which has what was installed since magpie started, taking a grok there only under a .grok folder; the install-first error gives the PowerShell command on Windows. Tested the order and names of the places looked at, and which grok is taken, in a fake home
2026-09-29 11:04:46 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
grok: Grok Build is found on Windows where its installer puts it (#180: the Grok Build installer finished, but magpie can't find it) — magpie looked for ~/.grok/bin/grok, without .exe, and then only at the first grok on PATH, which on Windows may be another (an npm grok.cmd). Now it looks at GROK_BIN_DIR, the grok home's bin and ~/.grok/bin (grok.exe on Windows), then every folder on PATH and on the registry's PATH, which has what was installed since magpie started, taking a grok there only under a .grok folder; the install-first error gives the PowerShell command on Windows. Tested the order and names of the places looked at, and which grok is taken, in a fake home
2026-09-29 11:04:46 +08:00
signin: Grok and Command Code sign in from magpie in Docker (xugui on Discord: docker版登不上grok和command code) — Grok's sign-in first installs Grok Build with its installer, curl … | bash, and the image has neither bash nor curl, so it stopped at "installing Grok Build failed (exec: "bash": executable file not found)"; the community Grok plugin, beside the built-in rather than moved onto, wasn't given the CLI at all and said "install Grok Build first". Where no shell and curl/wget can run, Grok Build is now installed as its installer does, from the same x.ai/cli (then its storage bucket) address: the stable version, its binary for the platform, checked with --version, linked as ~/.grok/bin/grok and agent, installer = "internal" noted in its config.toml; the plugin's sign-in installs it first too. The device sign-in itself needs nothing back from the browser and was fine. Command Code's Studio posts the key to magpie's 127.0.0.1 port in the background, which a browser outside the container can't reach and no address carries; while it waits, its sign-in now takes an API key made on commandcode.ai/settings/keys and pasted (as Command Code's own CLI offers), checked with whoami and its plan as Studio's was, and a plugin's browser sign-in offers "Use an API key instead", its own api way (the Command Code plugin has one). No identity, header or prompt changes. TestGrokInstallsWithoutShell, TestCommandCodeSignInPastedKey and TestGrokPluginSignInInstallsCLI fail without the change, signin-paste-key.test.cjs too. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; signin-paste-key, signin-paste-codex, plugin-signin, signin-callback, commandcode-risk, plugin-key-hint, signin-link, click-scroll, old-webkit pass.
2026-10-01 22:25:39 +08:00
claude: adding a Claude account is Claude Code's own claude auth login, and magpie never refreshes a Claude sign-in nor asks Anthropic anything with one (the user: 把 magpie 自己的 Claude 登录改成直接用 claude /login,只要体验上没什么差别就改) — magpie traded the sign-in page's code for tokens with Claude Code's OAuth client, asked Anthropic's profile and model list with them, refreshed saved accounts itself (daily keepalive included) and handed a saved account to Claude Code as CLAUDE_CODE_OAUTH_TOKEN. Now Add account runs claude auth login --claudeai in a config directory of magpie's own: the page Claude Code would open comes to magpie's window (Claude Code is given magpie as its BROWSER, which writes the page down and exits), the browser comes back to Claude Code's own listener, and when the browser can't reach this machine the address it ended on, or the code Claude's page shows, is pasted as before and handed to Claude Code. Who signed in is what Claude Code kept (.claude.json, auth status). A saved account in use beside the signed-in one runs Claude Code with CLAUDE_CONFIG_DIR set to its own directory (claude-accounts/ beside magpie's config), its sign-in put there once from logins.json and read back as Claude Code refreshes it; switching to it moves it into Claude Code's own store and removes the directory, as forgetting it does. Claude's models are the catalog's (models.dev), not asked of Anthropic; an imported Claude login is kept as the file has it, and Claude Code refreshes it on first use. Claude Code is required to add a Claude account. TestClaudeSignInByPaste, TestClaudeSignInByPastedAddress, TestClaudeSavedAccountDir (a fake claude CLI, and a server standing in for Anthropic that fails the test if asked) and the reworked sign-in, import and gateway tests fail without the change. With the real Claude Code 2.1.286 in a sandbox directory, its sign-in page (localhost callback) reached magpie's binary and the sign-in waited for the browser; nothing was left behind once it was canceled. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; claude-risk, plugin-signin, signin-callback, signin-link, signin-paste-codex, routing-signin, own-signin-remove, click-scroll, old-webkit pass.
2026-10-01 16:37:07 +08:00
claude: adding a Claude account is Claude Code's own claude auth login, and magpie never refreshes a Claude sign-in nor asks Anthropic anything with one (the user: 把 magpie 自己的 Claude 登录改成直接用 claude /login,只要体验上没什么差别就改) — magpie traded the sign-in page's code for tokens with Claude Code's OAuth client, asked Anthropic's profile and model list with them, refreshed saved accounts itself (daily keepalive included) and handed a saved account to Claude Code as CLAUDE_CODE_OAUTH_TOKEN. Now Add account runs claude auth login --claudeai in a config directory of magpie's own: the page Claude Code would open comes to magpie's window (Claude Code is given magpie as its BROWSER, which writes the page down and exits), the browser comes back to Claude Code's own listener, and when the browser can't reach this machine the address it ended on, or the code Claude's page shows, is pasted as before and handed to Claude Code. Who signed in is what Claude Code kept (.claude.json, auth status). A saved account in use beside the signed-in one runs Claude Code with CLAUDE_CONFIG_DIR set to its own directory (claude-accounts/ beside magpie's config), its sign-in put there once from logins.json and read back as Claude Code refreshes it; switching to it moves it into Claude Code's own store and removes the directory, as forgetting it does. Claude's models are the catalog's (models.dev), not asked of Anthropic; an imported Claude login is kept as the file has it, and Claude Code refreshes it on first use. Claude Code is required to add a Claude account. TestClaudeSignInByPaste, TestClaudeSignInByPastedAddress, TestClaudeSavedAccountDir (a fake claude CLI, and a server standing in for Anthropic that fails the test if asked) and the reworked sign-in, import and gateway tests fail without the change. With the real Claude Code 2.1.286 in a sandbox directory, its sign-in page (localhost callback) reached magpie's binary and the sign-in waited for the browser; nothing was left behind once it was canceled. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; claude-risk, plugin-signin, signin-callback, signin-link, signin-paste-codex, routing-signin, own-signin-remove, click-scroll, old-webkit pass.
2026-10-01 16:37:07 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
2026-09-24 14:54:56 +08:00
2026-09-24 14:54:56 +08:00
kiro: removing kiro-cli's or the Kiro IDE's own sign-in hides it in magpie, and it shows again when Kiro signs in anew (Discord 碳碳双键: 本机没安装 kiro,但旧的 Kiro 数据还在,magpie 列出一个"Kiro account"(登录已失效,请重新添加此账号),添加新账号并设为首位后,旧的数据无法移除) — magpie reads Kiro's own sign-in from kiro-cli's database or ~/.aws/sso/cache and lists it among the accounts it signed in; Remove on it said "that is kiro-cli's or the Kiro IDE's own sign-in; run kiro-cli logout or sign out in the IDE", which with neither installed left a dead account there for good. The same refusal was shared by every agent whose own sign-in magpie only reads (forgetSideLogin: Kiro, Devin, Grok, Copilot, ZCode, WorkBuddy and WorkBuddy AI, Command Code, Gemini CLI, Antigravity). Now Remove on the agent's own sign-in hides it: logins.json's entry for it keeps a Hidden mark, and it is left out of the account list and so of the gateway's tries (the first and the ones behind it both come from that list); the agent's files are never deleted or written. It shows again when that sign-in changes: for Kiro, by a mark that is a digest of where the sign-in is (kiro-cli's row or the IDE's file) and its refresh token (never the token itself), so a new kiro-cli login or IDE sign-in, to any account, brings it back; for the others, which have no such mark, when it is another account. Removing it while it is first is allowed now, the next account being put first (saved, so it stays first when the own one comes back); removed when it was the only one, the agent has no account left. One of magpie's own accounts is removed with its home as before, and still can't be while it is first. The error and its per-agent sign-out hints are gone. Logins carry own, and the accounts list shows Remove on the agent's own sign-in also while it is first, its title "magpie stops showing and using Kiro's own sign-in; its files are left as they are, and it shows again when Kiro signs in anew" (magpie 不再显示和使用 Kiro 自己的登录;它的文件保持原样,Kiro 重新登录后会再次出现). Tested with a new internal/provider/side_logins_hide_test.go in a sandbox HOME: an expired kiro-cli sign-in ("Kiro account") behind a Google one magpie signed in is removed, stays gone across reads, isn't the account used nor among AlsoOn, kiro-cli's database byte-for-byte and mtime as it was, the refresh token nowhere in magpie's files; a new kiro-cli sign-in brings it back behind the one first; put first and removed, the next is first; one of magpie's removed takes its home and leaves the other's; the only account removed leaves Kiro with none; Grok's CLI sign-in hidden with auth.json untouched, back once it is another account. The agents' tests that expected the refusal (Command Code, Copilot, Devin, Grok, WorkBuddy, ZCode) no longer do. A new internal/gui/tests/own-signin-remove.test.cjs in Chromium and WebKit, en and zh: kiro-cli's sign-in behind another and alone first both have Remove with that title and post login/forget, magpie's first account has none. go build -tags nogui (and GOOS=linux, GOOS=windows), go test -tags nogui ./... and the whole GUI suite (138) pass. Not tried with a real Kiro, kiro-cli or the Kiro IDE.
2026-09-29 23:52:33 +08:00
kiro: a Builder ID sign-in is asked with Builder ID's service profile, so its models are listed (#422, Q1CHENL: only Auto offered while kiro-cli lists Opus 5.5, Sonnet 5 …) — a Builder ID sign-in (kiro-cli's, the Kiro IDE's or magpie's own) names no profile, and Kiro won't list one for it: List-Available-Profiles answers 403 "AWS Builder ID is not supported for this operation" in both regions, so every call needing the account's auth failed — List-Available-Models (magpie fell back to Auto alone), Get-Usage-Limits (the account stayed "Kiro account") and chat. A sign-in kiro-cli keeps with Builder ID's start URL (or none, as kiro-cli takes it), or one saved with provider BuilderId, now takes the service profile the Kiro IDE and kiro-cli use for Builder ID (arn:aws:codewhisperer:us-east-1:638616132270:profile/AAAACCCCXXXX) without asking, and an AWS sign-in whose profile listing is that 403 takes it too. Identity Center sign-ins still have their profile listed. TestKiroBuilderIDListsItsModels and TestKiroBuilderIDFoundByKirosAnswer fail without the change (fake management API). go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestFXInState's temp-dir cleanup flaked once under load, passes alone and with its package).
2026-10-01 20:45:11 +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
providers: Kiro and Devin keep several accounts, as the other subscriptions do (Kiro要支持增加多个账号…Devin也要能够增加多个账号) — both only borrowed their CLI's one sign-in (Devin wrote devin's credentials.toml, Kiro kept one kiro-auth-token.json), so signing in again replaced the account. The CLI's or IDE's own account is now read as it is and each further account gets a home of magpie's: Kiro's token file is kept and refreshed there, and Devin's credentials.toml sits in a data folder the devin CLI is run with (XDG_DATA_HOME / APPDATA), so devin auth status and models list answer for it. They are listed, switched, ticked on and forgotten like the others, and the gateway moves on to the next when one is out; the single Kiro sign-in kept before is moved into a home of its own. Tested with a fake Kiro and a fake devin CLI (second account, signing in again, switching, forgetting); not with real accounts
2026-09-29 15:20:22 +08:00
kiro: a Builder ID sign-in is asked with Builder ID's service profile, so its models are listed (#422, Q1CHENL: only Auto offered while kiro-cli lists Opus 5.5, Sonnet 5 …) — a Builder ID sign-in (kiro-cli's, the Kiro IDE's or magpie's own) names no profile, and Kiro won't list one for it: List-Available-Profiles answers 403 "AWS Builder ID is not supported for this operation" in both regions, so every call needing the account's auth failed — List-Available-Models (magpie fell back to Auto alone), Get-Usage-Limits (the account stayed "Kiro account") and chat. A sign-in kiro-cli keeps with Builder ID's start URL (or none, as kiro-cli takes it), or one saved with provider BuilderId, now takes the service profile the Kiro IDE and kiro-cli use for Builder ID (arn:aws:codewhisperer:us-east-1:638616132270:profile/AAAACCCCXXXX) without asking, and an AWS sign-in whose profile listing is that 403 takes it too. Identity Center sign-ins still have their profile listed. TestKiroBuilderIDListsItsModels and TestKiroBuilderIDFoundByKirosAnswer fail without the change (fake management API). go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestFXInState's temp-dir cleanup flaked once under load, passes alone and with its package).
2026-10-01 20:45:11 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
kiro: a Builder ID sign-in is asked with Builder ID's service profile, so its models are listed (#422, Q1CHENL: only Auto offered while kiro-cli lists Opus 5.5, Sonnet 5 …) — a Builder ID sign-in (kiro-cli's, the Kiro IDE's or magpie's own) names no profile, and Kiro won't list one for it: List-Available-Profiles answers 403 "AWS Builder ID is not supported for this operation" in both regions, so every call needing the account's auth failed — List-Available-Models (magpie fell back to Auto alone), Get-Usage-Limits (the account stayed "Kiro account") and chat. A sign-in kiro-cli keeps with Builder ID's start URL (or none, as kiro-cli takes it), or one saved with provider BuilderId, now takes the service profile the Kiro IDE and kiro-cli use for Builder ID (arn:aws:codewhisperer:us-east-1:638616132270:profile/AAAACCCCXXXX) without asking, and an AWS sign-in whose profile listing is that 403 takes it too. Identity Center sign-ins still have their profile listed. TestKiroBuilderIDListsItsModels and TestKiroBuilderIDFoundByKirosAnswer fail without the change (fake management API). go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestFXInState's temp-dir cleanup flaked once under load, passes alone and with its package).
2026-10-01 20:45:11 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
claude: adding a Claude account is Claude Code's own claude auth login, and magpie never refreshes a Claude sign-in nor asks Anthropic anything with one (the user: 把 magpie 自己的 Claude 登录改成直接用 claude /login,只要体验上没什么差别就改) — magpie traded the sign-in page's code for tokens with Claude Code's OAuth client, asked Anthropic's profile and model list with them, refreshed saved accounts itself (daily keepalive included) and handed a saved account to Claude Code as CLAUDE_CODE_OAUTH_TOKEN. Now Add account runs claude auth login --claudeai in a config directory of magpie's own: the page Claude Code would open comes to magpie's window (Claude Code is given magpie as its BROWSER, which writes the page down and exits), the browser comes back to Claude Code's own listener, and when the browser can't reach this machine the address it ended on, or the code Claude's page shows, is pasted as before and handed to Claude Code. Who signed in is what Claude Code kept (.claude.json, auth status). A saved account in use beside the signed-in one runs Claude Code with CLAUDE_CONFIG_DIR set to its own directory (claude-accounts/ beside magpie's config), its sign-in put there once from logins.json and read back as Claude Code refreshes it; switching to it moves it into Claude Code's own store and removes the directory, as forgetting it does. Claude's models are the catalog's (models.dev), not asked of Anthropic; an imported Claude login is kept as the file has it, and Claude Code refreshes it on first use. Claude Code is required to add a Claude account. TestClaudeSignInByPaste, TestClaudeSignInByPastedAddress, TestClaudeSavedAccountDir (a fake claude CLI, and a server standing in for Anthropic that fails the test if asked) and the reworked sign-in, import and gateway tests fail without the change. With the real Claude Code 2.1.286 in a sandbox directory, its sign-in page (localhost callback) reached magpie's binary and the sign-in waited for the browser; nothing was left behind once it was canceled. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; claude-risk, plugin-signin, signin-callback, signin-link, signin-paste-codex, routing-signin, own-signin-remove, click-scroll, old-webkit pass.
2026-10-01 16:37:07 +08:00
claude: adding a Claude account is Claude Code's own claude auth login, and magpie never refreshes a Claude sign-in nor asks Anthropic anything with one (the user: 把 magpie 自己的 Claude 登录改成直接用 claude /login,只要体验上没什么差别就改) — magpie traded the sign-in page's code for tokens with Claude Code's OAuth client, asked Anthropic's profile and model list with them, refreshed saved accounts itself (daily keepalive included) and handed a saved account to Claude Code as CLAUDE_CODE_OAUTH_TOKEN. Now Add account runs claude auth login --claudeai in a config directory of magpie's own: the page Claude Code would open comes to magpie's window (Claude Code is given magpie as its BROWSER, which writes the page down and exits), the browser comes back to Claude Code's own listener, and when the browser can't reach this machine the address it ended on, or the code Claude's page shows, is pasted as before and handed to Claude Code. Who signed in is what Claude Code kept (.claude.json, auth status). A saved account in use beside the signed-in one runs Claude Code with CLAUDE_CONFIG_DIR set to its own directory (claude-accounts/ beside magpie's config), its sign-in put there once from logins.json and read back as Claude Code refreshes it; switching to it moves it into Claude Code's own store and removes the directory, as forgetting it does. Claude's models are the catalog's (models.dev), not asked of Anthropic; an imported Claude login is kept as the file has it, and Claude Code refreshes it on first use. Claude Code is required to add a Claude account. TestClaudeSignInByPaste, TestClaudeSignInByPastedAddress, TestClaudeSavedAccountDir (a fake claude CLI, and a server standing in for Anthropic that fails the test if asked) and the reworked sign-in, import and gateway tests fail without the change. With the real Claude Code 2.1.286 in a sandbox directory, its sign-in page (localhost callback) reached magpie's binary and the sign-in waited for the browser; nothing was left behind once it was canceled. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; claude-risk, plugin-signin, signin-callback, signin-link, signin-paste-codex, routing-signin, own-signin-remove, click-scroll, old-webkit pass.
2026-10-01 16:37:07 +08:00
gateway: a conversation stays with the account that answered it across a restart of magpie, and routing goes by each account's last known allowance until the first reading since the start is back (vincentzhang on Discord: in smart routing a restart moved a session to the first account, an update and restart back to the second, and the prompt cache was read by neither) — who answered a conversation last was kept in memory only, so after a restart every conversation was "first" and went to whoever routing put first; and until the accounts' allowances were read again (a first wait of 3s, the read itself up to 30s) none was known, every account counted as unused and the first in order went first, until the reading came back and put the one renewing soonest first again. Who answered is now also kept in affinity.json next to the providers (0600, written atomically, the latest 512 conversations, none older than the 24h a conversation is remembered), read again when a conversation isn't known here and the file changed — after a restart, or written by the magpie handing over. The rules for when a conversation moves are unchanged: within a turn it stays, across turns while the vendor read enough from its cache within the last five minutes, and never to an account resting, all but used up or gone. While the first reading is out, Allowances returns each account's last reading kept in quotas.json, its windows past their reset counted empty. Prompts and headers are unchanged. TestAffinitySurvivesRestart and TestAllowancesBeforeFirstReading fail without the change; TestAffinityFileBounded keeps the file bounded. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestFetchNewLeavesListedPlugins and TestFXInState flake under load on main too, pass alone).
2026-10-01 20:09:25 +08:00
providers, sign-in, tray, plugins: four of StringKe's reports on Discord — (1) Removing a provider left its editor open and listed, and a second Remove said there was no such provider: the removal had been made, but moving the agents off its models failed on one agent whose config couldn't be written, and Reseat returned that as the change's error; now such an agent is a move with its error ("still on X, not moved: …", a warning in the panel, a line in the CLI and TUI), the others are moved, and the panel, told a delete failed, re-reads the list and closes the editor when the provider is gone. (2) The sign-in waiting sheet shows the sign-in link itself, selected whole on a click, with a copy button, for a browser other than the one that opens. (3) A subscription with several accounts offers "Account in use" among the menu bar's usages, following the account the gateway goes to first. (4) The Antigravity plugin's sign-in never started: magpie called every plugin's authorize with an inputs object, the way OpenCode's CLI does, and opencode-antigravity-auth then asked its Project ID on the terminal — magpie's stdin — until the minute ran out; inputs now go only to a method with prompts, as OpenCode's TUI passes them (checked against the real package under Bun in a sandbox: the Google sign-in URL comes back at once). TestReseatUnmovable, TestTrayInUse, TestInUseOf, TestAuthorizeNoPrompts, provider-remove.test.cjs, signin-link.test.cjs and tray-inuse.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; click-scroll, old-webkit, tray-usages, plugin-signin, signin-callback, factory-sub pass.
2026-09-30 20:45:23 +08:00
2026-09-27 23:32:15 +08:00
claude: the Claude accounts saved in magpie are served while Claude Code is logged out, and none is dropped (StringKe on Discord: CC(API) -> Magpie -> CC Subscription, and as soon as I /logout in Claude Code all six accounts I manage in magpie disappear) — magpie served its saved Claude accounts only beside the one Claude Code was signed in to: claudeAccount gave no provider without Claude Code's own credentials (or with claude auth status saying no one is signed in), so the gateway had no Claude account at all and the page said the saved ones "are only offered beside the account it is signed in to". Claude Code itself tells the user to log out: with magpie's ANTHROPIC_AUTH_TOKEN beside a claude.ai sign-in it warns "ANTHROPIC_AUTH_TOKEN overriding Claude subscription login · unset it or /logout to sign it out". magpie keeps every account's sign-in in logins.json, so a logout now signs none of them out of magpie: the account seen last (the one Claude Code was signed in to until then, which magpie saw every 30s) stands in its place, run in a config directory of its own as the others on are, listed on, and it can be paused behind another as Claude Code's own could; the others on are served behind it, the Usage page reads it as a saved account, and the saved-but-signed-out notice is no longer given for Claude. An account whose saved sign-in is unreadable is listed as signed out ("its sign-in is gone; sign in again"), never dropped, and isn't picked to stand in while another has one. An account signed in in magpie while Claude Code is logged out and magpie has Claude accounts no longer signs Claude Code back in (which only brought back its warning); it is magpie's alone, on, and the one served first till then stays on behind it. Prompts, identity lines and headers are unchanged; magpie still never refreshes a Claude sign-in nor asks Anthropic anything itself. TestClaudeAccountsOutliveLogout, TestClaudeSignInWhileLoggedOut and TestSavedButSignedOutClaudeServed fail without the change; TestSavedButSignedOutCanBeRemoved now removes the account from the list. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestFetchNewLeavesListedPlugins, a bun plugin test, failed once under load and passes alone and in a rerun of the package).
2026-10-01 20:13:58 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
2026-10-02 03:32:41 +08:00
2026-09-25 18:05:37 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
migrate: built-ins move onto plugins that fail and mark the sign-in as they did — each mover now asks the plugin version that answers with its built-in's status and words and says through X-Magpie-Sign-In when the account's sign-in expired, stayed or renewed, in requests and usage reads alike: Command Code, Cursor, Devin, Kiro, MiMo, WorkBuddy and Zed 0.1.5, Factory and ZCode 0.1.4, Grok and Qoder 0.1.3, each published and installed from npm before this. go vet, go build -tags nogui (GOOS=linux), GOOS=windows go build, go test -tags nogui ./internal/provider ./internal/gateway ./internal/plugin pass.
2026-10-01 06:04:01 +08:00
2026-10-01 18:33:45 +08:00
plugins: built-in Devin shows its usage as the Devin plugin does, and a Grok account whose sign-in has expired no longer stops Grok's move (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样) — the plugin showed a Devin account's day and week quotas, its ACUs and extra balance from GetUserStatus while the built-in showed no usage at all, so routing had no allowance to fail over on until the move; the built-in now reads the same and fills the same windows (1 day, 7 days, ACUs aside), plan end and balance, and a refused key says to sign in again. A move checks each account through the plugin and stopped when one failed; Grok's plugin says an expired sign-in only in words ("Grok's sign-in has expired"), so one dead account kept every Grok account on the built-in. Such an account now moves along untried and unmarked, as a built-in Grok account was never marked; any other failure still stops the move. TestDevinUsage and TestMoveExpiredInWords fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 12:24:45 +08:00
migrate: built-ins move onto plugins that fail and mark the sign-in as they did — each mover now asks the plugin version that answers with its built-in's status and words and says through X-Magpie-Sign-In when the account's sign-in expired, stayed or renewed, in requests and usage reads alike: Command Code, Cursor, Devin, Kiro, MiMo, WorkBuddy and Zed 0.1.5, Factory and ZCode 0.1.4, Grok and Qoder 0.1.3, each published and installed from npm before this. go vet, go build -tags nogui (GOOS=linux), GOOS=windows go build, go test -tags nogui ./internal/provider ./internal/gateway ./internal/plugin pass.
2026-10-01 06:04:01 +08:00
migrate: moving Kiro back with an API key no longer hangs magpie, a move's lock left by a killed magpie frees itself, and plugins changed in a terminal reach the running app (要保证插件订阅 provider 跟内置的订阅 provider所有逻辑都要一模一样) — Kiro's back put the plugin's API key onto the Kiro provider while holding logins.json's lock; saving the provider syncs the agents, which read the accounts and waited on that same lock, so the move back never returned and every request after it hung. The key is now put back once the lock is let go (a mover's settle). A move killed while hung left migrations.json.lock, refusing every move for 15 minutes as "another magpie is moving"; the lock now holds its magpie's pid and one whose magpie is gone is taken. And magpie plugin add, remove or move in a terminal left a running app with the plugins it had loaded (a moved Kiro gone until restart, "magpie knows no model kiro/auto"): a plugins.json changed by another magpie now restarts the host and takes the providers that magpie was told meanwhile. Found walking Qoder, Kiro and Cursor through sandbox moves. TestKiroMover (hangs), TestMoveLockOfDeadMagpie and TestPluginsChangedElsewhere fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 06:53:29 +08:00
providers: a built-in subscription moves onto its community plugin and back, its accounts with it (the user: 慢慢下掉内置的那些 Subscription Provider…不要让用户一升级完之后,突然发现他的所有服务都不可用了) — eleven built-ins (Zed, Qoder, Factory, MiMo, Devin, Grok, Command Code Plan, Cursor, Kiro, WorkBuddy, ZCode) each get a mover to their @magpie-community package. A move installs the plugin (updated when older than the mover needs), hands it every account in the plugin's shape, checks the plugin lists models for them, and only then lets the plugin serve the same provider id, so agents' model ids don't change; any failure rolls back and the built-in keeps serving. The built-in's accounts are kept as a backup, and "Run built-in again" (magpie plugin move-back <id>) takes the plugin's current sign-ins back, never copying a rotating token: they are taken out of the plugin in one step, and an account the built-in renewed meanwhile keeps its newer token. An account only the plugin can hold (Cursor's browser sign-in) stays with it. The provider editor shows "Runs on" with the button, a failed move's reason, and the CLI has magpie plugin move / move-back. Automatic moves (Retiring) are wired in but the list stays empty until the packages are on npm. Checked with real accounts in a sandbox HOME: Command Code Plan and Devin moved, answered a chat through the gateway on the plugin, moved back and answered again on the built-in. TestMove*, TestPutBackKeepsNewer, the movers' round-trip tests and plugin-move.test.cjs (Chromium, WebKit, en/zh) are new. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; click-scroll, old-webkit pass.
2026-09-30 21:21:58 +08:00
2026-10-01 20:26:53 +08:00
2026-10-01 12:05:06 +08:00
plugins: a move installs the plugin as it now matches its built-in (插件版…保持一模一样) — each mover asks for the version published with the parity fixes (WorkBuddy 0.1.3; Command Code, Cursor, Devin, Factory, Kiro, MiMo, Zed, ZCode 0.1.2), updating an older one first, so a failed sign-in says why, a CLI's own account follows its key, refusals read as the built-in's. ZCode's own sign-in on its session alone (the Start Plan) no longer stops the move: zcode-auth 0.1.2 reads ZCode's credentials anew for each request, the session ZCode renews included, so the account goes marked as ZCode's and with no expiry of its own. TestCursorPluginContext and TestMoveDevin no longer lean on the machine: the first seeds its catalog (it failed wherever models.dev's cache wasn't there), the second waits for the fake CLI however loaded the machine. TestZCodeMover fails without the change. Each package installed from npm in an empty HOME comes at the version asked. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass but for TestUserPath and TestClaudeSignedOut, 5s timeouts under the whole run's load that pass alone.
2026-10-01 02:12:43 +08:00
2026-10-01 14:14:06 +08:00
accounts: on Linux an account put first is read first at once, and on Windows a file being replaced isn't read as none (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — the provider tests run on the Windows test box and in WSL found two bugs of magpie's own files. Linux stamps a file's time from a clock a tick (a few milliseconds) coarse, and filememo took same time and size for the same file: two accounts swapped (Devin, Grok, WorkBuddy, ZCode, Claude…) read back in the old order, so magpie kept using the account the user had just moved down, and a moved-back plugin's accounts read as before. A file written within the last two seconds is now also compared by its bytes. On Windows a file being renamed over refuses to open for a moment ("Access is denied"), and one held open refuses to be renamed over: plugin-auth.json, plugins.json and the plugin providers read as nothing (a usage fetch right after a move showed no cards), logins.json failed to save, and host.js, reading plugin-auth.json as {}, would have written the other accounts away on the next sign-in. New internal/steady waits such a read or rename out (half a second at most, Windows only); filememo, edit.WriteAtomic, writePrivate, Kiro's writes and the plugin store go through it, host.js retries its read and rename, and the plugin store writes its files by a rename. Tests: USERPROFILE beside HOME in the test homes, the fake devin (a shell script) skipped on Windows, plugin-auth.json's mode bits unchecked there. TestReadSameSizeSameTick fails on Linux and TestRenameOverAFileHeldOpen/TestReadAFileHeldOpen on Windows without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; on Linux (WSL) the provider and plugin packages pass whole (13 failed before), on Windows the plugin package and the move/plugin/Grok/Devin/usage tests pass 10 times over (TestMoveToPlugin failed one run in a few before); 15 built-in tests that assume Unix (mode bits, Keychain, shell-script CLIs) still fail there, as before.
2026-10-01 13:27:12 +08:00
providers: a built-in moved before its host was kept shows the vendor's host, not the plugin's id (要保证插件订阅 provider 跟内置的订阅 provider所有逻辑都要一模一样) — magpie providers and the Providers list showed "commandcode-plan", "zcode", "grok" for moves made before the move kept the built-in's host; those now show the built-in's own (api.commandcode.ai, api.z.ai, cli-chat-proxy.grok.com…), and one whose built-in showed none shows none. TestMovedShowsBuiltinHost fails without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 11:15:26 +08:00
migrate: built-ins move onto plugins that fail and mark the sign-in as they did — each mover now asks the plugin version that answers with its built-in's status and words and says through X-Magpie-Sign-In when the account's sign-in expired, stayed or renewed, in requests and usage reads alike: Command Code, Cursor, Devin, Kiro, MiMo, WorkBuddy and Zed 0.1.5, Factory and ZCode 0.1.4, Grok and Qoder 0.1.3, each published and installed from npm before this. go vet, go build -tags nogui (GOOS=linux), GOOS=windows go build, go test -tags nogui ./internal/provider ./internal/gateway ./internal/plugin pass.
2026-10-01 06:04:01 +08:00
2026-10-01 12:05:06 +08:00
2026-10-01 12:05:06 +08:00
plugins: built-in Devin shows its usage as the Devin plugin does, and a Grok account whose sign-in has expired no longer stops Grok's move (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样) — the plugin showed a Devin account's day and week quotas, its ACUs and extra balance from GetUserStatus while the built-in showed no usage at all, so routing had no allowance to fail over on until the move; the built-in now reads the same and fills the same windows (1 day, 7 days, ACUs aside), plan end and balance, and a refused key says to sign in again. A move checks each account through the plugin and stopped when one failed; Grok's plugin says an expired sign-in only in words ("Grok's sign-in has expired"), so one dead account kept every Grok account on the built-in. Such an account now moves along untried and unmarked, as a built-in Grok account was never marked; any other failure still stops the move. TestDevinUsage and TestMoveExpiredInWords fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 12:24:45 +08:00
mimo: a Xiaomi MiMo account (the one MiMo's app signs in to) is signed in inside magpie and its models served through the gateway to any agent, and MiMo Code is an agent magpie configures (#249 thedavidweng) — magpie had neither. The subscription (id mimo-app, shown as Xiaomi MiMo) signs in with Xiaomi's long-poll login (account.xiaomi.com/longPolling/loginUrl, sid mimosgp) and keeps the MiMo server's cookie session (serviceToken, userId) in logins.json at 0600; the passToken is replayed to renew the session after a day or on a 401. Requests go to POST <base>/route/chat/completions on mimo-server-{sgp,ru,in}.xiaomimimo.com/api with X-Mimo-Source mimocode-cli-free and X-Client-Version; mimo-auto is sent as mimo-pro; the models are mimo-pro and mimo-flash. Usage from /user/usage and /user/xiaomi/subscription/self. Several accounts, switched, on/off and forgotten as the other subscriptions. The add list has a Xiaomi MiMo tile (Free · Starter · Plus · Pro · Ultra) that says Xiaomi may treat this as third-party use before anything is posted; en and zh. magpie accounts takes mimo. MiMo Code (agent mimocode, OpenCode-like) is configured in its config dir (MIMOCODE_HOME/config when set), reading mimocode.jsonc, mimocode.json or config.json, whichever is there. Tested with internal/provider/mimo_test.go against fake Xiaomi SSO and MiMo servers in a temp HOME, internal/agent tests for MiMo Code's config, and internal/gui/tests/mimo-sub.test.cjs, Chromium and WebKit, en and zh; they fail without the change. factory-sub, click-scroll, old-webkit, zed-sub and add-sheet pass; go vet, go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried with a real Xiaomi account: the long-poll's success payload, the SSO cookie chain, whether /route accepts magpie's requests, the UTC+8 times, and whether MiMo Code picks up the config; not tried in the real Wails window.
2026-09-30 07:43:58 +08:00
mimo: a Xiaomi MiMo account (the one MiMo's app signs in to) is signed in inside magpie and its models served through the gateway to any agent, and MiMo Code is an agent magpie configures (#249 thedavidweng) — magpie had neither. The subscription (id mimo-app, shown as Xiaomi MiMo) signs in with Xiaomi's long-poll login (account.xiaomi.com/longPolling/loginUrl, sid mimosgp) and keeps the MiMo server's cookie session (serviceToken, userId) in logins.json at 0600; the passToken is replayed to renew the session after a day or on a 401. Requests go to POST <base>/route/chat/completions on mimo-server-{sgp,ru,in}.xiaomimimo.com/api with X-Mimo-Source mimocode-cli-free and X-Client-Version; mimo-auto is sent as mimo-pro; the models are mimo-pro and mimo-flash. Usage from /user/usage and /user/xiaomi/subscription/self. Several accounts, switched, on/off and forgotten as the other subscriptions. The add list has a Xiaomi MiMo tile (Free · Starter · Plus · Pro · Ultra) that says Xiaomi may treat this as third-party use before anything is posted; en and zh. magpie accounts takes mimo. MiMo Code (agent mimocode, OpenCode-like) is configured in its config dir (MIMOCODE_HOME/config when set), reading mimocode.jsonc, mimocode.json or config.json, whichever is there. Tested with internal/provider/mimo_test.go against fake Xiaomi SSO and MiMo servers in a temp HOME, internal/agent tests for MiMo Code's config, and internal/gui/tests/mimo-sub.test.cjs, Chromium and WebKit, en and zh; they fail without the change. factory-sub, click-scroll, old-webkit, zed-sub and add-sheet pass; go vet, go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried with a real Xiaomi account: the long-poll's success payload, the SSO cookie chain, whether /route accepts magpie's requests, the UTC+8 times, and whether MiMo Code picks up the config; not tried in the real Wails window.
2026-09-30 07:43:58 +08:00
mimo: a Xiaomi MiMo account (the one MiMo's app signs in to) is signed in inside magpie and its models served through the gateway to any agent, and MiMo Code is an agent magpie configures (#249 thedavidweng) — magpie had neither. The subscription (id mimo-app, shown as Xiaomi MiMo) signs in with Xiaomi's long-poll login (account.xiaomi.com/longPolling/loginUrl, sid mimosgp) and keeps the MiMo server's cookie session (serviceToken, userId) in logins.json at 0600; the passToken is replayed to renew the session after a day or on a 401. Requests go to POST <base>/route/chat/completions on mimo-server-{sgp,ru,in}.xiaomimimo.com/api with X-Mimo-Source mimocode-cli-free and X-Client-Version; mimo-auto is sent as mimo-pro; the models are mimo-pro and mimo-flash. Usage from /user/usage and /user/xiaomi/subscription/self. Several accounts, switched, on/off and forgotten as the other subscriptions. The add list has a Xiaomi MiMo tile (Free · Starter · Plus · Pro · Ultra) that says Xiaomi may treat this as third-party use before anything is posted; en and zh. magpie accounts takes mimo. MiMo Code (agent mimocode, OpenCode-like) is configured in its config dir (MIMOCODE_HOME/config when set), reading mimocode.jsonc, mimocode.json or config.json, whichever is there. Tested with internal/provider/mimo_test.go against fake Xiaomi SSO and MiMo servers in a temp HOME, internal/agent tests for MiMo Code's config, and internal/gui/tests/mimo-sub.test.cjs, Chromium and WebKit, en and zh; they fail without the change. factory-sub, click-scroll, old-webkit, zed-sub and add-sheet pass; go vet, go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried with a real Xiaomi account: the long-poll's success payload, the SSO cookie chain, whether /route accepts magpie's requests, the UTC+8 times, and whether MiMo Code picks up the config; not tried in the real Wails window.
2026-09-30 07:43:58 +08:00
mimo: a Xiaomi MiMo account (the one MiMo's app signs in to) is signed in inside magpie and its models served through the gateway to any agent, and MiMo Code is an agent magpie configures (#249 thedavidweng) — magpie had neither. The subscription (id mimo-app, shown as Xiaomi MiMo) signs in with Xiaomi's long-poll login (account.xiaomi.com/longPolling/loginUrl, sid mimosgp) and keeps the MiMo server's cookie session (serviceToken, userId) in logins.json at 0600; the passToken is replayed to renew the session after a day or on a 401. Requests go to POST <base>/route/chat/completions on mimo-server-{sgp,ru,in}.xiaomimimo.com/api with X-Mimo-Source mimocode-cli-free and X-Client-Version; mimo-auto is sent as mimo-pro; the models are mimo-pro and mimo-flash. Usage from /user/usage and /user/xiaomi/subscription/self. Several accounts, switched, on/off and forgotten as the other subscriptions. The add list has a Xiaomi MiMo tile (Free · Starter · Plus · Pro · Ultra) that says Xiaomi may treat this as third-party use before anything is posted; en and zh. magpie accounts takes mimo. MiMo Code (agent mimocode, OpenCode-like) is configured in its config dir (MIMOCODE_HOME/config when set), reading mimocode.jsonc, mimocode.json or config.json, whichever is there. Tested with internal/provider/mimo_test.go against fake Xiaomi SSO and MiMo servers in a temp HOME, internal/agent tests for MiMo Code's config, and internal/gui/tests/mimo-sub.test.cjs, Chromium and WebKit, en and zh; they fail without the change. factory-sub, click-scroll, old-webkit, zed-sub and add-sheet pass; go vet, go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried with a real Xiaomi account: the long-poll's success payload, the SSO cookie chain, whether /route accepts magpie's requests, the UTC+8 times, and whether MiMo Code picks up the config; not tried in the real Wails window.
2026-09-30 07:43:58 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +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
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
commandcode: a reply is asked for within Command Code's 200000 tokens, and the agents are told no more (Discord: every Command Code model, free or paid, failed with "Too big: expected number to be <=200000 at params.max_tokens") — magpie passed the client's max_tokens to /alpha/generate as it came, and told the agents each Command Code model's reply limit as models.dev gives it: DeepSeek V4's 384000, MiniMax M3's 512000, Space Bunny Alpha's 524288, Kimi K2.x's 262144, so an agent asking for what it was told had the whole request refused. params.max_tokens is now the asked number within the model's own limit as models.dev gives it and within 200000; less is sent as it was, and none asked is still the CLI's 64000. The Command Code subscription's models are listed to the agents (their configs, /v1/models) with a reply limit of at most 200000, a user's own limit included. Prompts and headers are unchanged. TestCommandCodeGoMaxTokens and TestCommandCodeOutputCapped fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-02 06:58:18 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
2026-09-27 08:39:08 +08:00
providers: NVIDIA and ModelScope are presets (#197: 增加 NVIDIA NIM 和魔搭 ModelScope 作为供应商预设) — NVIDIA NIM at integrate.api.nvidia.com/v1 with a key from build.nvidia.com, and 魔搭's API-Inference at api-inference.modelscope.cn/v1 with a ModelScope access token (not DashScope, which the Qwen presets are), each with its models.dev catalog (nvidia, modelscope) and its logo. NVIDIA's /v1/responses answers 404 for its models but a few, so it has chat completions only; ModelScope's /v1/responses is served (401 without a token, 404 for a path it doesn't know), so it has both. Neither has an Anthropic endpoint here. An entry imported at either base URL is the preset, and the import link pages and README list them. Tested: the presets' endpoints, catalogs and import, a /v1/models answer shaped as each sends it (NVIDIA's embedding models left out, ModelScope's object "" rows kept), and catalog.FetchAt against the live integrate.api.nvidia.com (74 models) and api-inference.modelscope.cn (35) lists
2026-09-29 16:40:02 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
2026-10-02 00:40:39 +08:00
routing, models: a rerouted request's tooltip names who answered it (#337), and model names can go without their provider (#335) — the Routing page's and the tray panel's rows named the member that answered a rerouted request, but their tooltip still said the path first resolved; it now says the provider · account · model that answered, and on a second line what it was rerouted from. A setting, Settings → Preferences "Provider in model names" or magpie model suffix off (on by default, as before), writes the models listed to Codex and the other agents (OpenCode, Pi, omp…) by their name alone, except two in an agent's list that would read the same, which keep theirs. routing-reroute-title.test.cjs and plain-names.test.cjs (Chromium, WebKit, en/zh), TestPlainNames, TestPlainNamesReachAgents and TestModelSuffixCmd fail without the change; click-scroll, old-webkit, currency, text-size, panel-routing, routing-served, routing-steady pass. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-09-30 23:09:04 +08:00
subscription: WorkBuddy AI, the international build, is its own subscription (Workbuddy国际版的Subscription是否也要支持呀?… 你应该新加一个Subscription Provider叫做Workbuddy国际版) — workbuddy-ai, "WorkBuddy 国际版 (WorkBuddy AI)" under 订阅. From WorkBuddy AI.app 5.6.2's product config: the same API as the Chinese build at its own endpoint, https://www.workbuddy.ai (isOversea, externalDomain www.codebuddy.ai / www.workbuddy.ai), signed in with platform=workbuddy-ai; its own account is read, never changed, from workbuddy-desktop-ai.info beside workbuddy-desktop.info in CodeBuddyExtension's auth folder, others kept in logins.json apart from the Chinese build's. Its models are its own (the Fast/Balanced/Primary/Deep tiers, GPT-5.5/5.4/5.3-Codex, Gemini 3.1 Pro/3.5 Flash, GLM-5.3/5.2, Hy3, Kimi-K3/K2.6, MiniMax-M3) until /v3/config is read; credits from the same resource summary. workbuddy.go is now parametrised by a wbSite (CN, AI); token cache keyed by site and uid. Checked live: auth/state at www.workbuddy.ai answers and magpie opens https://www.workbuddy.ai/login?platform=workbuddy-ai (200); chat and usage not tried against a real international account.
2026-09-29 00:31:45 +08:00
2026-09-28 00:07:47 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
provider: a MiniMax Coding Plan key shows its windows as rings (#387) — a MiniMax key (api.minimaxi.com, api.minimax.io) had no plan card, only what a balance URL could say in words. Its plan's windows are now asked where MiniMax tells them to the key, GET /v1/token_plan/remains with the key as Bearer (as MiniMax's docs in OpenClaw, oh-my-pi's minimax-code usage and Kilo Code ask it): each model_remains bucket's interval and week, told as what remains, so used is 100 minus it; status 2 (used up) is full whatever the percentage says; a bucket the plan doesn't have (both windows status 3, no totals) is left out; "general" is what the models draw on, another bucket (video…) is shown aside and doesn't stop them. MiniMax answers 200 to a key it refuses, so base_resp's code decides: a pay-as-you-go key gets no card. No relay-specific source is added. TestReadMiniMaxPlan, TestPlanQuotaSource and TestPlanQuotas fail without the change. go vet ./internal/..., go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath and the Claude account tests flake under load, pass alone). Not tried with a real Coding Plan key.
2026-10-01 12:44:48 +08:00
plugins: a moved built-in's own account stays the agent's, and Qoder's first goes (插件版…保持一模一样) — the plugin's accounts were listed with no own one, so removing the agent CLI's own account (Devin, Grok, Command Code, Cursor, Kiro, ZCode, WorkBuddy) signed it out of the plugin and its name stayed as signed in at the move; it is now told by the mark each mover leaves on it, named as the CLI is signed in now, only hidden when removed (the CLI stays signed in) and shown again once the CLI or magpie signs in anew, as the built-in's was. Qoder's first account showed Remove and was refused; it now goes, the next put first, as the built-in let it. plugin.UseCached lets a test stand a plugin's provider up without Bun. TestMovedOwnAccount and TestMovedQoderFirstGoes fail without the change.
2026-10-01 04:04:22 +08:00
plugins: a plugin subscription goes through every path a built-in one does (the user: 要保证插件订阅 provider 跟内置的订阅 provider所有逻辑都要一模一样) — a SOCKS5 proxy on a plugin provider or account now carries its requests: Bun speaks http(s) proxies only, so magpie stands a loopback http proxy in front of the SOCKS one, and a proxy that refuses says so as Go's transport does. A plugin's model list and its loader are asked through the account's own proxy, as a built-in's list is fetched through it. The Grok plugin draws and makes videos at Grok's Imagine API through the plugin, and keeps Codex's namespaced tools, as the built-in does; an official plugin beside its built-in (kiro-plugin, zcode-plugin) counts tokens by estimate as the built-in and the moved plugin do. FetchNew no longer re-lists plugin providers every ten minutes, their list being told by the plugin host; a plugin account's usage is cached under one name whichever way it is asked for; and a fetch hook that throws on its sign-in (a refused refresh) marks the account lapsed, as a built-in's refused refresh does. TestPluginSOCKSProxy, TestPluginModelListThroughAccountProxy, TestGrokPluginDraws, TestPluginBesideBuiltinCountsByEstimate, TestFetchNewLeavesListedPlugins, TestPluginUsageReadOnceWhicheverName and TestPluginFetchSignInExpiredLapses fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (the known load flakes pass alone); internal/plugin, netproxy and the plugin/proxy tests of provider and gateway pass on Linux and Windows.
2026-10-01 19:07:12 +08:00
test(provider): TestFetchNewLeavesListedPlugins waits for the refresh its sign-in started, and TestFetchNewRetriedSoon puts back what it set — signing in with a key (PluginAPIKey) shows the account, which lists the providers while the host's auth event has them stale, so Cached refreshes them in the background; that refresh could end after the test had set the list's time back, rewriting plugin-providers.json, which read as FetchNew asking the plugins again (failed 3 in 5 run after TestFetchNewRetriedSoon, and now and then after TestFetchNewAccount). plugin.Refreshed waits for those refreshes with the host left running, and the test waits before it sets the time. TestFetchNewRetriedSoon now resets newFetches, newSoonAt, wbTokens and the account caches, after waiting for a FetchNewSoon under way. The pair passes 10 in 10 (and with TestFetchNewAccount 10 in 10); ./internal/provider 3 in 3; go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 21:49:16 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
2026-10-01 11:42:45 +08:00
plugins: a plugin's subscription does what a built-in's does, in seven places it didn't (the user: 要保证插件订阅 provider 跟内置的订阅 provider所有逻辑都要一模一样) — an installed plugin's provider id is kept for it signed in or not, as a built-in's is: a provider of the user's own isn't saved on it, renamed onto it or imported as it (freeID gives id-2). A plugin's account whose plan lacks the model is tried after the ones that list it, as a Codex Free account behind a Plus, by the list the plugin told for it. Cursor's plugin has fast mode where the built-in Cursor has it: a model with a -fast one is saved :fast in a group and sent service_tier "priority", one without is refused. Removing a plugin's provider hides it as a built-in's is, its accounts kept and shown again from Hidden or by signing in, rather than signing every account out ("stays signed in" said so already). magpie accounts lists, adds, switches and forgets a plugin's accounts by its provider's id or name. Grok's plugin beside the built-in Grok (grok-plugin) searches by itself as Grok does. A plugin's plan is named as its built-in's ("Cursor Pro", "SuperGrok"), and a plugin's resets are shown but have no Use button or Auto-use, which spent Codex's reset of the same user. TestPluginIDReservedSignedOut, TestPluginAccountLackingTheModelGoesLast, TestCursorPluginGroupFast, TestAccountsOfAPlugin, TestGrokPluginSearchesItself, plugin-plan and codex-auto-reset fail without the change; TestPluginSignIn and TestPluginAccounts now expect a removed plugin hidden. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestClaudeSignedOut failed once under load, passes alone); the gateway, provider and plugin suites and TestAccountsOfAPlugin pass on Windows, the plugin tests on Linux.
2026-10-01 20:26:55 +08:00
2026-10-01 11:15:26 +08:00
2026-10-01 11:15:26 +08:00
2026-10-01 06:12:11 +08:00
2026-10-01 11:42:45 +08:00
plugins: a plugin's subscription does what a built-in's does, in seven places it didn't (the user: 要保证插件订阅 provider 跟内置的订阅 provider所有逻辑都要一模一样) — an installed plugin's provider id is kept for it signed in or not, as a built-in's is: a provider of the user's own isn't saved on it, renamed onto it or imported as it (freeID gives id-2). A plugin's account whose plan lacks the model is tried after the ones that list it, as a Codex Free account behind a Plus, by the list the plugin told for it. Cursor's plugin has fast mode where the built-in Cursor has it: a model with a -fast one is saved :fast in a group and sent service_tier "priority", one without is refused. Removing a plugin's provider hides it as a built-in's is, its accounts kept and shown again from Hidden or by signing in, rather than signing every account out ("stays signed in" said so already). magpie accounts lists, adds, switches and forgets a plugin's accounts by its provider's id or name. Grok's plugin beside the built-in Grok (grok-plugin) searches by itself as Grok does. A plugin's plan is named as its built-in's ("Cursor Pro", "SuperGrok"), and a plugin's resets are shown but have no Use button or Auto-use, which spent Codex's reset of the same user. TestPluginIDReservedSignedOut, TestPluginAccountLackingTheModelGoesLast, TestCursorPluginGroupFast, TestAccountsOfAPlugin, TestGrokPluginSearchesItself, plugin-plan and codex-auto-reset fail without the change; TestPluginSignIn and TestPluginAccounts now expect a removed plugin hidden. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestClaudeSignedOut failed once under load, passes alone); the gateway, provider and plugin suites and TestAccountsOfAPlugin pass on Windows, the plugin tests on Linux.
2026-10-01 20:26:55 +08:00
plugins: a plugin's subscription does what a built-in's does, in seven places it didn't (the user: 要保证插件订阅 provider 跟内置的订阅 provider所有逻辑都要一模一样) — an installed plugin's provider id is kept for it signed in or not, as a built-in's is: a provider of the user's own isn't saved on it, renamed onto it or imported as it (freeID gives id-2). A plugin's account whose plan lacks the model is tried after the ones that list it, as a Codex Free account behind a Plus, by the list the plugin told for it. Cursor's plugin has fast mode where the built-in Cursor has it: a model with a -fast one is saved :fast in a group and sent service_tier "priority", one without is refused. Removing a plugin's provider hides it as a built-in's is, its accounts kept and shown again from Hidden or by signing in, rather than signing every account out ("stays signed in" said so already). magpie accounts lists, adds, switches and forgets a plugin's accounts by its provider's id or name. Grok's plugin beside the built-in Grok (grok-plugin) searches by itself as Grok does. A plugin's plan is named as its built-in's ("Cursor Pro", "SuperGrok"), and a plugin's resets are shown but have no Use button or Auto-use, which spent Codex's reset of the same user. TestPluginIDReservedSignedOut, TestPluginAccountLackingTheModelGoesLast, TestCursorPluginGroupFast, TestAccountsOfAPlugin, TestGrokPluginSearchesItself, plugin-plan and codex-auto-reset fail without the change; TestPluginSignIn and TestPluginAccounts now expect a removed plugin hidden. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestClaudeSignedOut failed once under load, passes alone); the gateway, provider and plugin suites and TestAccountsOfAPlugin pass on Windows, the plugin tests on Linux.
2026-10-01 20:26:55 +08:00
signin: Grok and Command Code sign in from magpie in Docker (xugui on Discord: docker版登不上grok和command code) — Grok's sign-in first installs Grok Build with its installer, curl … | bash, and the image has neither bash nor curl, so it stopped at "installing Grok Build failed (exec: "bash": executable file not found)"; the community Grok plugin, beside the built-in rather than moved onto, wasn't given the CLI at all and said "install Grok Build first". Where no shell and curl/wget can run, Grok Build is now installed as its installer does, from the same x.ai/cli (then its storage bucket) address: the stable version, its binary for the platform, checked with --version, linked as ~/.grok/bin/grok and agent, installer = "internal" noted in its config.toml; the plugin's sign-in installs it first too. The device sign-in itself needs nothing back from the browser and was fine. Command Code's Studio posts the key to magpie's 127.0.0.1 port in the background, which a browser outside the container can't reach and no address carries; while it waits, its sign-in now takes an API key made on commandcode.ai/settings/keys and pasted (as Command Code's own CLI offers), checked with whoami and its plan as Studio's was, and a plugin's browser sign-in offers "Use an API key instead", its own api way (the Command Code plugin has one). No identity, header or prompt changes. TestGrokInstallsWithoutShell, TestCommandCodeSignInPastedKey and TestGrokPluginSignInInstallsCLI fail without the change, signin-paste-key.test.cjs too. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; signin-paste-key, signin-paste-codex, plugin-signin, signin-callback, commandcode-risk, plugin-key-hint, signin-link, click-scroll, old-webkit pass.
2026-10-01 22:25:39 +08:00
2026-10-02 00:40:39 +08:00
usage: a model spelled with a dotted version is priced at its maker's, and a model can be priced from any provider (tony on Discord: old sessions' copilot/claude models had no known price) — Copilot and its CLI's sessions name Anthropic's models claude-opus-4.6 and claude-haiku-4.5, models.dev's anthropic entry claude-opus-4-6 and claude-haiku-4-5, and a session's bare model was looked up only by its exact key at its maker, so neither was priced; a gateway call whose provider is gone or lists no price fell to the same miss. A price is now looked for with a dot and a dash taken for the same, after every exact match. gemini-3-pro-preview stays unpriced: Google's entry on models.dev no longer lists it and no price is made up. For it, and any model like it, magpie model price <model> <in>,<out>,<cache read>,<cache write> keeps a price under */<model> that counts from any provider not priced by the user, after <provider>/<model> and <provider>/* and before any list price, and for a session's bare model; --reset takes it away, magpie model prices lists it. TestDottedIDPricedAtItsMakers, TestAnyProviderPrice and TestPriceOfDottedAndAnyProvider fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 17:46:54 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
providers: each account of a subscription, and each key, can be kept for some of the provider's models only (#474: 增加账号级别的模型选项, a low-quota but verified account kept for the cheap models) — every account or key a provider had served every model it did, so one couldn't be spared for some. An account's or key's row in its provider's editor now has a models badge: a click opens the provider's models as chips, Save keeps the account for those picked, All models gives it every one again; one kept for some says how many, always shown. magpie provider account-models <id> [account|key [models…|all]] does the same and lists them. It is kept in providers.json as accountModels, an account by its name in lower case, a key by its id; one not in it serves every model, as before. The gateway never sends a model to an account or key whose list leaves it out, in every routing mode, in drag order, in a group and as a fallback, and never falls back to it all the same; the trace says it was left out as set to serve other models. When every account or key there is leaves the model out, the request is refused with a 403 saying so and how to change it, not "none of X's models is ready". TestKeyModelsNarrowCandidates, TestAccountModelsNeverChosen, TestAccountModelsCmd and account-models.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; account-models, click-scroll, old-webkit, account-arrange, account-proxy, account-return, routing-account-order, panel-routing, unlisted-models pass.
2026-10-02 05:50:23 +08:00
providers: each account of a subscription holding several can go through its own proxy — the provider's, none, or its own address (Discord, gakki: 是否可以为不同的codex账号设置不用的代理,现在是同一个供应商下使用相同的代理) — the per-provider proxy (#237) was one for all of Codex's signed-in accounts. A subscription's entry in providers.json now keeps accountProxies, by the account's name in lower case, each checked by settings.CheckProxy on save (ftp:// refused), addresses trimmed, accounts following the provider's proxy left out. Provider.ProxyChoice picks an account's own proxy, else the provider's, else the global one, so everything that already went through Provider.Via follows the account: gateway turns and fallback across accounts, usage and quota, token refresh, Codex's warm-up, reset and saved accounts' model lists, Claude's warm-up and the *_PROXY of Claude Code runs (ViaLogin / ProxyOfLogin), and Codex's own sign-in relayed as it came (ViaSignedIn). Extra accounts of Copilot, ZCode, Kiro and the like, made afresh without the provider's settings, now read them from providers.json, so they honour the provider's proxy too. A save without accountProxies keeps them; {} clears them. The provider editor, for a subscription with two or more accounts, lists each under the Proxy row: Provider's proxy | Direct | Custom, the address field's room kept so a pick moves nothing; Custom with no address is refused before anything is posted, its field focused without scrolling. en and zh together; no border stripes. Tested with internal/gateway/account_proxy_test.go in a sandbox HOME against fake proxies and a fake ChatGPT backend: three Codex accounts (own proxy, direct, following the provider) each reach the backend their own way in one turn and for usage; clearing an account's proxy sends it through the provider's, clearing the provider's through the global one, direct staying direct; ftp:// refused; TestClaudeAccountProxyEnv covers each Claude account's HTTPS_PROXY. Both fail with the per-account lookup off. account-proxy.test.cjs, Chromium and WebKit, en and zh (new), provider-proxy, click-scroll and old-webkit pass. go vet ./internal/..., go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried against a real proxy, real accounts or the real Wails window; Grok's per-account usage and Kiro's usage on a key still use the provider's proxy.
2026-09-30 04:52:03 +08:00
2026-09-29 02:37:58 +08:00
2026-09-29 23:25:56 +08:00
subscriptions: Qoder CN, for accounts on qoder.cn (#349) — Qoder's China site (qoder.cn, Alibaba Cloud or phone sign-in) has its own accounts, sign-in page, account API (openapi.qoder.com.cn) and gateway (gateway.qoder.com.cn), so a qoder.cn account couldn't sign in through magpie's Qoder, which only knows qoder.com. A new Qoder CN subscription signs in there with the client id Qoder CN's own CLI sends, and everything after — polling, job token and refresh, user info, models, usage and chat — follows the site saved with the account; if qoder.cn refuses the job token, the account chats with its device token and renews it, as that CLI does. Qoder's tile is now Qoder (international), each tile saying which accounts it is for. Accounts saved before keep working on qoder.com unchanged. Not tried with a real qoder.cn account. TestSites, TestCNDeviceChatRefresh, TestQoderCNSignIn, TestQoderCNDeviceChat, TestQoderGlobalUnchanged and TestQoderCNGateway fail without the change; qoder-cn-tile.test.cjs (Chromium, WebKit, en/zh) added. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass but for TestCursorPluginContext, which fails on main (1ce05f0) as well; click-scroll, old-webkit pass.
2026-10-01 01:42:12 +08:00
qoder: a model Qoder's listing marks free is shown free (lml on Discord asked which Qoder models cost no credits) — a model with is_free (isFree) true or a price_factor (priceFactor) of 0, as Qoder's own client reads its listing, gets catalog.Model.Free, so the model picker's free badge shows on it; a saved account's models, re-read from its stored listing, carry it too. TestParseModelsFree and TestQoderSavedModelsFree fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestClaudeSignedOut, a load flake, passes alone).
2026-09-30 17:29:55 +08:00
subscriptions: Qoder CN, for accounts on qoder.cn (#349) — Qoder's China site (qoder.cn, Alibaba Cloud or phone sign-in) has its own accounts, sign-in page, account API (openapi.qoder.com.cn) and gateway (gateway.qoder.com.cn), so a qoder.cn account couldn't sign in through magpie's Qoder, which only knows qoder.com. A new Qoder CN subscription signs in there with the client id Qoder CN's own CLI sends, and everything after — polling, job token and refresh, user info, models, usage and chat — follows the site saved with the account; if qoder.cn refuses the job token, the account chats with its device token and renews it, as that CLI does. Qoder's tile is now Qoder (international), each tile saying which accounts it is for. Accounts saved before keep working on qoder.com unchanged. Not tried with a real qoder.cn account. TestSites, TestCNDeviceChatRefresh, TestQoderCNSignIn, TestQoderCNDeviceChat, TestQoderGlobalUnchanged and TestQoderCNGateway fail without the change; qoder-cn-tile.test.cjs (Chromium, WebKit, en/zh) added. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass but for TestCursorPluginContext, which fails on main (1ce05f0) as well; click-scroll, old-webkit pass.
2026-10-01 01:42:12 +08:00
subscriptions: Qoder CN, for accounts on qoder.cn (#349) — Qoder's China site (qoder.cn, Alibaba Cloud or phone sign-in) has its own accounts, sign-in page, account API (openapi.qoder.com.cn) and gateway (gateway.qoder.com.cn), so a qoder.cn account couldn't sign in through magpie's Qoder, which only knows qoder.com. A new Qoder CN subscription signs in there with the client id Qoder CN's own CLI sends, and everything after — polling, job token and refresh, user info, models, usage and chat — follows the site saved with the account; if qoder.cn refuses the job token, the account chats with its device token and renews it, as that CLI does. Qoder's tile is now Qoder (international), each tile saying which accounts it is for. Accounts saved before keep working on qoder.com unchanged. Not tried with a real qoder.cn account. TestSites, TestCNDeviceChatRefresh, TestQoderCNSignIn, TestQoderCNDeviceChat, TestQoderGlobalUnchanged and TestQoderCNGateway fail without the change; qoder-cn-tile.test.cjs (Chromium, WebKit, en/zh) added. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass but for TestCursorPluginContext, which fails on main (1ce05f0) as well; click-scroll, old-webkit pass.
2026-10-01 01:42:12 +08:00
subscriptions: Qoder CN, for accounts on qoder.cn (#349) — Qoder's China site (qoder.cn, Alibaba Cloud or phone sign-in) has its own accounts, sign-in page, account API (openapi.qoder.com.cn) and gateway (gateway.qoder.com.cn), so a qoder.cn account couldn't sign in through magpie's Qoder, which only knows qoder.com. A new Qoder CN subscription signs in there with the client id Qoder CN's own CLI sends, and everything after — polling, job token and refresh, user info, models, usage and chat — follows the site saved with the account; if qoder.cn refuses the job token, the account chats with its device token and renews it, as that CLI does. Qoder's tile is now Qoder (international), each tile saying which accounts it is for. Accounts saved before keep working on qoder.com unchanged. Not tried with a real qoder.cn account. TestSites, TestCNDeviceChatRefresh, TestQoderCNSignIn, TestQoderCNDeviceChat, TestQoderGlobalUnchanged and TestQoderCNGateway fail without the change; qoder-cn-tile.test.cjs (Chromium, WebKit, en/zh) added. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass but for TestCursorPluginContext, which fails on main (1ce05f0) as well; click-scroll, old-webkit pass.
2026-10-01 01:42:12 +08:00
usage: a notification when a window is nearly used up or a balance runs low (#368) — Settings has Usage alert (off, or a share of 1–100%, 80 by default) and Low balance alert (off, or an amount, 5 by default), and magpie quota alert sets them from the command line. Each subscription or plan window, other than one set aside, is told once a run when it reaches the share, and a balance once until topped up past the amount again; what was said is kept, so a restart doesn't say it again, and a failed or stale reading neither alerts nor clears. The system's notifications are started only when first needed, so a Mac build that can't have them or a Linux desktop without a daemon still starts, and Settings says when they are refused or unavailable; a click opens the Usage page. TestDueAlerts and friends, TestAlertText and usage-alert.test.cjs fail without the change.
2026-10-01 04:16:28 +08:00
usage: a notification when a window is nearly used up or a balance runs low (#368) — Settings has Usage alert (off, or a share of 1–100%, 80 by default) and Low balance alert (off, or an amount, 5 by default), and magpie quota alert sets them from the command line. Each subscription or plan window, other than one set aside, is told once a run when it reaches the share, and a balance once until topped up past the amount again; what was said is kept, so a restart doesn't say it again, and a failed or stale reading neither alerts nor clears. The system's notifications are started only when first needed, so a Mac build that can't have them or a Linux desktop without a daemon still starts, and Settings says when they are refused or unavailable; a click opens the Usage page. TestDueAlerts and friends, TestAlertText and usage-alert.test.cjs fail without the change.
2026-10-01 04:16:28 +08:00
claude: magpie no longer asks Anthropic for a Claude account's usage, and adding a Claude account warns of a ban (the user: 不要伪造任何的 Claude 请求,能否通过 claude cli 获取 / 我害怕被封; 添加账号时要像其他的 Subscription Provider 一样显示风险提示) — the usage was read by magpie itself calling Anthropic's /api/oauth/usage with the account's token, on a timer, for every saved account, and Claude's usage-limit resets (cedar_ember) were listed, spent and auto-spent the same way. Now the usage is what Claude Code's own /usage prints (claude -p /usage, a command Claude Code answers itself without asking a model), run only when Usage is opened or Refresh pressed (GUI, magpie quota, accounts, TUI), for the account Claude Code is signed in to, at most once in 30s; a saved account shows only what Claude Code reported while using it, or the last reading kept. The Claude resets, Auto-use and their settings are gone (Codex's stay). Session jsonl files hold no usage figures, so they aren't read. Starting a Claude sign-in or import (GUI and CLI) first says Anthropic may suspend or ban the account and that it is at the user's own risk. TestClaudeWindowsAsked, TestParseClaudeUsage, TestClaudeUsageRunsClaudeCode, claude-usage-asked.test.cjs and claude-risk.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; routing-auto-reset, codex-auto-reset, quota-families, tray-usages, click-scroll, old-webkit, plugin-signin, usage-alert, usage-ledger pass.
2026-10-01 12:38:25 +08:00
gateway: a conversation stays with the account that answered it across a restart of magpie, and routing goes by each account's last known allowance until the first reading since the start is back (vincentzhang on Discord: in smart routing a restart moved a session to the first account, an update and restart back to the second, and the prompt cache was read by neither) — who answered a conversation last was kept in memory only, so after a restart every conversation was "first" and went to whoever routing put first; and until the accounts' allowances were read again (a first wait of 3s, the read itself up to 30s) none was known, every account counted as unused and the first in order went first, until the reading came back and put the one renewing soonest first again. Who answered is now also kept in affinity.json next to the providers (0600, written atomically, the latest 512 conversations, none older than the 24h a conversation is remembered), read again when a conversation isn't known here and the file changed — after a restart, or written by the magpie handing over. The rules for when a conversation moves are unchanged: within a turn it stays, across turns while the vendor read enough from its cache within the last five minutes, and never to an account resting, all but used up or gone. While the first reading is out, Allowances returns each account's last reading kept in quotas.json, its windows past their reset counted empty. Prompts and headers are unchanged. TestAffinitySurvivesRestart and TestAllowancesBeforeFirstReading fail without the change; TestAffinityFileBounded keeps the file bounded. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestFetchNewLeavesListedPlugins and TestFXInState flake under load on main too, pass alone).
2026-10-01 20:09:25 +08:00
2026-09-26 22:22:30 +08:00
usage: a Codex account's rate-limit resets are on its card, so they don't go unused (可能把 resets card 在里边反应出来么?免得我们忘了用) — wham/usage's rate_limit_reset_credits count, and from /wham/rate-limit-reset-credits when the first of those left runs out, show as "↺ 2 resets · until Sat 22:30" under a hairline on the tray's Usage card, under the account's windows in the window's Usage view, and in magpie quota / accounts and the TUI (nothing when there are none, no date when none expire); "Use one…" asks first — which account, that its windows start again at once, that it can't be undone, and that there is nothing to start again when no window has been used — then spends one with a fresh redeem_request_id on that account (POST /api/usage/codex-reset, or magpie quota reset [<account>] [--yes]), says what came of it in words and reads the usage again; the account signed in now is found from Codex's own auth.json, not only the list magpie keeps. panel: a section's account count is a quiet rounded pill by its name, not a bare 2 at the far end (那个 2 是没有仔细打磨), the "N accounts" kept as its tooltip
2026-09-28 18:01:48 +08:00
providers: a Remote magpie provider uses another computer's shared magpie, each request translated at most once (Jorben on Discord: 远程 magpie / magpie 接力) — a custom provider pointed at another magpie has one API per address and couldn't know which API each model's own provider serves, so a request was translated on both computers (Chat → Messages here, then again there). magpie's /v1/models now tells each model's native_endpoints (the APIs its provider serves it on; none for a routing group) and its image input, and reads them, with max_output_tokens and supported_reasoning_levels, from a list; the new remote-magpie preset takes the other magpie's address however typed (host:port, /v1, /v1/messages) for all three APIs and lists all its models, its user's choice already. Add sheet tile with the address field and a hint to Settings → Share on local network; CLI: magpie provider add remote-magpie <key> url=http://<ip>:3425. Checked with two sandbox magpies over the LAN address with the key check on and a Messages-only fake upstream: Chat, Messages (streamed), count_tokens, Responses, a routing group and Gemini all reached it as /v1/messages, translated once. TestRemoteMagpieNativeAPI, TestFetchMagpieFields and TestRemoteMagpie fail without the change; remote-magpie.test.cjs (Chromium, WebKit, en/zh) added. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass but for TestCursorPluginContext, which fails on main (1ce05f0) as well; click-scroll, old-webkit pass.
2026-10-01 01:35:18 +08:00
remote magpie: its image models reach this magpie, and look-alike models say which provider they are from (Jorben and 莫 on Discord) — another magpie's /v1/models listed chat models only, so its image models were never found here unless their id said "image"; a magpie now asks for them (X-Magpie-Drawers), the other lists them marked kind:image, and they show in Settings → Images and draw through its /v1/images/generations, which asks the model's vendor the way it draws there. Each model also comes with its name and its provider there (magpie_label), so two relays' "Claude Sonnet 5" no longer read the same. An older magpie on either side reads the list as before. TestRemoteMagpieModels fails without the change; TestRemoteMagpieOldList covers an old remote. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; remote-magpie passes.
2026-10-01 12:05:21 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
plugins: a plugin's subscription does what a built-in's does, in seven places it didn't (the user: 要保证插件订阅 provider 跟内置的订阅 provider所有逻辑都要一模一样) — an installed plugin's provider id is kept for it signed in or not, as a built-in's is: a provider of the user's own isn't saved on it, renamed onto it or imported as it (freeID gives id-2). A plugin's account whose plan lacks the model is tried after the ones that list it, as a Codex Free account behind a Plus, by the list the plugin told for it. Cursor's plugin has fast mode where the built-in Cursor has it: a model with a -fast one is saved :fast in a group and sent service_tier "priority", one without is refused. Removing a plugin's provider hides it as a built-in's is, its accounts kept and shown again from Hidden or by signing in, rather than signing every account out ("stays signed in" said so already). magpie accounts lists, adds, switches and forgets a plugin's accounts by its provider's id or name. Grok's plugin beside the built-in Grok (grok-plugin) searches by itself as Grok does. A plugin's plan is named as its built-in's ("Cursor Pro", "SuperGrok"), and a plugin's resets are shown but have no Use button or Auto-use, which spent Codex's reset of the same user. TestPluginIDReservedSignedOut, TestPluginAccountLackingTheModelGoesLast, TestCursorPluginGroupFast, TestAccountsOfAPlugin, TestGrokPluginSearchesItself, plugin-plan and codex-auto-reset fail without the change; TestPluginSignIn and TestPluginAccounts now expect a removed plugin hidden. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestClaudeSignedOut failed once under load, passes alone); the gateway, provider and plugin suites and TestAccountsOfAPlugin pass on Windows, the plugin tests on Linux.
2026-10-01 20:26:55 +08:00
2026-09-25 01:57:27 +08:00
gateway: a conversation stays with the account that answered it across a restart of magpie, and routing goes by each account's last known allowance until the first reading since the start is back (vincentzhang on Discord: in smart routing a restart moved a session to the first account, an update and restart back to the second, and the prompt cache was read by neither) — who answered a conversation last was kept in memory only, so after a restart every conversation was "first" and went to whoever routing put first; and until the accounts' allowances were read again (a first wait of 3s, the read itself up to 30s) none was known, every account counted as unused and the first in order went first, until the reading came back and put the one renewing soonest first again. Who answered is now also kept in affinity.json next to the providers (0600, written atomically, the latest 512 conversations, none older than the 24h a conversation is remembered), read again when a conversation isn't known here and the file changed — after a restart, or written by the magpie handing over. The rules for when a conversation moves are unchanged: within a turn it stays, across turns while the vendor read enough from its cache within the last five minutes, and never to an account resting, all but used up or gone. While the first reading is out, Allowances returns each account's last reading kept in quotas.json, its windows past their reset counted empty. Prompts and headers are unchanged. TestAffinitySurvivesRestart and TestAllowancesBeforeFirstReading fail without the change; TestAffinityFileBounded keeps the file bounded. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestFetchNewLeavesListedPlugins and TestFXInState flake under load on main too, pass alone).
2026-10-01 20:09:25 +08:00
routing: a group's rule can hold hours of the day (Discord: send DeepSeek's or GLM's peak-price hours to another provider) — a rule takes time: {from, to, days} in this computer's local time, HH:MM to HH:MM; hours that end before they begin run past midnight and belong to the day they begin on (Friday's 22:00–08:00 takes Saturday's early hours), days are optional, and the hours are checked as a turn begins, so a turn that began inside them finishes where it went. The rule reads "time 09:00–18:00 Mon–Fri" on the group and in the trace; the editor types the hours into one pill (从 … 到 …), notes past midnight, marks a time that isn't one and picks days like the agents (every day, weekdays, weekends, or each); magpie group rule add … time=14:00-18:00 days=mon-fri and the TUI's rule line take it too. Older versions ignore the field, and a rule with only hours then matches nothing there. TestRuleTimeMatches and TestRuleTimeWindowAtTurnStart (injected clock) and routing-time.test.cjs fail without the change. A sandbox magpie with two fake vendors sent a request inside the hours to the rule's member and one outside them, or on another day, to the first. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; routing-time, routing-compact, routing-manual, routing-steady, settings-groups, click-scroll, old-webkit pass.
2026-10-01 15:04:16 +08:00
gateway: a model's web search goes to a search API of the user's own when no provider can search (#419 by HwFee: let me set up Tavily, Brave or SearXNG with my key rather than lose the search tool) — with no provider that searches by itself and no provider magpie could search with, the gateway took the client's web search tool away. Tavily, Brave Search, Exa, Firecrawl and SearXNG (an address of one's own, a key only if it asks for one) can now be set up, in an order: the injected web_search tool is then offered, and a search goes to the searcher's model as before, or, with none or when it fails, to each search API in turn, called directly with no model, its results handed back as the same hits and text the searcher path gives, so clients see the same web_search_tool_result blocks. The order is provider searches itself, searcher provider, search APIs, strip. They are kept in providers.json (0600) like provider keys; a backup carries them, their keys only when it carries keys, and one restored without keys keeps the key here; sync does the same, and a backup or sync from a magpie before them leaves the ones here alone. magpie search lists them, magpie search add <api> [key] [url=…] adds or updates one, magpie search rm <api> removes one; Settings has a Web search section (联网搜索) to add and remove them. Prompts, identity lines and headers to model providers are unchanged. TestWebSearchBySearchAPI, TestNoSearchAPINoTool, TestBackupSearchAPIs, TestSyncSearchAPIs and search-api.test.cjs fail without the change; TestSearchAPIsEachAsked checks each vendor against a fake, TestSearchCLI the command. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; search-api, provider-search, click-scroll, old-webkit pass.
2026-10-01 19:44:44 +08:00
2026-10-01 17:42:10 +08:00
2026-10-01 17:42:10 +08:00
kiro: removing kiro-cli's or the Kiro IDE's own sign-in hides it in magpie, and it shows again when Kiro signs in anew (Discord 碳碳双键: 本机没安装 kiro,但旧的 Kiro 数据还在,magpie 列出一个"Kiro account"(登录已失效,请重新添加此账号),添加新账号并设为首位后,旧的数据无法移除) — magpie reads Kiro's own sign-in from kiro-cli's database or ~/.aws/sso/cache and lists it among the accounts it signed in; Remove on it said "that is kiro-cli's or the Kiro IDE's own sign-in; run kiro-cli logout or sign out in the IDE", which with neither installed left a dead account there for good. The same refusal was shared by every agent whose own sign-in magpie only reads (forgetSideLogin: Kiro, Devin, Grok, Copilot, ZCode, WorkBuddy and WorkBuddy AI, Command Code, Gemini CLI, Antigravity). Now Remove on the agent's own sign-in hides it: logins.json's entry for it keeps a Hidden mark, and it is left out of the account list and so of the gateway's tries (the first and the ones behind it both come from that list); the agent's files are never deleted or written. It shows again when that sign-in changes: for Kiro, by a mark that is a digest of where the sign-in is (kiro-cli's row or the IDE's file) and its refresh token (never the token itself), so a new kiro-cli login or IDE sign-in, to any account, brings it back; for the others, which have no such mark, when it is another account. Removing it while it is first is allowed now, the next account being put first (saved, so it stays first when the own one comes back); removed when it was the only one, the agent has no account left. One of magpie's own accounts is removed with its home as before, and still can't be while it is first. The error and its per-agent sign-out hints are gone. Logins carry own, and the accounts list shows Remove on the agent's own sign-in also while it is first, its title "magpie stops showing and using Kiro's own sign-in; its files are left as they are, and it shows again when Kiro signs in anew" (magpie 不再显示和使用 Kiro 自己的登录;它的文件保持原样,Kiro 重新登录后会再次出现). Tested with a new internal/provider/side_logins_hide_test.go in a sandbox HOME: an expired kiro-cli sign-in ("Kiro account") behind a Google one magpie signed in is removed, stays gone across reads, isn't the account used nor among AlsoOn, kiro-cli's database byte-for-byte and mtime as it was, the refresh token nowhere in magpie's files; a new kiro-cli sign-in brings it back behind the one first; put first and removed, the next is first; one of magpie's removed takes its home and leaves the other's; the only account removed leaves Kiro with none; Grok's CLI sign-in hidden with auth.json untouched, back once it is another account. The agents' tests that expected the refusal (Command Code, Copilot, Devin, Grok, WorkBuddy, ZCode) no longer do. A new internal/gui/tests/own-signin-remove.test.cjs in Chromium and WebKit, en and zh: kiro-cli's sign-in behind another and alone first both have Remove with that title and post login/forget, magpie's first account has none. go build -tags nogui (and GOOS=linux, GOOS=windows), go test -tags nogui ./... and the whole GUI suite (138) pass. Not tried with a real Kiro, kiro-cli or the Kiro IDE.
2026-09-29 23:52:33 +08:00
migrate: a moved built-in keeps its models' reasoning levels, its own account's plan and one own row, and the move checks each account through its proxy (要保证插件订阅 provider 跟内置的订阅 provider所有逻辑都要一模一样) — Command Code's, Grok's and WorkBuddy's models their vendor gives no levels for lost the ones the built-in borrowed from their maker; moved, they borrow them again. Devin's own account moved without the plan the Devin CLI says, which the built-in showed. The agent signing in to another account while moved wrote a new own row for the built-in, which came back beside the one set aside as a second own account; nothing is written while moved, and going back keeps the one. And the move's check of an account asked the vendor directly, not through the proxy its requests take. Found walking Command Code, Grok, Devin, ZCode and WorkBuddy through sandbox moves. TestMovedKeepsEfforts, TestMovedOwnRowNotWritten, TestDevinOwnMovesWithPlan and TestPluginProxy fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 07:04:40 +08:00
claude: the Claude accounts saved in magpie are served while Claude Code is logged out, and none is dropped (StringKe on Discord: CC(API) -> Magpie -> CC Subscription, and as soon as I /logout in Claude Code all six accounts I manage in magpie disappear) — magpie served its saved Claude accounts only beside the one Claude Code was signed in to: claudeAccount gave no provider without Claude Code's own credentials (or with claude auth status saying no one is signed in), so the gateway had no Claude account at all and the page said the saved ones "are only offered beside the account it is signed in to". Claude Code itself tells the user to log out: with magpie's ANTHROPIC_AUTH_TOKEN beside a claude.ai sign-in it warns "ANTHROPIC_AUTH_TOKEN overriding Claude subscription login · unset it or /logout to sign it out". magpie keeps every account's sign-in in logins.json, so a logout now signs none of them out of magpie: the account seen last (the one Claude Code was signed in to until then, which magpie saw every 30s) stands in its place, run in a config directory of its own as the others on are, listed on, and it can be paused behind another as Claude Code's own could; the others on are served behind it, the Usage page reads it as a saved account, and the saved-but-signed-out notice is no longer given for Claude. An account whose saved sign-in is unreadable is listed as signed out ("its sign-in is gone; sign in again"), never dropped, and isn't picked to stand in while another has one. An account signed in in magpie while Claude Code is logged out and magpie has Claude accounts no longer signs Claude Code back in (which only brought back its warning); it is magpie's alone, on, and the one served first till then stays on behind it. Prompts, identity lines and headers are unchanged; magpie still never refreshes a Claude sign-in nor asks Anthropic anything itself. TestClaudeAccountsOutliveLogout, TestClaudeSignInWhileLoggedOut and TestSavedButSignedOutClaudeServed fail without the change; TestSavedButSignedOutCanBeRemoved now removes the account from the list. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestFetchNewLeavesListedPlugins, a bun plugin test, failed once under load and passes alone and in a rerun of the package).
2026-10-01 20:13:58 +08:00
claude: adding a Claude account is Claude Code's own claude auth login, and magpie never refreshes a Claude sign-in nor asks Anthropic anything with one (the user: 把 magpie 自己的 Claude 登录改成直接用 claude /login,只要体验上没什么差别就改) — magpie traded the sign-in page's code for tokens with Claude Code's OAuth client, asked Anthropic's profile and model list with them, refreshed saved accounts itself (daily keepalive included) and handed a saved account to Claude Code as CLAUDE_CODE_OAUTH_TOKEN. Now Add account runs claude auth login --claudeai in a config directory of magpie's own: the page Claude Code would open comes to magpie's window (Claude Code is given magpie as its BROWSER, which writes the page down and exits), the browser comes back to Claude Code's own listener, and when the browser can't reach this machine the address it ended on, or the code Claude's page shows, is pasted as before and handed to Claude Code. Who signed in is what Claude Code kept (.claude.json, auth status). A saved account in use beside the signed-in one runs Claude Code with CLAUDE_CONFIG_DIR set to its own directory (claude-accounts/ beside magpie's config), its sign-in put there once from logins.json and read back as Claude Code refreshes it; switching to it moves it into Claude Code's own store and removes the directory, as forgetting it does. Claude's models are the catalog's (models.dev), not asked of Anthropic; an imported Claude login is kept as the file has it, and Claude Code refreshes it on first use. Claude Code is required to add a Claude account. TestClaudeSignInByPaste, TestClaudeSignInByPastedAddress, TestClaudeSavedAccountDir (a fake claude CLI, and a server standing in for Anthropic that fails the test if asked) and the reworked sign-in, import and gateway tests fail without the change. With the real Claude Code 2.1.286 in a sandbox directory, its sign-in page (localhost callback) reached magpie's binary and the sign-in waited for the browser; nothing was left behind once it was canceled. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; claude-risk, plugin-signin, signin-callback, signin-link, signin-paste-codex, routing-signin, own-signin-remove, click-scroll, old-webkit pass.
2026-10-01 16:37:07 +08:00
claude: adding a Claude account is Claude Code's own claude auth login, and magpie never refreshes a Claude sign-in nor asks Anthropic anything with one (the user: 把 magpie 自己的 Claude 登录改成直接用 claude /login,只要体验上没什么差别就改) — magpie traded the sign-in page's code for tokens with Claude Code's OAuth client, asked Anthropic's profile and model list with them, refreshed saved accounts itself (daily keepalive included) and handed a saved account to Claude Code as CLAUDE_CODE_OAUTH_TOKEN. Now Add account runs claude auth login --claudeai in a config directory of magpie's own: the page Claude Code would open comes to magpie's window (Claude Code is given magpie as its BROWSER, which writes the page down and exits), the browser comes back to Claude Code's own listener, and when the browser can't reach this machine the address it ended on, or the code Claude's page shows, is pasted as before and handed to Claude Code. Who signed in is what Claude Code kept (.claude.json, auth status). A saved account in use beside the signed-in one runs Claude Code with CLAUDE_CONFIG_DIR set to its own directory (claude-accounts/ beside magpie's config), its sign-in put there once from logins.json and read back as Claude Code refreshes it; switching to it moves it into Claude Code's own store and removes the directory, as forgetting it does. Claude's models are the catalog's (models.dev), not asked of Anthropic; an imported Claude login is kept as the file has it, and Claude Code refreshes it on first use. Claude Code is required to add a Claude account. TestClaudeSignInByPaste, TestClaudeSignInByPastedAddress, TestClaudeSavedAccountDir (a fake claude CLI, and a server standing in for Anthropic that fails the test if asked) and the reworked sign-in, import and gateway tests fail without the change. With the real Claude Code 2.1.286 in a sandbox directory, its sign-in page (localhost callback) reached magpie's binary and the sign-in waited for the browser; nothing was left behind once it was canceled. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; claude-risk, plugin-signin, signin-callback, signin-link, signin-paste-codex, routing-signin, own-signin-remove, click-scroll, old-webkit pass.
2026-10-01 16:37:07 +08:00
claude: adding a Claude account is Claude Code's own claude auth login, and magpie never refreshes a Claude sign-in nor asks Anthropic anything with one (the user: 把 magpie 自己的 Claude 登录改成直接用 claude /login,只要体验上没什么差别就改) — magpie traded the sign-in page's code for tokens with Claude Code's OAuth client, asked Anthropic's profile and model list with them, refreshed saved accounts itself (daily keepalive included) and handed a saved account to Claude Code as CLAUDE_CODE_OAUTH_TOKEN. Now Add account runs claude auth login --claudeai in a config directory of magpie's own: the page Claude Code would open comes to magpie's window (Claude Code is given magpie as its BROWSER, which writes the page down and exits), the browser comes back to Claude Code's own listener, and when the browser can't reach this machine the address it ended on, or the code Claude's page shows, is pasted as before and handed to Claude Code. Who signed in is what Claude Code kept (.claude.json, auth status). A saved account in use beside the signed-in one runs Claude Code with CLAUDE_CONFIG_DIR set to its own directory (claude-accounts/ beside magpie's config), its sign-in put there once from logins.json and read back as Claude Code refreshes it; switching to it moves it into Claude Code's own store and removes the directory, as forgetting it does. Claude's models are the catalog's (models.dev), not asked of Anthropic; an imported Claude login is kept as the file has it, and Claude Code refreshes it on first use. Claude Code is required to add a Claude account. TestClaudeSignInByPaste, TestClaudeSignInByPastedAddress, TestClaudeSavedAccountDir (a fake claude CLI, and a server standing in for Anthropic that fails the test if asked) and the reworked sign-in, import and gateway tests fail without the change. With the real Claude Code 2.1.286 in a sandbox directory, its sign-in page (localhost callback) reached magpie's binary and the sign-in waited for the browser; nothing was left behind once it was canceled. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; claude-risk, plugin-signin, signin-callback, signin-link, signin-paste-codex, routing-signin, own-signin-remove, click-scroll, old-webkit pass.
2026-10-01 16:37:07 +08:00
claude: adding a Claude account is Claude Code's own claude auth login, and magpie never refreshes a Claude sign-in nor asks Anthropic anything with one (the user: 把 magpie 自己的 Claude 登录改成直接用 claude /login,只要体验上没什么差别就改) — magpie traded the sign-in page's code for tokens with Claude Code's OAuth client, asked Anthropic's profile and model list with them, refreshed saved accounts itself (daily keepalive included) and handed a saved account to Claude Code as CLAUDE_CODE_OAUTH_TOKEN. Now Add account runs claude auth login --claudeai in a config directory of magpie's own: the page Claude Code would open comes to magpie's window (Claude Code is given magpie as its BROWSER, which writes the page down and exits), the browser comes back to Claude Code's own listener, and when the browser can't reach this machine the address it ended on, or the code Claude's page shows, is pasted as before and handed to Claude Code. Who signed in is what Claude Code kept (.claude.json, auth status). A saved account in use beside the signed-in one runs Claude Code with CLAUDE_CONFIG_DIR set to its own directory (claude-accounts/ beside magpie's config), its sign-in put there once from logins.json and read back as Claude Code refreshes it; switching to it moves it into Claude Code's own store and removes the directory, as forgetting it does. Claude's models are the catalog's (models.dev), not asked of Anthropic; an imported Claude login is kept as the file has it, and Claude Code refreshes it on first use. Claude Code is required to add a Claude account. TestClaudeSignInByPaste, TestClaudeSignInByPastedAddress, TestClaudeSavedAccountDir (a fake claude CLI, and a server standing in for Anthropic that fails the test if asked) and the reworked sign-in, import and gateway tests fail without the change. With the real Claude Code 2.1.286 in a sandbox directory, its sign-in page (localhost callback) reached magpie's binary and the sign-in waited for the browser; nothing was left behind once it was canceled. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; claude-risk, plugin-signin, signin-callback, signin-link, signin-paste-codex, routing-signin, own-signin-remove, click-scroll, old-webkit pass.
2026-10-01 16:37:07 +08:00
claude: adding a Claude account is Claude Code's own claude auth login, and magpie never refreshes a Claude sign-in nor asks Anthropic anything with one (the user: 把 magpie 自己的 Claude 登录改成直接用 claude /login,只要体验上没什么差别就改) — magpie traded the sign-in page's code for tokens with Claude Code's OAuth client, asked Anthropic's profile and model list with them, refreshed saved accounts itself (daily keepalive included) and handed a saved account to Claude Code as CLAUDE_CODE_OAUTH_TOKEN. Now Add account runs claude auth login --claudeai in a config directory of magpie's own: the page Claude Code would open comes to magpie's window (Claude Code is given magpie as its BROWSER, which writes the page down and exits), the browser comes back to Claude Code's own listener, and when the browser can't reach this machine the address it ended on, or the code Claude's page shows, is pasted as before and handed to Claude Code. Who signed in is what Claude Code kept (.claude.json, auth status). A saved account in use beside the signed-in one runs Claude Code with CLAUDE_CONFIG_DIR set to its own directory (claude-accounts/ beside magpie's config), its sign-in put there once from logins.json and read back as Claude Code refreshes it; switching to it moves it into Claude Code's own store and removes the directory, as forgetting it does. Claude's models are the catalog's (models.dev), not asked of Anthropic; an imported Claude login is kept as the file has it, and Claude Code refreshes it on first use. Claude Code is required to add a Claude account. TestClaudeSignInByPaste, TestClaudeSignInByPastedAddress, TestClaudeSavedAccountDir (a fake claude CLI, and a server standing in for Anthropic that fails the test if asked) and the reworked sign-in, import and gateway tests fail without the change. With the real Claude Code 2.1.286 in a sandbox directory, its sign-in page (localhost callback) reached magpie's binary and the sign-in waited for the browser; nothing was left behind once it was canceled. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; claude-risk, plugin-signin, signin-callback, signin-link, signin-paste-codex, routing-signin, own-signin-remove, click-scroll, old-webkit pass.
2026-10-01 16:37:07 +08:00
signin: Grok and Command Code sign in from magpie in Docker (xugui on Discord: docker版登不上grok和command code) — Grok's sign-in first installs Grok Build with its installer, curl … | bash, and the image has neither bash nor curl, so it stopped at "installing Grok Build failed (exec: "bash": executable file not found)"; the community Grok plugin, beside the built-in rather than moved onto, wasn't given the CLI at all and said "install Grok Build first". Where no shell and curl/wget can run, Grok Build is now installed as its installer does, from the same x.ai/cli (then its storage bucket) address: the stable version, its binary for the platform, checked with --version, linked as ~/.grok/bin/grok and agent, installer = "internal" noted in its config.toml; the plugin's sign-in installs it first too. The device sign-in itself needs nothing back from the browser and was fine. Command Code's Studio posts the key to magpie's 127.0.0.1 port in the background, which a browser outside the container can't reach and no address carries; while it waits, its sign-in now takes an API key made on commandcode.ai/settings/keys and pasted (as Command Code's own CLI offers), checked with whoami and its plan as Studio's was, and a plugin's browser sign-in offers "Use an API key instead", its own api way (the Command Code plugin has one). No identity, header or prompt changes. TestGrokInstallsWithoutShell, TestCommandCodeSignInPastedKey and TestGrokPluginSignInInstallsCLI fail without the change, signin-paste-key.test.cjs too. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; signin-paste-key, signin-paste-codex, plugin-signin, signin-callback, commandcode-risk, plugin-key-hint, signin-link, click-scroll, old-webkit pass.
2026-10-01 22:25:39 +08:00
2026-10-02 02:25:11 +08:00
2026-10-02 02:25:11 +08:00
2026-10-01 18:33:45 +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-01 14:43:13 +08:00
usage: an Antigravity account shows each group of models' 5-hour and weekly allowance, one row a group (a user on Discord: 这里显示5h 和一周剩余比较好吧,现在是只显示5h,这3个模型都是一样的,没必要分开…多加个7day 条就好) — fetchAvailableModels gives each model only its 5-hour figure, the same for every model drawing on one quota, so the Usage page, the panel and the account rows showed a figure a family (Gemini, Claude, GPT-OSS) and no week. Antigravity's retrieveUserQuotaSummary reports the quota a group ("Gemini Models"; "Claude and GPT models", Claude and GPT-OSS sharing one), each with a 5h and a weekly bucket; magpie now reads it beside the models' (best-effort: without it the windows are as before) and adds each group's windows, named "5 hours" and "7 days" with their pool (Gemini, Claude & GPT), each model's window naming its pool. The Usage page shows Gemini · 5 hours, Gemini · 7 days, Claude & GPT · 5 hours, Claude & GPT · 7 days, the pool's models in each tooltip; the panel four rings (Gemini 5h/7d, Claude 5h/7d); the account rows each pool with its 5h and 7d meters; the TUI the pools' windows in place of the models'. "Every model" lists the models' own windows. The pools' windows are aside for routing, which reads the models' as before; the tray's text is unchanged. TestAntigravityQuotaPools and quota-pools.test.cjs (Chromium, WebKit; en, zh) fail without the change; quota-families, click-scroll, old-webkit, tray-usages, panel-usage pass. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-02 07:03:17 +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
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
provider: Tencent Cloud Token Plan is a preset — TokenHub's coding subscription (its general and Hy plans on one sk-tp- key, from console.cloud.tencent.com/tokenhub/tokenplan), served at its own endpoints under api.lkeap.cloud.tencent.com/plan: v3 for chat completions and anthropic for messages, no Responses (its Codex page asks for wire_api chat); models.dev lists only its Hy models, so the preset gives the plan's (tc-code-latest, GLM 5–5.3, Kimi K3 and K2.7 Code, DeepSeek V4, MiniMax M3 and M2.7, hy4-preview, hy3) until the plan's own list is fetched, and an entry imported at those endpoints is the preset
2026-09-28 15:41:57 +08:00
claude: a Claude account's usage resets are read in the zone /usage names on Windows too, and the provider tests pass whole on Windows (goal: 插件订阅 provider 跟内置的所有逻辑都要一模一样, run on Windows and Linux) — Windows has no time zone database, so "resets Oct 1 at 3:30pm (Asia/Shanghai)" was read in the machine's own zone, hours off for anyone not in that zone; magpie now carries the database (time/tzdata). The provider tests set HOME but not USERPROFILE, which Windows takes the home from, so on Windows they read the test box's own agent sign-ins (Gemini models in a list, an extra provider, a Cursor version); every test home sets both now. Tests whose fake CLI is a shell script (Claude Code's auth status, codex --version, macOS's security) skip on Windows, as the fake devin did, and file mode bits go unchecked there. TestParseClaudeUsage fails on Windows without the change. On Windows and on Linux (WSL) the provider package passes whole, three times on Windows (15 failed before), the plugin package and the move/plugin/Grok/Devin/usage tests five times over on Linux. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 13:51:24 +08:00
zcode: the Start Plan's 405 block is said for what it is, not only as a firewall (#425: ZCode 405 Method Not Allowed on GLM-5.3-Flash from DeepSeek Harness, while zcode2api works with the same account) — zcode.z.ai answers a Start Plan request it turns away with 405 "request has been blocked due to unusual activity" (code 3012 "method not allowed"), which magpie read as Alibaba Cloud's firewall blocking the address and told the user to wait or switch network. zcode2api's own write-ups (a137460387/zcode2api "3012 的根因与修复", gakiyukr/zcode2api-plus request.go) find the endpoint checks what a request carries and takes only one with ZCode's own system prompt, which zcode2api injects; magpie's endpoint, method and protocol are the same as theirs, and magpie doesn't pretend to be ZCode. On a Start Plan account the 405 / 3012 / block page now reads "ZCode's Start Plan turns away requests that don't come from the ZCode app itself, and magpie doesn't pretend to be it; it can also be a network block of this IP. Use an account with a GLM Coding Plan, or add another provider to this group", in place of the generic hint, to the agent and in the trace, where the Routing page gives it on its own line in English or Chinese; the group still goes on to its next member. A Coding Plan account and every other provider keep the generic hint. Requests, headers and prompts are unchanged. TestZCodeStartBlockedSaid and routing-zcode-blocked.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath, a load flake, passes alone); routing-zcode-blocked, routing-blocked, routing-wb-refused, click-scroll, old-webkit pass.
2026-10-01 20:45:11 +08:00
gateway: an Antigravity account Google wants verified says so, and rests (marsxxl: Antigravity 返回「Verify your account to continue」403) — Cloud Code Assist refuses such an account with a 403 whose details say VALIDATION_REQUIRED, a validation_url in their metadata (as pi-ai's google-validation reads it); magpie passed on only the message, and every reconnect went back to the account Google had stopped. Now provider.Verification knows the refusal (the reason, or its words) and APIError adds what to do: open the link, when it's https, in a browser signed in to that account, or else the Antigravity app (or Gemini CLI), then try again. The account rests half an hour as failVerify ("needs verification", 账号需验证) — the last one left too, which rested never — and for a minute the agent's retries get the same error from magpie without asking Google. The Routing page shows the rest with a Verify link and "It's verified — try it again", which lifts it (POST /api/gateway/unrest, Server.Unrest); an answer lifts it as before. Tested with fake upstreams in a sandbox HOME: with a link and without, held retries not sent on, a group falling back past it; the exact body marsxxl got isn't known
2026-09-28 20:56:33 +08:00
claude: nothing is sent to Anthropic in Claude Code's name any more, and a Claude account's model test runs Claude Code (the user: 先把伪装代码删掉,测试模型改走 CLI) — claude_cloak.go made magpie's own requests on a Claude sign-in look like Claude Code's (its User-Agent, session and device ids, Stainless headers, betas, a billing header with a fingerprint and xxHash in the body). Generations already ran Claude Code through the bridge; the cloak was left driving the provider test (a direct /v1/messages "hi") and the model list. It is gone: a Claude account's direct requests are refused unsigned, the model test has Claude Code answer "hi" at the model tested (the warm-up's run, --model the one tested, a saved account's sign-in as CLAUDE_CODE_OAUTH_TOKEN), and the model list says it is magpie (User-Agent magpie, only the oauth beta). TestClaudeTestRunsThroughClaudeCode and TestClaudeTestRunsClaudeCode fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 11:12:27 +08:00
agents: each agent's own model list — under an agent's name on the Agents page, "Showing 5 / 32 models" (or "All 41 models") opens a list to take models out of that agent's picker one by one and put them back (@ChongkaiX on X: 在 magpie 里选哪些模型出现在 Codex 的模型列表里) — until now an agent's list could only be narrowed by whole providers or families (Visible). settings.HiddenModels holds, by agent, the catalog entries taken out, after Visible: a deny list, so a new model is shown. provider.CatalogFor drops them, so the gateway's /models, the agents' files and pickers and Codex's catalog all follow in one place, and catalog.Touched rewrites the agents' files; Codex's own ChatGPT models are dropped from the backend's list too (CodexNativeHidden), and the list's ETag and models_cache tag carry them (CodexListTag) so Codex asks again. The model an agent is set to is marked 在用 and never taken out, on the server as well. The list groups routing groups first, then providers with their logos and on/total, a long group folded; search, 全部/已显示, a group's 全部显示/全部隐藏 on hover, 恢复全部显示; a click on a row applies at once, Esc or a click elsewhere closes it, and nothing scrolls. A renamed provider's hidden models follow it. Tested with agent-models.test.cjs in Chromium and WebKit, English and Chinese; TestHiddenModels (provider), TestCodexModelListHidesOnAgentsPage (gateway) and TestAgentModelsAPI (gui) in sandbox HOMEs. click-scroll, panel-fold, old-webkit, model-pick, menu-scroll, add-button pass; GOOS=linux go vet, linux and windows builds, go test -tags nogui ./... pass. Not tried in the real Wails window or against a real Codex.
2026-09-30 12:44:59 +08:00
provider: Volcengine Ark (火山方舟) is a preset, its Coding Plan, Agent Plan and pay-as-you-go (tcdw: 提供一个选项能够取消自动给 LLM 提供商地址补全 /v1/ 的默认行为) — volcengine, a first-party vendor with a Plan picker: Coding Plan (default) at https://ark.cn-beijing.volces.com/api/coding/v3 for chat completions and Responses and /api/coding for messages (套餐概览 docs/82379/1925114, 快速开始 1928261; its Codex page 2556056 sets wire_api "responses"); Agent Plan, which tcdw is on, at /api/plan/v3 (chat completions and Responses, its Hermes Agent page 2373743) and /api/plan (其他工具 2373746, Claude Code 2373740), with a key of its own; pay-as-you-go at /api/v3 (兼容 OpenAI SDK 1330626, 创建 Response 1569618), which both plans' pages warn bills apart from the plan — no Anthropic endpoint is documented for it. Its models (ark-code-latest, whichever the console picked, then doubao-seed-evolving, doubao-seed-2.1-pro/-lite, doubao-seed-2.0-mini, minimax-m3, glm-5.3, glm-5.3-flash, deepseek-v4.1-flash, deepseek-v4-flash, deepseek-v4-pro, kimi-k2.7-code, kimi-k2.8-preview, kimi-k3, lowercase as the quick-start page gives them) are shown until a list is fetched; no models.dev catalog is tied to it, as its volcengine one has pay-as-you-go's dated ids and volcengine-coding-plan misses the Agent Plan's. Key from ark.volcengine.com/region:cn-beijing/apikey. Their versioned paths go out as written (previous commit). Icon is lobehub's volcengine-color, as the others are; the import page offers its three plans
2026-09-29 01:19:06 +08:00
2026-09-30 04:15:07 +08:00
2026-09-30 04:14:34 +08:00
workbuddy: an added account is told from the others by its uid, and the one WorkBuddy is signed in to stays once WorkBuddy moves on (#413: 添加已提前登录的 WorkBuddy 账号会顶掉默认第一个账号) — magpie matched a new sign-in to a listed account by its name, the nickname: another account of the same nickname replaced the one listed, or was taken for WorkBuddy's own and let go with "signed in". And WorkBuddy's own account is only read from WorkBuddy's file, so signing WorkBuddy in to the next account (to pick it on WorkBuddy's page from magpie) renamed that row, the last account gone, and the one picked, being WorkBuddy's own, was let go: one account at a time. A WorkBuddy or WorkBuddy AI sign-in is now matched by its uid (one of the same name whose uid isn't known is still taken to be it, #155); another account of the same name is added as "name (end of uid)"; the same account renews its sign-in where it is listed, and the one WorkBuddy is signed in to becomes magpie's own sign-in of it, first as it was, so it stays when WorkBuddy signs in to another. The sign-in says so: "该账号已在列表中,已更新登录" in the app, "is already listed — its sign-in was renewed" from magpie accounts add. On the plugin, the host no longer takes two sign-ins of one account id for one account when their uids differ. No request header or user agent changes. TestWorkBuddyAddSameNicknameAsOwn, TestWorkBuddyAddSameNicknameTwice, TestWorkBuddyAddWhatWorkBuddyIsSignedInTo, TestPluginSameNameOtherUID and signin-again.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; signin-again, click-scroll, old-webkit pass.
2026-10-01 19:38:36 +08:00
2026-09-29 11:40:00 +08:00
2026-09-29 11:40:00 +08:00
plugins: a built-in moved onto its plugin looks and works as it did (你确保插件版的订阅 provider 和其对应的内置的…都保持一模一样了吗?) — moved onto its plugin, a built-in lost pieces: its tile's name, icon, plans and risk note went to the plugin's own, "Add account" still opened the built-in's sign-in (in the app, on the server and in magpie accounts add), an agent's own sign-in the built-in still found showed a second usage card of the same account, the account's plan badge went, WorkBuddy's daily check-in stopped, the provider's icon and site were the plugin's, WorkBuddy AI's card was named WorkBuddy, and Devin, which had no card of its own, lost the plugin's. Now a moved built-in keeps its tile and risk sheet and signs in through its plugin; its cards take the built-in's place and name, and it has none of its own; the plan the plugin tells stays with the account; WorkBuddy checks in through the plugin, which signs the call; a card is left out only where its built-in's slot showed it. TestMovedBuiltinQuiet, TestWorkBuddyCheckinThroughPlugin, TestMoveToPlugin (Devin-like card) and TestPluginUsage (plan kept) fail without the change. Command Code and Devin moved and back in a sandbox HOME: one card each, plan, name. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; plugin-move, plugin-signin, commandcode-risk, old-webkit pass; click-scroll's WebKit fails the same on origin/main under this load.
2026-10-01 00:40:22 +08:00
plugins: a built-in moved onto its plugin looks and works as it did (你确保插件版的订阅 provider 和其对应的内置的…都保持一模一样了吗?) — moved onto its plugin, a built-in lost pieces: its tile's name, icon, plans and risk note went to the plugin's own, "Add account" still opened the built-in's sign-in (in the app, on the server and in magpie accounts add), an agent's own sign-in the built-in still found showed a second usage card of the same account, the account's plan badge went, WorkBuddy's daily check-in stopped, the provider's icon and site were the plugin's, WorkBuddy AI's card was named WorkBuddy, and Devin, which had no card of its own, lost the plugin's. Now a moved built-in keeps its tile and risk sheet and signs in through its plugin; its cards take the built-in's place and name, and it has none of its own; the plan the plugin tells stays with the account; WorkBuddy checks in through the plugin, which signs the call; a card is left out only where its built-in's slot showed it. TestMovedBuiltinQuiet, TestWorkBuddyCheckinThroughPlugin, TestMoveToPlugin (Devin-like card) and TestPluginUsage (plan kept) fail without the change. Command Code and Devin moved and back in a sandbox HOME: one card each, plan, name. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; plugin-move, plugin-signin, commandcode-risk, old-webkit pass; click-scroll's WebKit fails the same on origin/main under this load.
2026-10-01 00:40:22 +08:00
workbuddy: a model the plan serves free says so (这个应该是Workbuddy国际版免费的模型,要不要在模型名字后面加上一个免费标记?) — WorkBuddy's product config gives each model the credits a request costs, as its own picker shows them: WorkBuddy AI's deepseek-v4.1-flash is "x0.00", its -sg twin "x0.03", GPT-5.5 "x1.00". A model at x0.00 (or 0) is now Free in the catalog, and carries it to the provider editor's model chips and every agent's model picker, where it has a green 免费/free badge after its name ("free: it doesn't use the plan's credits" on hover); a rate that can't be read is not free. Both WorkBuddy sites, as they share the config. A list fetched before this has no rates: Refresh in the editor asks again. Checked: the credits parse (x0.00, 0 free; x0.03, x1.00, none not), and the badge on a chip and in the picker in the sandbox, dark
2026-09-29 03:02:34 +08:00
workbuddy: a model the plan serves free says so (这个应该是Workbuddy国际版免费的模型,要不要在模型名字后面加上一个免费标记?) — WorkBuddy's product config gives each model the credits a request costs, as its own picker shows them: WorkBuddy AI's deepseek-v4.1-flash is "x0.00", its -sg twin "x0.03", GPT-5.5 "x1.00". A model at x0.00 (or 0) is now Free in the catalog, and carries it to the provider editor's model chips and every agent's model picker, where it has a green 免费/free badge after its name ("free: it doesn't use the plan's credits" on hover); a rate that can't be read is not free. Both WorkBuddy sites, as they share the config. A list fetched before this has no rates: Refresh in the editor asks again. Checked: the credits parse (x0.00, 0 free; x0.03, x1.00, none not), and the badge on a chip and in the picker in the sandbox, dark
2026-09-29 03:02:34 +08:00
2026-09-29 00:49:07 +08:00
workbuddy: its "Illegal API invocation from an unapproved channel" says what to do (QuentinHsu on Discord, deepseek-v4-flash on WorkBuddy from Codex) — WorkBuddy, both builds, refuses a chat whose system prompt is Codex's or Claude Code's (#182), whatever the headers, and magpie does not rewrite that prompt. The refusal now carries "WorkBuddy refuses chats from Codex and Claude Code (their system prompt); use it from Hermes, OpenCode or Pi, or add another provider to this group", to the agent and on the Routing page (apart from the vendor's words, in the page's language); a group still passes the request on to its next member. workbuddy_refused_test (provider, gateway) and routing-wb-refused.test.cjs (Chromium, WebKit, en/zh) fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; click-scroll, old-webkit and the routing tests pass.
2026-09-30 17:41:16 +08:00
providers: a provider of the user's saved on a subscription's id is moved off it, so the subscription is listed once signed in (LingYi_Stu on X: workbuddy 国内版本无法使用呢 — "凌一 已登录,但 magpie 无法列出它,请反馈此问题", magpie 0.1.384, WorkBuddy 5.6.2 signed in, the international build listed with 3 accounts beside it) — before WorkBuddy's plan was a subscription (v0.1.261), a provider added as "WorkBuddy" was saved with the id workbuddy, and All() skips an account whose id a saved provider has: the sign-in said done, logins.json kept the account, and the Providers page listed only the user's own provider, the card still saying Free · Pro. Now start-up (agent.MoveOffAccountIDs, beside RenameLegacy) moves each provider with a base URL saved on a subscription's id to the next free one (workbuddy-2) the way a rename does: routing groups, fallbacks and the agents on its models follow; the old id is not kept as one it Was, being the subscription's. Rename allows it for such a provider alone, a subscription still keeps its id, and Find takes an id before a name, so workbuddy is the subscription and not a provider called WorkBuddy. Tested with a new TestWorkBuddyUnderUsersOwnID (the sign-in done and unlisted, then both listed after the move, a fallback moved, the subscription refused a rename), and end to end in a sandbox HOME with a WorkBuddy auth file and providers.json: main lists the custom WorkBuddy alone; with the change magpie providers lists workbuddy-2 (its fallback moved) and WorkBuddy signed in as 凌一. go test -tags nogui ./... (TestUserPath failed once under load, passes on its own), go build for linux and windows
2026-09-29 18:17:14 +08:00
kiro: removing kiro-cli's or the Kiro IDE's own sign-in hides it in magpie, and it shows again when Kiro signs in anew (Discord 碳碳双键: 本机没安装 kiro,但旧的 Kiro 数据还在,magpie 列出一个"Kiro account"(登录已失效,请重新添加此账号),添加新账号并设为首位后,旧的数据无法移除) — magpie reads Kiro's own sign-in from kiro-cli's database or ~/.aws/sso/cache and lists it among the accounts it signed in; Remove on it said "that is kiro-cli's or the Kiro IDE's own sign-in; run kiro-cli logout or sign out in the IDE", which with neither installed left a dead account there for good. The same refusal was shared by every agent whose own sign-in magpie only reads (forgetSideLogin: Kiro, Devin, Grok, Copilot, ZCode, WorkBuddy and WorkBuddy AI, Command Code, Gemini CLI, Antigravity). Now Remove on the agent's own sign-in hides it: logins.json's entry for it keeps a Hidden mark, and it is left out of the account list and so of the gateway's tries (the first and the ones behind it both come from that list); the agent's files are never deleted or written. It shows again when that sign-in changes: for Kiro, by a mark that is a digest of where the sign-in is (kiro-cli's row or the IDE's file) and its refresh token (never the token itself), so a new kiro-cli login or IDE sign-in, to any account, brings it back; for the others, which have no such mark, when it is another account. Removing it while it is first is allowed now, the next account being put first (saved, so it stays first when the own one comes back); removed when it was the only one, the agent has no account left. One of magpie's own accounts is removed with its home as before, and still can't be while it is first. The error and its per-agent sign-out hints are gone. Logins carry own, and the accounts list shows Remove on the agent's own sign-in also while it is first, its title "magpie stops showing and using Kiro's own sign-in; its files are left as they are, and it shows again when Kiro signs in anew" (magpie 不再显示和使用 Kiro 自己的登录;它的文件保持原样,Kiro 重新登录后会再次出现). Tested with a new internal/provider/side_logins_hide_test.go in a sandbox HOME: an expired kiro-cli sign-in ("Kiro account") behind a Google one magpie signed in is removed, stays gone across reads, isn't the account used nor among AlsoOn, kiro-cli's database byte-for-byte and mtime as it was, the refresh token nowhere in magpie's files; a new kiro-cli sign-in brings it back behind the one first; put first and removed, the next is first; one of magpie's removed takes its home and leaves the other's; the only account removed leaves Kiro with none; Grok's CLI sign-in hidden with auth.json untouched, back once it is another account. The agents' tests that expected the refusal (Command Code, Copilot, Devin, Grok, WorkBuddy, ZCode) no longer do. A new internal/gui/tests/own-signin-remove.test.cjs in Chromium and WebKit, en and zh: kiro-cli's sign-in behind another and alone first both have Remove with that title and post login/forget, magpie's first account has none. go build -tags nogui (and GOOS=linux, GOOS=windows), go test -tags nogui ./... and the whole GUI suite (138) pass. Not tried with a real Kiro, kiro-cli or the Kiro IDE.
2026-09-29 23:52:33 +08:00
workbuddy: an added account is told from the others by its uid, and the one WorkBuddy is signed in to stays once WorkBuddy moves on (#413: 添加已提前登录的 WorkBuddy 账号会顶掉默认第一个账号) — magpie matched a new sign-in to a listed account by its name, the nickname: another account of the same nickname replaced the one listed, or was taken for WorkBuddy's own and let go with "signed in". And WorkBuddy's own account is only read from WorkBuddy's file, so signing WorkBuddy in to the next account (to pick it on WorkBuddy's page from magpie) renamed that row, the last account gone, and the one picked, being WorkBuddy's own, was let go: one account at a time. A WorkBuddy or WorkBuddy AI sign-in is now matched by its uid (one of the same name whose uid isn't known is still taken to be it, #155); another account of the same name is added as "name (end of uid)"; the same account renews its sign-in where it is listed, and the one WorkBuddy is signed in to becomes magpie's own sign-in of it, first as it was, so it stays when WorkBuddy signs in to another. The sign-in says so: "该账号已在列表中,已更新登录" in the app, "is already listed — its sign-in was renewed" from magpie accounts add. On the plugin, the host no longer takes two sign-ins of one account id for one account when their uids differ. No request header or user agent changes. TestWorkBuddyAddSameNicknameAsOwn, TestWorkBuddyAddSameNicknameTwice, TestWorkBuddyAddWhatWorkBuddyIsSignedInTo, TestPluginSameNameOtherUID and signin-again.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; signin-again, click-scroll, old-webkit pass.
2026-10-01 19:38:36 +08:00
zcode: a Z.ai and a BigModel (智谱) account on the same phone number, or two accounts ZCode names alike, are kept apart (Bandit on Discord: authorising one replaced the other) — magpie kept ZCode's accounts by name alone, the name being the email, or the phone number of a phone sign-in (<phone>@phone.local), so a sign-in whose name an account already had overwrote that account's key, on whichever site; one named as ZCode's own account was taken for it and not kept at all. A sign-in now keeps the account's user id beside its key, and an account is the same only on the same site with the same id (one kept before ids, by its key's id); another account with the name is kept as '<name> (BigModel)' or '<name> (Z.ai)', numbered when that is taken, and signing in to an account again still updates it in place, by id. There is no cap on the number of accounts. TestZCodeAccountsKeptApart, TestZCodeOldAccountKeptByKey and TestZCodeOwnAccountKeptApart fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath, a known load flake, passes alone).
2026-10-02 02:24:48 +08:00
zcode: the Start Plan's 405 block is said for what it is, not only as a firewall (#425: ZCode 405 Method Not Allowed on GLM-5.3-Flash from DeepSeek Harness, while zcode2api works with the same account) — zcode.z.ai answers a Start Plan request it turns away with 405 "request has been blocked due to unusual activity" (code 3012 "method not allowed"), which magpie read as Alibaba Cloud's firewall blocking the address and told the user to wait or switch network. zcode2api's own write-ups (a137460387/zcode2api "3012 的根因与修复", gakiyukr/zcode2api-plus request.go) find the endpoint checks what a request carries and takes only one with ZCode's own system prompt, which zcode2api injects; magpie's endpoint, method and protocol are the same as theirs, and magpie doesn't pretend to be ZCode. On a Start Plan account the 405 / 3012 / block page now reads "ZCode's Start Plan turns away requests that don't come from the ZCode app itself, and magpie doesn't pretend to be it; it can also be a network block of this IP. Use an account with a GLM Coding Plan, or add another provider to this group", in place of the generic hint, to the agent and in the trace, where the Routing page gives it on its own line in English or Chinese; the group still goes on to its next member. A Coding Plan account and every other provider keep the generic hint. Requests, headers and prompts are unchanged. TestZCodeStartBlockedSaid and routing-zcode-blocked.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath, a load flake, passes alone); routing-zcode-blocked, routing-blocked, routing-wb-refused, click-scroll, old-webkit pass.
2026-10-01 20:45:11 +08:00
zcode: requests to zcode.z.ai name the machine with X-Device-Mid, so a Z.ai account with only ZCode's Start Plan signs in again (#282 volcanicll: /api/v1/zcode-plan/billing/balance now refuses a request without it, 400 code 3001 "parameter error", and sign-in read that as the Start Plan having ended) — ZCode's apiClient sends it on every request; the server asks only that it is there. magpie makes one v4 UUID for this machine, kept as zcode-device-mid beside providers.json (never ZCode's deviceMid, never ~/.zcode), and sends it on zcode.z.ai calls and Start Plan model requests; Z.ai's and BigModel's business APIs don't get it. A Start Plan balance that can't be read is now said as such in the sign-in error, with the server's code ("parameter error (400, code 3001)"), instead of "has ended or was never started", which stays for an account whose Start Plan really has. Tested with a fake zcode.z.ai refusing a request without the header like the real one (TestZCodeSignInStartPlan, TestZCodeStartPlanOwnAccount, TestZCodeStartPlanRouting and a new TestZCodeSignInStartPlanDeviceMid fail without it): the id is a v4 UUID, kept across a restart, sent to zcode.z.ai only; with it stripped sign-in says the server's reason; an ended Start Plan still says ended. go vet, go build (GUI, -tags nogui, GOOS=linux, GOOS=windows), go test -tags nogui ./... pass. Not tried against the real zcode.z.ai.
2026-09-30 12:51:59 +08:00
zcode: requests to zcode.z.ai name the machine with X-Device-Mid, so a Z.ai account with only ZCode's Start Plan signs in again (#282 volcanicll: /api/v1/zcode-plan/billing/balance now refuses a request without it, 400 code 3001 "parameter error", and sign-in read that as the Start Plan having ended) — ZCode's apiClient sends it on every request; the server asks only that it is there. magpie makes one v4 UUID for this machine, kept as zcode-device-mid beside providers.json (never ZCode's deviceMid, never ~/.zcode), and sends it on zcode.z.ai calls and Start Plan model requests; Z.ai's and BigModel's business APIs don't get it. A Start Plan balance that can't be read is now said as such in the sign-in error, with the server's code ("parameter error (400, code 3001)"), instead of "has ended or was never started", which stays for an account whose Start Plan really has. Tested with a fake zcode.z.ai refusing a request without the header like the real one (TestZCodeSignInStartPlan, TestZCodeStartPlanOwnAccount, TestZCodeStartPlanRouting and a new TestZCodeSignInStartPlanDeviceMid fail without it): the id is a v4 UUID, kept across a restart, sent to zcode.z.ai only; with it stripped sign-in says the server's reason; an ended Start Plan still says ended. go vet, go build (GUI, -tags nogui, GOOS=linux, GOOS=windows), go test -tags nogui ./... pass. Not tried against the real zcode.z.ai.
2026-09-30 12:51:59 +08:00
zcode: an account with no GLM Coding Plan uses ZCode's Start Plan (体验套餐) where ZCode does, with ZCode's own token, and shows its allowance (#236 tasselx: ZCode 3.14.4, magpie 0.1.410, a trial-only account, the free quota not read and every request refused with rate_limit_error "ZCode: [1113][Insufficient balance or no resource package. Please recharge.]"; #225 xiaozhu1337: ZCode ships a built-in trial package) — magpie sent every ZCode account to the Coding Plan's endpoint, api.z.ai/api/anthropic, with the account's zcode-api-key, and read its allowance only from /api/monitor/usage/quota/limit. That key is billed to a Coding Plan, or else to the account's API balance, so an account with only the Start Plan got 1113. ZCode itself (ZCode.app 3.14.3's zcode-builtin.json providerRules and host/index.js: resolveCurrent, buildZaiStartPlanBalanceUrl, hasActiveStartPlan, isZaiStartPlanIdentity, normalizeStartPlanExpiry, normalizeZaiStartPlanBalanceLimits, pollPendingOAuth) serves the Start Plan (account:zai-start-plan and account:bigmodel-start-plan) from zcode.z.ai/api/v1/zcode-plan/anthropic, keyed by its own session token (the credential store's zcodejwttoken, the token its sign-in's poll hands back, which magpie dropped), and reads what is left from /api/v1/zcode-plan/billing/balance?app_version= with that token. Now, in a new zcode_start.go: an account keeps ZCode's token beside its key (zcodeKey.JWT; zcodeOwn reads zcodejwttoken, and user_info from oauth:bigmodel:user_info when there is no Z.ai one; an account with the token and no coding plan key is an account). Whether it is on the Start Plan is asked of /api/biz/subscription/list (a Coding Plan: as before; none: the Start Plan; can't tell: the Start Plan if its balance has an active one), kept 10 minutes (1 when unsure); with no token it is the Coding Plan as before, asking nothing, and with no key it is the Start Plan. On the Start Plan a request is moved to zcode-plan/anthropic, signed with the token (x-api-key and Bearer) and ZCode's own headers (User-Agent ZCode/<ver>, X-ZCode-App-Version, X-Title, HTTP-Referer, X-Platform), refused with "sign in to ZCode again" once the token has run out; its models are the Start Plan's (zcodePlanID account:zai-start-plan for ZCode's config, zcodeModels less GLM-5.3 before it is read). Its allowance is the balance as ZCode reads it: a plan still "active" past ends_at (by server_time) is expired and the buckets of expired plans left out; the plan's name (Start Plan) with Until its end and Renew off; a window per bucket, named by its show_name (or its models, or Credits), Used and "used / total" from total/used/remaining units (numbers or strings), ResetsAt its expires_at, Span from its entitlement's period (daily/weekly/monthly) or period_start..end, and matched to the bucket's models. Signing in from magpie no longer refuses an account with no Coding Plan: with an active Start Plan it is added on that (its key kept too, so a Coding Plan bought later is used), and refused only when the Start Plan is over as well ("this Z.ai account has no GLM Coding Plan, and ZCode's Start Plan has ended or was never started — subscribe at z.ai/subscribe, then add it again"). Accounts with a Coding Plan are routed, signed and metered as before. The provider keeps the name ZCode (#225 asked for "GLM Coding Plan"; ZCode names these plans "Z.AI Individual Coding Plan" and "Start Plan", and the plan line already shows "GLM Coding <Level>"). Tested with a new internal/provider/zcode_start_test.go against a fake Z.ai/zcode.z.ai in a sandbox HOME, no real tokens: ZCode signed in with only its token (BigModel user_info) is an account, its provider served at zcode-plan/anthropic, a request signed with the token and ZCode's headers, the Start Plan's models and plan id, its allowance (Start Plan, Until, Renew off, GLM-5.1's window 25%, "250000 / 1000000", reset, a day's span, matching GLM-5.1 only); an expired plan and one active past its end give none; with a key and the token, no Coding Plan moves the request (query kept) to the Start Plan and it reaches it with the token, a Coding Plan keeps it on api.z.ai with the key and no ZCode headers, no token asks nothing, an expired token is refused; a sign-in with only the Start Plan is added on it, with a Coding Plan on that plan, with neither refused naming both. TestZCodeAccounts passes unchanged. go build -tags nogui (and GOOS=linux, GOOS=windows), go vet and go test -tags nogui ./... pass (TestUpdateCLI, TestClaudeSignedOut, TestClaudeAccountNamedAsItsLogin and TestUserPath timed out once each under load beside other builds and pass alone). Not tried with a real Start Plan account: the endpoint's acceptance of the token as x-api-key/Bearer and whether it needs ZCode's headers, the balance's real field values and period strings, what subscription/list returns for a trial-only account, and ZCode 3.14.4 (read from 3.14.3) are from ZCode's code, not seen on the wire.
2026-09-30 02:15:50 +08:00
2026-10-01 02:58:29 +08:00
zcode: requests to zcode.z.ai name the machine with X-Device-Mid, so a Z.ai account with only ZCode's Start Plan signs in again (#282 volcanicll: /api/v1/zcode-plan/billing/balance now refuses a request without it, 400 code 3001 "parameter error", and sign-in read that as the Start Plan having ended) — ZCode's apiClient sends it on every request; the server asks only that it is there. magpie makes one v4 UUID for this machine, kept as zcode-device-mid beside providers.json (never ZCode's deviceMid, never ~/.zcode), and sends it on zcode.z.ai calls and Start Plan model requests; Z.ai's and BigModel's business APIs don't get it. A Start Plan balance that can't be read is now said as such in the sign-in error, with the server's code ("parameter error (400, code 3001)"), instead of "has ended or was never started", which stays for an account whose Start Plan really has. Tested with a fake zcode.z.ai refusing a request without the header like the real one (TestZCodeSignInStartPlan, TestZCodeStartPlanOwnAccount, TestZCodeStartPlanRouting and a new TestZCodeSignInStartPlanDeviceMid fail without it): the id is a v4 UUID, kept across a restart, sent to zcode.z.ai only; with it stripped sign-in says the server's reason; an ended Start Plan still says ended. go vet, go build (GUI, -tags nogui, GOOS=linux, GOOS=windows), go test -tags nogui ./... pass. Not tried against the real zcode.z.ai.
2026-09-30 12:51:59 +08:00
zcode: the Start Plan's 405 block is said for what it is, not only as a firewall (#425: ZCode 405 Method Not Allowed on GLM-5.3-Flash from DeepSeek Harness, while zcode2api works with the same account) — zcode.z.ai answers a Start Plan request it turns away with 405 "request has been blocked due to unusual activity" (code 3012 "method not allowed"), which magpie read as Alibaba Cloud's firewall blocking the address and told the user to wait or switch network. zcode2api's own write-ups (a137460387/zcode2api "3012 的根因与修复", gakiyukr/zcode2api-plus request.go) find the endpoint checks what a request carries and takes only one with ZCode's own system prompt, which zcode2api injects; magpie's endpoint, method and protocol are the same as theirs, and magpie doesn't pretend to be ZCode. On a Start Plan account the 405 / 3012 / block page now reads "ZCode's Start Plan turns away requests that don't come from the ZCode app itself, and magpie doesn't pretend to be it; it can also be a network block of this IP. Use an account with a GLM Coding Plan, or add another provider to this group", in place of the generic hint, to the agent and in the trace, where the Routing page gives it on its own line in English or Chinese; the group still goes on to its next member. A Coding Plan account and every other provider keep the generic hint. Requests, headers and prompts are unchanged. TestZCodeStartBlockedSaid and routing-zcode-blocked.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath, a load flake, passes alone); routing-zcode-blocked, routing-blocked, routing-wb-refused, click-scroll, old-webkit pass.
2026-10-01 20:45:11 +08:00
providers: a Zhipu or Z.ai key on a team's GLM Coding Plan can be given the team's organization and project IDs, and the Usage page then shows the team's 5-hour and weekly windows (#236 EZN7L2C3: the IDs are in the BigModel console; CC Switch asks the team quota with them) — a key pasted alone was asked for the team's quota (type=2) without the Bigmodel-Organization / Bigmodel-Project headers, which magpie can't find from a key, so a team key showed nothing. providers.json keeps zhipuTeam {org, project} for those key providers (trimmed; both empty removes it; a save without it keeps it, {} clears it; carried through from the Zhipu and Z.ai presets). The team query sends the typed IDs, else those of a ZCode team login holding the key, and is now asked at the key's own host (open.bigmodel.cn, as CC Switch asks it) first and bigmodel.cn (where ZCode asks it) only when that gives no windows. It still runs only when the key's personal quota fails or has no windows. The provider editor shows Team org ID / Team project ID (团队组织 ID / 团队项目 ID), optional, for Zhipu and Z.ai key providers alone, adding and editing; one without the other is refused before anything is posted. Tested with internal/provider/zhipu_team_key_test.go against a fake open.bigmodel.cn / bigmodel.cn in a temp HOME: the IDs kept trimmed, the team asked with type=2, the key and both headers at open.bigmodel.cn and read as 5 hours 42% and weekly 10%, a key without them asked with no team headers at both hosts and showing nothing, a pay-as-you-go key with blank IDs no card, Z.ai taking the fields and DeepSeek not. internal/gui/tests/zhipu-team.test.cjs, Chromium and WebKit, en and zh: the fields for a saved Zhipu provider and from the add sheet for Z.ai, none for DeepSeek or a relay, trimmed values posted, one alone refused, both empty posting {}, nothing scrolled on a click. Both fail without the change. click-scroll, old-webkit, provider-proxy and account-proxy pass; go vet, go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried with a real team key or in the real Wails window; the team's reset counts are not read for a key (the reset list is asked only with a ZCode sign-in token).
2026-09-30 05:49:19 +08:00
zcode: a seat on a team's GLM Coding Plan (团队套餐) is signed in, routed and metered as ZCode does it, on BigModel (智谱) as well as Z.ai, and a Zhipu key on a team plan shows its 5-hour and weekly windows and resets (#236 EZN7L2C3: a BigModel team GLM Coding Plan, the sign-in refused it and the usage was never read) — magpie's ZCode sign-in only went to Z.ai and only looked for the account's own coding-plan key, so a member of a team's plan, whose seat lives in a team project, was refused, and a key on a team plan read nothing from /api/monitor/usage/quota/limit. Read from ZCode.app 3.14.3 (host/index.js and config/provider/zcode-builtin.json): the team rules account:{zai|bigmodel}-team-coding-plan use the individual plans' base URLs with no extra inference headers; getCustomerInfo lists the projects, projectType "2" being a team's (isBigModelTeamCodingPlanProject); fetchTeamCodingPlanEntitlement asks /api/biz/team/subscribe/product/querySubscribeDetail (EFFECTIVE + memberGrantStatus VALID usable, UNASSIGNED no seat, EXPIRED run out); ensureBigModelTeamPlanProjectApiKeyWithStatus / copyBigModelTeamPlanProjectApiKeySecret find or create "zcode-team-api-key" (keyType 2) in the team project and copy its secret; createBigModelBizHeaders sends the access token bare in Authorization with bigmodel-organization / bigmodel-project; resolveAccountTeamPlanRuntimeApiKey takes the stored oauth:{family}:access_token (skipping BigModel's when it equals zcodejwttoken); buildQuotaLimitUrl adds type=2 and createBigModelUsageHeaders sends the key with the org/project headers; ZCode keeps the chosen team in ~/.zcode/v2/setting.json providerFamilyConnectionSelections (legacy modelProviderFamilySelectedKeys "team-plan:builtin:…", migrateLegacyAccountConnectionSettings); pollPendingOAuth/startOAuthWithPolling init with {provider:"zai"|"bigmodel"}, BigModel's redirect param being redirect, its token the poll's bigmodel.access_token. Now: the sign-in first asks where the account is — Z.ai or BigModel (智谱) (POST /api/signin takes a site, StartSignInAt, "zcode:bigmodel" too) — and on its site tries the account's own plan, then a team project with a usable seat (a new zcode_team.go: zcodeTeamSignIn keeps the team key, org, project and the biz token, the plan named by its product, "GLM Coding Team" otherwise), then the Start Plan; a team seat not yet granted or a team plan expired is refused saying so ("…has no seat on it yet — ask the team's admin…"), and an account with none of them names both plans and the site's subscribe page. ZCode's own team login is read from its credentials and setting.json (zcodeOwnTeam), its key minted lazily and kept (zcodeTeamKeyOf, retried after a minute, "sign in to ZCode again" when refused). Team requests go to the family's Anthropic base signed with the team key, no ZCode headers, never the Start Plan. Team usage asks bigmodel.cn (or api.z.ai) /api/monitor/usage/quota/limit?type=2 with the key and Authorization, Bigmodel-Organization, Bigmodel-Project, Set-Language, Accept-Language: CREDIT_LIMIT windows, unit 3 "5 hours" and unit 6 weekly, "current / total" when there is no remaining; /api/biz/customer-package-reset/list?targetType=TEAM gives the resets, fiveHourResets and weekResets counted where available is true, the soonest expireTime as until; the plan's end from querySubscribeDetail, Renew off. ResetCredits gains byWindow/fiveHour/weekly and Words(), "2 five-hour resets · 1 weekly reset" in the CLI, TUI and GUI (en and zh), with no "Use a reset" button for them since they are spent on the vendor's page. The Zhipu GLM key provider (planquota.go) falls back to the team query when the personal one fails or has no windows, adding the team headers when a ZCode team login holds that key. Personal accounts, Coding Plan and Start Plan, are routed, signed and metered as before. Tested with a new internal/provider/zcode_team_test.go against a fake bigmodel.cn/Z.ai in a sandbox HOME, no real tokens: a BigModel team sign-in through StartSignIn("zcode:bigmodel") is added (redirect param, plan "GLM Coding Team Pro", key made with keyType 2, org/project kept), its requests at the BigModel base signed with the team key and no ZCode headers, usage 5 hours 42% "420 / 1000" with a 5h span and weekly 10%, the quota headers sent, resets 2 five-hour and 1 weekly until 2026-10-05, plan until 2026-12-31; an unassigned seat is refused with no key made; ZCode's own team login from credentials + setting.json is found and metered while an individual plan stays as it was; the key provider's team fallback. TestPlanQuotas gains the type=2 case; the zcode Start Plan and account tests pass. A new internal/gui/tests/zcode-site.test.cjs, Chromium and WebKit, en and zh: starting ZCode's sign-in asks the site and posts nothing, BigModel posts {agent:"zcode",site:"bigmodel"} and keeps it, and the by-window resets read in both languages; signin-callback, click-scroll and login-import pass. go vet ./internal/..., go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass (TestUserPath timed out under load and passes alone). Not tried against a real account: BigModel's OAuth sign-in and poll shape, the Set-Language values, customer-package-reset's field formats, querySubscribeDetail on Z.ai, type=2 for a pasted key with no org/project, and the time formats are from ZCode's code, not seen on the wire; not tried in the real Wails window.
2026-09-30 04:15:06 +08:00
kiro: removing kiro-cli's or the Kiro IDE's own sign-in hides it in magpie, and it shows again when Kiro signs in anew (Discord 碳碳双键: 本机没安装 kiro,但旧的 Kiro 数据还在,magpie 列出一个"Kiro account"(登录已失效,请重新添加此账号),添加新账号并设为首位后,旧的数据无法移除) — magpie reads Kiro's own sign-in from kiro-cli's database or ~/.aws/sso/cache and lists it among the accounts it signed in; Remove on it said "that is kiro-cli's or the Kiro IDE's own sign-in; run kiro-cli logout or sign out in the IDE", which with neither installed left a dead account there for good. The same refusal was shared by every agent whose own sign-in magpie only reads (forgetSideLogin: Kiro, Devin, Grok, Copilot, ZCode, WorkBuddy and WorkBuddy AI, Command Code, Gemini CLI, Antigravity). Now Remove on the agent's own sign-in hides it: logins.json's entry for it keeps a Hidden mark, and it is left out of the account list and so of the gateway's tries (the first and the ones behind it both come from that list); the agent's files are never deleted or written. It shows again when that sign-in changes: for Kiro, by a mark that is a digest of where the sign-in is (kiro-cli's row or the IDE's file) and its refresh token (never the token itself), so a new kiro-cli login or IDE sign-in, to any account, brings it back; for the others, which have no such mark, when it is another account. Removing it while it is first is allowed now, the next account being put first (saved, so it stays first when the own one comes back); removed when it was the only one, the agent has no account left. One of magpie's own accounts is removed with its home as before, and still can't be while it is first. The error and its per-agent sign-out hints are gone. Logins carry own, and the accounts list shows Remove on the agent's own sign-in also while it is first, its title "magpie stops showing and using Kiro's own sign-in; its files are left as they are, and it shows again when Kiro signs in anew" (magpie 不再显示和使用 Kiro 自己的登录;它的文件保持原样,Kiro 重新登录后会再次出现). Tested with a new internal/provider/side_logins_hide_test.go in a sandbox HOME: an expired kiro-cli sign-in ("Kiro account") behind a Google one magpie signed in is removed, stays gone across reads, isn't the account used nor among AlsoOn, kiro-cli's database byte-for-byte and mtime as it was, the refresh token nowhere in magpie's files; a new kiro-cli sign-in brings it back behind the one first; put first and removed, the next is first; one of magpie's removed takes its home and leaves the other's; the only account removed leaves Kiro with none; Grok's CLI sign-in hidden with auth.json untouched, back once it is another account. The agents' tests that expected the refusal (Command Code, Copilot, Devin, Grok, WorkBuddy, ZCode) no longer do. A new internal/gui/tests/own-signin-remove.test.cjs in Chromium and WebKit, en and zh: kiro-cli's sign-in behind another and alone first both have Remove with that title and post login/forget, magpie's first account has none. go build -tags nogui (and GOOS=linux, GOOS=windows), go test -tags nogui ./... and the whole GUI suite (138) pass. Not tried with a real Kiro, kiro-cli or the Kiro IDE.
2026-09-29 23:52:33 +08:00
zcode: a Z.ai and a BigModel (智谱) account on the same phone number, or two accounts ZCode names alike, are kept apart (Bandit on Discord: authorising one replaced the other) — magpie kept ZCode's accounts by name alone, the name being the email, or the phone number of a phone sign-in (<phone>@phone.local), so a sign-in whose name an account already had overwrote that account's key, on whichever site; one named as ZCode's own account was taken for it and not kept at all. A sign-in now keeps the account's user id beside its key, and an account is the same only on the same site with the same id (one kept before ids, by its key's id); another account with the name is kept as '<name> (BigModel)' or '<name> (Z.ai)', numbered when that is taken, and signing in to an account again still updates it in place, by id. There is no cap on the number of accounts. TestZCodeAccountsKeptApart, TestZCodeOldAccountKeptByKey and TestZCodeOwnAccountKeptApart fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestUserPath, a known load flake, passes alone).
2026-10-02 02:24:48 +08:00
signin: a sign-in whose browser can't reach magpie finishes with the address pasted (Jorben on Discord: ChatGPT sign-in in Docker on a server never finished) — ChatGPT sends the browser back only to localhost:1455, which is the user's own computer, not the server, and magpie's paste field refused every built-in sign-in. Claude, Codex, Devin, Kiro (both steps of an AWS sign-in), Gemini, Antigravity and Zed now take the address the browser ended on, in the app and in magpie accounts add: only this sign-in's own port, path and state, traded through the same handler as the browser's, and once, whichever comes first. TestCodexSignInFromPastedAddress, TestPastedAddressAndCallbackFinishOnce, TestLoopbackSignInsTakePastedAddress and signin-paste-codex.test.cjs fail without the change.
2026-10-01 04:09:16 +08:00
providers: DimAgent's subscription is taken out of magpie (a DimAgent team member on X: dim doesn't allow its subscription used through a proxy, and users doing so get banned or lose their discount) — #226 signed in to DimAgent as its desktop client does and served its models through the gateway. The sign-in, the account provider and its dimagent/<model> models, the quota card, magpie accounts … dimagent and the icon are gone, with internal/dimagent. An account signed in before is left out when logins.json is read and dropped from the file at its next write, so its tokens aren't kept. The pasted-callback field and route stay, generic, with no sign-in using them. Tested with TestDimAgentLoginDropped (fails without the filter); in a sandbox HOME with a DimAgent login left in logins.json, magpie accounts --json lists nothing and magpie accounts add dimagent is refused. signin-callback (fixture renamed), old-webkit and click-scroll pass; go vet, go build (GUI, -tags nogui, GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass (TestUserPath and the Claude/Devin sign-in tests flaked under the full run and pass alone).
2026-09-30 15:33:40 +08:00
zed: a Zed subscription (Pro, Student, Business) signed in from magpie, several accounts, served through Zed's own cloud (yosocoli5 on X: 买了 Zed 订阅,可以加进供应商吗 — yetone: 当然可以!) — magpie had no way to use Zed's hosted models. Zed is now a subscription in the add sheet (Zed's own logo from zed-industries/zed, lobe-icons has none), signed in as the Zed editor signs in (new internal/zed, the protocol): an RSA key is made, the browser opens zed.dev/native_app_signin with its PKCS#1 public half, magpie's loopback port and a system id, and comes back with user_id and the access token encrypted to the key (OAEP SHA-256, PKCS#1 v1.5 also read), answered with a redirect to zed.dev's succeeded page. The account is asked of /client/users/me (signed "<uid> <token>" with x-zed-system-id), kept with its GitHub login, its default organization and plan; an organization with hosted models turned off is refused. Several accounts can be added and switched like the other subscriptions. Requests get an LLM token from /client/llm_tokens (kept in memory, minted again when Zed answers 401 or x-zed-expired-token/x-zed-outdated-token, once; a refused pair marks the account lapsed, "sign in again"). The model list is Zed's /models for the account (disabled and unknown providers left out; context, output, images and effort levels kept). The gateway asks cloud.zed.dev/completions in Zed's envelope {provider, model, provider_request}, the request written in the model's own provider's API as Zed writes it — Anthropic Messages without stream, OpenAI Responses, xAI chat completions with max_completion_tokens, Gemini's request with models/<id> — and reads the NDJSON reply's events with that API's decoder: a failed status is an error with its status (upstream_http_N, rate limit 429, overloaded 529, payment 402), a reply without stream_ended is an error, not a shorter answer, a 402 says the plan doesn't include hosted models or its allowance is used up. relayQoder's status-keeping relay is now relayStatus, shared by Qoder and Zed. Usage shows the plan and its period's end; Zed reports no usage counter, so no windows. Signing in says first, as Antigravity's does, that Zed serves these models to its own editor and may treat magpie's use as third-party use (en and zh); the import box now uses a subscription's own risk note too. Tested in Go against fake zed.dev/cloud.zed.dev servers, no real account: internal/zed TestSignInKey, TestParseModels, TestReadLines; provider TestZedSignIn (the whole sign-in through the loopback callback, what is kept, the account and its models, the token kept and renewed, the quota's plan and end, a refused pair lapsing) and TestZedFreePlanQuota; gateway TestServeZedProviders (each of the four providers, streaming and not), TestServeZedFailures (stale token retried once, 402, upstream 529 with retry_after, a failed 429, cut short → 502), TestZedRequestShapes. New zed-sub.test.cjs in Chromium and WebKit, en and zh: the Zed row with its plans and logo, the risk note in Zed's words with nothing asked, then Sign in anyway asking for zed. add-sheet, add-button, old-webkit, signin-callback and own-signin-remove pass. go vet, go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried with a real Zed account: the sign-in page's real callback, the LLM token and completions endpoints' acceptance of magpie's headers, and each provider's real event shapes are from Zed's source, not seen on the wire.
2026-09-30 03:19:19 +08:00
zed: a Zed subscription (Pro, Student, Business) signed in from magpie, several accounts, served through Zed's own cloud (yosocoli5 on X: 买了 Zed 订阅,可以加进供应商吗 — yetone: 当然可以!) — magpie had no way to use Zed's hosted models. Zed is now a subscription in the add sheet (Zed's own logo from zed-industries/zed, lobe-icons has none), signed in as the Zed editor signs in (new internal/zed, the protocol): an RSA key is made, the browser opens zed.dev/native_app_signin with its PKCS#1 public half, magpie's loopback port and a system id, and comes back with user_id and the access token encrypted to the key (OAEP SHA-256, PKCS#1 v1.5 also read), answered with a redirect to zed.dev's succeeded page. The account is asked of /client/users/me (signed "<uid> <token>" with x-zed-system-id), kept with its GitHub login, its default organization and plan; an organization with hosted models turned off is refused. Several accounts can be added and switched like the other subscriptions. Requests get an LLM token from /client/llm_tokens (kept in memory, minted again when Zed answers 401 or x-zed-expired-token/x-zed-outdated-token, once; a refused pair marks the account lapsed, "sign in again"). The model list is Zed's /models for the account (disabled and unknown providers left out; context, output, images and effort levels kept). The gateway asks cloud.zed.dev/completions in Zed's envelope {provider, model, provider_request}, the request written in the model's own provider's API as Zed writes it — Anthropic Messages without stream, OpenAI Responses, xAI chat completions with max_completion_tokens, Gemini's request with models/<id> — and reads the NDJSON reply's events with that API's decoder: a failed status is an error with its status (upstream_http_N, rate limit 429, overloaded 529, payment 402), a reply without stream_ended is an error, not a shorter answer, a 402 says the plan doesn't include hosted models or its allowance is used up. relayQoder's status-keeping relay is now relayStatus, shared by Qoder and Zed. Usage shows the plan and its period's end; Zed reports no usage counter, so no windows. Signing in says first, as Antigravity's does, that Zed serves these models to its own editor and may treat magpie's use as third-party use (en and zh); the import box now uses a subscription's own risk note too. Tested in Go against fake zed.dev/cloud.zed.dev servers, no real account: internal/zed TestSignInKey, TestParseModels, TestReadLines; provider TestZedSignIn (the whole sign-in through the loopback callback, what is kept, the account and its models, the token kept and renewed, the quota's plan and end, a refused pair lapsing) and TestZedFreePlanQuota; gateway TestServeZedProviders (each of the four providers, streaming and not), TestServeZedFailures (stale token retried once, 402, upstream 529 with retry_after, a failed 429, cut short → 502), TestZedRequestShapes. New zed-sub.test.cjs in Chromium and WebKit, en and zh: the Zed row with its plans and logo, the risk note in Zed's words with nothing asked, then Sign in anyway asking for zed. add-sheet, add-button, old-webkit, signin-callback and own-signin-remove pass. go vet, go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried with a real Zed account: the sign-in page's real callback, the LLM token and completions endpoints' acceptance of magpie's headers, and each provider's real event shapes are from Zed's source, not seen on the wire.
2026-09-30 03:19:19 +08:00
2026-10-01 21:28:54 +08:00