export interface ModelInfo { id: string; model: string; displayName: string; hidden: boolean; upgrade: string | null; isDefault: boolean; } export interface ModelCatalog { visibleModels: ModelInfo[]; byId: Map; upgradeAliases: Map; defaultModelId?: string | undefined; } export interface ModelResolution { requested: string; resolved: string; remappedFrom?: string | undefined; } export function buildModelCatalog(models: ModelInfo[]): ModelCatalog { const byId = new Map(models.map((model) => [model.id, model])); const visibleModels = models.filter((model) => !model.hidden); const upgradeAliases = new Map(); for (const model of models) { if (!model.upgrade) { continue; } if (byId.has(model.upgrade)) { upgradeAliases.set(model.id, model.upgrade); } } const defaultModelId = visibleModels.find((model) => model.isDefault)?.id ?? visibleModels[0]?.id; return { visibleModels, byId, upgradeAliases, defaultModelId, }; } export function describeAllowedModels(catalog: ModelCatalog): string { return catalog.visibleModels.map((model) => model.id).sort().join(', '); } export function resolveModel( catalog: ModelCatalog, requestedModel?: string | undefined, ): ModelResolution { const requested = requestedModel ?? catalog.defaultModelId ?? 'gpt-5.4'; if (!requested) { throw new Error('No models available from model/list.'); } const direct = catalog.byId.get(requested); if (direct && !direct.hidden) { const upgraded = catalog.upgradeAliases.get(requested); if (upgraded) { return { requested, resolved: upgraded, remappedFrom: requested, }; } return { requested, resolved: requested }; } const upgraded = catalog.upgradeAliases.get(requested); if (upgraded) { return { requested, resolved: upgraded, remappedFrom: requested, }; } throw new Error( `Unsupported model "${requested}". Allowed models: ${describeAllowedModels(catalog)}`, ); }