1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { assert, it } from "@effect/vitest";
3import { CodexSettings } from "@t3tools/contracts";
4import * as DateTime from "effect/DateTime";
5import * as Effect from "effect/Effect";
6import * as FileSystem from "effect/FileSystem";
7import * as Path from "effect/Path";
8import * as Schema from "effect/Schema";
9
10import { checkCodexProviderStatus } from "./CodexProvider.ts";
11
12/**
13 * Stand-in for Codex 0.162's app-server catalog behavior:
14 * - `model/list` answers from `CODEX_HOME/models_cache.json` while it is fresh.
15 * - A startup refresh runs before `initialize`, so it uses the originator set
16 * at spawn (the override env var, else the plain CLI's `codex_cli_rs`).
17 * - The backend grants Ultrafast only to entitled accounts on app originators.
18 */
19const FAKE_CODEX_APP_SERVER = String.raw`#!/usr/bin/env node
20const fs = require("node:fs");
21const path = require("node:path");
22const readline = require("node:readline");
23const cachePath = path.join(process.env.CODEX_HOME, "models_cache.json");
24const originator = process.env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE ?? "codex_cli_rs";
25const ultrafast = process.env.FAKE_ULTRAFAST_ENTITLED === "1" && originator !== "codex_cli_rs";
26const model = (tiers) => ({
27 id: "gpt-6.1-sol", model: "gpt-6.1-sol", displayName: "GPT-6.1 Sol", description: "",
28 hidden: false, isDefault: true, defaultReasoningEffort: "high",
29 supportedReasoningEfforts: [{ reasoningEffort: "high", description: "" }],
30 serviceTiers: tiers.map((id) => ({ id, name: id, description: "" })),
31});
32setTimeout(() => {
33 const tiers = ultrafast ? ["priority", "ultrafast"] : ["priority"];
34 fs.writeFileSync(cachePath, JSON.stringify({ fetched_at: new Date().toISOString(), models: [model(tiers)] }));
35}, 300);
36const write = (message) => process.stdout.write(JSON.stringify(message) + "\n");
37readline.createInterface({ input: process.stdin }).on("line", (line) => {
38 const { id, method } = JSON.parse(line);
39 if (id === undefined) return;
40 if (method === "initialize") {
41 write({ id, result: { userAgent: "codex/0.162.0", codexHome: process.env.CODEX_HOME, platformFamily: "unix", platformOs: "macos" } });
42 } else if (method === "account/read") {
43 write({ id, result: { account: { type: "chatgpt", email: "test@example.com", planType: "promax" }, requiresOpenaiAuth: false } });
44 } else if (method === "skills/list") {
45 write({ id, result: { data: [] } });
46 } else if (method === "model/list") {
47 write({ id, result: { data: JSON.parse(fs.readFileSync(cachePath, "utf8")).models, nextCursor: null } });
48 } else {
49 write({ id, error: { code: -32601, message: "unsupported" } });
50 }
51});
52`;
53
54const decodeCodexSettings = Schema.decodeSync(CodexSettings);
55
56const solServiceTiers = Effect.fn("solServiceTiers")(function* (ultrafastEntitled: boolean) {
57 const fs = yield* FileSystem.FileSystem;
58 const path = yield* Path.Path;
59 const dir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-codex-catalog-" });
60 const binaryPath = path.join(dir, "codex");
61 yield* fs.writeFileString(binaryPath, FAKE_CODEX_APP_SERVER);
62 yield* fs.chmod(binaryPath, 0o755);
63 // A fresh cache written by another client: the plain CLI's (no Ultrafast)
64 // when entitled, or a stale entitled catalog when the entitlement is gone.
65 yield* fs.writeFileString(
66 path.join(dir, "models_cache.json"),
67 JSON.stringify({
68 fetched_at: DateTime.formatIso(DateTime.subtract(yield* DateTime.now, { minutes: 1 })),
69 models: [
70 {
71 id: "gpt-6.1-sol",
72 model: "gpt-6.1-sol",
73 displayName: "GPT-6.1 Sol",
74 description: "",
75 hidden: false,
76 isDefault: true,
77 defaultReasoningEffort: "high",
78 supportedReasoningEfforts: [{ reasoningEffort: "high", description: "" }],
79 serviceTiers: (ultrafastEntitled ? ["priority"] : ["priority", "ultrafast"]).map(
80 (id) => ({ id, name: id, description: "" }),
81 ),
82 },
83 ],
84 }),
85 );
86
87 const { CODEX_INTERNAL_ORIGINATOR_OVERRIDE: _ambient, ...environment } = process.env;
88 const provider = yield* checkCodexProviderStatus(
89 decodeCodexSettings({ binaryPath, homePath: dir }),
90 undefined,
91 { ...environment, FAKE_ULTRAFAST_ENTITLED: ultrafastEntitled ? "1" : "0" },
92 );
93 const serviceTier = provider.models
94 .find((model) => model.slug === "gpt-6.1-sol")
95 ?.capabilities?.optionDescriptors?.find((descriptor) => descriptor.id === "serviceTier");
96 return serviceTier?.type === "select" ? serviceTier.options.map((option) => option.id) : [];
97});
98
99it.layer(NodeServices.layer, { excludeTestServices: true })("Codex catalog discovery", (it) => {
100 it.effect("keeps Ultrafast when another Codex client wrote the shared catalog cache", () =>
101 Effect.gen(function* () {
102 assert.deepStrictEqual(yield* solServiceTiers(true), ["default", "priority", "ultrafast"]);
103 }).pipe(Effect.scoped),
104 );
105
106 it.effect("drops Ultrafast once the account is no longer entitled to it", () =>
107 Effect.gen(function* () {
108 assert.deepStrictEqual(yield* solServiceTiers(false), ["default", "priority"]);
109 }).pipe(Effect.scoped),
110 );
111});