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
yetone
134a788821
settings: magpie's own update checks can be turned off, and run every 30 minutes, hour, six hours or day ( #472 : 更新行为可配置) — the app asked the feed five seconds after start and every six hours, a constant, and downloaded any newer version at once; with releases out most days, a version out just after a check waited up to six hours, and there was no way to stop the checks or the downloads they start (Update button only hides the pill). Settings → About has Automatic updates (on by default) and Check every (30 min, 1 h, 6 h, 24 h; 6 h with nothing set), kept in settings.json as noAutoUpdate and updateEvery, and magpie update auto [on|off] [30m|1h|6h|24h] sets them from the terminal. The updater reads them each minute and asks once the interval since the last check, its own or a click on Check, is up, and never by itself while off; the version row, not asked yet, then says automatic updates are off and offers Check. Check every stays in place, dimmed, while off, so the click doesn't shorten the page under it. TestUpdateDue, TestUpdateAskedAt and TestUpdateAutoCmd fail without the change, as does update-auto.test.cjs (Chromium, WebKit; en, zh). go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; update-hide, update-check, whats-new, settings-groups, click-scroll, old-webkit pass.
2026-10-02 06:42:15 +08:00
yetone
03ab46dda3
library, plugins: the installed lists are sorted as the reader picks, and remember it ( #481 : the installed MCP servers, skills and plugins had no order the user could choose; the plugins came in the order they were installed) — the Library's MCP servers and the installed plugins now have A→Z and Z→A beside their list, A→Z until one is picked, so the plugins are no longer in the order they were installed in; the Library's skills have By source (the groups by repository and their parts, as before, and still the default), A→Z and Z→A, the last two one flat list of every skill by name, the filter still finding a skill by its repository. Each list keeps its own pick in the browser's storage (magpie.sort.<list>, read and written in try/catch), and a pick redraws only its list, the control left where it was on the screen. The skills' heading, the fullest, goes on to a second line in a narrow window rather than past the page's side. Sorting by use or by when a thing was installed waits for the library to keep those. list-sort (Chromium, WebKit; en, zh) fails without the change; library-items, library-all, own-skill, every-skill, the plugin tests, click-scroll and old-webkit pass; go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-02 06:33:46 +08:00
yetone
e3bf9d05d4
library: one agent's skills or MCP servers are turned on or off at once, and a hidden agent's taken out of it ( #475 : turning Copilot CLI's 32 skills off was a chip on every row, and once it was hidden on the Agents page it had no chips at all, so what it had been given stayed with no way to take it out) — By agent, beside "In the library" on the Skills and MCP tabs, opens a sheet of the agents that take them, each with how many it has, a Turn all on and a Turn all off; each writes that one agent, every other keeping what it has, and reports what couldn't be written as a row's chips do. An agent hidden on the Agents page is listed while it has any, tagged Hidden and given nothing new; its instructions row is shown while it reads the shared instructions, so it can be switched off. Skills use the existing skills/agents-all; servers get servers/agents-all (EveryServerAgents), which turns on only the servers the agent can reach (no SSE for Codex, no remote one for Claude Desktop). TestEveryServerAgents and by-agent.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; every-skill, library-all, library-items, library-toggle-status, remove-all-skills, click-scroll, old-webkit pass.
2026-10-02 06:33:40 +08:00
yetone
fe86fb3a4d
gui: the page is first drawn in its saved theme, not the system's (seg-contrast failed in Chromium on the release branch: in dark the view shown read at 3.96:1, the other views at 4.69:1) — the saved theme was put on the page by app.js, at the foot of index.html, so a window kept dark under a light system had its header parsed and styled light first, and its buttons' colour transitions (the switch's views, Sync, Settings) then faded them to dark as the page loaded; the test read them mid-way, the more so as #471 made the page longer to parse. theme.js, run in the head after boot.js and before the styles, sets it from bootPrefs (or ?theme=) for the first paint; app.js still sets it as before. seg-contrast.test.cjs now holds app.js back and checks the page was already drawn in its theme (fails without theme.js, Chromium and WebKit, en and zh, dark), and reads colours once the page's transitions are over. old-webkit lets theme.js (ES5, URLSearchParams) run before compat.js; api-key-theme, from the release branch, expects a text button in --ctl-fg as #477 set. seg-contrast, settings-sections, header-zoom-fit, header-centre, click-scroll, old-webkit, api-key-theme, omarchy, agent-grip, web-page, gateway-fold, sessions-toolbar pass; go vet, go build -tags nogui, go test ./internal/gui pass.
2026-10-02 06:12:01 +08:00
yetone
872e26e2d4
models: a favourite's star is filled, and a model not a favourite shows an outline one on hover ( #482 : 收藏后切换成实心星) — the model picker's star, in the window and the tray panel, was the same outline star whether the model was a favourite or not, only its colour changed, so which state it was in wasn't clear. A favourite's star is now filled in its own amber, light and dark, and shows always; one not a favourite is still an outline, shown on hover. The button says which with aria-pressed as well as its title. favorite-star (window and tray panel, light and dark, en and zh, Chromium and WebKit) fails without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass; click-scroll, old-webkit, model-pick pass.
2026-10-02 06:07:14 +08:00
yetone
10da2936da
gui: Settings is a page per part, under a tab each, the part kept in the address ( #471 : Settings is one long scroll of some 45 rows in 9 sections) — the page now opens with a tab list in the warm-ups' look (role=tablist, a tab each with aria-controls/aria-labelledby): General (appearance, language, text size, the icons, model names, login, Dock, session terminal), Usage (the menu bar's usage, refresh, logos, what usage shows, currency, number units, the two alerts, then the warm-up and check-in tabs), Network and sharing (proxy, local network), Models (images, web search), Privacy, Observability, Sync and backup, About; the part picked shows its rows alone. Every row, its id and what it saves are as they were; the duplicate heading of a one-section part and the Preferences heading are gone. The part is kept as ?view=settings&tab=<part> (dropped on any other view), so a reload or a link lands there, and remembered (magpie.settingsTab) for Settings opened again without one, as the tray's window/main?view=settings; an unknown one falls back to it. A part whose rows are all hidden on this system has no tab, and one picked falls back to the first shown. The arrows, Home and End move along the tabs, one in the Tab order; a click on a tab moves nothing on the page, the tabs staying where they were; a pill drawn while its part was hidden has its thumb put under its pick when shown (the warm-ups' fix, now shared). The tabs wrap to a line more when they don't fit (English in the 560x420 window, at 110 and 125%, a phone), no left-border stripe. The click hold also holds a click not yet held before taking the next (keys pressed within a frame on a tab list whose part shrank to the window: the second click was taken at the clamped top and the page stayed there). New strings General and Network and sharing are in i18n.js (常规, 网络与共享). Tests that reach a row now open or click its part: api-key-theme, currency, gateway-caller-keys, gateway-connect-keys, lan-docker, number-units, otel, redact-rule-row, s3-sync, search-api, settings-groups, sync-other-kind, tray-inuse, tray-logos, tray-usages, update-check, update-hide, usage-alert, webdav-settings-refresh, whats-new; those needing a scrolled page wheel a shorter window or in smaller steps, as a part is shorter than the whole page was. settings-sections.test.cjs (Chromium, WebKit, en, zh) fails without the change (10 of 10). go vet ./internal/..., go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestAccountProxy as on main); settings-sections, settings-groups, click-scroll, old-webkit, text-size and every settings test listed above pass.
2026-10-02 05:50:24 +08:00
yetone
69edf9f6e4
profiles: a chip's ↻ and × act on a second click, and a profile's details close with their own ×, or Escape, without hiding the tray panel (emo172, #478 : ↻ overwrote and × deleted a profile on the first click; the details closed only by clicking the chip again, and Escape on them in the tray panel hid the whole panel; closed by hand they came back with the list, closed by Apply they didn't) — a first click on ↻ or × now changes nothing and reads "Overwrite?" or "Delete?" (覆盖?, 删除?) in red, and a second does it; it goes back after 3.5s, on Escape, or when the other one is clicked, with no browser dialog. The details have a × beside Apply, which closes them, the chip where it was. Escape takes back a question, then closes the details, then the panel's list, and only then hides the panel (both the panel's Escape and the list's ran on one press, so it hid the panel with the list open). The details close with the list, so the list opens again on the chips alone, however they were closed, as after Apply. profile-confirm.test.cjs (Chromium, WebKit, en, zh, window and panel) fails without the change; panel-profiles clicks × twice. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; profile-details, panel-profiles, old-webkit, click-scroll pass (click-scroll's routing Replay case flaked once on WebKit, passes alone).
2026-10-02 05:50:23 +08:00
yetone
973bf4eb2c
profiles: a profile's details list all four of Claude Code's tiers, one left to follow the main model saying so ( #480 : opus and fable, following it, were missing from the details, so they read as not set) — a tier is a quiet field, empty while it follows the main model, and the details left every empty quiet field out. A field now says which one it follows (Follows, "model" for the tiers), and the details keep such a field, empty, with it; the panel shows it as "follows the main model (<model>)" (跟随主模型(…)), or "follows the main model" when the main is the agent's default. Other quiet fields (Codex's sign-in, subagents) are still left out while empty, and what applying a profile writes is unchanged. TestDetails and profile-details.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.
2026-10-02 05:50:23 +08:00
yetone
01d595817c
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
yetone
7de2b62191
gui: an agent row shows a faint grip in its margin, and a hidden agent's Show is always there ( #479 : hiding an agent was found only by right-clicking) — the row's handle is its logo, which turned into a grip and opened Move up, Move down, Hide on a click, but only showed it was a handle with the pointer on it, and a hidden agent's way back, the Show button in the fold at the foot of the list, came up only with the pointer on its row. Every row in the list now carries a faint grip (two columns of three dots, --faint, --muted with the pointer on the row) in its left margin, beside the logo: it is the handle's own ::before, so it takes no room from the row, a drag on it moves the row and a click on it opens the menu. The Show button on a row hidden by hand is drawn without the pointer on it. Rows in the fold carry no grip, since they aren't dragged. agent-grip.test.cjs (window and tray panel, Chromium, WebKit, en, zh) drags a row by its grip, hides one from the grip's menu and shows it again from the fold, and fails without either half of the change. account-arrange, agent-layout, panel-fold, rollup-short, click-scroll, old-webkit, seg-contrast, header-centre, header-zoom-fit pass. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass but for TestClaudeSignedOut, which fails on its own as well and doesn't build on internal/gui (TestUserPath and TestSubscriptionUsageEachAccount flaked under load, pass alone).
2026-10-02 05:50:17 +08:00
yetone
aa8e8cee2f
gui: the header's other views and the text buttons read at WCAG AA, and the view shown stands off the switch ( #477 : in light mode an unselected tab read at 3.25:1, a text button at 3.33:1 on the page; dark passed by 0.08) — both were drawn in --muted (#85858d light, #8b8b94 dark), meant for captions, not controls, and the thumb on the view shown was white on a pill-grey track (1.13:1) or a 10% white on a 4.5% one (1.36:1). A control's quiet text now has its own colour, --ctl-fg (#63636b light, #a1a1aa dark), for the switch's other views, the Accounts and Sessions switches on the same track, and every .text button: 4.79:1 on the light track, 5.4 to 6.0:1 on the page, a card and the inset editor, 6.1:1 and up in dark. The light track is a shade deeper (#e6e6eb) and its thumb's edge a little firmer, 1.24:1 against it; dark's track is 3.5% white and its thumb 15%, 1.61:1. Sizes and weights are unchanged, so the header fits as before (#442/#457). seg-contrast.test.cjs (Chromium, WebKit, en, zh; light, dark, system dark) reads the computed colours, each background laid over the ones under it, and fails without the change. header-centre, header-zoom-fit, text-size, sessions-toolbar, click-scroll, old-webkit pass.
2026-10-02 05:50:17 +08:00
yetone
2d5905ffc8
usage: every count on the Usage page and in the panel follows Settings' number units ( #476 : with 万 / 亿 picked, the Overview, the Requests summary line, Sessions and the panel's Routing "today" still said K/M/B, two units on one page) — the setting reached only ledShort, which the Requests tab's totals and axis and the panel's Usage tab used, while fmtN, behind the Overview's tiles and chart peak, the Requests summary (#ledSum), every Sessions figure and Routing's "today N tokens", always said K/M/B. fmtN now says a count in 万 and 亿 in Chinese unless K / M / B is picked, ledShort is gone and its callers use fmtN, and the panel's Routing redraws when the setting changes, not at the next request. Small counts (the scan's file counts, a picker's search count) are as they were below 10000 and in 万 above it in Chinese. English is unchanged. number-units.test.cjs (Chromium, WebKit, en, zh) now checks the Overview, the Requests summary, Sessions and the panel's Routing in both units and fails without the change; sessions-overview, sessions-today, panel-routing and api-key-usage expect 万 in Chinese. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; number-units, sessions-overview, sessions-today, panel-routing, api-key-usage, usage-chart-axis, panel-usage, usage-ledger, usage-ledger-chart, currency, sessions-bar-names, click-scroll, old-webkit pass.
2026-10-02 05:46:16 +08:00
yetone
8043e9436d
tests: cli-update's tight agent row is measured just above 600px, where the row is still beside its fields — since #440 ( 946c1d3b) a window 600px wide or less puts an agent's fields under its name, so at 540px, where the test looked for the version to have gone, the name's line spans the whole row and shows the name, the version and the whole pill again, as #440 meant. The version now has to be gone at 604px (the row about 148px), the tightest it gets beside its fields, and at 540px everything has to be back. No behaviour changes. cli-update.test.cjs (Chromium, WebKit) failed on main; click-scroll, old-webkit pass.
2026-10-02 05:29:14 +08:00
yetone
afe0014ebe
routing: the live stage seats a provider's accounts and keys in the order they were dragged into, at once (Koohoko, #217 : after dragging, the live routing animation kept the old account order) — the stage held each route's rows still by seating them by name, so a provider's accounts read alphabetically (by email, a key by its name) whatever order the provider's page lists them and the gateway tries them in, and a drag moved nothing there. The trace now tells each account's or key's place in its provider's own list (Weighed.Rank, from the order the provider lists them, the one signed in to first), and the stage and its Accounts and keys list seat a provider's rows by it, read from the providers as they are now, so after a drag the stage moves to the new order within a second of Routing being shown, with no reload or new request; a plugin's accounts, listed by its provider's id, follow it too. The order routing weighs them in, and who goes first, are unchanged. TestWeighedRankIsDraggedOrder and routing-account-order.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 (TestAccountProxy fails on main as well; TestFXInState flaked once under load, passes alone); account-arrange, click-scroll, old-webkit, routing-steady, routing-columns, routing-shape, panel-routing pass.
2026-10-02 04:32:36 +08:00
yetone
f22218a092
gui: after an update the window shows what changed since the version last run (a Discord user: 点更新后能弹个窗显示更新了啥吗, to see whether their issue was fixed) — magpie updated itself silently, and its release notes were only on GitHub. The version last run is now kept in magpie's own folder (last-version); started on a newer release, the window or magpie web's page asks usemagpie.ai's new /api/notes (beside /api/latest; site/worker.js lists the releases' notes from GitHub, cached as the feed is) for every release since, newest first, without their Install section, and shows them once in a What's new dialog. A fresh install, the same version, a downgrade or a build from source shows nothing; a magpie from before the version was kept, already in use, shows its own version's notes; offline nothing is shown and nothing waits on it; until the site is deployed, the update feed's newest notes stand in when they are the current version's. The tray's panel shows no dialog. The notes are drawn as text, never as HTML: headings, bullets, bold, code, http(s) links, and #NNN links to the issue, opened in the browser as the app's other links are. Settings has a What's new row under Version that opens them again, with a waiting update's notes first, marked Not installed yet; /api/update's notes leave out the Install section too. TestShowNotes, TestStripInstall, TestBetween, TestNotesBetween, TestWhatsNewAfterUpgrade, TestWhatsNewFromBefore, TestUpdateNotesWithoutInstall and whats-new.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, update-check, update-hide pass.
2026-10-02 03:57:55 +08:00
yetone
78aba760aa
gui: an agent's instructions opened at the foot of the Library's list leave the page where it is (emo172, #458 ) — the Library draws its whole page again on a click, so the click's hold (the element clicked, its neighbours and its parents, kept where they were on the screen) found none of them left and held nothing; the page went where the browser took it: down by what opened under the row (scroll anchoring), or clamped as it shut. A held element gone, with every one of its neighbours and parents, is now stood in for by what is at its place in the view's tree, of the same tag and first class, so the row clicked stays put. library-row-open-scroll.test.cjs (Chromium, WebKit, en, zh; a long set in a short window, shorter sets in a tall one) fails without the change (12 of 14); click-scroll, old-webkit, header-zoom-fit pass. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-02 03:38:15 +08:00
yetone
7e31cf7438
gui: a zoomed header with room to spare is drawn as at 100% (emo172, #457 ) — under the webview's page zoom (text size 110/125%) the header's buttons, which sit against its right padding, measure a hair past it (0.00004 CSS px in Chromium at 110%); fitTop took that for buttons running off and drew the header in step by step, at 110% all the way to packed, whatever the window's width. The comparison now allows half a pixel. header-zoom-fit.test.cjs zooms Chromium's page as the webview does and fails without the change; header-centre, text-size, brand, click-scroll, old-webkit pass.
2026-10-02 03:38:06 +08:00
关俊江
e230b9f31a
feat: support handle-free account reordering in all routing modes ( #216 )
2026-10-02 03:32:41 +08:00
yetone
cbd697693a
agents: Claude Code's subagents get no square while there is no model to pick ( #468 ) — before Claude Code runs through magpie its subagents field offers nothing, yet the agents page drew a square that could set nothing; it is left out, as an effort with no levels is. subagent-effort.test.cjs fails without the change.
2026-10-02 03:18:35 +08:00
yetone
4c69ff336b
agent: Codex's subagents can start at an effort of their own, and Claude Code's subagents can have a model of their own ( #468 , #469 ) — Codex reads [agents] default_subagent_reasoning_effort, the effort a spawned subagent starts at when the spawn names none (openai/codex core/src/agent/child_config.rs, config_toml.rs; in codex 0.159.2), and magpie never wrote it. Codex gets a subagent effort field: a square beside its subagents' one that opens the effort slider, unset said to mean the session's effort, or the subagent model's own default. Codex refuses a spawn at a level the subagents' model lacks, so only one it has is taken, and one a new subagent or main model lacks is dropped. Claude Code takes the Agent call's model, then the agent's frontmatter, then CLAUDE_CODE_SUBAGENT_MODEL, then the session's (2.1.287); magpie wrote that env only by itself, the main model while every tier followed it. It gets a subagents field, offered once routed through magpie, whose model outlives a new main model and a tier of its own; unset, the env is written as before. Claude Code has no setting for its subagents' effort beyond each agent's own frontmatter, and omp's task role already takes a thinking level, so neither changes. TestCodexSubagentEffort, TestClaudeSubagentModel and subagent-effort.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; subagent-effort, omp-roles, claude-effort, panel-effort, agent-layout, model-pick, click-scroll, old-webkit pass.
2026-10-02 03:18:26 +08:00
yetone
818621b75e
profiles: a click on a profile shows what it holds, and its Apply applies it ( #467 emo172: a saved profile could only be seen by applying it over the setup in use) — a profile's chip applied it at once, and all the page knew of it was a one-line summary of its models. The state now carries each profile's fields by agent, under the agents' names and the fields' labels, in the order magpie lists them, with the Library's servers, skills and instructions each agent gets (not the instructions' text); a value that reads as a key or a token (a field named for one, a known key prefix, a long run of letters and digits) is sent as hidden, never its text. A click on a chip opens its details under its line in the window, and over it in the tray panel with Apply at their foot by the chip, the chip clicked staying where it is; opening them changes nothing, a second click closes them, Apply applies the profile; ↻ and × stay on the chip. In English and Chinese. TestDetails and TestStateProfileDetails fail without the change, as does profile-details.test.cjs (Chromium and WebKit, en and zh, window and panel). go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestFXInState's TempDir cleanup flakes with or without the change); profile-details, panel-profiles, click-scroll, old-webkit pass.
2026-10-02 03:09:42 +08:00
yetone
623307e978
i18n(zh): plainer words where they read as slang, the rest kept ( #465 ) — the provider editor's Forget (dropping the vendor's fetched list) is 清除, not 忘掉; the Providers page's Take a look is 查看, not 看看; an account's forget tooltip says magpie 移除 its sign-in, as its siblings do; and the routing explanations that said {who} 先上 say 排第一, as every other "goes first" there already does. A session's details named its id line 整个会话, the routing affinity option's word for "Session": the line now uses the Session ID key (会话 ID, as the usage ledger's detail has it), and 整个会话 stays where it means the whole session, beside 一轮之内. 知道了 (OK) and 还有 {n} 个 (+{n} more) are kept: standard and clear where they show. plugin-move and provider-picks-stay assert the new words; sessions-manage and sessions-overview fail without the id line's label. plugin-move, provider-picks-stay, sessions-manage, sessions-overview, routing-steady, routing-manual, click-scroll, old-webkit pass (Chromium, WebKit, en, zh); go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-02 02:50:38 +08:00
yetone
16f14fdc10
providers: the models picked in one provider's editor never go to another's ( #464 : Claude models picked on one relay showed in another relay's editor, and its Forget and Refresh kept them) — a Refresh or Forget took the open draft's picks once the vendor answered and, after the list came back, wrote them into whatever draft was open by then; an editor left for another provider's in between was given the first one's picks, shown there as added by hand, and that editor's own Refresh and Forget then kept them as its own. The redraw already keeps the open draft, picks and all, so nothing is put back by hand any more: the other editor has its own picks only, while in the editor the button was pressed in a pick not yet saved and an id the vendor doesn't list (added by hand) still outlive both. provider-picks-stay.test.cjs (Chromium, WebKit, en, zh) fails without the change, for Refresh and for Forget each; click-scroll, old-webkit, provider-typed, unlisted-models, model-test-one, nokey-editor pass.
2026-10-02 02:50:38 +08:00
yetone
a409e1552a
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
yetone
456208945b
plugins: a plugin can be installed from a git repository — github:owner/repo, owner/repo, a GitHub URL or a git+https:// one (Lemon on Discord: can plugins be installed directly from git?) — magpie plugin add and the Plugins field took only an npm name or a path, and turned a git spec away as "isn't an npm package name". A git spec now goes to bun add as given and is kept as given in plugins.json; the package it installs is named by its repository's package.json, which bun records as the dependency whose spec it is, so the plugin is known (list, on/off, rm, its version, its README) by that name or by the spec. update and the row's Update run bun update on it, which fetches the repository's commit now where bun add keeps the one bun.lock has, the spec unchanged; npm is never asked for a newer version of it, nor auto-updates it. Adding the same package from another URL, or from npm, takes its entry's place. The Plugins field says it takes a GitHub repo (en+zh); an installed git plugin shows its package's name, an Update button, and a page with its README, no npm link and a Source link to the repository. Nothing that installed before is turned away. TestGitPlugin (a fake bun fetching from local bare repositories, the real one loading the plugin when on PATH) and plugin-git.test.cjs fail without the change; TestIsGit checks what counts as a git spec. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; plugin-git, plugin-local, plugin-market, plugin-updates, click-scroll, old-webkit pass.
2026-10-02 02:24:49 +08:00
TryWorld
876bec1b89
feat(gui): collapse overflowing Sessions agent tabs into a picker ( #461 )
2026-10-02 02:25:17 +08:00
TryWorld
946c1d3bf6
fix(gui): keep agent names visible in narrow windows ( #440 )
2026-10-02 01:50:38 +08:00
Alice and raper
0260716c9d
feat(usage): 可选的 OTLP 元数据导出(Trace/Metrics,支持 Langfuse) ( #412 )
...
* usage: add opt-in OTLP HTTP metadata export
Export gateway traces and optional duration/token histograms asynchronously with a bounded queue, retries, proxy support and a bounded shutdown. Add bilingual Settings controls and MAGPIE_OTEL_* overrides. Keep prompts, replies, sessions and provider credentials local; use the same OTLP path for Langfuse.
Validated: full Go tests (nogui), usage race tests, focused go vet, and Chromium/WebKit settings tests in English and Chinese.
Refs #213
* otel: protect collector credentials in backups and settings
Remove all OTLP headers from keyless backups and restrict both new and existing settings files to 0600 before saving. Clarify SIGTERM export behavior. Addresses the two blocking review findings in #412 .
* otel: preserve local credentials and read-only settings on restore
---------
Co-authored-by: raper <raper@raperdeMacBook-Air.local >
2026-10-02 01:51:04 +08:00
yetone
3c04877cfc
archive: a request the archive kept is opened and downloaded from the Usage page, with its bodies whole (jorben, #447 : 请求存档 reachable from usage history, full bodies, download) — the archive's name was only on the Gateway page's recent calls, gone once a call left the list or the gateway restarted, and the archive kept the first 256 KB of each body, the recent list's cut. The usage ledger's row now names the call's archive (archive in usage.jsonl, kept through the Requests page's packed rows), and its details on Usage → Requests show the Request archive panel, Fetch from archive and Download; with the archive on, a request it has no copy of says "Not archived". The bodies are kept whole up to requestArchiveMaxMB in settings.json (32 MB unless set, at most 1024): the response is teed to a temp file as it is sent, the request body written to one when the call ends, so the upload queue holds file handles, not bodies, and one upload at a time reads them; a body past the limit is kept to it and marked cut, with its whole size. What goes upstream is unchanged, the archive stays off unless turned on, headers and bodies are scrubbed as before, and the temp files are removed after the upload or when the queue is full. The page is sent a body to show only when it is 256 KB or less (a longer one is said by its size), an archive over 80 MB is only said to be; Download streams the object whole, to Downloads in the app (archive/export, -2, -3… for a name taken) and as the browser's download in magpie web (archive/file). TestArchiveWholeBodies, TestArchiveLimit, TestRowKeepsArchive and TestArchivePreviewAndDownload fail without the change; TestArchiveOffUsage, TestArchiveTooLargeToPreview, TestArchiveOldPreview keep the rest. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; request-archive-usage (new), request-archive, click-scroll, old-webkit, usage-ledger, usage-ledger-detail, usage-ledger-content, web-page, sse-body pass.
2026-10-02 00:57:51 +08:00
yetone and Claude Opus 5.5
03b4cadb1f
library: Remove all beside Turn all on/off takes every skill out of the library at once ( #449 ) — a library of many skills could only be emptied a row's Remove at a time. Remove all, in red, asks in the page first, naming the agents that lose the skills, the projects magpie placed them in, the folders that go to magpie's backups and those of the user's own that are only unlinked; Cancel sends nothing. Confirming sends every name in one call, library.RemoveSkills, which takes each as RemoveSkill does, the folders kept aside together under one backup; one that can't be taken out stays, and is said, while the rest go. magpie library skill rm --all does the same, asking y/N on a terminal and, with none, only with --yes. TestRemoveSkills and TestLibrarySkillRmAll fail without the change, as does remove-all-skills.test.cjs (Chromium and WebKit, English and Chinese); click-scroll, old-webkit, every-skill pass. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (bar the known Claude account flake TestClaudeSignedOut).
...
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com >
2026-10-02 00:47:15 +08:00
czyt
bde39aef5e
gateway: advertise MAGPIE_PUBLIC_URL in the console and CLIs ( #373 )
2026-10-02 00:46:45 +08:00
yetone
f232a5df45
sessions: the agent tabs scroll under the app's thin thumb on Windows, not its classic scrollbar (ARNO on Discord: 会话面板是不是被改坏了…现在变得好丑) — the strip, and a provider's region picker that shares its class, set scrollbar-width: thin, and in Chromium (WebView2) that drops every ::-webkit-scrollbar rule, so Windows drew its own bar, arrows and all, under the tabs. The strip now leaves scrollbar-width alone and takes the app's thumb, 6px high; on a Mac the overlay bar is as it was. strip-scrollbar fails without the change; click-scroll, old-webkit, sessions-manage pass.
2026-10-02 00:31:16 +08:00
yetone
7ed38530f6
gui: the header's tabs stay in the middle when closed up, and halfway between the edge and the buttons when in the row (emo172, #442 ) — at text size 110% on Windows the header's tabs sat about 67px left of the middle: fitTop's cramped both closed the tabs up and put them in the row, where auto margins left a third of the room to their left and two thirds to their right. The closer tabs are now tried in the middle first; only when they don't fit there does a new inrow step put them in the row, with the buttons' auto margin dropped so the room either side is the same, give or take the header's padding against the row's gap. header-centre.test.cjs fails without the change.
2026-10-01 23:38:15 +08:00
yetone
09ee1bbf58
library: every skill on or off at once ( #443 )
...
With 30+ skills, turning them all on or off was a row's All at a time.
"Turn all on" and "Turn all off" beside "In the library" give every skill
to every agent shown that can take skills, or take every one from them, in
one write (POST library/skills/agents-all, EverySkillAgents); an agent not
shown keeps what it has, as with a row's All. Off asks first in the page;
each is greyed when there's nothing for it to do. TestEverySkillAgents and
every-skill.test.cjs fail without the change.
2026-10-01 23:38:15 +08:00
yetone
728cb83c47
routing: a request's changed reasoning keeps to its own box, cut with an ellipsis, never drawn over its numbers ( #435 , azir12345: 文字重叠) — the Requests list's rows share their columns, and the numbers' one is as wide as the longest numbers in the list (three tries · minutes · TTFT · a million tokens), so where a request went could be left next to no room; its reasoning would not shrink and ran on over "15 秒 · 首字 14 秒 · 6.9k token", while a short "· low" still fit. Where it went now gives way first, then the level asked for ("m… → xhigh"), each with an ellipsis, and the level sent stays whole; the reasoning cell clips as a last resort. Safari 15's styles (no subgrid, no container queries) lay each row out by itself and stay as they were. routing-effort-change.test.cjs (Chromium and WebKit, English and Chinese, dark, 1440 to 400px, and with Safari 15's styles) fails without the change; routing-effort-row.test.cjs counts the reasoning's new inner spans as the reasoning. routing-effort, routing-effort-row, routing-kind, routing-served, routing-sessions, routing-columns, remote-group-served, routing-reroute-title, routing-steady, routing-time, routing-flood, request-archive, panel-routing, click-scroll, old-webkit, text-size pass; go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build pass.
2026-10-01 23:20:57 +08:00
yetone
4547dafe95
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
yetone
41dde238dd
usage: a sessions bar's name takes the width it needs, its bar what is left (John on Discord: widened, the names stayed cut short with … while the bars grew) — the Sessions overview's projects, models, tools and skills rows held their names to 9em, 10em and 11em whatever the window's width, every extra pixel going to the bar. Each card is now one grid whose rows are subgrids: the names' column is as wide as the longest (minmax(0, max-content)), the bars take the rest and are never under 5em, and every row's bar starts at the same place; narrow, the names are shortened rather than a bar. Without subgrid (before Safari 16) each row sizes its own name the same way. sessions-bar-names.test.cjs fails without the change (196px name shown in 108px at 1600 wide); it, sessions-overview, sessions-calendar-fill, sessions-today, click-scroll and old-webkit pass in Chromium and WebKit, en and zh.
2026-10-01 23:20:56 +08:00
yetone
cbf51ec7a4
settings: Number units lets Chinese say a large count in K/M/B instead of 万/亿 (John on Discord asked for K/M/B with the UI in Chinese) — the Requests tab's totals and chart axis and the tray panel's Usage tab shortened every count with 万 and 亿 whenever the language was Chinese (ledShort, the one place either is used). A Number units row under Currency, shown in Chinese only, picks 中文(万 / 亿)(the default, unchanged) or 英文(K / M / B), kept as settings.westernUnits and sent with the rest of Settings; picked, ledShort says it as English does (1.54B, 80M), the Usage page and an open panel redraw at once, and the axis labels are still measured before the plot. number-units.test.cjs fails without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; number-units, click-scroll, old-webkit, usage-chart-axis, text-size, currency, panel-usage pass.
2026-10-01 23:20:56 +08:00
yetone
38f184ae0e
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
yetone
cd201d888c
sessions: a Sessions page lists an agent's sessions by folder, to resume or delete, and deleted ones wait in magpie's trash to be restored (TJHHHH on Discord: session management like CC Switch's, deleting above all, in the GUI) — sessions were only seen on Usage, with no way to remove one. The new Sessions tab shows, per agent, every session under the folder it ran in, with its title or first prompt, when, how many messages and how big, a filter, its resume command to copy and, in the Mac app, Open in terminal. Picked sessions (or one, by its own button) are deleted after magpie's own dialog: their files (Claude Code's .jsonl, its subagents folder and what it keeps by the id under file-history, session-env and todos; every segment of a Codex rollout; Qoder's, WorkBuddy's, Pi's, oh-my-pi's) are moved into magpie's folder, trash/sessions/<agent>/<when>-<id>, with a manifest, never erased; Trash lists them and Restore puts them back where they were. A session written to in the last minute is left, and said so, as the agent may still be running it. Agents' own indexes (Codex's session_index.jsonl and state database, Claude Code's history.jsonl) are not edited: they are written while the agent runs, and a stale entry there is harmless. OpenCode, ZCode, dsh, Cline and Grok keep sessions in databases magpie doesn't write, and show no delete. With nine tabs the narrowest header gets a further step that draws the tabs in, and past that they scroll sideways rather than push the page wider (560px in English, or at 150% text). The dialog uses the shared confirmAsk/closeConfirmAsk, as the gateway keys' do. TestListAgent, TestDeleteRestoreClaude, TestDeleteRestoreCodex, TestDeleteActiveRefused (fails without the running check) and TestDeleteOnlyKnownAgents run in a temp HOME; sessions-manage.test.cjs (Chromium, WebKit, en, zh) fails without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; sessions-manage, click-scroll, old-webkit, text-size, session-terminal, sessions-today, brand, rail-tip, web-page, omarchy, model-test-one, gateway-caller-keys, gateway-connect-keys, api-key-usage, api-key-theme pass.
2026-10-01 22:11:46 +08:00
yetone
92760896e3
usage: the chart's side labels keep the card's padding (John on Discord: 这是bug吗?贴边了) — the plot of the Requests tab and the tray panel's Usage tab started a fixed 44px (34px in the panel) from the left, and the labels were drawn to end 6px short of it, so any label wider than that ran out leftward: "8000 万" in the panel reached past the card's 10px padding to its edge, and "200,000" or "$0.50" in the window crossed its padding too. The labels are now measured as drawn and the plot starts where the widest one ends, so every label stands as far in as the tabs above it, in English and Chinese, for tokens, cost in $ and ¥, and requests, small and large, wide and narrow. usage-chart-axis.test.cjs (Chromium and WebKit, en and zh) fails without the change. click-scroll, old-webkit, usage-ledger-chart, panel-usage, usage-ledger*, usage-refresh, usage-alert, api-key-usage, tray-usages, claude-usage-asked, currency pass; go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.
2026-10-01 21:59:55 +08:00
Ns2Kracy
bb1aa3acbd
feat(gateway): named gateway keys with per-client usage ( #344 )
...
* feat(gui): show and filter usage for each API key
* feat(gateway): issue per-user caller keys and attribute usage
* feat(gui): manage gateway users and filter caller-key usage
* test: verify caller-key failover and document user management
* refactor(gateway): use named caller keys without user accounts
* feat(gui): manage named caller keys with existing account styles
* fix: remove user breakdown from CLI and leftover gateway styling
* fix(usage): drop stale user field from request response
* feat(gateway): authenticate LAN calls with named caller keys
* fix(gateway): preserve LAN key rotation in the named caller store
* fix(gui): retain native LAN key copy and rotation controls
* fix(gui): inherit the global theme for API key inputs
* fix(usage): show client API keys using the existing terminology
* fix(gateway): rotate named keys without changing usage identity
* fix(gui): unify gateway keys and selectable connection examples
Keep sharing controls in Settings and manage credentials only in Gateway. Refresh the named-key list on navigation, ignore stale reads after key actions, and generate all API examples from the selected address and enabled key.
* fix(gui): keep caller key names literal in connection menus
* fix(access): use Magpie as default key and drop user migration
* refactor(gui): name caller key source and tests consistently
* refactor(usage): split provider-key accounting out of caller-key PR
* fix(gateway): preserve LAN compatibility and add headless key management
* fix(gui): clarify gateway keys and confirm destructive actions
* test(gateway): guard caller attribution under 120 concurrent requests
* fix(gateway): keep open access, tolerate migration errors and revoke legacy keys
* fix(backup): preserve named gateway keys and honor no-keys restores
* fix(gui): keep local API-key semantics and disambiguate shared credentials
* docs(gateway): keep review scope focused and append browser test documentation
* fix(backup): retain existing default keys when old backups lack their store
* fix(gateway): attribute video creation usage to the caller key
* fix(access): explain default key revocation blocked by read-only settings
* test(usage): preserve provider and caller identities after rebase
* test(gui): reconcile caller key fixtures with merged main
* docs(usage): clarify caller coverage and independent provider accounting
* fix(gui): initialize fast members for model-shortcut groups
Latest main introduced fast-member arrays but omitted the model shortcut's draft. The existing unlisted-models browser regression fails unchanged on main. Initialize fast to an empty list and assert a standard-speed group is saved, without relaxing existing assertions.
* fix(access): retain legacy LAN access when the key store cannot be created
Allow only the configured legacy credential before either migration marker exists. Refuse revoked mirrors, disabled matches and unreadable stores; keep the fallback's caller identity stable when migration later succeeds. Cover read-only configuration directories, remote credential transports and revocation.
* fix(backup): save settings before replacing gateway credentials
Leave the key store untouched when settings validation or writes fail. Restore the previous settings association when the key store refuses its write, and report a rollback failure separately. Cover invalid settings and read-only settings/store failures.
* fix(gui): reset missing caller filters and focus key controls without scrolling
* test(provider): synchronize Zhipu quota fixture observations
2026-10-01 21:28:54 +08:00
Zhu Wang
1adb2b571e
feat(routing): group requests by session with names and estimated costs ( #396 )
...
* feat(routing): group requests by session with names and estimated costs
* fix(routing): address session view review feedback
Preserve Luna Reserve and other header fallbacks for ordinary Codex turn metadata; reuse metadata and the kind across trace and native accounting. Default to By request and persist the grouping choice. Store only token accounting fields in route history while retaining legacy JSON compatibility.
Add regressions for helper precedence, native kind accounting, history compatibility and grouping preferences.
2026-10-01 20:50:15 +08:00
yetone
986a4474fe
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
yetone
a999770531
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
yetone
9c54a560cc
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
yetone
f654bec468
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
yetone
044f61f50f
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
yetone
6532e018b1
web: the page asks for no Wails runtime in a browser, and its files are asked for again by their content (Jorben on Discord: in the remote web UI the Gateway page had no 请求存档 switch and the usage charts no icons, and /wails/runtime.js was a 404) — nothing in the page or the server holds the archive switch or the charts back from magpie web: the same Handler serves both, /api/settings/archive, /api/archive and /api/usage/requests are there behind the web key, and a sandbox magpie web of v0.1.578 and of main, opened in headless Chromium at 127.0.0.1 and at a non-loopback host, drew the switch with no page error. The 404 was the page's import of /wails/runtime.js, which the app's window has and a browser doesn't; it was caught, and only Close and Maximise use it, so it broke nothing, but a browser now never asks for it. What can hide a version's new parts is an older app.js: the page's files went out with no Cache-Control, no ETag and no date (an embedded file has none), so a cache in front of magpie web (a proxy, a CDN, a tunnel's) could keep an older version's app.js under the new index.html, untouched by a cleared browser cache or a private window. They now go out with Cache-Control: no-cache and an ETag of their content's hash, an unchanged one a 304; boot.js stays no-store, the web key's guard still answers first. TestPageFilesRevalidate and web-page.test.cjs fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; web-page, request-archive, click-scroll, old-webkit, usage-ledger-chart, gateway-fold, model-test-one pass.
2026-10-01 19:44:44 +08:00