22 Commits
Author SHA1 Message Date
yetone c65d9fb473 codex: magpie-models.json keeps the keys the user added by hand to a model, and says supports_reasoning_summaries itself, so Codex before 0.145 sends the effort and shows thinking (heng91, #1450)
What was wrong: every write of ~/.codex/magpie-models.json rendered the
catalog from magpie's models alone, so a key the user had put into an
entry was gone after the next model switch, catalog sync (Refresh, a
provider added, a gateway start) or a switch to Codex's own default,
which also deleted the file outright. The key heng91 added,
supports_reasoning_summaries, is one Codex before 0.145 needs: its
client.rs build_reasoning sends no `reasoning` (no effort, no summary,
so no thinking shown) for a model whose entry doesn't say true, until
openai/codex#32206 (first in 0.145). 0.144 also refuses to load a
catalog an entry of which lacks the key at all.

What changed:
- codexcat: every entry says supports_reasoning_summaries, true for a
  model with effort levels, false otherwise. Later Codex ignore it.
- codexcat.Keep: before a write, the keys of an entry on disk magpie
  doesn't write are carried over to the entry of the same slug, and a
  true of supports_reasoning_summaries stays over magpie's false. A key
  magpie writes keeps magpie's value; a model magpie no longer serves
  drops out; an unreadable file keeps nothing.
- agent/codex.go: the write when magpie becomes the provider and the
  catalog sync go through Keep; the three places that removed the file
  remove it only when nothing of the user's is in it.

Run:
- New tests TestCodexCatalogKeepsWhatTheUserAdded,
  TestCodexCatalogRemovedWhenNothingAdded (agent, from the file magpie
  writes, edited by hand) and TestCodexCatalogReasoningSummaries,
  TestKeepUserKeys (codexcat). Each fails on origin/main's code.
- Real Codex in a sandbox CODEX_HOME against a capture server:
  0.144.0 fails to load the old catalog ("missing field
  supports_reasoning_summaries"), loads the new one and sends
  reasoning {effort: high, summary: auto}; with the user's keys kept
  it sends summary "detailed". 0.162.0 loads both and sends the same.
- gofmt -l clean; go vet, GOOS=linux and GOOS=windows go vet of
  ./internal/agent ./internal/codexcat; linux and windows builds;
  go test -tags nogui ./... under a temp HOME, all ok.
2026-10-10 09:07:44 +08:00
yetone 5aca7d0924 codex: effort left at Default stays Default and says the level Codex takes then ("default (medium)"), and isn't written over with medium when a model is picked or the catalog synced (lgtm on Discord)
lgtm set Codex · WSL Ubuntu's 推理强度 to 默认 and it came back as 中.
Two things did that, on every platform (the WSL row is the same codexIn
code as the local one):

- The effort field's Get answered an unset model_reasoning_effort on a
  magpie model with codexcat.DefaultEffort (medium), so right after the
  pick the slider and the row read 中, not 默认.
- settle() counted an unset effort as one the model doesn't take and
  wrote DefaultEffort into config.toml: on every Sync for a magpie
  model, on Join, and on a model pick, Codex's own models included. So
  Default was pinned as medium, and on Codex's own models whose default
  is low (gpt-6.1-sol, gpt-6-astra, gpt-5.6-sol in 0.162's models.json)
  magpie overrode Codex's own default.

With model_reasoning_effort unset, Codex takes the catalog entry's
default_reasoning_level (core/src/client.rs build_reasoning). Checked
for real with codex-cli 0.162.0 in a sandbox CODEX_HOME: a
model_catalog_json entry with default_reasoning_level "low" and no
model_reasoning_effort sent {"reasoning":{"effort":"low"}} to a stand-in
Responses endpoint.

Now settle replaces only a set effort the model doesn't take, Get
returns the unset value, and the effort control's options start with
Default carrying Takes: the level Codex then takes, from the entry it
reads (codexcat.TakesEffort: Codex's own models_cache entry for its
models and a ChatGPT account's codex/ ones, else the one Entries writes).
The GUI shows it as "default (medium)" / 默认(中) / 預設(中) /
デフォルト(中) / Standard (mittel). A stopped WSL distro's options get the
same Default (codexEfforts).

Tests: TestCodexDefaultEffortStaysDefault fails on the old settle
("Default written over: model_reasoning_effort = \"high\"", "Default
shows as \"high\"") and passes now. TestCodexCustomProviderModelHasEfforts
now expects Default first with Takes "high" and an unset value read as
"". codex-default-effort.test.cjs (window at 560 and 360px, tray panel;
en, zh, ja, de; Chromium and WebKit) fails on the old effortName and
passes now.

Run: gofmt -l (clean); go vet -tags nogui on darwin, GOOS=linux and
GOOS=windows for ./internal/agent ./internal/codexcat ./internal/gui
./internal/tui and the main package; go test -tags nogui of those and
./internal/catalog under a scratch HOME (all ok); the GUI effort, gui-ja,
gui-de, gui-zh-tw and i18n-keys tests (all pass), and the whole GUI suite
in both engines: 4711 pass, 8 fail, all in library-servers-bulk
(chromium, ".lib-everyon moved from 290 to 288") and purpose-filter
(webkit), which fail the same way run alone on origin/main c1c88779.
Not run on a real WSL distro.
2026-10-10 06:27:40 +08:00
yetone 68aab298d3 gateway, codex: a provider the user added by its address is sent the service_tier Codex asks for, and offered Fast and Ultrafast (hsiangron on X)
Codex's Fast (service_tier=priority) and Ultrafast (ultrafast) were dropped
on the way to a custom provider: the gateway only passed a tier on to
chatgpt.com and Cursor, and magpie's models.json entries for such a
provider's models offered no tiers, so the user's own picks were written
over.

- Request.Tier keeps the client's service_tier as sent; for a provider with
  no preset and no account (OwnTier) both buildResponses and buildChat send
  it as it is. One that refuses the field by name is asked again without it
  and remembered as unfit for it, as the other optional fields are.
- codexcat offers such a provider's model the tiers Codex's own entry gives
  the same slug (dated snapshot and provider prefix stripped), Fast on
  another GPT model, none otherwise. Presets and groups are unchanged.

Run: TestOwnProviderGetsTier (Responses/Chat x priority/ultrafast/flex),
TestPresetProviderGetsNoTier, TestOwnProviderRefusingTier,
TestOwnProviderTiers; the gateway ones fail without the gateway change and
TestOwnProviderTiers fails without the codexcat change. go test gateway,
codexcat, catalog, provider; go vet darwin/linux/windows; gofmt -l clean.
Not tried against the reporter's relay.
2026-10-09 14:16:53 +08:00
yetone 5a9c0c21ca codexcat: a third-party entry for a model Codex has its own entry for (s2a/gpt-6-astra) says the same multi_agent_reasoning_effort, so Codex's Ultra sends xhigh for it as for OpenAI's gpt-6-astra instead of falling back to max (#1108)
Codex resolves Ultra to the entry's multi_agent_reasoning_effort, and to
max when the entry has none and lists max. magpie's entries never carried
the field, so the same model ran at max through a relay and at xhigh
through the ChatGPT account. The value is taken from Codex's own entry in
models_cache.json for the model's slug (after the provider prefix and a
dated snapshot suffix), only when the third-party entry offers Ultra and
the effort itself; models whose own entry says nothing (gpt-6-sol today)
keep Codex's max. The gateway's literal "ultra" -> max mapping is
unchanged: Codex sends the resolved effort, not "ultra".

TestUltraEffortAsCodexOwnEntry, built from the reporter's entries, fails
without the change ("s2a/gpt-6-astra: multi_agent_reasoning_effort <nil>,
want xhigh"). go test -race ./internal/codexcat ./internal/gateway
./internal/agent and go vet ./... pass in a sandbox HOME.
2026-10-08 02:15:01 +08:00
yetone ede0efb054 codexcat, gateway, gui: Settings › Codex auto-review model picks the model Codex's auto-review decides approvals on (#938, guitaoliu)
Codex's auto-review (approvals_reviewer = "auto_review") runs on the
auto_review_model_override of the conversation model's entry in its list,
else on codex-auto-review, else on the conversation's model at low effort,
so a conversation on an expensive model reviewed every approval on it.
settings.CodexAutoReview, picked from the app's menu (magpie's models and
groups, or Codex's own pick), is now put as auto_review_model_override in
every entry magpie hands Codex: magpie-models.json and a signed-in Codex's
/models, the ChatGPT backend's entries included. Unset, the list is as it
was (an override magpie left in Codex's cache is taken out, one OpenAI gives
kept). POST /api/settings/codex-auto-review refuses an id magpie doesn't
serve; settings refuse a value that is no model's id; the list's ETag
carries it so Codex asks again; another Settings save keeps it.

Tested end to end in a sandbox HOME with a real DeepSeek account and Codex
0.160.0 (codex exec, approval_policy on-request, approvals_reviewer
auto_review, read-only sandbox, a command asking for escalation): with the
setting deepseek/deepseek-flash the guardian request (kind guardian) went
to deepseek-flash while the conversation stayed on deepseek-v4-pro; unset,
magpie-models.json had no override and the review ran on deepseek-v4-pro.
Picking DeepSeek V4.1 Flash in the real web UI's Settings row wrote the
setting and rewrote magpie-models.json (4 entries with the override), and
the next codex exec reviewed on deepseek-flash. TestCodexAutoReviewEntries,
TestCodexAutoReviewChecked, TestCodexModelsAutoReview,
TestCodexAutoReviewSetting and codex-auto-review.test.cjs (Chromium and
WebKit, en and zh) are new and fail without the change; gateway-mode and
settings_keep cover the new row and field. go vet, go build (GOOS=linux
nogui, GOOS=windows) and go test -tags nogui ./... under a temp HOME pass.
2026-10-06 01:58:42 +08:00
yetone 1aaac93b52 provider, gui: Compact at — where Codex and Claude Code compact a long conversation, set per provider or per model in its editor and to any size in Settings → Long conversations (#876, hisiling)
Until now the only choice was 272K for every model or Full window for every model. The 272K default stays as it is (e950eb08: OpenAI runs its own 1M models at 272K in Codex, and Chen saw 70–90s to a first token at 550K).

What changes:

- A provider's editor has Compact at beside Context window and Max output, in the same form: "500k" for all of its models, "deepseek-v4-flash=272k" for one, and empty to follow Settings. A size at or above a model's window means the whole window. The values are kept in settings.ModelCompacts.
- Settings → Long conversations takes a size of its own beside Compact at / Full window (settings.CompactAt).
- `magpie model compact` takes a size such as 500k.

Order: the model's own value, then its provider's "*", then Settings. Full window turns off only the Settings value. A group uses the smallest value among its members.

Where it applies:

- Codex's model_catalog is told the threshold as context_window, with the whole window as max_context_window.
- Claude Code's CLAUDE_CODE_AUTO_COMPACT_WINDOW follows the main model. A Claude model now takes its provider's value when one is set.
- The Codex list tag changes when the Settings size or Full window changes.

Tests:

- New: TestModelCompactsSetFromTheEditor, TestSetCompactAt, TestCodexCatalogCompactAt and TestClaudeCompactAt.
- TestSettingsSaveKeepsWhatItDoesNotSend now covers the two new fields.
- compact-at.test.cjs (WebKit, en/zh) checks the editor field (shown, refused, chips, saved) and the Settings size (posted, hidden under Full window, no scroll).
- go vet ./..., go test -tags nogui of the root package, provider, codexcat, agent, gui, gateway, settings and catalog under a temp HOME, and GOOS=linux/windows builds all pass.
2026-10-05 15:20:05 +08:00
yetone 273be22cac agents: Codex's /model lists its models in the order dragged on the Agents page (M3chD09, #855) — Codex lists the models by the priority magpie gives them: a ChatGPT account's own first, as the backend has them, then magpie's in the catalog's order, with no way to change it. Codex's model list (Pick on its row) now has a third view, Order: the models shown as Codex lists them, numbered, each dragged elsewhere (its grip shows on hover) or moved with Alt+↑/↓; it is saved at once (settings orderedModels, by agent and entry id), and the account's own models and magpie's go in one order. A model not in the order (one added later) goes after those that are, as it stood; the hidden stay hidden and out of the order view, hiding keeps the order, and a provider renamed renames its ids in the order too. Default order puts magpie's back. Codex gets it at once: signed in to ChatGPT, the gateway's /models gives the backend's and magpie's models priorities 1..n in that order and the list's ETag carries the order so Codex asks again; not signed in, the catalog file magpie writes for Codex (ListedFor → InOrder) is rewritten in it. Only Codex's list can be ordered; base_instructions are untouched. zh, ja, de strings. TestCodexModelListInUsersOrder (gateway: default order, an order across the account's and magpie's, the ETag changing, CatalogFor, opencode's untouched, none restoring it) and TestAgentModelOrderAPI (gui: orderable, an order read back, a new model last, hidden kept, hiding keeping it, reset, opencode refused) fail on the old code (no SetModelOrder/ModelOrder); codex-model-order.test.cjs (WebKit, en and zh: Order lists the own first and leaves the hidden out, Alt+↓ and a drag post the order, Default order posts none, nothing scrolls; a list that can't be ordered has no Order) fails on the old code (no Order). agent-models, agent-models-all-hidden, agent-models-loading, agent-model-groups, click-scroll, gui-ja and gui-de pass on WebKit. go vet, builds (darwin, GOOS=linux nogui, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass. 2026-10-05 11:52:34 +08:00
tobitege 21702d01ff Add German translation; harden paths against unset env vars (#770)
* Add German translation and harden paths against unset env vars

Add a German locale to the GUI, tray menu, usage alerts and website home page, and refuse to start when the home folder is unset or relative so nothing is written under the working folder; the pi plugin no longer adopts the user's PI_CODING_AGENT_DIR, and an inherited APPIMAGE no longer selects portable mode. Scripts refuse to run from the wrong folder or empty a shared out folder, and a new internal/testenv sandboxes every test package from the user's real files, which also fixes the Claude picker and Termux installer tests on Windows.

* Makefile: know magpie's folder by its go.mod, so paths with spaces work

The check compared $(CURDIR) with $(dir $(abspath …)), which make splits on spaces, so a checkout under 'My Projects' or 'John Doe' refused every target. It now reads go.mod relative to the working folder and wants magpie's module there: make -C and a symlinked Makefile work, make -f from another folder still stops before any recipe runs.

* i18n: German for the strings main added since, with a parity test

75 strings main added (group order, patterns, slow-start wait, usage caps, RTK savings …) get their German, and two that main dropped go. gui-de.test.cjs checks, as gui-ja does, that de has every zh string with its placeholders and tags, and that the window reads in German when picked or on a German system.

* appdir: ignore relative folder variables when reading, keep them for children

CheckEnv no longer unsets anything. magpie reads the XDG folders, APPDATA/LOCALAPPDATA and every agent's folder variable through appdir.Getenv/LookupEnv, which pass over a relative value; the environment stays as it is, so the agents magpie starts get the variable as the user set it. That covers what proc.UserPath lends from the login shell too, which is set after main's check and reached the desktop app unchecked. On Windows a path rooted on the current drive (\Users\x, Git Bash's /c/x) counts as usable, and magpie version and help answer without a home, before run makes any folder.

* Sandbox the tests main added since

internal/wslrun gets testenv's TestMain, and four tests main added that set HOME alone set their home with testenv.SetHome, so on Windows they don't read the runner's profile through USERPROFILE.

* agentenv: PI_CONFIG_DIR and OPENCODE_DB take relative names on purpose

omp puts $PI_CONFIG_DIR under the home and OpenCode a relative $OPENCODE_DB in its data folder, so neither depends on the working folder: appdir no longer passes them over.

* i18n: German for the Library's multi-select and System One's decision API

The 19 strings main added since (#791's skill multi-select, the decision API snippets) get their German; the one main replaced (four APIs → five APIs) goes.

* appdir: tidy the import into magpie's group; say what Go makes of /c/x

The appdir import joins the group of magpie's own imports where a file has one. rooted's comment now says that Go takes a Git Bash path like /c/x as \c\x on the current drive, not C:\x.
2026-10-04 23:30:56 +08:00
yetone e950eb080a codex, claude: a model with a window above 272K is compacted at 272K, as OpenAI's and Anthropic's own are (X: Chen — through magpie on DeepSeek flash, Codex and Claude Code both "wait" before every answer, and more the longer the task) — magpie told both agents a 1M model's whole window, so neither compacted until near 1M and every turn sent the whole conversation again: the live ledger had turns of ~550K tokens waiting 70–90s for a first token, while magpie's own time before the vendor stays under 0.2s. OpenAI runs its own 1M-capable models at 272K in Codex (context_window 272000, max_context_window 872000) and Anthropic its at 200K unless a [1m] one is picked; magpie now does the same by default. Codex's catalog gives such a model context_window 272000 and its whole window as max_context_window; Claude Code gets CLAUDE_CODE_AUTO_COMPACT_WINDOW=272000 while it runs on magpie (it compacts at the smaller of that and the model's window, a [1m] model's too), kept apart from a value the user set and taken out with magpie. Settings → Long conversations ("Compact at 272K" / "Full window", en and zh) turns it off (settings.FullContext), and both agents' lists are written again at once. In a sandbox with the owner's real accounts: Codex's /models listed group/test and group/auto-glm-5-3-flash at 272000 with max 1000000 (stepfun's 32K and 16K as they were, gpt-6-* still 272000/872000), Claude Code on deepseek/deepseek-flash[1m] answered and its /context said 16.3k / 272k, and Full window turned both back to 1M (/context 16.3k / 1m). TestClaudeCompactWindow and the extended TestCodexCatalogToolSearch fail on the old code. go vet (darwin, GOOS=windows), builds (darwin, GOOS=linux, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass. 2026-10-04 18:27:09 +08:00
yetone 9f7b6bd86c codex: a cached entry keeps the cache's own max when magpie's list has none, and Codex's models_cache.json is read under CODEX_HOME everywhere (follow-up to #674, from reviewing #679) — restoring a cached native entry (backend away) set max_context_window to max(MaxContext, Context) from magpie's live list, so a list saved without the max (before magpie kept it) wrote the window over the cache's own (872000 became 272000); now a list with no max leaves the cache's, and codexcat.Window still raises it to a window past it. codexcat.CacheEntries and catalog.Codex read ~/.codex/models_cache.json even with CODEX_HOME set, while codexVersion and codexInstructions followed it; all four now take catalog.CodexModelsCache() (CODEX_HOME, else ~/.codex), and provider's codexCLIHome and the copy in codexInstructions are gone. TestCodexReadsCacheUnderCodexHome, TestCodexCachedListUnderCodexHomeKeepsItsMax and TestCodexCatalogEntryFromCodexHome fail on the old code (the ~/.codex cache read, none listed from CODEX_HOME); TestCodexNativeModelsTakeSetWindows now wants a cached gpt-5.5 with no live max to keep the cache's 400000 (old code: 272000). go vet, builds (darwin, GOOS=linux, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass but TestProvidersAnswerWhileListsComeIn, a timing test that passes alone. 2026-10-03 21:39:13 +08:00
yetone 64665bb249 codex: a window set on a ChatGPT account's model reaches Codex's own model list (#674)
With Codex signed in to ChatGPT through magpie (openai_base_url at
/backend-api/codex), Codex reads the backend's model entries from magpie's
/backend-api/codex/models, which passed them on as the backend gave them:
a window the user set on the codex provider (magpie model context
codex/gpt-6.1-sol 600k, or "*" for all) was in /v1/models but Codex still
got context_window 272000. The model_catalog_json path did the same: an
own model's entry, taken from Codex's models_cache.json, kept the cache's
window instead of the one magpie resolved for it.

Now each native entry takes the window the user set (Provider.ContextOf,
as /v1/models says it) — context_window, and max_context_window raised to
it where the window is past it, so the entry never says less than its
window — and nothing else in it changes; a model with none set keeps the
backend's. The ETag carries the windows set, so setting or taking one away
has Codex ask again. A list made from Codex's cache (the backend not
answering), which keeps what magpie last handed Codex, takes the account's
own list's window back for a model with none set, so a window taken away
doesn't stay. The model_catalog_json entry takes the window magpie
resolved. base_instructions and the rest of each entry are untouched.

TestCodexNativeModelsTakeSetWindows (set windows on, other models as the
backend says, max raised, ETag changing on reset, the cache restored) and
TestCodexCatalogOwnEntryTakesResolvedWindow fail on the old code and pass.
Against the owner's real ChatGPT account in a sandbox gateway under a temp
HOME (codex provider only, gpt-6-sol 600000 and gpt-5.5 400000 set):
/backend-api/codex/models gave gpt-6-sol 600000/872000, gpt-5.5
400000/400000 (max raised from 272000), the other five 272000/872000 as
the backend lists them, all 52 fields and prompts kept; /v1/models agrees
for the two set; no token rotated. go vet, builds (darwin, GOOS=linux,
GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME
pass. A Codex session's usable window wasn't checked.
2026-10-03 20:45:58 +08:00
yetone b6467c9551 codex: Ultra on GPT-6.1 Sol wherever it is served, Copilot's too, with Codex's agents taking parts of the task (#656) — Codex offers Ultra on a model whose entry lists "ultra", and on a thread at multi-agent V2 hands parts of the task to agents of its own; its catalog (models-manager/models.json) lists it for gpt-6.1-sol, gpt-6-sol, gpt-6-astra, gpt-5.6-sol and gpt-5.6-terra, not the Lunas, which stop at max. magpie listed Copilot's gpt-6.1-sol only up to max, so Codex had no Ultra for it. Now an entry for one of those models (by the id the vendor serves: openai/…, dated snapshots) that reaches max lists ultra too, in Codex's catalog and /v1/models, and its Codex entry says multi_agent_version v2, as Codex's own does; GPT-6 Luna still stops at max. A ChatGPT account's entry stays as the backend lists it, and a group with a ChatGPT account in it offers ultra but isn't told V2 (its lead's subagent tasks come sealed, #141); the "subagents on any model" setting still stamps v1 on OpenAI's entries. Ultra is no API's level: the gateway now always sends max for it (fitEffort), even to a model whose list says ultra. Subagent tasks with web_search kept (the translated path) were fixed in v0.1.689 (#613); TestCopilotUltraSubagentWithWebSearch now covers it against a stub Copilot: the lead's spawn_agent comes back with plain arguments and encrypted_function_args [], no "encrypted" goes upstream, and the subagent's agent_message reaches Copilot as text. TestCopilotSolOffersUltra (sol has ultra in /v1/models and Codex's catalog with v2, luna not; ultra goes to Copilot as max, with and without web_search) and TestUltraIsSentAsMax fail on the old code; TestUltraOnModelsThatOfferIt and TestUltraEntriesSayV2 cover entries, groups and the catalog. go vet, builds (darwin, GOOS=linux, GOOS=windows) and go test -tags nogui -count=1 ./... under a temp HOME pass. Not tried in the Codex App with a real Copilot account. 2026-10-03 16:08:26 +08:00
yetone eb7c45ac9f codex: a Settings switch has Codex's OpenAI models say multi-agent V1, so a GPT lead's subagents can run on magpie's other models (#141, congee949: with "v1" in the entry and multi_agent_v2 off, the Codex App's GPT lead spawned V1 subagents on Opus/Grok groups and they ran there) — Settings › "Codex subagents on any model", off by default. On, the ChatGPT backend's /models list magpie passes Codex (and the cached one it falls back to), the codex/ entries and the GPT routing groups (the Fast ones) in model_catalog_json say multi_agent_version "v1"; nothing else in an entry changes, base_instructions untouched. The setting is in CodexListTag as a "v1." prefix (so neither tag is found inside the other), so ETag and X-Models-Etag change and Codex asks again; catalog.Touched rewrites the catalog. Codex keeps the stamped list in models_cache.json, so the backend's own versions are kept in codex-agent-versions.json (from each fresh list, and from an unstamped cache) and CacheEntries puts them back when the cache's ETag is a stamped one: turned off, gpt-6 is "v2" again and a model the backend gave none has none. Codex's features.multi_agent_v2=true still wins, and a thread keeps its version. TestCodexAgentsV1Entries, TestCodexAgentsV1CacheRestores, TestCodexModelsAgentsV1 cover on/off/revert and the ETag; go vet, builds (darwin, linux, windows) and go test ./... under a temp HOME pass. Not tried in the Codex App. 2026-10-03 14:35:38 +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 4fc980347c agents: Codex's OpenAI models are its own, not magpie's routing groups read back (group/semantic, group/test … listed under OPENAI in Codex's model picker) — Codex keeps the list it was last handed in models_cache.json, and handed through the gateway it has magpie's models in it too; magpie read the file back as Codex's own models, so its groups (one since removed among them) were listed under OpenAI, and stayed after Codex was routed elsewhere. An entry magpie added (a magpie id — provider/model, group/<id>, codex/<slug> — in a list whose ETag magpie tagged, or described "… via magpie") is left out of Codex's own models and of the entries the gateway falls back to. TestCodexCacheLeavesMagpieOut 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:19:39 +08:00
yetone bce583dc6e codexcat: each model magpie lists for Codex says it takes parallel tool calls, so Codex 0.147 loads the catalog again (#298) — it failed on every start with "failed to parse model_catalog_json … missing field supports_parallel_tool_calls", leaving Codex unusable with magpie. Codex 0.147 requires the field; later Codex (0.159) default it and ask for parallel calls whatever it says, so true is what they already do. Reproduced in a sandbox HOME with codex-cli 0.147.0 and magpie's catalog; with the field, 0.147.0 and 0.159.2 both load it and send the request (parallel_tool_calls true, as before on 0.159). TestCodexCatalogParallelToolCalls checks every entry; it fails without the field. go vet, go build -tags nogui (darwin, GOOS=linux), GOOS=windows go build, go test -tags nogui ./... pass. 2026-09-30 15:39:37 +08:00
yetone 224304ab08 codex: third-party and group models get Codex's tool search, so the first request no longer carries every MCP and ChatGPT-app tool's schema (#258: 190K tokens before the first word on a magpie model, ~26K on Codex's own)
Codex sends every MCP tool's full schema inline in `tools` unless the model's catalog entry says supports_search_tool (core/src/tools/spec_plan.rs search_tool_enabled; mcp_tool_exposure.rs Deferred vs Direct); its own gpt-5.5/5.6 entries say so, magpie's generic entries didn't, so with a ChatGPT sign-in's apps a turn began at ~190K tokens. The generic entries now set supports_search_tool: true; base_instructions, the context window and the rest are as they were, and code mode and Responses Lite stay off. The gateway serves the search to models that don't know it: for a model it translates for (Chat, Anthropic…), the client-run tool_search is offered as a function, earlier tool_search_call/tool_search_output become a call and its result ("These tools are now available to call: …"), the tools found are offered after those sent (once, namespaces merged), and a call to it goes back to Codex as the tool_search_call Codex runs, streamed or not. A request relayed to another Responses API (not the ChatGPT backend, which runs it as sent) is rewritten the same way, the found tools' defer_loading dropped, and its stream line by line (toolsearch.go). Measured with codex exec in a sandbox HOME against a fake Responses backend and a fake MCP server with 150 tools: the first request's body went from 307,198 to 23,580 bytes. Tested with toolsearch_test.go (translated, streamed and rendered, end to end through a Chat fake and a relayed Responses fake, merging, the stream split mid-line) and TestCodexCatalogToolSearch (search on, prompt, context window and the other fields unchanged). go vet, go build -tags nogui (and GOOS=linux, GOOS=windows) and go test -tags nogui ./... pass. Not tried with real Gemini/antigravity calling the search, real ChatGPT apps, or real third-party Responses providers; a non-streamed relayed reply isn't rewritten (Codex always streams).
2026-09-30 10:49:28 +08:00
yetone ab7dd01506 codex: /fast works on a routing group too — a group with a ChatGPT account's GPT model in it is listed to Codex with the Fast tier, and the service_tier Codex then sends is kept through the group's routing and passed on to OpenAI's own backends (a ChatGPT account, api.openai.com) only; before, the request was rebuilt without it and Fast did nothing 2026-09-27 17:51:38 +08:00
yetone 0ce1888a32 codex: Fast mode through a ChatGPT account — a GPT model Codex's own catalog doesn't list carries the Fast tier Codex gives its GPT models, and the priority service_tier Codex sends for /fast reaches the backend instead of being dropped; other providers' models don't offer it, and other tiers are still left out 2026-09-27 17:42:43 +08:00
yetone 09c635cf03 agents: a model through magpie tells Pi, Crush, omp and Codex how much it holds, and a provider added, edited or removed reaches the model lists agents keep in files of their own — the catalog carried no context window, so Pi took every model through magpie for a 128K one (a CLIProxyAPI's gpt-5.5 holds 922K) and Crush for a 200K one; each model now carries models.dev's input limit, else its context, looked up by bare id as most of the providers serving it give it (a proxy's "openai/gpt-5.4", "gpt-5.4(high)", "glm-4.6:free" find it too; a group holds the least of its members'). And those lists were written only when a model was picked: Codex's magpie-models.json, Pi's models.json, OpenCode's, Crush's, Command Code's, omp's and Hermes' provider blocks and dsh's llm-deepseek entry kept the catalog as it was then, so a provider added later never showed. Saving a provider, a vendor's list fetched anew or models.dev synced now rewrites each one magpie wrote, where it differs, and the app does once at start-up; a Codex signed in to ChatGPT, which asks the gateway, kept its cached list under the backend's ETag, which a change of magpie's never changed — the ETag (and a reply's X-Models-Etag) now carries a tag of magpie's models, and a cache from before a change is aged so the next Codex asks again 2026-09-25 12:32:14 +08:00
yetone 626933ff2b codex: a magpie model that takes images says so in the catalog magpie gives Codex, which otherwise drops an attached image before sending — every magpie model was listed as text-only, so a picture pasted into Codex never reached a vision model; whether a model takes images is what its vendor's models.dev entry says, or for one served by a vendor models.dev doesn't list, what most of the providers serving that model say, and a routing group takes them only when every member does 2026-09-25 06:59:45 +08:00
yetone c3931c91df codex: magpie's models join Codex's own rather than replacing them — signed in (ChatGPT or an API key), Codex keeps its built-in OpenAI provider and sign-in and is pointed at magpie with openai_base_url alone, so its official models still go to OpenAI on the user's own account, its threads (listed per provider) stay together, and the Codex app keeps its model picker; magpie's gateway answers at /backend-api/codex, passing Codex's own models through as they came, serving magpie's (provider/model) itself, and handing out OpenAI's model list with magpie's after it for /model. Compacting a magpie model's conversation is done by that model with Codex's own prompt; Codex's compressed request bodies are read, and usage is counted for both. Not signed in, magpie stays a provider of Codex's as before; a magpie set up that way moves over the next time a magpie model is picked 2026-09-25 02:42:24 +08:00