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.
137 lines
7.5 KiB
JavaScript
137 lines
7.5 KiB
JavaScript
// Run with Node's test runner and Playwright on the module path; see README.md.
|
|
// Codex's effort left at Default reads as Default, with the level Codex
|
|
// then takes for the model beside it (lgtm on Discord: Default turned into
|
|
// 中 on Codex · WSL Ubuntu). Its row and slider say "default (medium)", a
|
|
// level picked shows the level, and Default picked again posts "" and
|
|
// reads as Default again, not as medium.
|
|
// English, Chinese, Japanese and German, Chromium and WebKit, the window
|
|
// and the tray panel.
|
|
const assert = require("node:assert/strict");
|
|
const fs = require("node:fs/promises");
|
|
const path = require("node:path");
|
|
const { test } = require("node:test");
|
|
const { chromium, webkit } = require("playwright");
|
|
|
|
const assets = path.resolve(__dirname, "../assets");
|
|
const levels = ["low", "medium", "high", "xhigh"];
|
|
const codex = (effort) => ({
|
|
id: "codex", name: "Codex", icon: "codex-color", path: "/h/.codex/config.toml", wired: true,
|
|
fields: [
|
|
{ key: "model", label: "model", value: "volc/glm", options: [{ value: "volc/glm", label: "GLM", ref: "volc/glm" }] },
|
|
{ key: "effort", label: "effort", value: effort, options: [{ value: "", note: "Codex's default for the model: medium", takes: "medium" }, ...levels.map((value) => ({ value }))] },
|
|
],
|
|
});
|
|
const filler = Array.from({ length: 6 }, (_, i) => ({ id: "pi" + i, name: "Pi " + i, path: "/p", fields: [{ key: "model", label: "model", value: "", options: [] }] }));
|
|
|
|
function serve(lang, sets) {
|
|
let effort = "";
|
|
const st = () => ({ agents: [codex(effort), ...filler], profiles: [], settings: { lang, theme: "light" } });
|
|
return async (route) => {
|
|
const req = route.request(), url = new URL(req.url());
|
|
if (url.pathname === "/boot.js") return route.fulfill({ contentType: "text/javascript", body: `window.bootPrefs = {lang:"${lang}",theme:"light",web:true};` });
|
|
if (url.pathname === "/wails/runtime.js") return route.fulfill({ contentType: "text/javascript", body: "export const Window = {};" });
|
|
if (url.pathname === "/api/state") return route.fulfill({ json: st() });
|
|
if (url.pathname === "/api/set") {
|
|
const b = req.postDataJSON();
|
|
sets.push(b);
|
|
if (b.field === "effort") effort = b.value;
|
|
return route.fulfill({ json: st() });
|
|
}
|
|
if (url.pathname === "/api/plugins") return route.fulfill({ json: { plugins: [] } });
|
|
if (url.pathname === "/api/usage/quotas") return route.fulfill({ json: [] });
|
|
if (url.pathname === "/api/groups") return route.fulfill({ json: { groups: [] } });
|
|
if (url.pathname === "/api/providers") return route.fulfill({ json: { providers: [], gateway: { running: true } } });
|
|
if (url.pathname.startsWith("/api/")) return route.fulfill({ json: {} });
|
|
const file = path.join(assets, url.pathname === "/" ? "index.html" : url.pathname);
|
|
const contentType = { ".html": "text/html", ".js": "text/javascript", ".css": "text/css", ".svg": "image/svg+xml", ".png": "image/png" }[path.extname(file)];
|
|
await route.fulfill({ body: await fs.readFile(file), contentType });
|
|
};
|
|
}
|
|
|
|
const words = {
|
|
en: { def: "default (medium)", high: "high" },
|
|
zh: { def: "默认(中)", high: "高" },
|
|
ja: { def: "デフォルト(中)", high: "高" },
|
|
de: { def: "Standard (mittel)", high: "hoch" },
|
|
};
|
|
const row = `.row.agent[data-id="codex"]`;
|
|
const noSideScroll = (page) => page.evaluate(() => document.scrollingElement.scrollWidth <= innerWidth);
|
|
|
|
for (const engine of (process.env.BROWSER ? [process.env.BROWSER] : ["chromium", "webkit"])) {
|
|
for (const lang of ["en", "zh", "ja", "de"]) {
|
|
const w = words[lang];
|
|
test(`${engine} ${lang}: Codex's Default effort reads as Default`, async (t) => {
|
|
const browser = await (engine === "webkit" ? webkit.launch() : chromium.launch({ channel: "chromium" }));
|
|
const errors = [];
|
|
t.after(async () => {
|
|
if (errors.length) console.log(errors);
|
|
await browser.close();
|
|
});
|
|
const open = async (mode, sets, width) => {
|
|
const page = await (await browser.newContext({ viewport: { width, height: 640 }, reducedMotion: "reduce" })).newPage();
|
|
page.setDefaultTimeout(5000);
|
|
page.on("pageerror", (e) => errors.push(e.message));
|
|
await page.route("**/*", serve(lang, sets));
|
|
await page.goto("http://magpie.test/" + (mode ? "?mode=" + mode : ""));
|
|
await page.locator(row).waitFor();
|
|
return page;
|
|
};
|
|
const slide = (page, i) => page.locator("#effortRange").evaluate((r, i) => {
|
|
r.value = String(i);
|
|
r.dispatchEvent(new Event("input", { bubbles: true }));
|
|
r.dispatchEvent(new Event("change", { bubbles: true }));
|
|
}, i);
|
|
|
|
for (const width of [560, 360]) {
|
|
await t.test(`the window at ${width}px`, async () => {
|
|
const sets = [];
|
|
const page = await open("", sets, width);
|
|
let field = page.locator(`${row} .field[data-key="effort"]`).first();
|
|
if (!(await field.isVisible())) {
|
|
await page.locator(`${row} .ag-link`).click();
|
|
field = page.locator(`${row} .ag-exp .field[data-key="effort"]`);
|
|
}
|
|
await field.waitFor();
|
|
assert.equal(await field.locator(".v").textContent(), w.def);
|
|
const box = await field.boundingBox();
|
|
assert(box.x >= 0 && box.x + box.width <= width, `the effort runs off the window: ${JSON.stringify(box)}`);
|
|
|
|
await field.click();
|
|
await page.locator("#effortControl:not([hidden])").waitFor();
|
|
assert.equal(await page.locator("#effortValue").textContent(), w.def);
|
|
assert.equal(await page.locator("#effortMin").textContent(), w.def);
|
|
// Default, then the model's four levels: no stop of its own added
|
|
assert.equal(await page.locator("#effortTicks i").count(), 5);
|
|
await slide(page, 3);
|
|
assert.equal(await page.locator("#effortValue").textContent(), w.high);
|
|
await page.waitForFunction(() => document.querySelector('.row.agent[data-id="codex"] .field[data-key="effort"] .v')?.textContent !== document.querySelector("#effortMin")?.textContent);
|
|
await slide(page, 0);
|
|
assert.equal(await page.locator("#effortValue").textContent(), w.def);
|
|
for (let i = 0; i < 100 && sets.length < 2; i++) await page.waitForTimeout(50);
|
|
await page.waitForFunction((d) => [...document.querySelectorAll('.row.agent[data-id="codex"] .field[data-key="effort"] .v')].some((v) => v.textContent === d), w.def);
|
|
assert.deepEqual(sets, [{ agent: "codex", field: "effort", value: "high" }, { agent: "codex", field: "effort", value: "" }]);
|
|
assert(await noSideScroll(page), "the window scrolls sideways");
|
|
});
|
|
}
|
|
|
|
await t.test("the panel", async () => {
|
|
const sets = [];
|
|
const page = await open("panel", sets, 440);
|
|
assert.equal(await page.locator(`${row} .ag-sum .eff`).getAttribute("data-l"), "0");
|
|
await page.locator(`${row} .ag-sum`).click();
|
|
await page.waitForTimeout(700);
|
|
const box = page.locator(`${row} .ag-open .effort-control`);
|
|
assert.equal(await box.locator(".effort-ticks i").count(), 5);
|
|
assert.equal(await box.locator(".effort-head b").textContent(), w.def);
|
|
assert.equal(await box.locator(".effort-ends span").first().textContent(), w.def);
|
|
await box.locator(".eslide").press("ArrowRight");
|
|
await page.waitForTimeout(300);
|
|
assert.deepEqual(sets, [{ agent: "codex", field: "effort", value: "low" }]);
|
|
assert(await noSideScroll(page), "the panel scrolls sideways");
|
|
});
|
|
|
|
assert.deepEqual(errors, []);
|
|
});
|
|
}
|
|
}
|