Open History to see the last commit
1import { assert, describe, it } from "@effect/vitest";
2import type { ServerProviderModel } from "@t3tools/contracts";
3import type * as ModelCatalog from "@t3tools/provider-core/server/ModelCatalog";
4
5import { applyCodexModelCatalog } from "./codexModelCatalog.ts";
6
7const model = (overrides: Partial<ServerProviderModel>): ServerProviderModel => ({
8 slug: "gpt-test",
9 name: "GPT Test",
10 isCustom: false,
11 capabilities: null,
12 ...overrides,
13});
14
15const entry = (
16 overrides: Partial<ModelCatalog.ProviderCatalogModel> & { readonly slug: string },
17): ModelCatalog.ProviderCatalogModel => ({
18 name: overrides.slug,
19 status: "current",
20 capabilities: null,
21 adapter: undefined,
22 profileAdapter: undefined,
23 ...overrides,
24});
25
26const catalog: ModelCatalog.ProviderCatalog = {
27 defaultChatModel: undefined,
28 models: [
29 entry({
30 slug: "gpt-next",
31 name: "GPT Next",
32 badge: "new",
33 adapter: { codex: { minVersion: "1.2.0" } },
34 }),
35 entry({ slug: "gpt-unversioned" }),
36 entry({ slug: "gpt-retired", status: "legacy", adapter: { codex: { minVersion: "1.2.0" } } }),
37 ],
38};
39
40const draft = (version: string | null, models: ReadonlyArray<ServerProviderModel> = []) => ({
41 enabled: true,
42 installed: true,
43 version,
44 status: "ready" as const,
45 auth: { status: "authenticated" as const },
46 checkedAt: "2026-01-01T00:00:00.000Z",
47 models,
48 slashCommands: [],
49 skills: [],
50});
51
52describe("applyCodexModelCatalog", () => {
53 it("names current models that need a newer Codex and are missing from discovery", () => {
54 assert.deepStrictEqual(applyCodexModelCatalog(draft("1.1.9"), catalog).updateRequiredModels, [
55 { slug: "gpt-next", name: "GPT Next", badge: "new", minVersion: "1.2.0" },
56 ]);
57 for (const result of [
58 applyCodexModelCatalog(draft("1.2.0"), catalog),
59 applyCodexModelCatalog(draft("1.1.9", [model({ slug: "openai.gpt-next" })]), catalog),
60 applyCodexModelCatalog(draft(null), catalog),
61 applyCodexModelCatalog(draft("1.1.9", [model({ slug: "gpt-next" })]), {
62 ...catalog,
63 models: [{ ...catalog.models[0]!, slug: "openai.gpt-next" }],
64 }),
65 ]) {
66 assert.isUndefined(result.updateRequiredModels);
67 }
68 });
69
70 it("classifies qualified Codex families without changing their wire ids", () => {
71 const classified = applyCodexModelCatalog(
72 draft("1.2.0", [
73 model({ slug: "openai.gpt-test", isLegacy: true }),
74 model({ slug: "openai.gpt-retired" }),
75 ]),
76 catalog,
77 );
78 assert.deepStrictEqual(
79 classified.models.map((entry) => [entry.slug, entry.isLegacy ?? false]),
80 [
81 ["openai.gpt-test", false],
82 ["openai.gpt-retired", true],
83 ],
84 );
85 });
86});