Skip to main content

llmsdk_provider/
provider.rs

1//! Top-level [`Provider`] trait — the factory for model instances.
2//!
3//! Mirrors `provider-v4.ts`. ai-sdk uses optional methods
4//! (`transcriptionModel?`, `speechModel?`, ...); Rust has none, so we
5//! ship default impls that return [`crate::ProviderError::unsupported`].
6//! Callers branch on [`crate::ProviderError::is_unsupported`].
7// Rust guideline compliant 2026-02-21
8
9use std::sync::Arc;
10
11use crate::embedding_model::EmbeddingModel;
12use crate::error::Result;
13use crate::image_model::ImageModel;
14use crate::language_model::LanguageModel;
15
16/// Factory returning model instances by id.
17///
18/// Implementations typically hold a single `reqwest::Client` and shared
19/// auth state, then mint thin model wrappers on demand.
20pub trait Provider: Send + Sync + std::fmt::Debug {
21    /// Look up a language model by id.
22    ///
23    /// # Errors
24    ///
25    /// Returns [`crate::ProviderError::no_such_model`] if the id is unknown.
26    fn language_model(&self, model_id: &str) -> Result<DynLanguageModel>;
27
28    /// Look up a text-embedding model by id.
29    ///
30    /// # Errors
31    ///
32    /// Defaults to [`crate::ProviderError::unsupported`]; override when
33    /// the provider supports embeddings. Implementations should return
34    /// [`crate::ProviderError::no_such_model`] for unknown ids.
35    fn embedding_model(&self, _model_id: &str) -> Result<DynEmbeddingModel> {
36        Err(crate::ProviderError::unsupported("embedding_model"))
37    }
38
39    /// Look up an image-generation model by id.
40    ///
41    /// # Errors
42    ///
43    /// Same conventions as [`Self::embedding_model`].
44    fn image_model(&self, _model_id: &str) -> Result<DynImageModel> {
45        Err(crate::ProviderError::unsupported("image_model"))
46    }
47}
48
49/// Type-erased language model handle.
50///
51/// Newtype over `Arc<dyn LanguageModel>` so the API does not leak a smart
52/// pointer (see M-AVOID-WRAPPERS). Cheap to clone; implements
53/// [`LanguageModel`] by delegation so callers can use it directly.
54#[derive(Debug, Clone)]
55pub struct DynLanguageModel(Arc<dyn LanguageModel>);
56
57impl DynLanguageModel {
58    /// Wrap a concrete model implementation.
59    pub fn new<M: LanguageModel + 'static>(model: M) -> Self {
60        Self(Arc::new(model))
61    }
62
63    /// Wrap an already-shared `Arc`.
64    #[must_use]
65    pub fn from_arc(model: Arc<dyn LanguageModel>) -> Self {
66        Self(model)
67    }
68
69    /// Consume the wrapper and return the underlying `Arc`.
70    #[must_use]
71    pub fn into_inner(self) -> Arc<dyn LanguageModel> {
72        self.0
73    }
74}
75
76impl std::ops::Deref for DynLanguageModel {
77    type Target = dyn LanguageModel;
78    fn deref(&self) -> &Self::Target {
79        &*self.0
80    }
81}
82
83/// Type-erased embedding model handle. See [`DynLanguageModel`] for rationale.
84#[derive(Debug, Clone)]
85pub struct DynEmbeddingModel(Arc<dyn EmbeddingModel>);
86
87impl DynEmbeddingModel {
88    /// Wrap a concrete model implementation.
89    pub fn new<M: EmbeddingModel + 'static>(model: M) -> Self {
90        Self(Arc::new(model))
91    }
92
93    /// Wrap an already-shared `Arc`.
94    #[must_use]
95    pub fn from_arc(model: Arc<dyn EmbeddingModel>) -> Self {
96        Self(model)
97    }
98
99    /// Consume the wrapper and return the underlying `Arc`.
100    #[must_use]
101    pub fn into_inner(self) -> Arc<dyn EmbeddingModel> {
102        self.0
103    }
104}
105
106impl std::ops::Deref for DynEmbeddingModel {
107    type Target = dyn EmbeddingModel;
108    fn deref(&self) -> &Self::Target {
109        &*self.0
110    }
111}
112
113/// Type-erased image model handle. See [`DynLanguageModel`] for rationale.
114#[derive(Debug, Clone)]
115pub struct DynImageModel(Arc<dyn ImageModel>);
116
117impl DynImageModel {
118    /// Wrap a concrete model implementation.
119    pub fn new<M: ImageModel + 'static>(model: M) -> Self {
120        Self(Arc::new(model))
121    }
122
123    /// Wrap an already-shared `Arc`.
124    #[must_use]
125    pub fn from_arc(model: Arc<dyn ImageModel>) -> Self {
126        Self(model)
127    }
128
129    /// Consume the wrapper and return the underlying `Arc`.
130    #[must_use]
131    pub fn into_inner(self) -> Arc<dyn ImageModel> {
132        self.0
133    }
134}
135
136impl std::ops::Deref for DynImageModel {
137    type Target = dyn ImageModel;
138    fn deref(&self) -> &Self::Target {
139        &*self.0
140    }
141}