File: //lib/node_modules/openclaw/dist/model-catalog-B5adpD0Z.js
import { s as createSubsystemLogger } from "./entry.js";
import { E as resolveOpenClawAgentDir } from "./auth-profiles-BLqWs5Ho.js";
import { i as loadConfig } from "./config-DWx3SXRc.js";
import { t as ensureOpenClawModelsJson } from "./models-config-CSZqabpA.js";
//#region src/agents/model-catalog.ts
const log = createSubsystemLogger("model-catalog");
let modelCatalogPromise = null;
let hasLoggedModelCatalogError = false;
const defaultImportPiSdk = () => import("./pi-model-discovery-CwESh4K1.js").then((n) => n.r);
let importPiSdk = defaultImportPiSdk;
const CODEX_PROVIDER = "openai-codex";
const OPENAI_CODEX_GPT53_MODEL_ID = "gpt-5.3-codex";
const OPENAI_CODEX_GPT53_SPARK_MODEL_ID = "gpt-5.3-codex-spark";
const NON_PI_NATIVE_MODEL_PROVIDERS = new Set(["kilocode"]);
function applyOpenAICodexSparkFallback(models) {
if (models.some((entry) => entry.provider === CODEX_PROVIDER && entry.id.toLowerCase() === OPENAI_CODEX_GPT53_SPARK_MODEL_ID)) return;
const baseModel = models.find((entry) => entry.provider === CODEX_PROVIDER && entry.id.toLowerCase() === OPENAI_CODEX_GPT53_MODEL_ID);
if (!baseModel) return;
models.push({
...baseModel,
id: OPENAI_CODEX_GPT53_SPARK_MODEL_ID,
name: OPENAI_CODEX_GPT53_SPARK_MODEL_ID
});
}
function normalizeConfiguredModelInput(input) {
if (!Array.isArray(input)) return;
const normalized = input.filter((item) => item === "text" || item === "image");
return normalized.length > 0 ? normalized : void 0;
}
function readConfiguredOptInProviderModels(config) {
const providers = config.models?.providers;
if (!providers || typeof providers !== "object") return [];
const out = [];
for (const [providerRaw, providerValue] of Object.entries(providers)) {
const provider = providerRaw.toLowerCase().trim();
if (!NON_PI_NATIVE_MODEL_PROVIDERS.has(provider)) continue;
if (!providerValue || typeof providerValue !== "object") continue;
const configuredModels = providerValue.models;
if (!Array.isArray(configuredModels)) continue;
for (const configuredModel of configuredModels) {
if (!configuredModel || typeof configuredModel !== "object") continue;
const idRaw = configuredModel.id;
if (typeof idRaw !== "string") continue;
const id = idRaw.trim();
if (!id) continue;
const rawName = configuredModel.name;
const name = (typeof rawName === "string" ? rawName : id).trim() || id;
const contextWindowRaw = configuredModel.contextWindow;
const contextWindow = typeof contextWindowRaw === "number" && contextWindowRaw > 0 ? contextWindowRaw : void 0;
const reasoningRaw = configuredModel.reasoning;
const reasoning = typeof reasoningRaw === "boolean" ? reasoningRaw : void 0;
const input = normalizeConfiguredModelInput(configuredModel.input);
out.push({
id,
name,
provider,
contextWindow,
reasoning,
input
});
}
}
return out;
}
function mergeConfiguredOptInProviderModels(params) {
const configured = readConfiguredOptInProviderModels(params.config);
if (configured.length === 0) return;
const seen = new Set(params.models.map((entry) => `${entry.provider.toLowerCase().trim()}::${entry.id.toLowerCase().trim()}`));
for (const entry of configured) {
const key = `${entry.provider.toLowerCase().trim()}::${entry.id.toLowerCase().trim()}`;
if (seen.has(key)) continue;
params.models.push(entry);
seen.add(key);
}
}
function createAuthStorage(AuthStorageLike, path) {
const withFactory = AuthStorageLike;
if (typeof withFactory.create === "function") return withFactory.create(path);
return new AuthStorageLike(path);
}
async function loadModelCatalog(params) {
if (params?.useCache === false) modelCatalogPromise = null;
if (modelCatalogPromise) return modelCatalogPromise;
modelCatalogPromise = (async () => {
const models = [];
const sortModels = (entries) => entries.sort((a, b) => {
const p = a.provider.localeCompare(b.provider);
if (p !== 0) return p;
return a.name.localeCompare(b.name);
});
try {
const cfg = params?.config ?? loadConfig();
await ensureOpenClawModelsJson(cfg);
await (await import("./pi-auth-json-D-7btJXk.js").then((n) => n.n)).ensurePiAuthJsonFromAuthProfiles(resolveOpenClawAgentDir());
const piSdk = await importPiSdk();
const agentDir = resolveOpenClawAgentDir();
const { join } = await import("node:path");
const authStorage = createAuthStorage(piSdk.AuthStorage, join(agentDir, "auth.json"));
const registry = new piSdk.ModelRegistry(authStorage, join(agentDir, "models.json"));
const entries = Array.isArray(registry) ? registry : registry.getAll();
for (const entry of entries) {
const id = String(entry?.id ?? "").trim();
if (!id) continue;
const provider = String(entry?.provider ?? "").trim();
if (!provider) continue;
const name = String(entry?.name ?? id).trim() || id;
const contextWindow = typeof entry?.contextWindow === "number" && entry.contextWindow > 0 ? entry.contextWindow : void 0;
const reasoning = typeof entry?.reasoning === "boolean" ? entry.reasoning : void 0;
const input = Array.isArray(entry?.input) ? entry.input : void 0;
models.push({
id,
name,
provider,
contextWindow,
reasoning,
input
});
}
mergeConfiguredOptInProviderModels({
config: cfg,
models
});
applyOpenAICodexSparkFallback(models);
if (models.length === 0) modelCatalogPromise = null;
return sortModels(models);
} catch (error) {
if (!hasLoggedModelCatalogError) {
hasLoggedModelCatalogError = true;
log.warn(`Failed to load model catalog: ${String(error)}`);
}
modelCatalogPromise = null;
if (models.length > 0) return sortModels(models);
return [];
}
})();
return modelCatalogPromise;
}
/**
* Check if a model supports image input based on its catalog entry.
*/
function modelSupportsVision(entry) {
return entry?.input?.includes("image") ?? false;
}
/**
* Find a model in the catalog by provider and model ID.
*/
function findModelInCatalog(catalog, provider, modelId) {
const normalizedProvider = provider.toLowerCase().trim();
const normalizedModelId = modelId.toLowerCase().trim();
return catalog.find((entry) => entry.provider.toLowerCase() === normalizedProvider && entry.id.toLowerCase() === normalizedModelId);
}
//#endregion
export { loadModelCatalog as n, modelSupportsVision as r, findModelInCatalog as t };