Files
backnotprop__plannotator/packages/ui/utils/codexModels.ts
Michael Ramos 6fbf0ef560 fix: align Codex model catalog and reasoning efforts with the current Codex CLI (#1096)
* fix(agents): align Codex model catalog and reasoning efforts with Codex CLI 0.144

- Remove gpt-5.3-codex from the Codex model picker: saved picks of it are
  already force-migrated to the fallback (ChatGPT-account Codex rejects it),
  so offering it was incoherent. The 5.2/5.1 family stays — those models
  remain available to API-key Codex users.
- Per-model reasoning-effort gating: the catalog (now in
  packages/ui/utils/codexModels.ts, re-exported from AgentsTab) carries each
  model's supported efforts and default effort from the CLI catalog. The
  reasoning pickers only offer the selected model's efforts, including the
  new max/ultra tiers on the GPT-5.6 family, and useAgentSettings clamps an
  unsupported saved effort to the model's catalog default before it reaches
  the pickers or a launch payload.
- Drop `minimal` everywhere: no current Codex model supports it. Saved
  perModel reasoning entries migrate minimal -> low, and the guide repair
  launch no longer hardcodes it.
- Ask AI: bump the codex-app-server static fallback model and DEFAULT_MODEL
  from gpt-5.4 to gpt-5.6-sol (runtime model/list discovery still replaces
  the fallback and already carries per-model efforts; added Max/Ultra labels).

Claude-Session: https://claude.ai/code/session_01YXkgsNucxDwAL4GdR4XYRk

* fix(agents): prune API-shut-down Codex models per OpenAI deprecations

OpenAI's API deprecations page schedules an API-level shutdown on
2026-07-23 for gpt-5.2-codex (-> gpt-5.5), gpt-5.1-codex-max (-> gpt-5.5),
and gpt-5.1-codex-mini (-> gpt-5.4-mini) — dead for ALL auth modes, not
just ChatGPT accounts — so they leave the picker and saved picks migrate:
the first two to the surface fallback (already gpt-5.5), codex-mini to
gpt-5.4-mini with its perModel preference carried under the new key (same
pattern as the gpt-5.6 -> gpt-5.6-sol rename).

gpt-5.2 stays selectable with no migration: it was retired from the
ChatGPT product (steered to 5.5) but the API still serves it, so API-key
Codex users retain it.

Claude-Session: https://claude.ai/code/session_01YXkgsNucxDwAL4GdR4XYRk
2026-07-20 11:54:09 -07:00

80 lines
4.0 KiB
TypeScript

/**
* Codex Model Catalog
*
* Single source of truth for the Codex models offered by the launch panels
* (AgentsTab + GuideEmptyState) and their per-model reasoning efforts.
* Aligned with the Codex CLI's own model catalog (codex-cli 0.144): each
* entry carries the efforts that model actually accepts plus the CLI's
* default effort for it, so the UI never offers (or launches) an effort the
* model would reject. Lives in utils/ rather than AgentsTab so
* useAgentSettings can clamp saved efforts without importing a component.
*/
export interface CodexModelOption {
value: string;
label: string;
/** Reasoning efforts this model supports, per the Codex CLI catalog. */
efforts: string[];
/** The CLI's default effort for this model — the clamp target when a saved
* effort isn't in `efforts`. */
defaultEffort: string;
}
// The two effort ladders in the current catalog. No model supports `minimal`
// anymore (saved picks migrate to `low` — see useAgentSettings).
const EFFORTS_THROUGH_XHIGH = ['low', 'medium', 'high', 'xhigh'];
const EFFORTS_THROUGH_MAX = [...EFFORTS_THROUGH_XHIGH, 'max'];
const EFFORTS_THROUGH_ULTRA = [...EFFORTS_THROUGH_MAX, 'ultra'];
export const CODEX_MODELS: CodexModelOption[] = [
// GPT-5.6 naming scheme: `-sol` is the flagship, `-terra` is the mid
// price/performance tier, and `-luna` is the efficient high-volume tier.
{ value: 'gpt-5.6-sol', label: 'GPT-5.6 Sol', efforts: EFFORTS_THROUGH_ULTRA, defaultEffort: 'low' },
{ value: 'gpt-5.6-terra', label: 'GPT-5.6 Terra', efforts: EFFORTS_THROUGH_ULTRA, defaultEffort: 'medium' },
{ value: 'gpt-5.6-luna', label: 'GPT-5.6 Luna', efforts: EFFORTS_THROUGH_MAX, defaultEffort: 'medium' },
{ value: 'gpt-5.5', label: 'GPT-5.5', efforts: EFFORTS_THROUGH_XHIGH, defaultEffort: 'medium' },
{ value: 'gpt-5.4', label: 'GPT-5.4', efforts: EFFORTS_THROUGH_XHIGH, defaultEffort: 'medium' },
{ value: 'gpt-5.3-codex-spark', label: 'GPT-5.3 Codex Spark', efforts: EFFORTS_THROUGH_XHIGH, defaultEffort: 'high' },
// gpt-5.2 is retained: it was retired from the ChatGPT product (steered to
// 5.5) but the API still serves it, so API-key Codex users keep it. The
// rest of the 5.2/5.1 family (gpt-5.2-codex, gpt-5.1-codex-max,
// gpt-5.1-codex-mini — and gpt-5.3-codex before them) is API-shut-down per
// OpenAI's deprecations page (2026-07-23), dead for ALL auth modes; saved
// picks migrate in useAgentSettings. gpt-5.2 predates max/ultra, so it
// gets the safe historical effort set.
{ value: 'gpt-5.2', label: 'GPT-5.2', efforts: EFFORTS_THROUGH_XHIGH, defaultEffort: 'medium' },
{ value: 'gpt-5.4-mini', label: 'GPT-5.4 Mini', efforts: EFFORTS_THROUGH_XHIGH, defaultEffort: 'medium' },
];
/** Display labels for the reasoning-effort ids across every model. */
export const CODEX_EFFORT_LABELS: Record<string, string> = {
low: 'Low',
medium: 'Medium',
high: 'High',
xhigh: 'XHigh',
max: 'Max',
ultra: 'Ultra',
};
// Fallback effort set for a model we don't know (a saved pick of a future
// model id passes through migration untouched, so the picker still needs
// SOMETHING to offer). low..xhigh is supported by every catalog model.
const UNKNOWN_MODEL_EFFORTS = EFFORTS_THROUGH_XHIGH;
/** The reasoning-effort picker options for one model — only the efforts that
* model actually supports. */
export function codexReasoningOptions(model: string): Array<{ value: string; label: string }> {
const entry = CODEX_MODELS.find((m) => m.value === model);
const efforts = entry?.efforts ?? UNKNOWN_MODEL_EFFORTS;
return efforts.map((value) => ({ value, label: CODEX_EFFORT_LABELS[value] ?? value }));
}
/** Clamp a saved reasoning effort to what the model supports: an unsupported
* effort snaps to the model's catalog default effort. Unknown models pass
* through unchanged (we can't know their supported set). */
export function clampCodexReasoning(model: string, reasoning: string): string {
const entry = CODEX_MODELS.find((m) => m.value === model);
if (!entry) return reasoning;
return entry.efforts.includes(reasoning) ? reasoning : entry.defaultEffort;
}