ferrin_spec/error/
model.rs1use serde::Deserialize;
4use serde::Serialize;
5
6use crate::shared::ModelId;
7use crate::shared::ProviderId;
8use crate::shared::ProviderReference;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
12#[serde(rename_all = "kebab-case")]
13#[non_exhaustive]
14pub enum ModelKind {
15 Language,
17 Embedding,
19 Image,
21 Transcription,
23 Speech,
25 Reranking,
27 Video,
29 SpeechTranslation,
31 Realtime,
33}
34
35impl ModelKind {
36 #[must_use]
38 pub fn as_str(self) -> &'static str {
39 match self {
40 Self::Language => "language model",
41 Self::Embedding => "embedding model",
42 Self::Image => "image model",
43 Self::Transcription => "transcription model",
44 Self::Speech => "speech model",
45 Self::Reranking => "reranking model",
46 Self::Video => "video model",
47 Self::SpeechTranslation => "speech translation model",
48 Self::Realtime => "realtime model",
49 }
50 }
51}
52
53impl std::fmt::Display for ModelKind {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 f.write_str(self.as_str())
56 }
57}
58
59#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
61#[error("{message}")]
62pub struct NoSuchModelError {
63 pub provider: Option<ProviderId>,
65 pub model_id: String,
67 pub model_kind: ModelKind,
69 pub message: String,
71}
72
73impl NoSuchModelError {
74 #[must_use]
76 pub fn new(model_id: impl Into<String>, model_kind: ModelKind) -> Self {
77 let model_id = model_id.into();
78 Self {
79 provider: None,
80 message: format!("no such {model_kind}: {model_id}"),
81 model_id,
82 model_kind,
83 }
84 }
85
86 #[must_use]
88 pub fn with_provider(mut self, provider: &ProviderId) -> Self {
89 self.provider = Some(provider.clone());
90 self.message = format!(
91 "no such {}: {} (provider {provider})",
92 self.model_kind, self.model_id
93 );
94 self
95 }
96
97 #[must_use]
99 pub fn unsupported_kind(provider: &ProviderId, model_id: &str, model_kind: ModelKind) -> Self {
100 Self {
101 provider: Some(provider.clone()),
102 model_id: model_id.to_owned(),
103 model_kind,
104 message: format!(
105 "provider {provider} does not expose {model_kind}s (requested {model_id})"
106 ),
107 }
108 }
109
110 #[must_use]
112 pub fn with_message(mut self, message: impl Into<String>) -> Self {
113 self.message = message.into();
114 self
115 }
116}
117
118#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
120#[error("{message}")]
121pub struct NoSuchProviderReferenceError {
122 pub provider: String,
124 pub reference: ProviderReference,
126 pub message: String,
128}
129
130impl NoSuchProviderReferenceError {
131 #[must_use]
133 pub fn new(provider: impl Into<String>, reference: ProviderReference) -> Self {
134 let provider = provider.into();
135 let available: Vec<&str> = reference.keys().map(String::as_str).collect();
136 Self {
137 message: format!(
138 "no provider reference found for provider `{provider}`; available providers: {}",
139 available.join(", ")
140 ),
141 provider,
142 reference,
143 }
144 }
145}
146
147#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
149#[error(
150 "too many values for a single embedding call: {provider} model `{model_id}` accepts up to \
151 {max_embeddings_per_call} values per call, got {value_count}"
152)]
153pub struct TooManyEmbeddingValuesForCallError {
154 pub provider: ProviderId,
156 pub model_id: ModelId,
158 pub max_embeddings_per_call: usize,
160 pub value_count: usize,
162}
163
164#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
166#[error("{message}")]
167pub struct UnsupportedFunctionalityError {
168 pub functionality: String,
170 pub message: String,
172}
173
174impl UnsupportedFunctionalityError {
175 #[must_use]
177 pub fn new(functionality: impl Into<String>) -> Self {
178 let functionality = functionality.into();
179 Self {
180 message: format!("`{functionality}` functionality not supported"),
181 functionality,
182 }
183 }
184
185 #[must_use]
187 pub fn with_message(functionality: impl Into<String>, message: impl Into<String>) -> Self {
188 Self {
189 functionality: functionality.into(),
190 message: message.into(),
191 }
192 }
193}