feat(openai): add gpt-5.4 support for API and Codex OAuth (#36590)

* feat(openai): add gpt-5.4 support and priority processing

* feat(openai-codex): add gpt-5.4 oauth support

* fix(openai): preserve provider overrides in gpt-5.4 fallback

* fix(openai-codex): keep xhigh for gpt-5.4 default

* fix(models): preserve configured overrides in list output

* fix(models): close gpt-5.4 integration gaps

* fix(openai): scope service tier to public api

* fix(openai): complete prep followups for gpt-5.4 support (#36590) (thanks @dorukardahan)

---------

Co-authored-by: Tyler Yust <TYTYYUST@YAHOO.COM>
This commit is contained in:
dorukardahan
2026-03-06 08:01:37 +03:00
committed by GitHub
parent 8c85ad540a
commit 5d4b04040d
27 changed files with 913 additions and 178 deletions

View File

@@ -33,33 +33,67 @@ const defaultImportPiSdk = () => import("./pi-model-discovery.js");
let importPiSdk = defaultImportPiSdk;
const CODEX_PROVIDER = "openai-codex";
const OPENAI_PROVIDER = "openai";
const OPENAI_GPT54_MODEL_ID = "gpt-5.4";
const OPENAI_GPT54_PRO_MODEL_ID = "gpt-5.4-pro";
const OPENAI_CODEX_GPT53_MODEL_ID = "gpt-5.3-codex";
const OPENAI_CODEX_GPT53_SPARK_MODEL_ID = "gpt-5.3-codex-spark";
const OPENAI_CODEX_GPT54_MODEL_ID = "gpt-5.4";
const NON_PI_NATIVE_MODEL_PROVIDERS = new Set(["kilocode"]);
function applyOpenAICodexSparkFallback(models: ModelCatalogEntry[]): void {
const hasSpark = models.some(
(entry) =>
entry.provider === CODEX_PROVIDER &&
entry.id.toLowerCase() === OPENAI_CODEX_GPT53_SPARK_MODEL_ID,
);
if (hasSpark) {
return;
}
type SyntheticCatalogFallback = {
provider: string;
id: string;
templateIds: readonly string[];
};
const baseModel = models.find(
(entry) =>
entry.provider === CODEX_PROVIDER && entry.id.toLowerCase() === OPENAI_CODEX_GPT53_MODEL_ID,
);
if (!baseModel) {
return;
}
models.push({
...baseModel,
const SYNTHETIC_CATALOG_FALLBACKS: readonly SyntheticCatalogFallback[] = [
{
provider: OPENAI_PROVIDER,
id: OPENAI_GPT54_MODEL_ID,
templateIds: ["gpt-5.2"],
},
{
provider: OPENAI_PROVIDER,
id: OPENAI_GPT54_PRO_MODEL_ID,
templateIds: ["gpt-5.2-pro", "gpt-5.2"],
},
{
provider: CODEX_PROVIDER,
id: OPENAI_CODEX_GPT54_MODEL_ID,
templateIds: ["gpt-5.3-codex", "gpt-5.2-codex"],
},
{
provider: CODEX_PROVIDER,
id: OPENAI_CODEX_GPT53_SPARK_MODEL_ID,
name: OPENAI_CODEX_GPT53_SPARK_MODEL_ID,
});
templateIds: [OPENAI_CODEX_GPT53_MODEL_ID],
},
] as const;
function applySyntheticCatalogFallbacks(models: ModelCatalogEntry[]): void {
const findCatalogEntry = (provider: string, id: string) =>
models.find(
(entry) =>
entry.provider.toLowerCase() === provider.toLowerCase() &&
entry.id.toLowerCase() === id.toLowerCase(),
);
for (const fallback of SYNTHETIC_CATALOG_FALLBACKS) {
if (findCatalogEntry(fallback.provider, fallback.id)) {
continue;
}
const template = fallback.templateIds
.map((templateId) => findCatalogEntry(fallback.provider, templateId))
.find((entry) => entry !== undefined);
if (!template) {
continue;
}
models.push({
...template,
id: fallback.id,
name: fallback.id,
});
}
}
function normalizeConfiguredModelInput(input: unknown): ModelInputType[] | undefined {
@@ -218,7 +252,7 @@ export async function loadModelCatalog(params?: {
models.push({ id, name, provider, contextWindow, reasoning, input });
}
mergeConfiguredOptInProviderModels({ config: cfg, models });
applyOpenAICodexSparkFallback(models);
applySyntheticCatalogFallbacks(models);
if (models.length === 0) {
// If we found nothing, don't cache this result so we can try again.