6 Commits
Author SHA1 Message Date
yetone c20a072026 agent: OpenCode is told a magpie model reasons when it thinks with no levels to pick, or has low, medium and high (#725, Sun1090: OpenCode's tooltip for mimo-v2.6-flash-free · opencode-zen said 推理: 不支持推理, where OpenCode's own Zen says it reasons) — the opencode block magpie writes into opencode.json never set reasoning, and OpenCode 1 (1.18.34, npm's latest) takes a model of a provider models.dev doesn't list (magpie) as reasoning only when the config says so (provider.ts: model.reasoning ?? false). models.dev lists Zen's mimo-v2.6-flash-free reasoning: true with no reasoning_options, so it has no levels, and magpieModels didn't hand agents the entry's Reasoning (the flag #402 added for /v1/models), so nothing could say it thinks. magpieModels now carries Reasoning, and OpenCode's block (and its WSL, mimocode and OpenChamber forms) sets "reasoning": true through openCodeReasons: a model that thinks with no levels, or one whose levels hold low, medium and high. OpenCode 1 adds low, medium and high of its own to a reasoning model's variants (ProviderTransform.variants, merged under the config's), checked under a sandbox HOME with 1.18.34's opencode models magpie --verbose: reasoning true with variants {} lists low, medium, high, and with low and max lists low, medium, high, max. So a model with other levels (deepseek-v4-flash-free's low, high, max) is left unmarked, as before, rather than offered levels it doesn't have; a "disabled" variant would hide them in 1 but OpenCode 2 (OpenChamber's) reads it as a variant of its own. A levelless thinker gets low, medium and high, as under OpenCode's own provider, and the gateway asks a model with a thinking switch alone no more than high (fitFor). OpenCode 2 doesn't read the flag. TestOpenCodeZenModelReasons (Zen's models from a models.dev cache: mimo-v2.6-flash-free and laguna-s-2.1-free marked, deepseek-v4-flash-free and ling-2.6-flash-free not) fails on the old code and passes. go vet, builds (darwin, GOOS=linux, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass. Not tried in the reporter's OpenCode app; OpenCode reads its config at start, so one already open shows it after it is reopened. 2026-10-04 07:21:48 +08:00
yetone 8323b0ae87 agent: OpenCode and OpenChamber list a magpie model's reasoning levels weakest first, not alphabetically (#713, Hu9956 on v0.1.780: 思考 offered 默认, High, Low, Max, Medium, Ultra, Xhigh, where other providers in the same OpenCode go by strength and MiniMax Code had magpie's in order) — openCodeVariants returned a map[string]any, which encoding/json writes with its keys sorted, so each model's variants object in opencode.json came out high, low, max, medium, ultra, xhigh, and OpenCode builds its variant list from the object in key order (checked with OpenCode 1.18.34: opencode models --verbose under a sandbox HOME/XDG dirs keeps a config's variants in the file's order, alphabetical or by strength; it doesn't sort them itself). openCodeVariants now returns an orderedJSON (a key/value list whose MarshalJSON writes keys as given) of the model's efforts put weakest first by gateway.ByStrength, the gateway's effortRank order (none, minimal, low, medium, high, xhigh, max, ultra; a level it doesn't know after them, stably), so a level appended after max (ultra) lands last too; edit.SetJSON keeps the custom marshaller's order when it indents the block. An opencode.json an older magpie wrote would have stayed alphabetical, as Sync's sameJSON compares decoded values and took it for the same block: OpenCode's (and its WSL and mimocode forms', through openCodeLike) and OpenChamber's Sync now use syncJSONInOrder, which also rewrites the block when its tokens, keys included, don't read in the same order as magpie's (sameOrder), and leaves one in order alone; the other agents' syncs are as before. TestOpenCodeVariants now checks the marshalled bytes (weakest first, an out-of-order list sorted, none as {}), and TestOpenCodeVariantsInOrder writes opencode.json under a temp HOME and checks the raw file lists low, medium, high, xhigh, max, ultra, that a block in the old alphabetical order is put in order by Sync and that a second Sync leaves the file byte for byte; both fail on the old code, and the Sync half fails with plain syncJSON. go vet, builds (darwin, GOOS=linux, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass. Not tried in OpenCode's or OpenChamber's own picker with the reporter's setup; OpenCode reads its config at start, so one already open shows the new order after it is reopened. 2026-10-04 03:19:37 +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 2493bd72c5 pi: a model's thinkingLevelMap in models.json names every one of Pi's levels, the model's own mapped to its effort and the rest null, so Pi's /thinking offers only what the vendor takes (#243) — magpie wrote only xhigh and max (glm-5.3-flash at low/high/max got {"max":"max"}), and Pi offers every level a map leaves out but xhigh and max, so minimal and medium were offered and sent efforts the vendor turned away. Now glm-5.3-flash gets {"off":null,"minimal":null,"low":"low","medium":null,"high":"high","xhigh":null,"max":"max"}. Pi's off (read from pi-ai 0.99's getSupportedThinkingLevels and its openai-completions, openai-responses and anthropic-messages streams) maps to none for a model that takes none, so off really turns reasoning off; a model without none has off null, since Pi's off asks a Responses model for effort none and leaves a Chat model on the vendor's default; on Anthropic's Messages API off is left out, as before, since there Pi's off sends thinking disabled, which Claude takes, and Claude keeps its xhigh and max. A model whose levels magpie doesn't know still gets no map and reasoning false. Tested with TestPiThinkingLevels (full maps with and without none, Anthropic keeping off, none for unknown) and TestOpenCodeNoResellerLevelsForSwitchModel, which now checks the full map written for a relay's low/high/max model and no map for an unknown one (fails on main with map[max:max]). go vet ./internal/agent, go build -tags nogui (and GOOS=linux), GOOS=windows go build and go test -tags nogui ./... pass (TestUserPath, TestClaudeSignedOut, TestClaudeAccountNamedAsItsLogin, TestClaudeIdentityServedWhileAsked, TestCodexVersion and TestAddSecondOfPreset failed in the full run under load and pass alone). Not tried in a real Pi session. 2026-09-30 02:48:10 +08:00
yetone 729f6bdbdf models: a model its maker lists with a thinking switch alone takes no borrowed levels, and the gateway sends it no more than high (#214 Moody-Max: opencode 的 mimo-v2.6 Flash 你这边设置的默认推理强度是 max 导致400报错)
A model not under its provider's own models.dev vendor (a relay or provider of the user's, a live id that doesn't match, or a preview/-exp or typed id Known looks up) took the levels most listed for it across all of models.dev. For mimo-v2.6-flash those are the resellers' (llmgateway, counted once per upstream host it lists, and requesty, up to max), while Xiaomi lists it with a thinking switch alone. OpenCode was offered variants up to max, Pi and Codex the same levels, and the gateway passed max on unchanged (fitEffort keeps an effort when no levels are known), which Xiaomi turned away with a 400. The same held for Zhipu's glm-5/5.1/5v-turbo, Kimi k2.6, MiniMax M2.x, gemma-4 and others whose makers give no levels while resellers give up to max.

Now catalog.ListedBy looks a model up in given catalogs (vendor prefix, case, a ':free' or '(…)' suffix aside) and gives the levels listed there, none for a switch or no options, and skips an entry with a token budget alone (Claude 4.5), which says nothing of efforts. Known looks in the provider's own catalogs first, and every borrow (Known, effortsOf) asks the makers' catalogs (vendor presets, less Groq and Ollama Cloud, marked Hosts as they serve others' models) before the crowd. The crowd vote counts a provider once per list, so an aggregator listing a model under several hosts no longer outvotes the rest. Provider.Levelless says a model is known to have no levels, and the gateway (fitFor, on the direct and fallback paths) sends such a model no more than high; a model whose levels are simply unknown is still sent what was asked.

Tests: TestEffortsOfOneVoteAProvider and TestListedBy (catalog); TestMakerLevelsBeforeResellers (provider: Xiaomi's preset, a preview left out of the list and a relay get no levels, an unlisted model and a budget-only Claude one still borrow, Levelless); TestOpenCodeNoResellerLevelsForSwitchModel (opencode.json has empty variants for Xiaomi's and a relay's mimo, three for a reseller-only model; Pi has no reasoning or thinkingLevelMap for mimo); TestSwitchModelSentNoMoreThanHigh (gateway: mimo asked max/xhigh sent high, low as asked, an unknown model max). The agent and gateway tests fail on main. An audit of every preset against the current models.dev snapshot found the cases above. Not tested with a real Xiaomi key or a running OpenCode. go build -tags nogui (and linux, windows), go test -tags nogui ./... pass.
2026-09-29 19:41:29 +08:00
yetone 5f73e4f4fc agent: OpenCode's magpie models name the reasoning levels each really has as variants ({level: {reasoningEffort: level}}, an empty set for a model without any) — OpenCode 2 otherwise makes low, medium and high of its own for every openai-compatible model (packages/core/src/variant.ts), so a model with none/high/max or none at all was offered levels it doesn't take; OpenCode 1 merges the same variants as before (kkgg) 2026-09-28 16:36:01 +08:00