codex: the restart advice after a model or catalog change names the app-server codex sessions share ("codex app-server daemon restart"), on Windows and WSL too (TJHHHH, luci on Discord)

TJHHHH and luci (magpie 0.1.1137, codex-cli 0.162.0): the Codex app
listed magpie's models while the codex CLI showed only the official
list, on and off. Codex 0.162's TUI attaches to a background
`codex app-server --managed-daemon` (feature daemon_auto_start, stable
and on by default on every OS; skipped on Windows only when elevated or
detached launch is restricted, on WSL only when CODEX_HOME is on drvfs).
That daemon builds its model list once, when it starts, and restarts
itself only when its binary or version changes. So closing every codex
session and opening a new one keeps the list from before magpie wrote
model_catalog_json, while the desktop app's own app-server, restarted
with the app, has magpie's.

Reproduced with the real codex-cli 0.162.0 in a sandbox CODEX_HOME: a
daemon started with no catalog kept listing Codex's 8 models in model/list
after config.toml switched to a magpie catalog and every client closed;
`codex app-server daemon restart` made it list the catalog's models.
Nothing since v0.1.1137 changed this.

magpie's advice only said "restart the Codex app (and open codex
sessions)", which doesn't reach the daemon. On macOS and Linux the
Agents row already flags a stale daemon copy (StaleCopies), but that
returns nil on Windows and WSL, where the reporters may be. The Notice,
and the WSL codex kind's restart text, now name the shared app-server
and provider.CodexDaemonRestart. magpie still doesn't restart it itself:
that ends every session attached to it (as 03dbde12 decided).

Test: TestCodexAdviceNamesTheSharedAppServer (codexRunning stubbed)
fails on the old texts and passes now; it also checks nothing is said
when no codex runs.

Run: gofmt -l (clean); go vet -tags nogui on darwin, GOOS=linux and
GOOS=windows for ./internal/agent ./internal/gui ./internal/tui and the
main package; go test -tags nogui of those under a scratch HOME (all
ok). Not run on Windows or a real WSL distro, and the reporters haven't
confirmed their codex had a daemon running from before the switch.
This commit is contained in:
yetone committed 2026-10-10 06:27:40 +08:00
1 parent 5aca7d0924
commit 1134c7a8af
3 files changed
+50 -4

No files matched your search

+13 -3
View File
@@ -80,6 +80,10 @@ func codex(home string) *Agent { return codexIn(here(home)) }
// codexIn is Codex as it lives at a place: this machine's home, or a WSL
// distro's (see wsl.go).
// codexRunning is whether a Codex runs here, whose list a change reaches
// only once it restarts; a var so tests can say.
var codexRunning = func() bool { return Running(`(^|/)codex( |$)`) }
// codexEfforts are the effort control's choices for a model among ms:
// Default first, with the level Codex takes for it when none is set, as
// the catalog entry it reads says it, then the model's levels.
@@ -956,10 +960,16 @@ func codexIn(at place) *Agent {
// model request they open
Reached: func(since time.Time) (time.Time, string, bool) { return codexReached(dir, since) },
// the app-server behind the Codex app (and every codex TUI) builds
// its model list once, at start-up.
// its model list once, at start-up. Codex 0.162's TUI attaches to a
// background app-server it starts once and leaves running (its
// daemon_auto_start, on by default on every OS), so closing every
// codex session keeps the old list: a new one shows Codex's own
// models until that daemon is restarted, while the desktop app's
// own app-server, restarted with the app, has magpie's (TJHHHH,
// luci). magpie doesn't restart it: that ends its sessions.
Notice: func() string {
if Running(`(^|/)codex( |$)`) {
return "Codex builds its model list at start-up — restart the Codex app (and open codex sessions) to see this."
if codexRunning() {
return "Codex builds its model list at start-up — restart the Codex app, open codex sessions and the app-server they share (" + provider.CodexDaemonRestart + ") to see this."
}
return ""
},
@@ -0,0 +1,36 @@
package agent
import (
"strings"
"testing"
"github.com/yetone/magpie/internal/provider"
)
// Codex 0.162's TUI runs on a background app-server it starts once and
// leaves running, which built its model list when it started: after magpie
// changes Codex's list, a new codex session still shows Codex's own models
// until that app-server is restarted, while the desktop app, restarted,
// shows magpie's (TJHHHH, luci on Discord). Restarting the app and the open
// sessions, as the advice said, leaves it; the advice after a change names
// it and the command that restarts it, here and in WSL, where the Agents
// row can't tell a stale copy.
func TestCodexAdviceNamesTheSharedAppServer(t *testing.T) {
home, _ := codexHome(t, "", "")
was := codexRunning
codexRunning = func() bool { return true }
t.Cleanup(func() { codexRunning = was })
if n := codex(home).Notice(); !strings.Contains(n, provider.CodexDaemonRestart) {
t.Errorf("Codex's advice leaves out its app-server: %q", n)
}
for _, k := range wslKinds {
if k.id == "codex" && !strings.Contains(k.restart, provider.CodexDaemonRestart) {
t.Errorf("Codex in WSL's advice leaves out its app-server: %q", k.restart)
}
}
// nothing running, nothing to restart
codexRunning = func() bool { return false }
if n := codex(home).Notice(); strings.Contains(n, provider.CodexDaemonRestart) {
t.Errorf("advice with no Codex running: %q", n)
}
}
+1 -1
View File
@@ -246,7 +246,7 @@ type wslKind struct {
var wslKinds = []wslKind{
{id: "codex", name: "Codex", dir: ".codex", bin: "codex", in: codexIn,
restart: "builds its model list at start-up — restart it (and the Codex app's WSL connection) to see this.",
restart: "builds its model list at start-up — restart it, the app-server its sessions share (" + provider.CodexDaemonRestart + " there) and the Codex app's WSL connection to see this.",
asleep: func(key string) func(map[string]string) []Option {
switch key {
case "model", "subagent":