import { type Experimental_EvaluationModelV4 as EvaluationModelV4, type EmbeddingModelV4, type Experimental_VideoModelV3, type Experimental_VideoModelV4, type FilesV4, type ImageModelV4, type LanguageModelV4, NoSuchModelError, type ProviderV2, type ProviderV3, type ProviderV4, type RerankingModelV4, type SkillsV4, type SpeechModelV4, type TranscriptionModelV4, } from '@ai-sdk/provider'; import type { EvaluationModel } from '../evaluate/evaluation-result'; import type { EvaluationProvider } from '../evaluate/evaluation-provider'; import { asProviderV4 } from '../model/as-provider-v4'; import { resolveEmbeddingModel, resolveImageModel, resolveLanguageModel, resolveRerankingModel, resolveSpeechModel, resolveTranscriptionModel, resolveVideoModel, resolveEvaluationModel, } from '../model/resolve-model'; import type { EmbeddingModel } from '../types/embedding-model'; import type { ImageModel } from '../types/image-model'; import type { LanguageModel } from '../types/language-model'; import type { RerankingModel } from '../types/reranking-model'; import type { SpeechModel } from '../types/speech-model'; import type { TranscriptionModel } from '../types/transcription-model'; import type { VideoModel } from '../types/video-model'; type ProviderWithOptionalVideoModel = { videoModel?: ( modelId: string, ) => Experimental_VideoModelV3 | Experimental_VideoModelV4; }; /** * Creates a custom provider with specified language models, text embedding models, image models, transcription models, speech models, file APIs, skill APIs, and an optional fallback provider. * * @param {Object} options - The options for creating the custom provider. * @param {Record} [options.languageModels] - A record of language models, where keys are model IDs and values are language model instances. * @param {Record} [options.embeddingModels] - A record of text embedding models, where keys are model IDs and values are embedding model instances. * @param {Record} [options.imageModels] - A record of image models, where keys are model IDs and values are image model instances. * @param {Record} [options.transcriptionModels] - A record of transcription models, where keys are model IDs and values are transcription model instances. * @param {Record} [options.speechModels] - A record of speech models, where keys are model IDs and values are speech model instances. * @param {Record} [options.rerankingModels] - A record of reranking models, where keys are model IDs and values are reranking model instances. * @param {Record} [options.videoModels] - A record of video models, where keys are model IDs and values are video model instances. * @param {Record} [options.evaluationModels] - Experimental evaluation models or default-provider model IDs, keyed by alias. * @param {FilesV4} [options.files] - A files interface for uploading files. * @param {SkillsV4} [options.skills] - A skills interface for uploading skills. * @param {ProviderV2 | ProviderV3 | ProviderV4} [options.fallbackProvider] - An optional fallback provider to use when a requested model is not found in the custom provider. * @returns {ProviderV4} A ProviderV4 object with languageModel, embeddingModel, imageModel, transcriptionModel, speechModel, rerankingModel, and videoModel methods. * * @throws {NoSuchModelError} Throws when a requested model is not found and no fallback provider is available. */ export function customProvider< LANGUAGE_MODELS extends Record, EMBEDDING_MODELS extends Record, IMAGE_MODELS extends Record, TRANSCRIPTION_MODELS extends Record, SPEECH_MODELS extends Record, RERANKING_MODELS extends Record, VIDEO_MODELS extends Record, FILES extends FilesV4 | undefined = undefined, SKILLS extends SkillsV4 | undefined = undefined, FALLBACK extends ProviderV2 | ProviderV3 | ProviderV4 | undefined = undefined, EVALUATION_MODELS extends Record = Record< string, EvaluationModel >, >({ languageModels, embeddingModels, imageModels, transcriptionModels, speechModels, rerankingModels, videoModels, evaluationModels, files, skills, fallbackProvider: fallbackProviderArg, }: { languageModels?: LANGUAGE_MODELS; embeddingModels?: EMBEDDING_MODELS; imageModels?: IMAGE_MODELS; transcriptionModels?: TRANSCRIPTION_MODELS; speechModels?: SPEECH_MODELS; rerankingModels?: RERANKING_MODELS; videoModels?: VIDEO_MODELS; evaluationModels?: EVALUATION_MODELS; files?: FILES; skills?: SKILLS; fallbackProvider?: FALLBACK; }): ProviderV4 & { languageModel(modelId: ExtractModelId): LanguageModelV4; embeddingModel(modelId: ExtractModelId): EmbeddingModelV4; imageModel(modelId: ExtractModelId): ImageModelV4; transcriptionModel( modelId: ExtractModelId, ): TranscriptionModelV4; rerankingModel(modelId: ExtractModelId): RerankingModelV4; speechModel(modelId: ExtractModelId): SpeechModelV4; videoModel(modelId: ExtractModelId): Experimental_VideoModelV4; evaluationModel( modelId: ExtractModelId, ): EvaluationModelV4; } & (FILES extends FilesV4 ? { files(): FilesV4 } : [FALLBACK] extends [{ files: () => FilesV4 }] ? { files(): FilesV4 } : { files?(): FilesV4 }) & (SKILLS extends SkillsV4 ? { skills(): SkillsV4 } : [FALLBACK] extends [{ skills: () => SkillsV4 }] ? { skills(): SkillsV4 } : { skills?(): SkillsV4 }) { const fallbackProvider = fallbackProviderArg == null ? undefined : asProviderV4(fallbackProviderArg); const baseProvider: ProviderV4 & { languageModel(modelId: ExtractModelId): LanguageModelV4; embeddingModel(modelId: ExtractModelId): EmbeddingModelV4; imageModel(modelId: ExtractModelId): ImageModelV4; transcriptionModel( modelId: ExtractModelId, ): TranscriptionModelV4; rerankingModel(modelId: ExtractModelId): RerankingModelV4; speechModel(modelId: ExtractModelId): SpeechModelV4; videoModel( modelId: ExtractModelId, ): Experimental_VideoModelV4; evaluationModel( modelId: ExtractModelId, ): EvaluationModelV4; } = { specificationVersion: 'v4', languageModel(modelId: ExtractModelId): LanguageModelV4 { if (languageModels != null && modelId in languageModels) { return resolveLanguageModel(languageModels[modelId]); } if (fallbackProvider) { return fallbackProvider.languageModel(modelId); } throw new NoSuchModelError({ modelId, modelType: 'languageModel' }); }, embeddingModel( modelId: ExtractModelId, ): EmbeddingModelV4 { if (embeddingModels != null && modelId in embeddingModels) { return resolveEmbeddingModel(embeddingModels[modelId]); } if (fallbackProvider) { return fallbackProvider.embeddingModel(modelId); } throw new NoSuchModelError({ modelId, modelType: 'embeddingModel' }); }, imageModel(modelId: ExtractModelId): ImageModelV4 { if (imageModels != null && modelId in imageModels) { return resolveImageModel(imageModels[modelId]); } if (fallbackProvider?.imageModel) { return fallbackProvider.imageModel(modelId); } throw new NoSuchModelError({ modelId, modelType: 'imageModel' }); }, transcriptionModel( modelId: ExtractModelId, ): TranscriptionModelV4 { if (transcriptionModels != null && modelId in transcriptionModels) { const model = resolveTranscriptionModel(transcriptionModels[modelId]); if (model != null) { return model; } } if (fallbackProvider?.transcriptionModel) { return fallbackProvider.transcriptionModel(modelId); } throw new NoSuchModelError({ modelId, modelType: 'transcriptionModel' }); }, speechModel(modelId: ExtractModelId): SpeechModelV4 { if (speechModels != null && modelId in speechModels) { const model = resolveSpeechModel(speechModels[modelId]); if (model != null) { return model; } } if (fallbackProvider?.speechModel) { return fallbackProvider.speechModel(modelId); } throw new NoSuchModelError({ modelId, modelType: 'speechModel' }); }, rerankingModel( modelId: ExtractModelId, ): RerankingModelV4 { if (rerankingModels != null && modelId in rerankingModels) { return resolveRerankingModel(rerankingModels[modelId]); } if (fallbackProvider?.rerankingModel) { return fallbackProvider.rerankingModel(modelId); } throw new NoSuchModelError({ modelId, modelType: 'rerankingModel' }); }, evaluationModel( modelId: ExtractModelId, ): EvaluationModelV4 { if ( evaluationModels != null && Object.hasOwn(evaluationModels, modelId) ) { return resolveEvaluationModel(evaluationModels[modelId]); } const provider = fallbackProviderArg as EvaluationProvider | undefined; if (typeof provider?.evaluationModel === 'function') { const model = provider.evaluationModel(modelId); if (model != null) { return resolveEvaluationModel(model); } } throw new NoSuchModelError({ modelId, modelType: 'evaluationModel' }); }, videoModel( modelId: ExtractModelId, ): Experimental_VideoModelV4 { if (videoModels != null && modelId in videoModels) { return resolveVideoModel(videoModels[modelId]); } const provider = fallbackProviderArg as | ProviderWithOptionalVideoModel | undefined; if (provider?.videoModel) { return resolveVideoModel(provider.videoModel(modelId)); } throw new NoSuchModelError({ modelId, modelType: 'videoModel' }); }, }; const filesAndSkills = { ...(files != null || fallbackProvider?.files != null ? { files(): FilesV4 { return files ?? fallbackProvider!.files!(); }, } : {}), ...(skills != null || fallbackProvider?.skills != null ? { skills(): SkillsV4 { return skills ?? fallbackProvider!.skills!(); }, } : {}), } as (FILES extends FilesV4 ? { files(): FilesV4 } : [FALLBACK] extends [{ files: () => FilesV4 }] ? { files(): FilesV4 } : { files?(): FilesV4 }) & (SKILLS extends SkillsV4 ? { skills(): SkillsV4 } : [FALLBACK] extends [{ skills: () => SkillsV4 }] ? { skills(): SkillsV4 } : { skills?(): SkillsV4 }); return Object.assign(baseProvider, filesAndSkills); } type ExtractModelId> = Extract< keyof MODELS, string >;