1mod api_call;
9mod config;
10mod data;
11mod model;
12
13use http::StatusCode;
14
15pub use api_call::ApiCallError;
16pub use api_call::default_retryable;
17pub use config::InvalidArgumentError;
18pub use config::InvalidPromptError;
19pub use config::LoadApiKeyError;
20pub use config::LoadSettingError;
21pub use data::EmptyResponseBodyError;
22pub use data::InvalidResponseDataError;
23pub use data::JsonParseError;
24pub use data::NoContentGeneratedError;
25pub use data::TypeValidationContext;
26pub use data::TypeValidationError;
27pub use model::ModelKind;
28pub use model::NoSuchModelError;
29pub use model::NoSuchProviderReferenceError;
30pub use model::TooManyEmbeddingValuesForCallError;
31pub use model::UnsupportedFunctionalityError;
32
33pub type BoxError = Box<dyn std::error::Error + Send + Sync>;
35
36#[derive(Debug, thiserror::Error)]
38#[non_exhaustive]
39pub enum ProviderError {
40 #[error(transparent)]
42 ApiCall(Box<ApiCallError>),
43 #[error(transparent)]
45 EmptyResponseBody(#[from] EmptyResponseBodyError),
46 #[error(transparent)]
48 InvalidArgument(#[from] InvalidArgumentError),
49 #[error(transparent)]
51 InvalidPrompt(Box<InvalidPromptError>),
52 #[error(transparent)]
54 InvalidResponseData(Box<InvalidResponseDataError>),
55 #[error(transparent)]
57 JsonParse(Box<JsonParseError>),
58 #[error(transparent)]
60 LoadApiKey(#[from] LoadApiKeyError),
61 #[error(transparent)]
63 LoadSetting(#[from] LoadSettingError),
64 #[error(transparent)]
66 NoContentGenerated(#[from] NoContentGeneratedError),
67 #[error(transparent)]
69 NoSuchModel(Box<NoSuchModelError>),
70 #[error(transparent)]
72 NoSuchProviderReference(Box<NoSuchProviderReferenceError>),
73 #[error(transparent)]
75 TooManyEmbeddingValues(Box<TooManyEmbeddingValuesForCallError>),
76 #[error(transparent)]
78 TypeValidation(#[from] TypeValidationError),
79 #[error(transparent)]
81 UnsupportedFunctionality(#[from] UnsupportedFunctionalityError),
82 #[error("operation cancelled")]
84 Cancelled,
85 #[error(transparent)]
87 Other(#[from] BoxError),
88}
89
90impl ProviderError {
91 #[must_use]
93 pub fn other(error: impl std::error::Error + Send + Sync + 'static) -> Self {
94 Self::Other(Box::new(error))
95 }
96
97 #[must_use]
99 pub fn message(message: impl Into<String>) -> Self {
100 Self::Other(message.into().into())
101 }
102
103 #[must_use]
105 pub fn unsupported(functionality: impl Into<String>) -> Self {
106 Self::UnsupportedFunctionality(UnsupportedFunctionalityError::new(functionality))
107 }
108
109 #[must_use]
114 pub fn is_retryable(&self) -> bool {
115 match self {
116 Self::ApiCall(error) => error.is_retryable,
117 _ => false,
118 }
119 }
120
121 #[must_use]
123 pub fn status_code(&self) -> Option<StatusCode> {
124 match self {
125 Self::ApiCall(error) => error.status_code,
126 _ => None,
127 }
128 }
129
130 #[must_use]
132 pub fn as_api_call(&self) -> Option<&ApiCallError> {
133 match self {
134 Self::ApiCall(error) => Some(error),
135 _ => None,
136 }
137 }
138
139 #[must_use]
141 pub fn kind_name(&self) -> &'static str {
142 match self {
143 Self::ApiCall(_) => "api_call",
144 Self::EmptyResponseBody(_) => "empty_response_body",
145 Self::InvalidArgument(_) => "invalid_argument",
146 Self::InvalidPrompt(_) => "invalid_prompt",
147 Self::InvalidResponseData(_) => "invalid_response_data",
148 Self::JsonParse(_) => "json_parse",
149 Self::LoadApiKey(_) => "load_api_key",
150 Self::LoadSetting(_) => "load_setting",
151 Self::NoContentGenerated(_) => "no_content_generated",
152 Self::NoSuchModel(_) => "no_such_model",
153 Self::NoSuchProviderReference(_) => "no_such_provider_reference",
154 Self::TooManyEmbeddingValues(_) => "too_many_embedding_values",
155 Self::TypeValidation(_) => "type_validation",
156 Self::UnsupportedFunctionality(_) => "unsupported_functionality",
157 Self::Cancelled => "cancelled",
158 Self::Other(_) => "other",
159 }
160 }
161}
162
163macro_rules! boxed_from {
164 ($($variant:ident($error:ty)),* $(,)?) => {
165 $(
166 impl From<$error> for ProviderError {
167 fn from(error: $error) -> Self {
168 Self::$variant(Box::new(error))
169 }
170 }
171
172 impl From<Box<$error>> for ProviderError {
173 fn from(error: Box<$error>) -> Self {
174 Self::$variant(error)
175 }
176 }
177 )*
178 };
179}
180
181boxed_from! {
182 ApiCall(ApiCallError),
183 InvalidPrompt(InvalidPromptError),
184 InvalidResponseData(InvalidResponseDataError),
185 JsonParse(JsonParseError),
186 NoSuchModel(NoSuchModelError),
187 NoSuchProviderReference(NoSuchProviderReferenceError),
188 TooManyEmbeddingValues(TooManyEmbeddingValuesForCallError),
189}
190
191pub(crate) fn truncate_for_display(text: &str, max_bytes: usize) -> std::borrow::Cow<'_, str> {
194 if text.len() <= max_bytes {
195 return std::borrow::Cow::Borrowed(text);
196 }
197 let mut end = max_bytes;
198 while !text.is_char_boundary(end) {
199 end -= 1;
200 }
201 std::borrow::Cow::Owned(format!("{}... [truncated]", &text[..end]))
202}