openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
916 lines (915 loc) • 30.7 kB
JavaScript
import { a as normalizeLowercaseStringOrEmpty, c as normalizeOptionalString } from "./string-coerce-mnp54Vah.js";
import "./defaults-mDjiWzE5.js";
import { a as normalizeModelCompat } from "./provider-model-compat-DhKi-Qv5.js";
import "./string-coerce-runtime-CEGJWkQ_.js";
import { d as matchesExactOrPrefix, l as normalizeProviderId, u as cloneFirstTemplateModel } from "./provider-model-shared-D-lyTLvb.js";
import { t as createProviderApiKeyAuthMethod } from "./provider-api-key-auth-VMMQYUA9.js";
import "./provider-auth-api-key-nSdfYNnB.js";
import { l as findCatalogTemplate, n as buildManifestModelProviderConfig } from "./provider-catalog-shared-DZr41kLr.js";
import { a as getCachedLiveProviderModelRows, n as buildLiveModelProviderConfig } from "./provider-catalog-live-runtime-D65zJRSj.js";
import { a as isOpenAICodexBaseUrl, i as isOpenAIApiBaseUrl, n as OPENAI_CODEX_RESPONSES_BASE_URL, o as resolveOpenAIDefaultBaseUrl } from "./base-url-Cy9EayYQ.js";
import { a as OPENAI_DEFAULT_MODEL, c as applyOpenAIConfig } from "./default-models-CV6ZCMki.js";
import { n as buildOpenAISyntheticCatalogEntry, t as buildOpenAIResponsesProviderHooks } from "./shared-CB5TWJl_.js";
import { n as OPENAI_API_KEY_LABEL, t as OPENAI_ACCOUNT_WIZARD_GROUP } from "./auth-choice-copy-CI2uePXw.js";
import { r as resolveUnifiedOpenAIThinkingProfile } from "./thinking-policy-D2pce6l8.js";
import { n as buildOpenAICodexProviderHooks, t as buildOpenAIChatGPTAuthMethods } from "./openai-chatgpt-provider-CKn1kg3Y.js";
//#region extensions/openai/openclaw.plugin.json
var modelCatalog = {
"providers": { "openai": {
"baseUrl": "https://api.openai.com/v1",
"api": "openai-responses",
"models": [
{
"id": "gpt-5.3-chat-latest",
"name": "GPT-5.3 Chat (latest)",
"reasoning": false,
"input": ["text", "image"],
"contextWindow": 128e3,
"maxTokens": 16384,
"cost": {
"input": 1.75,
"output": 14,
"cacheRead": .175,
"cacheWrite": 0
}
},
{
"id": "gpt-5.3-codex",
"name": "GPT-5.3 Codex",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 4e5,
"maxTokens": 128e3,
"cost": {
"input": 1.75,
"output": 14,
"cacheRead": .175,
"cacheWrite": 0
}
},
{
"id": "gpt-5.4",
"name": "GPT-5.4",
"reasoning": true,
"input": ["text", "image"],
"mediaInput": { "image": {
"maxSidePx": 2048,
"preferredSidePx": 2048,
"tokenMode": "detail"
} },
"contextWindow": 272e3,
"maxTokens": 128e3,
"cost": {
"input": 2.5,
"output": 15,
"cacheRead": .25,
"cacheWrite": 0
}
},
{
"id": "gpt-5.4-mini",
"name": "GPT-5.4 mini",
"reasoning": true,
"input": ["text", "image"],
"mediaInput": { "image": {
"maxSidePx": 2048,
"preferredSidePx": 2048,
"tokenMode": "detail"
} },
"contextWindow": 4e5,
"maxTokens": 128e3,
"cost": {
"input": .75,
"output": 4.5,
"cacheRead": .075,
"cacheWrite": 0
}
},
{
"id": "gpt-5.4-nano",
"name": "GPT-5.4 nano",
"reasoning": true,
"input": ["text", "image"],
"mediaInput": { "image": {
"maxSidePx": 2048,
"preferredSidePx": 2048,
"tokenMode": "detail"
} },
"contextWindow": 4e5,
"maxTokens": 128e3,
"cost": {
"input": .2,
"output": 1.25,
"cacheRead": .02,
"cacheWrite": 0
}
},
{
"id": "gpt-5.4-pro",
"name": "GPT-5.4 Pro",
"reasoning": true,
"input": ["text", "image"],
"mediaInput": { "image": {
"maxSidePx": 2048,
"preferredSidePx": 2048,
"tokenMode": "detail"
} },
"contextWindow": 105e4,
"maxTokens": 128e3,
"cost": {
"input": 30,
"output": 180,
"cacheRead": 0,
"cacheWrite": 0
}
},
{
"id": "gpt-5.5",
"name": "GPT-5.5",
"reasoning": true,
"input": ["text", "image"],
"mediaInput": { "image": {
"maxSidePx": 6e3,
"preferredSidePx": 2048,
"tokenMode": "detail"
} },
"contextWindow": 1e6,
"contextTokens": 272e3,
"maxTokens": 128e3,
"cost": {
"input": 5,
"output": 30,
"cacheRead": .5,
"cacheWrite": 0
}
},
{
"id": "o1",
"name": "o1",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 2e5,
"maxTokens": 1e5,
"cost": {
"input": 15,
"output": 60,
"cacheRead": 7.5,
"cacheWrite": 0
}
},
{
"id": "o1-pro",
"name": "o1-pro",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 2e5,
"maxTokens": 1e5,
"cost": {
"input": 150,
"output": 600,
"cacheRead": 0,
"cacheWrite": 0
}
},
{
"id": "o3",
"name": "o3",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 2e5,
"maxTokens": 1e5,
"cost": {
"input": 2,
"output": 8,
"cacheRead": .5,
"cacheWrite": 0
}
},
{
"id": "o3-deep-research",
"name": "o3-deep-research",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 2e5,
"maxTokens": 1e5,
"cost": {
"input": 10,
"output": 40,
"cacheRead": 2.5,
"cacheWrite": 0
}
},
{
"id": "o3-mini",
"name": "o3-mini",
"reasoning": true,
"input": ["text"],
"contextWindow": 2e5,
"maxTokens": 1e5,
"cost": {
"input": 1.1,
"output": 4.4,
"cacheRead": .55,
"cacheWrite": 0
}
},
{
"id": "o3-pro",
"name": "o3-pro",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 2e5,
"maxTokens": 1e5,
"cost": {
"input": 20,
"output": 80,
"cacheRead": 0,
"cacheWrite": 0
}
},
{
"id": "o4-mini",
"name": "o4-mini",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 2e5,
"maxTokens": 1e5,
"cost": {
"input": 1.1,
"output": 4.4,
"cacheRead": .28,
"cacheWrite": 0
}
},
{
"id": "o4-mini-deep-research",
"name": "o4-mini-deep-research",
"reasoning": true,
"input": ["text", "image"],
"contextWindow": 2e5,
"maxTokens": 1e5,
"cost": {
"input": 2,
"output": 8,
"cacheRead": .5,
"cacheWrite": 0
}
},
{
"id": "gpt-5.5-pro",
"name": "gpt-5.5-pro",
"reasoning": true,
"input": ["text", "image"],
"mediaInput": { "image": {
"maxSidePx": 6e3,
"preferredSidePx": 2048,
"tokenMode": "detail"
} },
"contextWindow": 1e6,
"maxTokens": 128e3,
"cost": {
"input": 30,
"output": 180,
"cacheRead": 0,
"cacheWrite": 0
}
}
]
} },
"aliases": { "azure-openai-responses": {
"provider": "openai",
"api": "azure-openai-responses"
} },
"discovery": { "openai": "runtime" },
"suppressions": [{
"provider": "openai",
"model": "gpt-5.3-codex-spark",
"reason": "gpt-5.3-codex-spark is not exposed by the OpenAI API catalog. Use openai/gpt-5.5."
}, {
"provider": "azure-openai-responses",
"model": "gpt-5.3-codex-spark",
"reason": "gpt-5.3-codex-spark is not exposed by the OpenAI API catalog. Use openai/gpt-5.5."
}]
};
//#endregion
//#region extensions/openai/openai-provider.ts
const PROVIDER_ID = "openai";
const OPENAI_MODELS_ENDPOINT = "https://api.openai.com/v1/models";
const OPENAI_CODEX_MODELS_ENDPOINT = `${OPENAI_CODEX_RESPONSES_BASE_URL}/models?client_version=1.0.0`;
const OPENAI_MODELS_CACHE_TTL_MS = 6e4;
const OPENAI_CODEX_MODELS_CACHE_TTL_MS = 6e4;
const OPENAI_CHAT_LATEST_MODEL_ID = "chat-latest";
const OPENAI_GPT_55_MODEL_ID = "gpt-5.5";
const OPENAI_GPT_55_PRO_MODEL_ID = "gpt-5.5-pro";
const OPENAI_GPT_54_MODEL_ID = "gpt-5.4";
const OPENAI_GPT_54_PRO_MODEL_ID = "gpt-5.4-pro";
const OPENAI_GPT_54_MINI_MODEL_ID = "gpt-5.4-mini";
const OPENAI_GPT_54_NANO_MODEL_ID = "gpt-5.4-nano";
const OPENAI_GPT_55_CONTEXT_WINDOW = 1e6;
const OPENAI_GPT_55_CONTEXT_TOKENS = 272e3;
const OPENAI_GPT_55_PRO_CONTEXT_TOKENS = 1e6;
const OPENAI_GPT_54_CONTEXT_TOKENS = 105e4;
const OPENAI_GPT_54_PRO_CONTEXT_TOKENS = 105e4;
const OPENAI_GPT_54_MINI_CONTEXT_TOKENS = 4e5;
const OPENAI_GPT_54_NANO_CONTEXT_TOKENS = 4e5;
const OPENAI_GPT_54_MAX_TOKENS = 128e3;
const OPENAI_CHAT_LATEST_COST = {
input: 5,
output: 30,
cacheRead: .5,
cacheWrite: 0
};
const OPENAI_GPT_55_COST = {
input: 5,
output: 30,
cacheRead: .5,
cacheWrite: 0
};
const OPENAI_GPT_55_PRO_COST = {
input: 30,
output: 180,
cacheRead: 0,
cacheWrite: 0
};
const OPENAI_GPT_54_COST = {
input: 2.5,
output: 15,
cacheRead: .25,
cacheWrite: 0
};
const OPENAI_GPT_54_PRO_COST = {
input: 30,
output: 180,
cacheRead: 0,
cacheWrite: 0
};
const OPENAI_GPT_54_MINI_COST = {
input: .75,
output: 4.5,
cacheRead: .075,
cacheWrite: 0
};
const OPENAI_GPT_54_NANO_COST = {
input: .2,
output: 1.25,
cacheRead: .02,
cacheWrite: 0
};
const OPENAI_GPT_55_PRO_TEMPLATE_MODEL_IDS = [OPENAI_GPT_54_PRO_MODEL_ID, OPENAI_GPT_54_MODEL_ID];
const OPENAI_GPT_55_MEDIA_INPUT = { image: {
maxSidePx: 6e3,
preferredSidePx: 2048,
tokenMode: "detail"
} };
const OPENAI_GPT_54_TEMPLATE_MODEL_IDS = [OPENAI_GPT_55_MODEL_ID];
const OPENAI_GPT_54_PRO_TEMPLATE_MODEL_IDS = [OPENAI_GPT_55_PRO_MODEL_ID];
const OPENAI_GPT_54_MINI_TEMPLATE_MODEL_IDS = ["gpt-5-mini"];
const OPENAI_GPT_54_NANO_TEMPLATE_MODEL_IDS = ["gpt-5-nano", "gpt-5-mini"];
const OPENAI_CHAT_LATEST_TEMPLATE_MODEL_IDS = [OPENAI_GPT_55_MODEL_ID, OPENAI_GPT_54_MODEL_ID];
const OPENAI_MODERN_MODEL_IDS = [
OPENAI_CHAT_LATEST_MODEL_ID,
OPENAI_GPT_55_MODEL_ID,
OPENAI_GPT_55_PRO_MODEL_ID,
OPENAI_GPT_54_MODEL_ID,
OPENAI_GPT_54_PRO_MODEL_ID,
OPENAI_GPT_54_MINI_MODEL_ID,
OPENAI_GPT_54_NANO_MODEL_ID
];
const OPENAI_UNKNOWN_MODEL_COST = {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0
};
const OPENAI_MANIFEST_PROVIDER = buildManifestModelProviderConfig({
providerId: PROVIDER_ID,
catalog: modelCatalog.providers.openai
});
function shouldFetchOpenAILiveModels(baseUrl) {
return /^https:/i.test(baseUrl) && isOpenAIApiBaseUrl(baseUrl);
}
function buildOpenAIManifestModelsForBaseUrl(baseUrl) {
return OPENAI_MANIFEST_PROVIDER.models.map((model) => model.api === "openai-chatgpt-responses" || isOpenAICodexBaseUrl(model.baseUrl) ? { ...model } : {
...model,
baseUrl
});
}
async function buildOpenAILiveProviderConfig(params) {
const baseUrl = normalizeOptionalString(params.baseUrl) ?? resolveOpenAIDefaultBaseUrl(params.env);
const models = buildOpenAIManifestModelsForBaseUrl(baseUrl);
if (!shouldFetchOpenAILiveModels(baseUrl)) return {
baseUrl,
api: "openai-responses",
apiKey: params.apiKey,
models
};
return await buildLiveModelProviderConfig({
providerId: PROVIDER_ID,
endpoint: OPENAI_MODELS_ENDPOINT,
providerConfig: {
baseUrl,
api: "openai-responses"
},
models,
apiKey: params.apiKey,
discoveryApiKey: params.discoveryApiKey,
fetchGuard: params.fetchGuard,
signal: params.signal,
ttlMs: OPENAI_MODELS_CACHE_TTL_MS,
auditContext: "openai-model-discovery"
});
}
function readCodexModelString(row, key) {
if (!row || typeof row !== "object" || Array.isArray(row)) return;
const value = row[key];
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
}
function readCodexModelPositiveInteger(row, keys) {
if (!row || typeof row !== "object" || Array.isArray(row)) return;
const record = row;
for (const key of keys) {
const value = record[key];
if (typeof value === "number" && Number.isSafeInteger(value) && value > 0) return value;
}
}
function readCodexModelStringArray(row, keys) {
if (!row || typeof row !== "object" || Array.isArray(row)) return [];
const record = row;
for (const key of keys) {
const value = record[key];
if (Array.isArray(value)) return value.filter((entry) => typeof entry === "string");
}
return [];
}
function readCodexReasoningLevels(row) {
if (!row || typeof row !== "object" || Array.isArray(row)) return [];
const record = row;
const value = record.supported_reasoning_levels ?? record.supportedReasoningLevels;
if (!Array.isArray(value)) return [];
return value.flatMap((entry) => {
if (typeof entry === "string" && entry.trim().length > 0) return [entry.trim()];
if (entry && typeof entry === "object" && !Array.isArray(entry)) {
const effort = entry.effort;
return typeof effort === "string" && effort.trim().length > 0 ? [effort.trim()] : [];
}
return [];
});
}
function readCodexModelBoolean(row, key) {
if (!row || typeof row !== "object" || Array.isArray(row)) return;
const value = row[key];
return typeof value === "boolean" ? value : void 0;
}
function readCodexModelRows(body) {
if (!body || typeof body !== "object" || Array.isArray(body)) throw new Error("OpenAI Codex model discovery response must be { models: [] }");
const models = body.models;
if (!Array.isArray(models)) throw new Error("OpenAI Codex model discovery response must be { models: [] }");
return models;
}
function shouldIncludeCodexModelRow(row) {
const visibility = normalizeLowercaseStringOrEmpty(readCodexModelString(row, "visibility") ?? "");
if (visibility && visibility !== "list") return false;
return (readCodexModelBoolean(row, "show_in_picker") ?? readCodexModelBoolean(row, "showInPicker")) !== false;
}
function resolveCodexModelInput(row, fallback) {
const rawModalities = readCodexModelStringArray(row, ["input_modalities", "inputModalities"]);
if (rawModalities.length === 0) return fallback?.input ?? ["text", "image"];
const modalities = new Set(rawModalities.map((modality) => normalizeLowercaseStringOrEmpty(modality)));
const input = /* @__PURE__ */ new Set();
if (modalities.has("text")) input.add("text");
if (modalities.has("image") || modalities.has("vision")) input.add("image");
if (modalities.has("audio")) input.add("audio");
if (modalities.has("video")) input.add("video");
return input.size > 0 ? [...input] : fallback?.input ?? ["text", "image"];
}
function resolveCodexModelFallback(modelId) {
return OPENAI_MANIFEST_PROVIDER.models.find((model) => normalizeLowercaseStringOrEmpty(model.id) === normalizeLowercaseStringOrEmpty(modelId));
}
function buildOpenAICodexModelFromLiveRow(row) {
if (!shouldIncludeCodexModelRow(row)) return;
const modelId = readCodexModelString(row, "slug") ?? readCodexModelString(row, "id");
if (!modelId) return;
const fallback = resolveCodexModelFallback(modelId);
const reasoningLevels = readCodexReasoningLevels(row);
const contextTokens = readCodexModelPositiveInteger(row, ["context_window", "contextWindow"]);
const contextWindow = readCodexModelPositiveInteger(row, ["max_context_window", "maxContextWindow"]) ?? fallback?.contextWindow ?? contextTokens ?? 2e5;
const maxTokens = readCodexModelPositiveInteger(row, [
"max_output_tokens",
"maxOutputTokens",
"max_completion_tokens",
"maxCompletionTokens"
]) ?? fallback?.maxTokens ?? OPENAI_GPT_54_MAX_TOKENS;
return {
id: modelId,
name: readCodexModelString(row, "display_name") ?? fallback?.name ?? modelId,
api: "openai-chatgpt-responses",
baseUrl: OPENAI_CODEX_RESPONSES_BASE_URL,
reasoning: reasoningLevels.length > 0 || fallback?.reasoning || false,
input: resolveCodexModelInput(row, fallback),
cost: fallback?.cost ?? OPENAI_UNKNOWN_MODEL_COST,
contextWindow,
maxTokens,
...contextTokens ?? fallback?.contextTokens ? { contextTokens: contextTokens ?? fallback?.contextTokens } : {},
...fallback?.mediaInput ? { mediaInput: fallback.mediaInput } : {},
...fallback?.compat ? { compat: fallback.compat } : {},
...fallback?.thinkingLevelMap ? { thinkingLevelMap: fallback.thinkingLevelMap } : {}
};
}
function buildOpenAICodexStaticProviderConfig() {
return {
baseUrl: OPENAI_CODEX_RESPONSES_BASE_URL,
api: "openai-chatgpt-responses",
auth: "oauth",
models: OPENAI_MANIFEST_PROVIDER.models
};
}
async function buildOpenAICodexLiveProviderConfig(params) {
try {
const models = (await getCachedLiveProviderModelRows({
providerId: PROVIDER_ID,
endpoint: OPENAI_CODEX_MODELS_ENDPOINT,
discoveryApiKey: params.discoveryApiKey,
fetchGuard: params.fetchGuard,
signal: params.signal,
ttlMs: OPENAI_CODEX_MODELS_CACHE_TTL_MS,
auditContext: "openai-codex-model-discovery",
readRows: readCodexModelRows,
buildRequestHeaders: ({ discoveryApiKey }) => ({
Accept: "application/json",
...discoveryApiKey ? { Authorization: `Bearer ${discoveryApiKey}` } : {},
...params.accountId ? { "ChatGPT-Account-ID": params.accountId } : {}
}),
cacheKeyParts: [
PROVIDER_ID,
"codex-model-rows",
OPENAI_CODEX_MODELS_ENDPOINT,
params.discoveryApiKey,
params.accountId ?? ""
]
})).map(buildOpenAICodexModelFromLiveRow).filter((model) => Boolean(model));
if (models.length > 0) return {
baseUrl: OPENAI_CODEX_RESPONSES_BASE_URL,
api: "openai-chatgpt-responses",
auth: "oauth",
models
};
} catch {}
return buildOpenAICodexStaticProviderConfig();
}
function isCodexCatalogAuthMode(mode) {
return mode === "oauth" || mode === "token";
}
function resolveOpenAICatalogBaseUrl(ctx) {
const configuredProvider = Object.entries(ctx.config?.models?.providers ?? {}).find(([providerId]) => normalizeProviderId(providerId) === PROVIDER_ID)?.[1];
return normalizeOptionalString(configuredProvider?.baseUrl) ?? resolveOpenAIDefaultBaseUrl(ctx.env ?? process.env);
}
function shouldUseOpenAIResponsesTransport(params) {
if (params.api !== "openai-completions") return false;
if (normalizeProviderId(params.provider) === PROVIDER_ID) return !params.baseUrl || isOpenAIApiBaseUrl(params.baseUrl);
return typeof params.baseUrl === "string" && isOpenAIApiBaseUrl(params.baseUrl);
}
function isOpenAIProvider(provider) {
return normalizeProviderId(provider ?? "") === PROVIDER_ID;
}
function normalizeOpenAITransport(model) {
if (!shouldUseOpenAIResponsesTransport({
provider: model.provider,
api: model.api,
baseUrl: model.baseUrl
})) return model;
return {
...model,
api: "openai-responses"
};
}
function shouldUseCodexResponsesHooks(params) {
if (params.api === "openai-chatgpt-responses") return true;
return typeof params.baseUrl === "string" && isOpenAICodexBaseUrl(params.baseUrl);
}
function resolveConfiguredAuthTransport(ctx) {
if (ctx.authProfileMode === "oauth" || ctx.authProfileMode === "token") return "codex";
if (ctx.authProfileMode === "api_key" || ctx.authProfileMode === "aws-sdk") return "responses";
const authMode = ctx.providerConfig?.auth;
if (authMode === "oauth" || authMode === "token") return "codex";
if (authMode === "api-key") return "responses";
const auth = ctx.config?.auth;
const profiles = auth?.profiles ?? {};
const orderedProfileIds = auth?.order?.[PROVIDER_ID] ?? [];
for (const profileId of orderedProfileIds) {
const mode = profiles[profileId]?.mode;
if (mode === "oauth" || mode === "token") return "codex";
if (mode === "api_key") return "responses";
}
const providerModes = Object.values(profiles).filter((profile) => normalizeProviderId(profile.provider) === PROVIDER_ID).map((profile) => profile.mode);
if (providerModes.some((mode) => mode === "oauth" || mode === "token")) return "codex";
if (providerModes.includes("api_key")) return "responses";
}
function shouldResolveDynamicModelThroughCodex(ctx) {
if (shouldUseCodexResponsesHooks({
provider: ctx.provider,
api: ctx.providerConfig?.api,
baseUrl: ctx.providerConfig?.baseUrl
})) return true;
if (ctx.providerConfig?.baseUrl && !isOpenAIApiBaseUrl(ctx.providerConfig.baseUrl)) return false;
return resolveConfiguredAuthTransport(ctx) === "codex";
}
function resolveOpenAIGptForwardCompatModel(ctx) {
const trimmedModelId = ctx.modelId.trim();
const lower = normalizeLowercaseStringOrEmpty(trimmedModelId);
let templateIds;
let patch;
if (lower === OPENAI_CHAT_LATEST_MODEL_ID) {
templateIds = OPENAI_CHAT_LATEST_TEMPLATE_MODEL_IDS;
patch = {
api: "openai-responses",
provider: PROVIDER_ID,
baseUrl: resolveOpenAIDefaultBaseUrl(),
reasoning: false,
input: ["text", "image"],
cost: OPENAI_CHAT_LATEST_COST,
contextWindow: 4e5,
maxTokens: OPENAI_GPT_54_MAX_TOKENS
};
} else if (lower === OPENAI_GPT_55_MODEL_ID) {
templateIds = [OPENAI_GPT_55_MODEL_ID, OPENAI_GPT_54_MODEL_ID];
patch = {
api: "openai-responses",
provider: PROVIDER_ID,
baseUrl: resolveOpenAIDefaultBaseUrl(),
reasoning: true,
input: ["text", "image"],
mediaInput: OPENAI_GPT_55_MEDIA_INPUT,
cost: OPENAI_GPT_55_COST,
contextWindow: OPENAI_GPT_55_CONTEXT_WINDOW,
contextTokens: OPENAI_GPT_55_CONTEXT_TOKENS,
maxTokens: OPENAI_GPT_54_MAX_TOKENS
};
} else if (lower === OPENAI_GPT_55_PRO_MODEL_ID) {
templateIds = OPENAI_GPT_55_PRO_TEMPLATE_MODEL_IDS;
patch = {
api: "openai-responses",
provider: PROVIDER_ID,
baseUrl: resolveOpenAIDefaultBaseUrl(),
reasoning: true,
input: ["text", "image"],
cost: OPENAI_GPT_55_PRO_COST,
contextWindow: OPENAI_GPT_55_PRO_CONTEXT_TOKENS,
maxTokens: OPENAI_GPT_54_MAX_TOKENS
};
} else if (lower === OPENAI_GPT_54_MODEL_ID) {
templateIds = OPENAI_GPT_54_TEMPLATE_MODEL_IDS;
patch = {
api: "openai-responses",
provider: PROVIDER_ID,
baseUrl: resolveOpenAIDefaultBaseUrl(),
reasoning: true,
input: ["text", "image"],
cost: OPENAI_GPT_54_COST,
contextWindow: OPENAI_GPT_54_CONTEXT_TOKENS,
maxTokens: OPENAI_GPT_54_MAX_TOKENS
};
} else if (lower === OPENAI_GPT_54_PRO_MODEL_ID) {
templateIds = OPENAI_GPT_54_PRO_TEMPLATE_MODEL_IDS;
patch = {
api: "openai-responses",
provider: PROVIDER_ID,
baseUrl: resolveOpenAIDefaultBaseUrl(),
reasoning: true,
input: ["text", "image"],
cost: OPENAI_GPT_54_PRO_COST,
contextWindow: OPENAI_GPT_54_PRO_CONTEXT_TOKENS,
maxTokens: OPENAI_GPT_54_MAX_TOKENS
};
} else if (lower === OPENAI_GPT_54_MINI_MODEL_ID) {
templateIds = OPENAI_GPT_54_MINI_TEMPLATE_MODEL_IDS;
patch = {
api: "openai-responses",
provider: PROVIDER_ID,
baseUrl: resolveOpenAIDefaultBaseUrl(),
reasoning: true,
input: ["text", "image"],
cost: OPENAI_GPT_54_MINI_COST,
contextWindow: OPENAI_GPT_54_MINI_CONTEXT_TOKENS,
maxTokens: OPENAI_GPT_54_MAX_TOKENS
};
} else if (lower === OPENAI_GPT_54_NANO_MODEL_ID) {
templateIds = OPENAI_GPT_54_NANO_TEMPLATE_MODEL_IDS;
patch = {
api: "openai-responses",
provider: PROVIDER_ID,
baseUrl: resolveOpenAIDefaultBaseUrl(),
reasoning: true,
input: ["text", "image"],
cost: OPENAI_GPT_54_NANO_COST,
contextWindow: OPENAI_GPT_54_NANO_CONTEXT_TOKENS,
maxTokens: OPENAI_GPT_54_MAX_TOKENS
};
} else return;
return cloneFirstTemplateModel({
providerId: PROVIDER_ID,
modelId: trimmedModelId,
templateIds,
ctx,
patch
}) ?? normalizeModelCompat({
id: trimmedModelId,
name: trimmedModelId,
...patch,
cost: patch.cost ?? {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0
},
contextWindow: patch.contextWindow ?? 2e5,
maxTokens: patch.maxTokens ?? 2e5
});
}
function buildOpenAIProvider() {
const codexHooks = buildOpenAICodexProviderHooks();
const codexResponsesHooks = buildOpenAIResponsesProviderHooks();
const responsesHooks = buildOpenAIResponsesProviderHooks({ transport: "sse" });
return {
id: PROVIDER_ID,
label: "OpenAI",
hookAliases: ["azure-openai", "azure-openai-responses"],
docsPath: "/providers/models",
envVars: ["OPENAI_API_KEY"],
auth: [...buildOpenAIChatGPTAuthMethods(), createProviderApiKeyAuthMethod({
providerId: PROVIDER_ID,
methodId: "api-key",
label: OPENAI_API_KEY_LABEL,
hint: "Use your OpenAI API key directly",
optionKey: "openaiApiKey",
flagName: "--openai-api-key",
envVar: "OPENAI_API_KEY",
promptMessage: "Enter OpenAI API key",
profileId: "openai:api-key",
defaultModel: OPENAI_DEFAULT_MODEL,
expectedProviders: ["openai"],
applyConfig: (cfg) => applyOpenAIConfig(cfg),
wizard: {
choiceId: "openai-api-key",
choiceLabel: OPENAI_API_KEY_LABEL,
choiceHint: "Use your OpenAI API key directly",
assistantPriority: 5,
...OPENAI_ACCOUNT_WIZARD_GROUP
}
})],
catalog: {
order: "simple",
run: async (ctx) => {
const auth = ctx.resolveProviderAuth(PROVIDER_ID);
try {
const { resolveApiKeyForProvider, resolveProviderAuthProfileMetadata } = await import("./plugin-sdk/provider-auth-runtime.js");
const runtimeAuth = await resolveApiKeyForProvider({
provider: PROVIDER_ID,
cfg: ctx.config,
...ctx.agentDir ? { agentDir: ctx.agentDir } : {},
...ctx.workspaceDir ? { workspaceDir: ctx.workspaceDir } : {},
...auth.profileId ? {
profileId: auth.profileId,
lockedProfile: true
} : {}
});
if (runtimeAuth && isCodexCatalogAuthMode(runtimeAuth.mode) && runtimeAuth.apiKey) {
const metadata = resolveProviderAuthProfileMetadata({
provider: PROVIDER_ID,
cfg: ctx.config,
...ctx.agentDir ? { agentDir: ctx.agentDir } : {},
...runtimeAuth.profileId ?? auth.profileId ? { profileId: runtimeAuth.profileId ?? auth.profileId } : {}
});
const provider = await buildOpenAICodexLiveProviderConfig({
discoveryApiKey: runtimeAuth.apiKey,
accountId: metadata.accountId
});
return { providers: { [PROVIDER_ID]: provider } };
}
} catch {}
if (auth.mode === "api_key" && auth.apiKey) return { providers: { [PROVIDER_ID]: await buildOpenAILiveProviderConfig({
apiKey: auth.apiKey,
baseUrl: resolveOpenAICatalogBaseUrl(ctx),
discoveryApiKey: auth.discoveryApiKey
}) } };
const apiKey = ctx.resolveProviderApiKey(PROVIDER_ID);
if (!apiKey.apiKey) return null;
return { providers: { [PROVIDER_ID]: await buildOpenAILiveProviderConfig({
apiKey: apiKey.apiKey,
baseUrl: resolveOpenAICatalogBaseUrl(ctx),
discoveryApiKey: apiKey.discoveryApiKey
}) } };
}
},
staticCatalog: {
order: "simple",
run: async () => ({ providers: { [PROVIDER_ID]: OPENAI_MANIFEST_PROVIDER } })
},
resolveDynamicModel: (ctx) => shouldResolveDynamicModelThroughCodex(ctx) ? codexHooks.resolveDynamicModel?.(ctx) : resolveOpenAIGptForwardCompatModel(ctx),
preferRuntimeResolvedModel: (ctx) => codexHooks.preferRuntimeResolvedModel?.(ctx) ?? false,
normalizeResolvedModel: (ctx) => {
if (!isOpenAIProvider(ctx.provider)) return;
if (shouldUseCodexResponsesHooks({
provider: ctx.provider,
api: ctx.model.api,
baseUrl: ctx.model.baseUrl
})) return codexHooks.normalizeResolvedModel?.(ctx);
return normalizeOpenAITransport(ctx.model);
},
normalizeTransport: (ctx) => {
if (shouldUseCodexResponsesHooks(ctx)) return codexHooks.normalizeTransport?.(ctx);
return shouldUseOpenAIResponsesTransport(ctx) ? {
api: "openai-responses",
baseUrl: ctx.baseUrl
} : void 0;
},
...responsesHooks,
prepareExtraParams: (ctx) => {
const providerConfig = ctx.config?.models?.providers?.[PROVIDER_ID];
return (shouldUseCodexResponsesHooks({
provider: ctx.provider,
api: ctx.model?.api,
baseUrl: ctx.model?.baseUrl
}) || normalizeProviderId(ctx.provider) === PROVIDER_ID && (!providerConfig?.baseUrl || isOpenAIApiBaseUrl(providerConfig.baseUrl)) && resolveConfiguredAuthTransport({
config: ctx.config,
providerConfig
}) === "codex" ? codexResponsesHooks : responsesHooks).prepareExtraParams?.(ctx);
},
resolveUsageAuth: codexHooks.resolveUsageAuth,
fetchUsageSnapshot: codexHooks.fetchUsageSnapshot,
refreshOAuth: codexHooks.refreshOAuth,
buildMissingAuthMessage: (ctx) => {
if (normalizeProviderId(ctx.provider) !== PROVIDER_ID) return;
if (ctx.listProfileIds(PROVIDER_ID).length === 0) return;
return "No API key found for provider \"openai\". You are authenticated with OpenAI ChatGPT/Codex OAuth. Use openai/gpt-5.5 with the ChatGPT/Codex OAuth profile, or set OPENAI_API_KEY for direct OpenAI API access.";
},
matchesContextOverflowError: ({ errorMessage }) => /content_filter.*(?:prompt|input).*(?:too long|exceed)/i.test(errorMessage),
resolveReasoningOutputMode: () => "native",
resolveThinkingProfile: ({ provider, modelId }) => normalizeProviderId(provider) === PROVIDER_ID ? resolveUnifiedOpenAIThinkingProfile(modelId) : null,
isModernModelRef: ({ modelId }) => matchesExactOrPrefix(modelId, OPENAI_MODERN_MODEL_IDS),
augmentModelCatalog: (ctx) => {
const openAiGpt55ProTemplate = findCatalogTemplate({
entries: ctx.entries,
providerId: PROVIDER_ID,
templateIds: OPENAI_GPT_55_PRO_TEMPLATE_MODEL_IDS
});
const openAiGpt54Template = findCatalogTemplate({
entries: ctx.entries,
providerId: PROVIDER_ID,
templateIds: OPENAI_GPT_54_TEMPLATE_MODEL_IDS
});
const openAiGpt54ProTemplate = findCatalogTemplate({
entries: ctx.entries,
providerId: PROVIDER_ID,
templateIds: OPENAI_GPT_54_PRO_TEMPLATE_MODEL_IDS
});
const openAiGpt54MiniTemplate = findCatalogTemplate({
entries: ctx.entries,
providerId: PROVIDER_ID,
templateIds: OPENAI_GPT_54_MINI_TEMPLATE_MODEL_IDS
});
const openAiGpt54NanoTemplate = findCatalogTemplate({
entries: ctx.entries,
providerId: PROVIDER_ID,
templateIds: OPENAI_GPT_54_NANO_TEMPLATE_MODEL_IDS
});
return [
buildOpenAISyntheticCatalogEntry(openAiGpt55ProTemplate, {
id: OPENAI_GPT_55_PRO_MODEL_ID,
reasoning: true,
input: ["text", "image"],
contextWindow: OPENAI_GPT_55_PRO_CONTEXT_TOKENS
}),
buildOpenAISyntheticCatalogEntry(openAiGpt54Template, {
id: OPENAI_GPT_54_MODEL_ID,
reasoning: true,
input: ["text", "image"],
contextWindow: OPENAI_GPT_54_CONTEXT_TOKENS
}),
buildOpenAISyntheticCatalogEntry(openAiGpt54ProTemplate, {
id: OPENAI_GPT_54_PRO_MODEL_ID,
reasoning: true,
input: ["text", "image"],
contextWindow: OPENAI_GPT_54_PRO_CONTEXT_TOKENS
}),
buildOpenAISyntheticCatalogEntry(openAiGpt54MiniTemplate, {
id: OPENAI_GPT_54_MINI_MODEL_ID,
reasoning: true,
input: ["text", "image"],
contextWindow: OPENAI_GPT_54_MINI_CONTEXT_TOKENS
}),
buildOpenAISyntheticCatalogEntry(openAiGpt54NanoTemplate, {
id: OPENAI_GPT_54_NANO_MODEL_ID,
reasoning: true,
input: ["text", "image"],
contextWindow: OPENAI_GPT_54_NANO_CONTEXT_TOKENS
})
].filter((entry) => entry !== void 0);
}
};
}
/** @deprecated Use buildOpenAIProvider; OpenAI Codex is now an OpenAI auth/transport mode. */
function buildOpenAICodexProviderPlugin() {
return buildOpenAIProvider();
}
//#endregion
export { buildOpenAIProvider as i, buildOpenAICodexProviderPlugin as n, buildOpenAILiveProviderConfig as r, buildOpenAICodexLiveProviderConfig as t };