feat: unify installation model catalog

This commit is contained in:
Codex
2026-09-02 18:45:33 +02:00
parent ae053961a3
commit 7b7927bfe5
169 changed files with 3696 additions and 4572 deletions
+16 -16
View File
@@ -21,7 +21,7 @@ function appWithTmpSettings(extraEnv: Record<string, string> = {}, deps = {}) {
return { app, dir };
}
test("GET /settings returns effective defaults (env provider/model/thinking, first workspace)", async () => {
test("GET /settings returns thinking and the first workspace without legacy model defaults", async () => {
const { app, dir } = appWithTmpSettings({ PI_PROVIDER: "zai", PI_MODEL: "glm-5.2", PI_THINKING: "medium" }, {
listModels: async () => [{ provider: "zai", id: "glm-5.2", name: "GLM 5.2", reasoning: true }],
});
@@ -29,8 +29,8 @@ test("GET /settings returns effective defaults (env provider/model/thinking, fir
const res = await app.inject({ method: "GET", url: "/settings" });
expect(res.statusCode).toBe(200);
const body = res.json();
expect(body.provider).toBe("zai");
expect(body.model).toBe("glm-5.2");
expect(body).not.toHaveProperty("provider");
expect(body).not.toHaveProperty("model");
expect(body.thinking).toBe("medium");
expect(typeof body.workspace).toBe("string"); // first workspace from ../harness/workspaces
} finally {
@@ -62,7 +62,9 @@ test("PUT /settings does not persist personal workspace or LLM choices", async (
});
expect(put.statusCode).toBe(200);
const got = await app.inject({ method: "GET", url: "/settings" });
expect(got.json()).toMatchObject({ provider: "zai", model: "glm-5.2", thinking: "medium" });
expect(got.json()).toMatchObject({ thinking: "medium" });
expect(got.json()).not.toHaveProperty("provider");
expect(got.json()).not.toHaveProperty("model");
expect(got.json()).not.toMatchObject({ workspace: "psd", thinking: "high" });
} finally {
rmSync(dir, { recursive: true, force: true });
@@ -114,7 +116,7 @@ test("settings no longer read or write principal-specific preferences", async ()
expect(preferences.size).toBe(0);
});
test("GET /settings retains complete legacy installation defaults without seeding a private profile", async () => {
test("GET /settings drops legacy installation model fields without seeding a private profile", async () => {
let preferences: Record<string, unknown> = {};
const writes: Record<string, unknown>[] = [];
const runner = {
@@ -135,9 +137,7 @@ test("GET /settings retains complete legacy installation defaults without seedin
const first = await app.inject({ method: "GET", url: "/settings" });
const second = await app.inject({ method: "GET", url: "/settings" });
const expected = {
workspace: "local", provider: "local-qwen", model: "qwen3.6-35b-a3b", thinking: "low",
};
const expected = { workspace: "local", thinking: "low" };
expect(first.statusCode).toBe(200);
expect(first.json()).toEqual(expected);
expect(second.json()).toEqual(expected);
@@ -167,15 +167,13 @@ test("GET /settings ignores stale private preferences in favor of installation d
const response = await app.inject({ method: "GET", url: "/settings" });
expect(response.statusCode).toBe(200);
expect(response.json()).toEqual({
workspace: "local", provider: "local-qwen", model: "qwen3.6-35b-a3b", thinking: "low",
});
expect(response.json()).toEqual({ workspace: "local", thinking: "low" });
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
test("PUT /settings rejects an unknown model when a model list is available", async () => {
test("PUT /settings ignores a legacy unknown model because the catalog owns model validity", async () => {
const { app, dir } = appWithTmpSettings({}, {
listModels: async () => [{ provider: "zai", id: "glm-5.2", name: "GLM 5.2", reasoning: true }],
});
@@ -184,14 +182,14 @@ test("PUT /settings rejects an unknown model when a model list is available", as
method: "PUT", url: "/settings",
payload: { workspace: "psd", provider: "zai", model: "does-not-exist", thinking: "low" },
});
expect(put.statusCode).toBe(400);
expect(put.json()).toMatchObject({ error: expect.stringMatching(/model/i) });
expect(put.statusCode).toBe(200);
expect(put.json()).not.toHaveProperty("model");
} finally {
rmSync(dir, { recursive: true, force: true });
}
});
test("PUT /settings validates provider and model as one composite identifier", async () => {
test("PUT /settings ignores legacy provider/model pairs", async () => {
const { app, dir } = appWithTmpSettings({}, {
listModels: async () => [
{ provider: "provider-a", id: "shared-id", name: "A", reasoning: false },
@@ -204,7 +202,7 @@ test("PUT /settings validates provider and model as one composite identifier", a
workspace: "psd", provider: "provider-b", model: "shared-id", thinking: "low",
},
});
expect(wrongProvider.statusCode).toBe(400);
expect(wrongProvider.statusCode).toBe(200);
const exactPair = await app.inject({
method: "PUT", url: "/settings",
@@ -213,6 +211,8 @@ test("PUT /settings validates provider and model as one composite identifier", a
},
});
expect(exactPair.statusCode).toBe(200);
expect(exactPair.json()).not.toHaveProperty("provider");
expect(exactPair.json()).not.toHaveProperty("model");
} finally {
rmSync(dir, { recursive: true, force: true });
}