import logger from '~/config/winston'; import { EModelEndpoint } from 'librechat-data-provider'; import type { TCustomConfig } from 'librechat-data-provider'; /** * Normalize the endpoint name to system-expected value. * @param name */ function normalizeEndpointName(name = ''): string { return name.toLowerCase() === 'ollama' ? 'ollama' : name; } /** * Sets up Model Specs from the config (`librechat.yaml`) file. * @param [endpoints] - The loaded custom configuration for endpoints. * @param [modelSpecs] - The loaded custom configuration for model specs. * @param [interfaceConfig] - The loaded interface configuration. * @returns The processed model specs, if any. */ export function processModelSpecs( endpoints?: TCustomConfig['endpoints'], _modelSpecs?: TCustomConfig['modelSpecs'], interfaceConfig?: TCustomConfig['interface'], ): TCustomConfig['modelSpecs'] | undefined { if (!_modelSpecs) { return undefined; } const list = _modelSpecs.list; const modelSpecs: typeof list = []; const customEndpoints = endpoints?.[EModelEndpoint.custom] ?? []; if (interfaceConfig?.modelSelect !== true && (_modelSpecs.addedEndpoints?.length ?? 0) > 0) { logger.warn( `To utilize \`addedEndpoints\`, which allows provider/model selections alongside model specs, set \`modelSelect: true\` in the interface configuration. Example: \`\`\`yaml interface: modelSelect: true \`\`\` `, ); } if (!list || list.length === 0) { return undefined; } for (const spec of list) { const currentEndpoint = spec.preset?.endpoint as EModelEndpoint | undefined; if (!currentEndpoint) { logger.warn( 'A model spec is missing the `endpoint` field within its `preset`. Skipping model spec...', ); continue; } if (EModelEndpoint[currentEndpoint] && currentEndpoint !== EModelEndpoint.custom) { modelSpecs.push(spec); continue; } else if (currentEndpoint === EModelEndpoint.custom) { logger.warn( `Model Spec with endpoint "${currentEndpoint}" is not supported. You must specify the name of the custom endpoint (case-sensitive, as defined in your config). Skipping model spec...`, ); continue; } const normalizedName = normalizeEndpointName(currentEndpoint); const endpoint = customEndpoints.find( (customEndpoint) => normalizedName === normalizeEndpointName(customEndpoint.name), ); if (!endpoint) { logger.warn(`Model spec with endpoint "${currentEndpoint}" was skipped: Endpoint not found in configuration. The \`endpoint\` value must exactly match either a system-defined endpoint or a custom endpoint defined by the user. For more information, see the documentation at https://www.librechat.ai/docs/configuration/librechat_yaml/object_structure/model_specs#endpoint`); continue; } modelSpecs.push({ ...spec, preset: { ...spec.preset, endpoint: normalizedName, }, }); } return { ..._modelSpecs, list: modelSpecs, }; }