mod api_call;
mod config;
mod data;
mod model;
use http::StatusCode;
pub use api_call::ApiCallError;
pub use api_call::default_retryable;
pub use config::InvalidArgumentError;
pub use config::InvalidPromptError;
pub use config::LoadApiKeyError;
pub use config::LoadSettingError;
pub use data::EmptyResponseBodyError;
pub use data::InvalidResponseDataError;
pub use data::JsonParseError;
pub use data::NoContentGeneratedError;
pub use data::TypeValidationContext;
pub use data::TypeValidationError;
pub use model::ModelKind;
pub use model::NoSuchModelError;
pub use model::NoSuchProviderReferenceError;
pub use model::TooManyEmbeddingValuesForCallError;
pub use model::UnsupportedFunctionalityError;
pub type BoxError = Box<dyn std::error::Error + Send + Sync>;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum ProviderError {
#[error(transparent)]
ApiCall(Box<ApiCallError>),
#[error(transparent)]
EmptyResponseBody(#[from] EmptyResponseBodyError),
#[error(transparent)]
InvalidArgument(#[from] InvalidArgumentError),
#[error(transparent)]
InvalidPrompt(Box<InvalidPromptError>),
#[error(transparent)]
InvalidResponseData(Box<InvalidResponseDataError>),
#[error(transparent)]
JsonParse(Box<JsonParseError>),
#[error(transparent)]
LoadApiKey(#[from] LoadApiKeyError),
#[error(transparent)]
LoadSetting(#[from] LoadSettingError),
#[error(transparent)]
NoContentGenerated(#[from] NoContentGeneratedError),
#[error(transparent)]
NoSuchModel(Box<NoSuchModelError>),
#[error(transparent)]
NoSuchProviderReference(Box<NoSuchProviderReferenceError>),
#[error(transparent)]
TooManyEmbeddingValues(Box<TooManyEmbeddingValuesForCallError>),
#[error(transparent)]
TypeValidation(#[from] TypeValidationError),
#[error(transparent)]
UnsupportedFunctionality(#[from] UnsupportedFunctionalityError),
#[error("operation cancelled")]
Cancelled,
#[error(transparent)]
Other(#[from] BoxError),
}
impl ProviderError {
#[must_use]
pub fn other(error: impl std::error::Error + Send + Sync + 'static) -> Self {
Self::Other(Box::new(error))
}
#[must_use]
pub fn message(message: impl Into<String>) -> Self {
Self::Other(message.into().into())
}
#[must_use]
pub fn unsupported(functionality: impl Into<String>) -> Self {
Self::UnsupportedFunctionality(UnsupportedFunctionalityError::new(functionality))
}
#[must_use]
pub fn is_retryable(&self) -> bool {
match self {
Self::ApiCall(error) => error.is_retryable,
_ => false,
}
}
#[must_use]
pub fn status_code(&self) -> Option<StatusCode> {
match self {
Self::ApiCall(error) => error.status_code,
_ => None,
}
}
#[must_use]
pub fn as_api_call(&self) -> Option<&ApiCallError> {
match self {
Self::ApiCall(error) => Some(error),
_ => None,
}
}
#[must_use]
pub fn kind_name(&self) -> &'static str {
match self {
Self::ApiCall(_) => "api_call",
Self::EmptyResponseBody(_) => "empty_response_body",
Self::InvalidArgument(_) => "invalid_argument",
Self::InvalidPrompt(_) => "invalid_prompt",
Self::InvalidResponseData(_) => "invalid_response_data",
Self::JsonParse(_) => "json_parse",
Self::LoadApiKey(_) => "load_api_key",
Self::LoadSetting(_) => "load_setting",
Self::NoContentGenerated(_) => "no_content_generated",
Self::NoSuchModel(_) => "no_such_model",
Self::NoSuchProviderReference(_) => "no_such_provider_reference",
Self::TooManyEmbeddingValues(_) => "too_many_embedding_values",
Self::TypeValidation(_) => "type_validation",
Self::UnsupportedFunctionality(_) => "unsupported_functionality",
Self::Cancelled => "cancelled",
Self::Other(_) => "other",
}
}
}
macro_rules! boxed_from {
($($variant:ident($error:ty)),* $(,)?) => {
$(
impl From<$error> for ProviderError {
fn from(error: $error) -> Self {
Self::$variant(Box::new(error))
}
}
impl From<Box<$error>> for ProviderError {
fn from(error: Box<$error>) -> Self {
Self::$variant(error)
}
}
)*
};
}
boxed_from! {
ApiCall(ApiCallError),
InvalidPrompt(InvalidPromptError),
InvalidResponseData(InvalidResponseDataError),
JsonParse(JsonParseError),
NoSuchModel(NoSuchModelError),
NoSuchProviderReference(NoSuchProviderReferenceError),
TooManyEmbeddingValues(TooManyEmbeddingValuesForCallError),
}
pub(crate) fn truncate_for_display(text: &str, max_bytes: usize) -> std::borrow::Cow<'_, str> {
if text.len() <= max_bytes {
return std::borrow::Cow::Borrowed(text);
}
let mut end = max_bytes;
while !text.is_char_boundary(end) {
end -= 1;
}
std::borrow::Cow::Owned(format!("{}... [truncated]", &text[..end]))
}