Commit Graph
168 Commits
Author SHA1 Message Date
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 efa6fe65b4 dsh: a model through magpie that lists no thinking levels offers none, rather than dsh's own four it then turned away (Dazzle-sys, #473: on LongCat-2.5-Preview, every step of DeepSeek Harness's thinking slider failed with "takes an effort of for this model, not \"low\"") — the Agents page's effort field fell back to dsh's own off, low, high and max when a gateway model's catalog entry listed no levels, while setting one checked the model's own levels, which were none, so the slider offered four stops and each was refused with an empty list. Such a model has no levels in dsh either (its route gives it no reasoningEfforts), so none is offered now and the Agents page shows no thinking control for it, as it does for Claude Code on Haiku 4.5; an effort asked for anyway (magpie dsh effort low) says the model has no thinking levels in magpie, never an empty list. dsh's own models and gateway models with levels are unchanged; no other agent's effort field offers levels its setter refuses. TestDshEffortModelWithoutLevels fails without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; panel-effort, claude-effort, click-scroll, old-webkit pass. 2026-10-02 05:08:06 +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
Charan Rathore d21f2f6021 agent: read TOML literal-quoted Kimi model keys (#446)
* agent: read TOML literal-quoted Kimi model keys

* agent: match Kimi model tables by decoded key
2026-10-02 02:48:47 +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
czyt bde39aef5e gateway: advertise MAGPIE_PUBLIC_URL in the console and CLIs (#373) 2026-10-02 00:46:45 +08:00
AronnaxandClaude Opus 5.5 ec4ee5a3a4 fix(proc): end what a CLI probe started, on its timeout and when magpie exits (#414)
* fix(proc): end what a CLI probe started, on its timeout and when magpie exits

The probes that ask an agent's CLI something (claude auth status,
cursor-agent about/models/status, the --version checks) ran through
proc.CommandContext, which on its timeout kills only the command itself.
A CLI that is a script (a version manager's wrapper, a shim) left what it
had started running, adopted by init; and a probe still asking when magpie
exited (a one-shot command, an update, a restart) was left whole, with
nothing to end it. With Omarchy's mise wrappers stuck in their exec loop
(omacom/omarchy#7234) that was five processes holding about half a core
each for up to six hours.

proc.ProbeContext gives such a probe a session of its own on Unix, as
StartTree does, and its context ending kills the whole group. Probes still
running are listed, and proc.EndProbes kills them when magpie exits (after
run in main) or puts a new version in its place (update.Reexec). On
Windows a probe is killed alone, as before, a job being joined only once
the command has started.

TestProbeTimeoutEndsWhatItStarted and TestEndProbes fail without the
change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(proc): end probes on a terminal's signals and on a Mac's quit

Review of the first change: a probe leading its own session no longer
gets the Ctrl+C, hang-up or SIGTERM sent to magpie's terminal or service,
and magpie ending on the signal never reached EndProbes, so the probe was
left to init where before it died with magpie. main now catches SIGINT,
SIGTERM and SIGHUP, ends the probes and exits as the signal would have
(128+n). A signal magpie was started ignoring (nohup, a background job)
stays ignored. The account sign-in and plugin commands, which end
themselves on Ctrl+C, go through interruptContext and are left to do so.

On a Mac the desktop app's quit ([NSApp terminate:], also the restart to
update) exits without returning to main, so OnShutdown ends the probes.

TestProbeTimeoutEndsWhatItStarted ended its probe on a 500ms timeout,
which on a Mac could come before the script had written its child's pid
(6 of 10 runs failed in review). It now ends the context once that pid is
read, the same Cancel path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: let the app and the TUI quit on a signal their own way

Review of the signal handling: endProbesOnSignal exited ahead of Wails
and bubbletea, which quit on SIGINT and SIGTERM themselves. `magpie tray`
exited 143 without OnShutdown (no downloaded update installed, and
sessions.Saved skipped in main), and `magpie tui` left the terminal on its
alternate screen with the cursor hidden. The app's and the TUI's entry
points now hand the signals back (ownSignals): the app's OnShutdown ends
the probes, and the TUI comes back to main, which ends them too. A
one-shot command keeps the handler.

TestOwnSignalsHandsThemBack fails without the change (magpie exited 143
before the command could quit its own way); TestSignalExits keeps the
one-shot behavior.

childPid waited 3s for a script just written to start its child, which a
busy Mac can exceed (2 of 3 full runs failed in review). It waits 30s now
and, should the probe end first, says the probe's error rather than "the
script started nothing".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: keep SIGHUP for the app and the TUI, and die of the signal

ownSignals handed SIGHUP back along with SIGINT and SIGTERM, but neither
Wails nor bubbletea handles it: the terminal closing under the TUI or an
app started from a shell ended magpie on the spot, and its probes, in a
session of their own, out of the hang-up's reach, kept running (before
this PR they were in the terminal's group and ended with it). SIGHUP now
stays with endProbesOnSignal. A tray under a pty whose terminal closes
left 2 processes before, none now.

The handler asked whether a command was ending itself on Ctrl+C only
after EndProbes, which can take up to a second; a sign-in done in the
meantime got magpie ended in the middle of its own cleanup. It is asked
first.

It exited 128+n, which a shell takes for a child that handled the signal:
a loop running magpie went on to the next run on Ctrl+C. It now dies of
the signal (handling reset, the signal sent again); Windows, which can't
send one, still exits with the code.

agentProbe and agentCommand share withProxy; the Windows probeGroup
comment no longer says EndProbes ends what a shim started.

TestOwnSignalsKeepsHangUp and TestInterruptWhileEndingProbes fail without
the change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix: hand signals to the TUI and the app only once they listen

Review: runTUI handed SIGINT and SIGTERM back before tui.Run, whose
newModel asks agents' CLIs (claude auth status, up to 5s) before
bubbletea listens for signals. Ctrl+C, SIGTERM or SIGINT while it loaded
ended magpie by Go's default and left the probe and its child running.
tui.Run now takes ready, called once the model is made, and runTUI passes
ownSignals.

The app had the same window: runGUI handed them back before gui.Run,
which starts the backend (probes included) before Wails' Run starts
listening. ownSignals is now gui.Started, called on ApplicationStarted,
which Wails emits after its signal handler is set up. A tray sent SIGTERM
0.05s after starting, a probe under way, left 2 processes before and
none now; one sent it once started still quits through OnShutdown
(exit 0).

TestTUIKeepsSignalsWhileLoading fails without the change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 00:42:48 +08:00
Snowyy 1cf069712e agents: dsh says when the model a profile starts on is not one its route lists (#453)
dshCheck now names an agent-default-model its route's models: list cannot serve, and says whether Apply again can fix it or another model is needed.
2026-10-02 00:42:31 +08:00
Snowyy a3704c422b tests: keep the suite out of a real DSH_HOME, as the other homes already are (#454)
DSH_HOME beats HOME in DshDir and in dsh's own dir, so a suite that sandboxes HOME still reads and writes the developer's ~/.dsh.
2026-10-02 00:42:23 +08:00
yetone e2e5f4bb64 agents: dsh's patch list written in flow style is edited like a block one, and a file magpie can't edit is named as itself (#445) — a profile's cordis.patch.yml whose top-level array was written as [ { id: some-plugin, disabled: false } ] (valid YAML, and what dsh's own writers keep the template's [] as once they add a row) failed every model switch with "config.yaml is not a list of entries magpie can edit": the patch-list reader took only '- ' lines, and the error named config.yaml whatever the file; since web's list goes first, one such profile stopped all of them. New edit.BlockList reads a file whose one document is a flow sequence as the same list in block style (nested mappings and lists in block style, scalars quoted and tagged as they were, the lines before it and the comments after it kept); dsh's model/effort wiring and its MCP servers (internal/library) read and write such a file through it, and its errors name the real path. dshProfiles puts web first by partition instead of a sort whose less wasn't a strict weak order. TestDshFlowPatchList (agent, library) fails without the change; TestBlockList covers one-line, folded/nested/!!js, empty, CRLF and what isn't a flow list. Sandbox HOME: magpie dsh deepseek-v4-pro on main fails with the config.yaml error, with the change both profiles get the model and web keeps some-plugin. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass. 2026-10-01 23:25:05 +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 0361189f9e 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
yetone 99b1b15d98 claude: Claude Code is told what each magpie model can do, so ultracode works on one with xhigh (#430) — Claude Code run on a gateway (CLAUDE_CODE_USE_GATEWAY, as Claude Desktop's Code tab runs it) takes no model it doesn't know for one with effort, xhigh or max, and "ultracode": true needs xhigh, so on group/…, provider/model and mythos-magpie-<number> it was silently off. While Claude Code is routed through magpie, settings.json's env now has CLAUDE_CODE_MODEL_CAPABILITIES: <model>=effort[,xhigh_effort][,max_effort] for each magpie model with reasoning levels, only the levels magpie knows it has (a Claude model's no more than Claude Code gives it, a model of no known levels not named), lowercased exact ids, the models Claude Code is set to first and the whole within 8000 characters; while Claude Desktop runs on magpie, its mythos-magpie-<number> ids too. It is rewritten as the catalog changes and when Desktop is put on or off magpie, and goes when Claude Code is taken off magpie; a value the user set is left as it is. Prompts and headers are unchanged. TestClaudeModelCapabilities and TestClaudeCapabilitiesSync fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; in a sandbox HOME, claude 2.1.286 -p '/effort ultracode' on the settings.json magpie wrote, in gateway mode: group/auto-deep (xhigh) and its Desktop alias are on, group/auto-mid (no xhigh) and the same settings without the env are not. 2026-10-01 22:04:28 +08:00
yetone 7caba10d9c omp: a model's or group's max is offered as max to omp 16.4.0 and later (whqtian on Discord: a routing group with max ticked showed only xhigh in oh-my-pi, while Pi had max) — magpie wrote every model's thinking efforts into omp's models.yml with max taken out and xhigh in its place, since omp 16.3.5's schema stops at xhigh and turns the whole file away over a max; but a group whose levels name both xhigh and max then had no way to max at all, as the gateway keeps an xhigh asked for. omp has taken max since 16.4.0 (pi-ai's changelog; 18.4.8's EffortSchema has it), so an omp on PATH at 16.4.0 or later is now given max as it is; an older one, or one whose version isn't known, keeps xhigh standing in. omp 18.4.8 in a sandbox HOME lists the group's thinking as high,xhigh,max and sends reasoning_effort max with --thinking max. TestOmpGroupOffersMax 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 20:18:02 +08:00
yetone 47fd3bcb97 agents: Claude Code's alias reads as the model it stands for, and a model it asks Anthropic for itself says it isn't through magpie (StringKe on Discord: "model": "sonnet" showed as a bare sonnet; no ANTHROPIC_BASE_URL in settings.json read as magpie having failed to set it up) — with "model": "sonnet" (or opus[1m], best, haiku, opusplan, default) in Claude Code's settings.json the row showed the word with no logo, matching none of the models offered. The alias is now offered first in the Claude Code group as the model Claude Code takes it for: "sonnet · claude-sonnet-5-5", the newest of its family in the catalog's Anthropic list (no compiled-in table), or the model the user's own env gives that tier (ANTHROPIC_DEFAULT_SONNET_MODEL); [1m] keeps its mark, best is the newest Opus, opusplan names both, default is left to Claude Code's plan. Claude's logo with it; the file is only read, never rewritten, and a model picked in magpie is written as before. Each of Claude Code's own models now carries who it goes to (Anthropic, or the host of the user's own ANTHROPIC_BASE_URL): the row's tooltip says it isn't through magpie, so settings.json names no magpie endpoint and that is expected, and picking one says "straight to Anthropic, not through magpie"; a magpie model says neither. TestClaudeAliasShown and claude-direct.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 and TestClaudeAccountNamedAsItsLogin, load flakes, pass alone); claude-direct, model-pick, claude-effort, agent-model-groups, plain-names, old-webkit pass; click-scroll's WebKit run fails as it does on main without the change. 2026-10-01 19:38:36 +08:00
yetone 6b361b4698 agents: a command WSL finds on a Windows drive is not the distro's (#406) — WSL appends Windows' PATH, so command -v pi in Ubuntu found /mnt/c/Users/<u>/AppData/Roaming/npm/pi, the Windows npm shim, and magpie listed "Pi · WSL Ubuntu-24.04" and kept bin:pi in wsl.json. The probe now says where each command is and where /proc/mounts puts Windows' drives (/mnt/<letter>/ when it can't), and a command on one is not taken as installed in the distro, for Codex, Pi, OmO and Claude Code alike; one inside the distro, or its config directory, still is. A distro's findings carry the probe that made them, and a command found by an older probe is forgotten on load, so a stale bin:pi goes without the distro running. TestWSLWindowsCommandIsNotTheDistros, TestWSLOldProbeBinsForgotten and TestWSLRunningStaleWindowsPiReprobed fail without the change; TestWSLProbeScriptSaysWhere runs the script under sh. On a real WSL2 distro the probe said win:/mnt/c and win:/mnt/d. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass. 2026-10-01 17:13:34 +08:00
yetone d5bb8eedd9 agents: Antigravity CLI's calls through magpie are agy's (X: agy 的请求和会话在Magpie 检测不到吗?) — agy asks as Google's Gemini SDK, its User-Agent google-genai-sdk/… with nothing of agy's own, and the command magpie gives to start it on the gateway set GEMINI_API_KEY to the plain token, so the Usage page and the routing trace put its calls under "google-genai-sdk", never Antigravity CLI. The command now sets agy's own key (magpie-agy), which agy sends as x-goog-api-key and the gateway reads as the agent's, as for Alma, Hanako and WorkBuddy; a command copied before still gets answers, recorded as before. agy's sessions from its own Google sign-in are still not listed: their tokens are only in its conversation databases' undocumented protobuf. Verified with agy 1.2.14 in a sandbox HOME on a sandbox gateway and a fake upstream: the new command's call recorded as agy ("Antigravity CLI" in magpie usage), the old one's as google-genai-sdk. TestAgy (the launch command) fails without the change; TestAgyAgent guards the gateway side (x-goog-api-key and ?key=). go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass; agy-launch, click-scroll, old-webkit pass. 2026-10-01 14:33:04 +08:00
yetone 23472507c0 agents: Muse Code, Meta's muse CLI, is an agent magpie sets up (Discord: Muse Code 能加进来吗) — magpie points its endpoint_transport (~/.config/muse/settings.json, $XDG_CONFIG_HOME) at the gateway with auth "none", so the Meta sign-in's token is neither read nor sent, and sets its model to the catalog id; the endpoint and model the user had are stashed and put back on reset, the file's other keys (mcpServers, tui, proxy…) kept, and a settings file magpie had to make (with the schema_version Muse refuses one without) goes again. Muse lists its models from /muse-code/models on its endpoint's host before every session and starts none without it, so the gateway now serves that list, each row with the metadata["muse-code"] Muse shows and a limit with both window and reply size (one without either is hidden; none has it ask for 128K-token replies). A Responses stream the gateway translates from another API started with output null, which Muse reads as a broken stream and retries ten times; it is an empty list, as OpenAI's is. Its requests (muse-build/…) count under Muse Code in usage; Meta's icon from dev.meta.ai. Checked with muse 1.4.2 in a sandbox HOME against a sandbox gateway: exec answered through a Responses fake and through a chat fake (25 tools flattened, a read_file round trip), and switching back left settings.json byte-identical, or removed the one magpie made. TestMuse, TestMuseNoSettings, TestMuseModels and TestResponsesStartOutputList fail without the change (TestDriftUnwiredEveryAgent covers it too). go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass (TestSavedButSignedOutClaudeSaysWhy flaked once, passes alone); click-scroll, old-webkit pass. 2026-10-01 14:23:04 +08:00
cyxer000 7a3df78ff7 agents: omp's model picker lists the models of the providers in its own models.yml (#326)
* agents: omp's model pickers list the models of the providers in its own models.yml

Every role's picker (model, subagents, smol and slow, all made by role())
only looked up the current value's provider on models.dev, so a provider
the user added to omp's models.yml (a company gateway, a relay) showed none
of its models. Its models now come first, grouped by provider, before
models.dev's for the current provider, each value once; magpie's own entry
is left out, and a provider with only discovery, whose models omp learns at
run time, offers none.

* agents: omp's models.yml options are spelled as ownOptions spells them, and a model offered twice keeps its name

Review of the models.yml options: they put the model's name in the label where ownOptions puts it in the note, and dedup kept whichever came first, so a models.yml entry with no name hid models.dev's name for the same model (zai/glm-5 lost "GLM-5"). The name now goes in the note, with the label left empty, and an option offered twice takes the note, icon and group icon from whichever copy has them.

* agents: a provider both in omp's models.yml and on models.dev stays one group in the picker

From #326's review: with the current value's provider in models.yml (say
anthropic, with a model of the user's) and another provider after it, the
provider's models.dev models came after that one, so its group was drawn
twice ("Anthropic → codemaker → zzrelay → Anthropic"; the picker draws a
heading at each change of group). The options are now sorted, stably, by
where each group first comes. TestOmpOwnModels fails without it (Z.AI's
models split in two), and checks the subagents' picker offers models.yml's
models as the model's does.
2026-10-01 11:10:49 +08:00
yetone 471956c837 agents: dsh takes magpie as a custom provider of its own, Magpie, not by taking over its DeepSeek one (01huadalang on Discord: 集成进 dsh 会有 bug,会被 dsh 覆写,应该走 dsh 的那个另外的供应商) — magpie rewrote dsh's llm-deepseek entry in every profile to point at the gateway with the key MAGPIE_API_KEY. dsh's Models page showed it as DeepSeek, so a DeepSeek key typed there went into dsh's key store under that name, which dsh reads before .env: the next request carried the DeepSeek key and failed, magpie seemingly overwritten; dsh's own DeepSeek models were gone meanwhile. magpie now adds a magpie provider under llm-pi-ai, as dsh's Add model provider → Custom model API writes one (gateway URL, openai-completions, MAGPIE_GATEWAY_KEY, magpie's models with their limits, images and effort levels), and points the default model at it; llm-deepseek and the user's other providers are left alone, a profile wired the old way is moved on sync with its model and effort kept, new profiles get it, switching to a dsh model or clearing takes it out, and the check says when dsh's key store holds another MAGPIE_GATEWAY_KEY. Verified with dsh 0.2.0-rc.2 in a sandbox HOME against a fake gateway: headless and web requests carry magpie's token, a DeepSeek key saved in dsh's Models page no longer displaces it. TestDshCustomProvider and TestDshMovesOffDeepSeekRow 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:34:13 +08:00
yetone 04805abf39 agent: MiniMax Code (#362) — MiniMax's mcode CLI (and its desktop app, same runtime) reads $MINIMAX_DATA_DIR/config.yaml, else ~/.minimax/config.yaml. Choosing a magpie model adds custom_provider.magpie there (the gateway, spoken to as Anthropic messages, with the catalog's models, efforts, limits and image support) and sets defaultModel to custom_provider:magpie/<model>; the user's own default and variant are kept and put back on reset, their comments, providers and keys on magpie's entry stay, and an emptied custom_provider goes. The Library installs skills into its skills folder; it reads no user-wide MCP file, so it gets no MCP target. Checked against @minimax-ai/code 0.5.10 in a sandbox HOME: mcode provider list shows magpie's entry and mcode exec reaches a fake upstream through it with magpie's key, model and effort; after a reset it loads the restored file. TestMiniMaxCode, TestMiniMaxCodeSync, TestMiniMaxCodeLeavesNoEmptyProviders, TestMiniMaxCodeDataDir and TestMiniMaxCodeSkills fail 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 pass alone). 2026-10-01 03:24:34 +08:00
Comic Chang 49f40b463f Configure per-model context windows and output limits (#279)
A provider that serves a model the catalogue does not list, or lists at the
wrong size, has a window and a reply limit magpie cannot know: both fall
back to whatever the catalogue says about the model's maker, which for such
a provider is nothing at all.

  magpie model context relay-a/gpt-5.5 262144
  magpie model output  relay-a/gpt-5.5 131072
  magpie model context 'relay-a/*' 200000
  magpie model output  relay-a/gpt-5.5 --reset

Both are looked for in the same order as each other: this model, then
`<provider id>/*`, then the provider's own list, then the catalogue. A
model's own value wins over its provider's. The reply limit is new; the
window is not — `Provider.Contexts` has been there, with a `"*"` of its own,
settable through `magpie provider set <id> context.<model>=`, and this
reuses it rather than shadowing it.

That reuse is the point rather than a detail. A context is a routing input
and not only a number agents are shown: at 95% of a held member's window a
request moves to a member that takes more, so two sources of truth would
mean the gateway routing on one number while agents are told another.
`magpie model context` is a second way to set the same field, not a second
field.

Both reach the agents. Pi keeps a model's window and reply limit in its own
models.json, OpenCode keeps its limit, and Crush, Droid, Cline, Qoder and
Zcode keep their own; an agent reads those files when it starts, so a limit
set here that never reaches them is a limit that does not take effect.
`magpie provider set` has always told the agents, and this behaves the same
way rather than introducing a second, quieter path. The test asserts each
setter reaches them exactly once — the two paths differ (one saves the
provider file, the other settings and then says so) and that difference is
worth pinning. An end-to-end pass confirms it: with a Pi models.json in
place, `magpie model context relay-a/sol 999999` writes `contextWindow:
999999` into `providers.magpie.models`.

A `0` is refused rather than read as a reset, naming `--reset`; a mistyped
model id is refused the way `magpie model name` refuses the same id; a reset
says what is actually in force instead of claiming to be back to the
vendor's list while a provider-wide value still applies; and
`magpie model context <provider>/*` reports that value rather than saying
the provider serves no such model. Validation happens where the entry is
written, so one hand-edited bad key cannot stop a theme or a window size
from saving, and #288's walk moves these on a provider rename without a
line here.
2026-10-01 02:14:22 +08:00
yetone f1299714bf agents: Claude Code's effort reaches Opus 5.5 and Sonnet 5.5, follows each model's levels, and gets an ultracode switch (#351, #352, #353, #354) — Claude Code 2.1.251 on reads Opus 5.5's, Sonnet 5.5's and any newer Claude's effort only from modelSettings.<model>.effortLevel, so the top-level effortLevel magpie wrote left them at medium; it now writes modelSettings for the model (and the top key for the models that still read it), and a reset takes out only its own level. The levels offered follow what Claude Code 2.1.285 sends each model: Opus 4.5 low–high, Opus/Sonnet 4.6 without xhigh, Haiku 4.5, Sonnet 4.5 and older none; a level a model doesn't take is refused. A new ultracode square writes "ultracode": true, on models taking xhigh, and magpie claude ultra no longer writes "ultra" as the model. An open session keeps the effort it started with, so a change says to restart it while Claude Code runs. Checked against real Claude Code 2.1.285 in a sandbox HOME with a fake API recording the effort sent. TestClaudeEffortModelSettings, TestClaudeEffortPerModel, TestClaudeUltracode and TestClaudeEffortNotice fail without the change; claude-effort.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; omp-roles, panel-effort, click-scroll, old-webkit pass. 2026-10-01 01:24:32 +08:00
cyxer000andyetone 1ec5495b26 agents: omp's roles pick their own models (subagents, smol, slow), keep their thinking level, and get back what they had before magpie (#325)
* agents: omp's subagents and small role pick their own models, through magpie too

* agents: omp keeps a role's thinking level and the model it had before magpie, and offers the slow and designer roles

A role set to "anthropic/claude-opus-5:max" and switched to a magpie model lost its ":max", and resetting it deleted the key rather than putting the user's model back. The level now goes with the new model (omp clamps one the model lacks, never fails), the model the role had before magpie is stashed and restored, and the reviewer's @slow and the designer's @designer roles are fields beside subagents and small.

* gui: omp's slow and designer roles follow the model, as its subagents do

Unset, both roles take the session's model, yet the picker offered them omp's Default and no typed model. They are now squares beside subagents, with Same as model first and a model typed in taken as it is.

* agents: omp's thinking level no longer hides a role's model from magpie, and the model alone clears it — magpie omp magpie/x/y:high is taken, a role moved back to omp's own is drift, a list of models comes back on reset, and designer (gone in omp 18.1.5) goes

A role on "magpie/deepseek/pro:max" matched the picker only through the
option offered for its level beside the model, and only for the value in
the file now. So the CLI refused a model typed at a level, a recorded
value at a level the current one didn't share wasn't known for magpie's
(no "replaced" drift), and a level could never be taken away: a model
picked without one took the old one on.

An agent may now say what it keeps after the model (Agent.SplitSuffix;
omp's is its level). Drift, Reseat, RenameProvider, Spell and the CLI's
field-for-value match the model and put the suffix back after the one
they move to; agents without it are unchanged. The option at the level
stays: it keeps the level. Another model keeps it too; the same model
picked alone clears it.

A role omp falls back through (a YAML list, or the comma list omp joins
it into, settings.ts modelRoleValueFromUnknown) read as nothing, so it
wasn't stashed and a reset deleted it. It reads as that comma list now,
is stashed and comes back; a list has no level of its own.

omp 18.1.5 removed the designer role (CHANGELOG), so its field goes. The
smol role, like task and slow, gives its agents the session's model when
unset; its field is labelled smol, as omp names it, so the GUI can show it
as the others without touching other agents' "small".

* gui: omp's smol role follows the model as its subagents and slow role do, and designer goes

smol unset gives omp's scout and sonic the session's model, so it is a
square after the pickers with "Same as model" first, as subagents and
slow are (a feather). Its label is smol, not small: OpenCode's, Crush's
and OpenChamber's small model stays a picker. designer, a role omp 18.1.5
removed, leaves FOLLOWS_MODEL, the glyphs and i18n.

* agents: the note on omp's fallback chains says their keys are roles, and from omp 18 models too

ompRefKeys' comment had retry.fallbackChains keyed by model. omp 16.3.5 takes only a role's name there (session/agent-session.ts: "a mapping of role names to selector arrays"); omp 18.4.4 takes a role's name or a model selector (session/retry-fallback-chains.ts). Walking the keys stays: a role's name is no magpie model and is passed over. Follow-up to the review of #340.

* agents: omp reads whether it is on magpie one way, and a role at a level that a fallback chain names too is renamed once in each

Rebased on #340, one scan over omp's config (ompRefs) answers both questions: magpie's provider stays in models.yml while anything under ompRefKeys is on magpie, as #340 has it, and Check looks at the wiring while any role under modelRoles is, as this PR had it; a fallback chain or enabledModels alone keeps the provider without being checked.

A provider renamed moves a role at a thinking level through SplitSuffix first, then RenameRefs the rest, which finds no old name left in the roles: each place moves once, the level kept.

* agents: a fallback chain alone on magpie has omp's wiring checked, and a role set off magpie mends it

Check now reads the same keys dropMagpie does (ompRefKeys: every role, retry.fallbackChains, enabledModels, task.agentModelOverrides): whatever keeps magpie's provider in models.yml has its baseUrl checked, so a chain on magpie whose wiring something else moved no longer fails its fallback silently. Applying again sets the model role, which may be omp's own; a role set off magpie while something else still names it now writes magpie's provider afresh instead of leaving it as it is, so that mends the wiring. Review of #325.

* agents: an omp role that is a list of models stays the user's own, even starting on one of magpie's, and comes back as it was written

A role omp falls back through ([magpie/deepseek/flash, openai/gpt-6], or the same as a comma-separated string) was taken for one of magpie's models because it started with magpie/: magpie taking the role over stashed nothing, and a reset deleted it. Only one model, no comma, is magpie's now: SplitSuffix answers whether a value is one model, and Spell, drift (magpieValue), Reseat, RenameProvider and the CLI's fieldForValue leave a list alone. The stash keeps a YAML list as the YAML it was written in (edit.GetYAMLText), and a reset puts it back so, flow or block; a comma-separated string comes back a string. A provider renamed moves the names inside a list through RenameRefs, once, and in the lists the stash keeps too. Review of #325.

* gui: a test holds omp's subagents, smol and slow roles as squares that follow the model, and OpenCode's small model a picker

omp-roles.test.cjs, in Chromium and WebKit, English and Chinese, API faked: the three roles are squares after the model's picker, unset named "same as model" (「同主模型」) and set naming their model; smol's picker opens on "Same as model" with the model beside it, and a pick sends it and shows it. OpenCode's small model stays a picker. With smol and slow taken out of FOLLOWS_MODEL it fails at "small is a square". Review of #325.

* gateway: a Claude Code run whose subagent ended on StructuredOutput is let go, and runs left waiting on tool calls are bounded (#345) — a workflow's subagents end on StructuredOutput, which the client answers itself, so the bridge's claude -p waited 30 minutes for a result that never came, one process per subagent. Such a run now waits 30s (for a schema error the client sends at once) and ends; of other runs waiting 5 minutes or more on their caller's tools, 16 are kept, the longest waiting let go first (one that then gets its results starts anew with the whole conversation). TestClaudeRunEndsAfterStructuredOutput and TestClaudeParkedRunsAreBounded fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.

* 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.

* provider: the Providers and Gateway pages no longer wait on `claude --version` (deluxe on Discord: on Omarchy the two pages never loaded) — on Omarchy `claude` is a mise wrapper that installs or updates Claude Code before it answers, which on a slow network takes minutes or never ends; magpie asked it with no limit and with a lock held, so /api/providers (fetching the Claude account's models) and every Claude request waited with it. The CLI is now asked in the background, given a minute, and a caller waits at most 3s before the version it has stands in; a late answer is taken once it comes. Reproduced on an Omarchy VM (/api/providers unanswered after 100s on v0.1.516, 3.7s with the change). TestClaudeVersionDoesNotWaitForAStalledCLI and TestClaudeVersionTakenWhenItComes fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.

* plugins: a plugin's account behaves as its built-in's (the user: 插件版的订阅 provider 和内置的…保持一模一样了吗) — a plugin's failed sign-in now says why ("the sign-in failed: the sign-in page expired") instead of a bare failure; a plugin account the provider refuses with 401 is marked lapsed, "<user>'s <provider> sign-in has expired — sign in again", beside the account and on its usage card as a built-in's is, and the mark goes when it answers again or is signed in anew; a Devin or Command Code account taken from the agent's CLI moves to the plugin marked as the CLI's and back as the agent's own, so the one it follows stays the one the CLI is signed in to. TestPluginProvider (lapsed), TestMoveSideState (cli) and TestPluginSignIn (reason) fail without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass.

* agents: "Hide all" in an agent's model list keeps its line, and an uninstalled Gemini CLI goes from the Agents page (#356, #230) — the line under an agent ("Showing 0 / N models") came only when a picker still listed one of magpie's models, so hiding them all took away the one way back; it now stays while any is hidden. Gemini CLI was taken as present from what it leaves in ~/.gemini (settings.json, .env, installation_id…), which stays after it is uninstalled, so its row stayed, offering to set up a CLI that can't run; it is now its gemini binary. TestAgentModelLineAllHidden and TestGeminiNotAntigravity fail without the change; agent-models-all-hidden.test.cjs (Chromium, WebKit, en/zh) added. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./internal/agent ./internal/gui ./internal/library ./internal/provider pass; agent-models, click-scroll, old-webkit pass.

* gateway: Codex's Responses Lite tools reach SuperGrok and every other backend, and a group moves on when a member can't read a request (#350) — Codex sends a Lite model's tools as an additional_tools input item, its own functions in a "functions" namespace; magpie relayed the item to xAI, which 422s on it (unknown item type), and translated routes (Cursor, Anthropic, Chat…) dropped it, so the model had no tools. Outside OpenAI the item's tools now go in tools, the functions namespace opened into plain tools and earlier calls un-namespaced; OpenAI and the ChatGPT account still get Codex's own form. A 400/422 over the request's shape (failed to deserialize, unknown item type/parameter…) now moves to the group's next member, each asked once, the member not resting; the Routing page says so. TestAdditionalToolsRelayed, TestAdditionalToolsTranslated and TestGroupFailsOverARequestShape fail without the change; routing-shape.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; click-scroll, old-webkit, routing-wb-refused pass.

---------

Co-authored-by: yetone <yetoneful@gmail.com>
2026-10-01 01:15:55 +08:00
yetone c47b22ee27 agents: "Hide all" in an agent's model list keeps its line, and an uninstalled Gemini CLI goes from the Agents page (#356, #230) — the line under an agent ("Showing 0 / N models") came only when a picker still listed one of magpie's models, so hiding them all took away the one way back; it now stays while any is hidden. Gemini CLI was taken as present from what it leaves in ~/.gemini (settings.json, .env, installation_id…), which stays after it is uninstalled, so its row stayed, offering to set up a CLI that can't run; it is now its gemini binary. TestAgentModelLineAllHidden and TestGeminiNotAntigravity fail without the change; agent-models-all-hidden.test.cjs (Chromium, WebKit, en/zh) added. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./internal/agent ./internal/gui ./internal/library ./internal/provider pass; agent-models, click-scroll, old-webkit pass. 2026-10-01 01:03:57 +08:00
cyxer000 f3b45634a3 agents: Droid, Qoder, OpenHanako, WorkBuddy, OpenCode and ZCode no longer get an output limit above the model's context window (#347) 2026-10-01 00:27:00 +08:00
cyxer000 abbffd73a4 agents: magpie omp auto sets omp's thinking to auto, and the panel's effort slider shows a level it doesn't list as it is (#339)
* agents: `magpie omp auto` sets omp's thinking to auto, and the panel's effort slider shows a level it doesn't list as it is

omp keeps defaultThinkingLevel at minimal … max or auto (omp picks a
level each turn), but magpie offered only the six levels. So
`magpie omp auto` found no field offering auto and took it for a model:
modelRoles.default became the literal "auto". auto is now offered
first, as omp's own picker has it, and kept out of ompEfforts, which a
model's thinking levels in models.yml are filtered by.

The tray panel's effort slider drew a value that isn't one of its
options (an agent with no effort set, a level magpie doesn't list) at
the first stop, named as the lowest level, and a touch there wrote that
level over it. It now gets a stop of its own, as the window's picker
gives the current value, so it reads as it is and a touch leaves it.

* agents: the note on omp's thinking picker holds for omp 16.3.5 too

omp 16.3.5 takes auto for defaultThinkingLevel as 18.4.4 does (config/settings-schema.ts there), as checked on #339.
2026-10-01 00:20:19 +08:00
cyxer000 49f02c6f03 agents: omp's requests through magpie are known for omp's on omp 16 too (#343)
omp 16.3.5 asks a custom provider with Bun's User-Agent (Bun/1.3.14), and
only omp 18 with its own (omp/18.4.4), so the gateway counted omp 16's
requests as Bun's and passed over omp's rules and stand-ins. magpie's
provider in models.yml now carries User-Agent: omp, as it does for Hermes
and Cline. Checked with omp 16.3.5 and 18.4.4: both send it and accept the
file. TestOmpNamedToTheGateway fails without the change.
2026-10-01 00:19:49 +08:00
yetone 2c432fe3fa 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
yetone adde88ef23 agents: Kimi Code offers a model's thinking levels, and the level picked reaches the model (#333) — the new Kimi Code (2.x) builds its thinking picker from a model's support_efforts and default_effort, which magpie never wrote, so it offered thinking only on or off. magpie now writes the model's levels (none left out: Kimi Code's Off is that) and default_effort high when the model has it, to ~/.kimi-code only; the old kimi-cli's schema has neither. Kimi Code sends the level inside thinking ({"type":"enabled","effort":…}), not as reasoning_effort, so the gateway moves it there on a Chat request that doesn't say reasoning_effort itself, and fits it like any other agent's. Checked with the real kimi CLI (2.1.1) in a sandbox HOME against a fake upstream: kimi doctor passes, /model shows Off Low Medium High Max, a pick reaches upstream as reasoning_effort; unknown values don't make it reject the file. TestKimiEfforts and TestKimiCodeEffortReachesChatVendor 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 23:02:50 +08:00
cyxer000 6035cf99c8 agents: omp keeps magpie while a fallback chain or another role is on it, and a provider renamed takes those along (#340)
omp names models beyond modelRoles.default: its other roles, retry.fallbackChains, enabledModels and task.agentModelOverrides. magpie looked only at modelRoles' scalar roles before dropping its provider from models.yml, and a rename moved only the default, so a chain on magpie/<p>/x:max was left pointing at a model omp no longer had, which it skips with a warning.
2026-09-30 22:58:42 +08:00
cyxer000 b60cfa6787 agents: omp, Pi, Cline and dsh are no longer told a model writes more than its window holds (#338)
models.dev lists some models' output above their context (deepseek-chat:
384000 out, 128000 in), and magpie handed that on as maxTokens. The limit
is now kept within the contextWindow written beside it; a model whose
window isn't known keeps its output as before. Follow-up to the review of
2026-09-30 22:58:08 +08:00
yetone 69b366adec omp: each model is asked on its provider's own API (#329) — magpie wrote every model into omp's models.yml as openai-completions, so a Claude's thinking signatures had no place between tool turns. As for Pi, a Responses model now gets api: openai-responses and an Anthropic one api: anthropic-messages at the gateway's /v1/messages, thinking adaptively on Claude 4.6 and later, else on a budget (budget-effort would send output_config.effort, which Sonnet/Haiku 4.5 refuse); groups and the rest stay on Chat. A model offering max made omp 16.3.5 reject the whole file, so every magpie model vanished; max is now offered as xhigh, which the gateway fits to max. Checked with the real omp 16.3.5 in a sandbox HOME against a fake upstream: Claude → POST /v1/messages, deepseek → /v1/chat/completions. TestOmpModelsAskedOnTheirNativeAPI fails without the change; TestOmpMessagesRelayedAsSent guards the relay. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass. 2026-09-30 22:27:11 +08:00
yetone b03967bb79 library: agents in a running WSL distro take skills, MCP servers and instructions (#331) — the Library knew only this machine's agent ids, so codex@wsl:Ubuntu and the like were never offered, and the id's colon was refused as an agent's name and can't be in a Windows file name. Claude Code, Codex, Pi and OmO in a distro now get them at their default places under the distro's $HOME through \\wsl.localhost, only while it runs (opening a stopped one's files starts it; its state is kept and asking for it says to start it). Skills go in as copies, made beside and renamed into place and made again when the library's changes, since a Linux agent can't follow a link to a Windows folder (project skills share the same copy code); an MCP server that runs a Windows program (C:\…, *.exe/.cmd/.bat/.ps1) is refused for them with a message; Pi there gets no MCP servers, where its version decides the file. The id's colon is a dot in file and folder names, and setup export/import turns it back. TestWSLTargets, TestWSLSkillsCopied, TestWSLServers and TestWSLInstructions (a fake distro) fail without the change. go vet (and GOOS=windows for agent, library), go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass. Not run against a real distro. 2026-09-30 22:17:23 +08:00
cyxer000 007a84964a agents: omp takes magpie's vision models for text-only (#327)
magpie's models.yml entries had no input or maxTokens, so omp fell back to a fuzzy-matched bundled model or text-only / 16384. Write input from the model's image answer (omitted when unknown) and maxTokens from its output limit; carry ImageInput through magpieModels.
2026-09-30 22:13:50 +08:00
yetone ad90eced2b claude: every 1M model magpie writes for Claude Code is marked [1m] (StringKe on Discord: Autocompact is thrashing on Opus 5.5 with a Max subscription) — Claude Code 2.1.284 and before takes any Claude model not named with [1m] for 200K, CLAUDE_CODE_MAX_CONTEXT_TOKENS or not (it applies that only to models it doesn't know), and compacts at 160–190K over and over; magpie marked only its picker's options, and only when it knew the window, so a model typed, or picked while the window wasn't known, went into ANTHROPIC_MODEL, model, every tier and CLAUDE_CODE_SUBAGENT_MODEL bare. Each is now marked when magpie's list or models.dev gives a window of 1M or more. Checked with /context and full sessions of 2.1.280–2.1.285 in a sandbox HOME: unmarked compacted 3 times at 190K, marked 0. TestClaude1MMarked fails without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass. 2026-09-30 22:11:08 +08:00
yetone e92994b37a agents, library: Antigravity alone no longer shows Gemini CLI (#330), and turning an agent off on a skill or MCP server says it was removed (#332) — Gemini CLI was found from ~/.gemini existing, where Antigravity keeps its own folders (antigravity, antigravity-cli, config) and reads GEMINI.md; it now takes only what Gemini CLI writes there (settings.json, .env, google_accounts.json, installation_id, trustedFolders.json, mcp-oauth-tokens.json, an oauth_creds.json its own OAuth client minted, as #143) or a gemini on PATH. The Library's agent chips said 「已写入 X」 on the way off too; they now say 「已从 X 中移除」 (or N agents, or N updated for a mix). TestGeminiNotAntigravity and library-toggle-status.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; library-items, shared-skills, click-scroll, old-webkit pass. 2026-09-30 21:57:06 +08:00
yetone 52c8e838d2 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
yetone 1ba6939185 agents: OpenChamber gets its own row, its model and small model set to magpie's (#321) — OpenChamber keeps its own default model (preferences.json, a copy in settings.json, under $OPENCHAMBER_DATA_DIR or ~/.config/openchamber) and sends it with every session over OpenCode's, so setting OpenCode's model changed nothing it used. Its row writes defaultModel (a fresh updatedAt, defaultVariant cleared as its own settings do) and the small-model override, keeping every other key and refusing a preferences.json it can't read; magpie's provider goes into the OpenCode config it runs on, and stays there while either uses it. OpenCode's config now follows $OPENCODE_CONFIG_DIR: the OpenCode 2 OpenChamber bundles reads only that folder, so what magpie wrote to ~/.config/opencode was never read; OpenCode 1 reads it last, so it wins there too. A project with its own model in OpenChamber is named in the row. Checked against @openchamber/web 2.0.4 on OpenCode 2.0.18 in a sandbox HOME: its settings API returned magpie's model and OpenCode listed magpie's provider. TestOpenCodeConfigDir, TestOpenChamberModel and TestOpenChamberSettingsOnly 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 pass. 2026-09-30 20:12:07 +08:00
yetone 953bce2cfb agents: Codex signed in with only an API key gets magpie as its provider, its picker listing magpie's models (#322, dakango: switching the Codex app to one of its own models went to OpenAI, 502) — magpie counted an API key in auth.json as a ChatGPT sign-in and only set openai_base_url, counting on Codex to ask the gateway for its models; but Codex asks for none with an API key (models-manager refresh_available_models returns early), so the picker showed Codex's built-in models and the one magpie model, and a built-in one went to OpenAI with the relay's key. Now only a ChatGPT sign-in takes that route; with an API key alone magpie is the model_provider with model_catalog_json listing every magpie model on for Codex, as when signed out, and a sync moves a setup an older magpie wrote; going back to Codex's own model restores the user's model_provider. A Codex model whose OpenAI can't be reached now fails naming the model and what to do instead of a bare 502. TestCodexAPIKeyUsesProvider, TestCodexAPIKeyBaseURLMoved and TestCodexOwnModelUnreached 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 20:08:27 +08:00
yetone 6c5ed2acf5 agents: CC Switch's provider tables in Codex's config go through magpie too, and the Library brings in every skill found at once (JasonLeeForOnly on Discord: after moving from CC Switch, Codex threads still went to the relay, "model not found" for a magpie model) — CC Switch writes a [model_providers.custom] table (cc-switch, cc-switch-N in older versions) and moves every third-party Codex thread onto it, and a reopened thread takes the provider it was saved with, not model_provider; magpie left those tables pointing at the relay. While a magpie model is on, signed in or not, their base_url is magpie's /v1, the relay's kept in the stash and the table's other keys as they were; a table a profile names, and cc-switch-official, are left alone; Codex's own model or a reset puts the URL back, unless the table was changed since; one pointed away again is named on the agent row and taken back on sync. The Skills tab's "In your agents" gets Bring in all (2+ found), one library write, one that fails named and the others brought in. TestCodexTakesCCSwitchTables, TestImportSkills and import-all-skills.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, shared-skills pass. 2026-09-30 18:16:22 +08:00
yetone 98cbea0ffb agents: Pi's models go to PI_CODING_AGENT_DIR (#304), and the Codex app offers magpie's models' efforts (#310) — Pi keeps settings.json and models.json in PI_CODING_AGENT_DIR when set (~ expanded; @earendil-works/pi-coding-agent config.js), and magpie wrote ~/.pi/agent regardless; omp is read by its own rules (PI_CONFIG_DIR, OMP_PROFILE/PI_PROFILE, then PI_CODING_AGENT_DIR), and the library's Pi and omp targets follow. The Codex app's model picker offers only the efforts in [desktop] enabled-reasoning-efforts of config.toml (ChatGPT.app 26.924: default low…xhigh, ultra, persistent), so a magpie model's max or minimal was never offered; routed through magpie, the efforts its models take are added to the user's list (or the default), nothing else changed, only values the app knows (it drops the setting for any other), comments kept, nothing written when nothing is missing. TestPiAgentDir, TestOmpAgentDir and TestCodexDesktopEfforts 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 18:09:09 +08:00
yetone 7e454bba9b agents: Claude Code on a magpie model is told the model's context window (#311: its auto-compact settings stay as they were for another model) — Claude Code takes any model it doesn't know by name (all but Claude's own) for 200K, and CLAUDE_CODE_AUTO_COMPACT_WINDOW is only ever the smaller of its value and that, so a 128K model compacted too late and a 400K one far too early; CLAUDE_AUTOCOMPACT_PCT_OVERRIDE is a share of the window and holds for any model (read in Claude Code 2.1.285). magpie now writes CLAUDE_CODE_MAX_CONTEXT_TOKENS, the window Claude Code takes those names for, from the model's known context (a group's smallest), with the model: another model's replaces it, one magpie doesn't know the window of, a switch back to a Claude model or a reset removes it; with a [1m] main model, the smallest of the tiers not marked. A value the user set, or changed magpie's to, is left as it is (magpie keeps the one it wrote). TestClaudeContextWindow fails without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass. 2026-09-30 17:44:44 +08:00
yetone e31384b1f9 gateway: Codex on magpie as its provider has its approvals auto-reviewed again (shihao H on X: 自动审批未执行 … 404: magpie knows no model "codex-auto-review") — Codex asks for its guardian review by OpenAI's reviewer model, codex-auto-review, whatever the provider ("independent of current login"), and magpie, knowing no such model, answered 404, which Codex reports as the review service failing. A model Codex names that magpie does not serve now goes to the model Codex is set to (config.toml model), when magpie is its provider, as Codex itself reviews with the turn's model when its catalog lacks the reviewer; the Routing view shows it as the Approval check. Signed in, Codex's own names go on to OpenAI as before. TestCodexStandIn fails without the change; TestCodexAutoReviewStandIn has the Codex request go to the stand-in. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass. 2026-09-30 16:55:50 +08:00
yetone 7c0b5441a8 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
yetone a69ae948dc library: Claude Desktop's MCP servers go into Claude-3p/claude_desktop_config.json as well, where its 3p mode reads them (#297: Claude Desktop 使用 magpie 三方网关(3p)后,library 写入的 MCP 在 Desktop 里看不到) — in 3p mode, which magpie's own provider switch turns on, Desktop's whole userData is Claude-3p (~/Library/Application Support/Claude-3p, %LOCALAPPDATA%\Claude-3p on Windows, ~/.config/Claude-3p), its MCP servers included, so the servers the library wrote into Claude/'s file never showed in Settings → Developer. Where the Claude-3p folder is, its file is now written with Claude/'s, in one edit with each file's own keys kept, read for servers to bring in, and cleared on removal even when Claude/'s no longer has the entry — both, not whichever mode is on, so switching the provider leaves nothing stale and Desktop finds them in either mode; no Claude-3p folder is made for a Desktop never in 3p, and one only ever in 3p (no Claude folder) gets its servers there alone. A server given before reaches Claude-3p on the next sync. Tested with new desktop3p_test.go in a sandbox HOME (both files written and cleared, the user's servers and keys kept, sync of an older server, 3p only); each fails without the change. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass. Not tried against a real Desktop in 3p. 2026-09-30 15:56:52 +08:00
Eachann 3dc5577d43 pi: changing the thinking level writes only that level, and only when it changed — with the model on magpie it rebuilt providers.magpie, so a contextWindow (or any other field) edited by hand was replaced. Default still clears defaultThinkingLevel and leaves the model and the provider where they are. Picking a model, and the catalog sync, still refresh the provider. OmO shares this path. (#285)
Tested with TestPiThinkingLeavesTheProvider: a hand-edited contextWindow and another provider stay byte for byte through an unchanged level, a changed level and Default; the level itself changes or clears, and Default again does not rewrite the file. gofmt, go vet -tags nogui ./internal/agent/ and go test -tags nogui ./internal/agent/ pass.
2026-09-30 15:41:17 +08:00
yetone 4dc3d93343 kimi: the new Kimi Code (2.x) is wired in ~/.kimi-code, where it reads its settings — a model picked in magpie never reached it, nor did magpie's models reach its /model (#290, kyzhouxu: Gemini 3.8 flash picked, Kimi Code still starts on the old one). magpie wrote only ~/.kimi/config.toml, the old kimi-cli's; the new CLI copies that over once when it first starts and never reads it again. KimiDir picks $KIMI_CODE_HOME, ~/.kimi-code if there, $KIMI_SHARE_DIR, ~/.kimi if there, else ~/.kimi-code. The new CLI's model tables also say tool_use (kimi-cli refuses the word, so it isn't written there), and its skills go to ~/.agents/skills, which it reads (not ~/.config/agents/skills). Tested with TestKimiCode (fails on main: path .kimi/config.toml, want .kimi-code/config.toml) and TestKimi; in a sandbox HOME the new CLI's kimi provider list shows magpie and the new default model, kimi doctor finds the config valid, and kimi -p went through a sandbox gateway to a fake upstream asked for gemini-3.8-flash with its 26 tools. go vet, go build -tags nogui (darwin, GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass (flaky tests under load pass alone). 2026-09-30 15:29:14 +08:00
yetone c9d9652380 library: an agent whose folder is a file isn't written, and skills reach 13 more agents with one link in ~/.agents/skills for those that share it (neiko on Discord: with DeepSeek Harness not installed the Library kept failing on "open ~/.dsh/AGENTS.md: not a directory" and ~/.dsh/config.yaml; inaction: the skills list is short of the Agents page, Kimi Code has none). An agent counted as there when its folder path existed or its command was on PATH, never asking whether the path was a folder — a file at ~/.dsh, or another dsh, made DeepSeek Harness look installed. Now an agent whose folder is a file (or under one) isn't detected (agent.Taken; Goose's, Cindy's and Claude Desktop's own checks want a folder too), a Library target leaves out each place a file stands in the way of, one with none left isn't listed, and an agent given no MCP server with none of magpie's isn't read. Skills: Kimi Code, Goose and Cindy get ~/.agents/skills (Kimi's ~/.config/agents/skills when there, as Kimi reads it first; never ~/.kimi/skills, which would hide Claude Code's from it); Command Code, Devin, Hermes, Droid, Cline, Qoder, Qoder CN, Grok, WorkBuddy, Hanako and fx their own skills folder; Kimi, Goose and Grok a project's .agents/skills. The shared folder is filled first, and an agent that reads ~/.agents/skills besides its own (Codex, Gemini CLI, OpenCode, Crush, DeepSeek Harness and those above) gets no second link to a skill already there. Tested with new taken_test.go (neiko's two errors without the change) and agent_skills_test.go (skills folders, written once, a shared skill imported for Kimi), in sandbox HOMEs; library-items and shared-skills 24/24 in Chromium and WebKit; go vet, go build (-tags nogui, GOOS=linux, GOOS=windows), go test -tags nogui ./... pass. Not tried with real Kimi Code, Goose or Cindy. 2026-09-30 14:40:41 +08:00
yetone 59aec42beb agents: an agent's model list shows each model's maker's logo (这里能否显示模型的图标?) — the list had a logo only on a provider's heading, so a relay's or a routing group's rows were names alone. Now each row has its maker's: known by the model's family (gpt → OpenAI, claude, gemini, grok, qwen, glm, mimo/xiaomi, step, …; "vendor/model" ids too), a routing group by the name it was given or its id, a model of a vendor's own provider by the provider's logo; a routing group whose maker isn't known shows the routing mark, anything else keeps the slot empty so the names line up; a model turned off has its logo dimmed. Checked in a sandbox HOME with a copy of the real providers (keys blanked): 路由组 shows OpenAI for GPT-6 Sol/Luna/Astra, Claude, MiMo, Grok, Qwen and the routing mark for semantic/test; AiHubMix's rows each their maker's; light and dark 2026-09-30 14:23:48 +08:00