mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 06:30:03 +00:00
fix(media-use): accept renamed codex image_generation feature flag
The codex image provider's fail-fast gate required an `imagegenext` row in
`codex features list`. Codex CLI 0.145 renamed that flag to `image_generation`
and dropped the old row, so the gate rejected every up-to-date CLI:
media-use: codex image upsell unavailable: codex imagegenext unavailable
(upgrade Codex CLI)
`resolve --type image --provider codex` returned that without ever attempting
a render, on hosts where image generation works fine. Codex itself now warns
`[features].imagegenext is deprecated. Use [features].image_generation`.
Resolve the flag name from the feature list instead of hardcoding it, and pass
whichever name the installed CLI exposes to `--enable`. The old name is
preferred when present, since CLIs that still list it reject the new one.
`codexUnavailableReason()` now returns `{ flag }` / `{ reason }` so the
resolved name reaches the exec.
Verified against codex-cli 0.145.0: `resolve --type image --provider codex`
generates and freezes an image. New unit tests pin both flag layouts so a
future rename fails loudly instead of silently disabling the provider.
This commit is contained in:
@@ -8,9 +8,15 @@ import { join } from "node:path";
|
||||
// no key (CLI-only). The image UPSELL behind local mflux; skipped by --local-only.
|
||||
//
|
||||
// Retrieval mirrors illo-skill rather than trusting the model to save a file:
|
||||
// `--enable imagegenext` makes the built-in tool drop the rendered artifact into
|
||||
// $CODEX_HOME/generated_images/, and we fetch the freshest file that postdates
|
||||
// this run. The save-to-path instruction is only a best-effort verify-first.
|
||||
// `--enable image_generation` makes the built-in tool drop the rendered artifact
|
||||
// into $CODEX_HOME/generated_images/, and we fetch the freshest file that
|
||||
// postdates this run. The save-to-path instruction is only a best-effort
|
||||
// verify-first.
|
||||
//
|
||||
// The flag was called `imagegenext` until Codex CLI ~0.145, which renamed it to
|
||||
// `image_generation` and dropped the old row from `codex features list`. Both
|
||||
// the gate below and the --enable arg track the new name, with a fallback to
|
||||
// the old one so older CLIs keep working.
|
||||
|
||||
const TIMEOUT_MS = 600000; // codex exec round-trips the sub; first-run tool spin-up is slow
|
||||
const MTIME_SKEW_MS = 2000; // tolerate mtime granularity / clock skew (illo uses 2s)
|
||||
@@ -53,10 +59,19 @@ function codexRun(args) {
|
||||
}
|
||||
}
|
||||
|
||||
// Name of the feature flag this CLI uses for the extended image tool, or null if
|
||||
// it exposes neither. Newer CLIs list only `image_generation`; older ones list
|
||||
// `imagegenext` alongside it and reject the new name on --enable.
|
||||
export function imageGenFlag(feats) {
|
||||
if (/\bimagegenext\b/.test(feats)) return "imagegenext";
|
||||
if (/\bimage_generation\b/.test(feats)) return "image_generation";
|
||||
return null;
|
||||
}
|
||||
|
||||
// Fail-fast host check (mirrors illo): don't burn a minutes-long exec when Codex
|
||||
// isn't usable. Returns null when ready, else a human reason. imagegenext ships
|
||||
// default-disabled ("under development"), so we check the ROW is present (the
|
||||
// capability signal) — the exec enables it per-render with --enable.
|
||||
// isn't usable. Returns { flag } when ready, else { reason }. The flag ships
|
||||
// default-disabled, so we check the ROW is present (the capability signal) — the
|
||||
// exec enables it per-render with --enable.
|
||||
function codexUnavailableReason() {
|
||||
try {
|
||||
const which = process.platform === "win32" ? "where" : "which";
|
||||
@@ -65,7 +80,10 @@ function codexUnavailableReason() {
|
||||
// A shell alias (e.g. `codex → /Applications/Codex.app/...`) is NOT enough:
|
||||
// aliases live only in the interactive shell, so a spawned subprocess's PATH
|
||||
// lookup can't see them. Symlink the real binary onto PATH.
|
||||
return 'codex CLI not reachable on PATH (a shell alias won\'t work — spawned processes can\'t see aliases; symlink the real binary onto PATH, e.g. ln -s "$(readlink -f "$(command -v codex)")" ~/.local/bin/codex)';
|
||||
return {
|
||||
reason:
|
||||
'codex CLI not reachable on PATH (a shell alias won\'t work — spawned processes can\'t see aliases; symlink the real binary onto PATH, e.g. ln -s "$(readlink -f "$(command -v codex)")" ~/.local/bin/codex)',
|
||||
};
|
||||
}
|
||||
// Auth marker: presence of the credentials file, NOT `codex login status`.
|
||||
// That command prints "Logged in using ChatGPT" only to a human stream
|
||||
@@ -75,18 +93,18 @@ function codexUnavailableReason() {
|
||||
// auth.json is the durable, TTY-independent signal; token validity is proven
|
||||
// by the exec itself, which fails cleanly if the login is stale.
|
||||
const authPath = join(process.env.CODEX_HOME || join(homedir(), ".codex"), "auth.json");
|
||||
if (!existsSync(authPath)) return "codex not logged in (run: codex login)";
|
||||
if (!existsSync(authPath)) return { reason: "codex not logged in (run: codex login)" };
|
||||
const feats = codexRun(["features", "list"]);
|
||||
if (feats == null) return "could not read `codex features list`";
|
||||
if (!/\bimage_generation\b/.test(feats)) return "codex image_generation feature unavailable";
|
||||
if (!/\bimagegenext\b/.test(feats)) return "codex imagegenext unavailable (upgrade Codex CLI)";
|
||||
return null;
|
||||
if (feats == null) return { reason: "could not read `codex features list`" };
|
||||
const flag = imageGenFlag(feats);
|
||||
if (!flag) return { reason: "codex image generation feature unavailable (upgrade Codex CLI)" };
|
||||
return { flag };
|
||||
}
|
||||
|
||||
export async function codexImageGenerate(intent) {
|
||||
const unavailable = codexUnavailableReason();
|
||||
if (unavailable) {
|
||||
console.error(`media-use: codex image upsell unavailable: ${unavailable}`);
|
||||
const { reason, flag } = codexUnavailableReason();
|
||||
if (reason) {
|
||||
console.error(`media-use: codex image upsell unavailable: ${reason}`);
|
||||
return null;
|
||||
}
|
||||
const outPath = join(tmpdir(), `media-use-codex-${process.pid}-${Date.now()}.png`);
|
||||
@@ -112,7 +130,7 @@ export async function codexImageGenerate(intent) {
|
||||
"workspace-write",
|
||||
"--skip-git-repo-check",
|
||||
"--enable",
|
||||
"imagegenext",
|
||||
flag,
|
||||
"-",
|
||||
],
|
||||
{ input: prompt, encoding: "utf8", timeout: TIMEOUT_MS, stdio: ["pipe", "pipe", "pipe"] },
|
||||
@@ -123,7 +141,7 @@ export async function codexImageGenerate(intent) {
|
||||
);
|
||||
return null;
|
||||
}
|
||||
// Verify-first (save-to-path may have worked), else fetch the imagegenext artifact.
|
||||
// Verify-first (save-to-path may have worked), else fetch the image-tool artifact.
|
||||
const produced =
|
||||
existsSync(outPath) && statSync(outPath).size > 0 ? outPath : freshestGeneratedImage(started);
|
||||
if (!produced) return null;
|
||||
|
||||
Reference in New Issue
Block a user