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}