pub use crate::ollama::OllamaError;
pub use crate::openai::responses::types::ResponsesError;
pub use crate::openai::AssistantError;
pub use crate::openai::OpenAIError;
pub use crate::providers::anthropic::error::AnthropicError;
pub use crate::providers::azure::AzureOpenAIError;
pub use crate::providers::cohere::CohereError;
pub use crate::providers::gemini::GeminiError;
#[derive(Debug)]
#[non_exhaustive]
pub enum ProviderError {
OpenAI(OpenAIError),
Anthropic(AnthropicError),
Gemini(GeminiError),
Azure(AzureOpenAIError),
Cohere(CohereError),
Ollama(OllamaError),
Assistant(AssistantError),
Responses(ResponsesError),
DeepSeek(OpenAIError),
Qwen(OpenAIError),
Moonshot(OpenAIError),
Zhipu(OpenAIError),
Mistral(OpenAIError),
OpenAICompatible {
provider: String,
source: OpenAIError,
},
Config(String),
Testkit(String),
}
impl std::fmt::Display for ProviderError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
ProviderError::OpenAI(e) => write!(f, "OpenAI error: {e}"),
ProviderError::Anthropic(e) => write!(f, "Anthropic error: {e}"),
ProviderError::Gemini(e) => write!(f, "Gemini error: {e}"),
ProviderError::Azure(e) => write!(f, "Azure OpenAI error: {e}"),
ProviderError::Cohere(e) => write!(f, "Cohere error: {e}"),
ProviderError::Ollama(e) => write!(f, "Ollama error: {e}"),
ProviderError::Assistant(e) => write!(f, "Assistant error: {e}"),
ProviderError::Responses(e) => write!(f, "Responses error: {e}"),
ProviderError::DeepSeek(e) => write!(f, "DeepSeek error: {e}"),
ProviderError::Qwen(e) => write!(f, "Qwen error: {e}"),
ProviderError::Moonshot(e) => write!(f, "Moonshot error: {e}"),
ProviderError::Zhipu(e) => write!(f, "Zhipu error: {e}"),
ProviderError::Mistral(e) => write!(f, "Mistral error: {e}"),
ProviderError::OpenAICompatible { provider, source } => {
write!(f, "{provider} (OpenAI-compatible) error: {source}")
}
ProviderError::Config(msg) => write!(f, "Configuration error: {msg}"),
ProviderError::Testkit(msg) => write!(f, "Testkit error: {msg}"),
}
}
}
impl std::error::Error for ProviderError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
ProviderError::OpenAI(e) => Some(e),
ProviderError::Anthropic(e) => Some(e),
ProviderError::Gemini(e) => Some(e),
ProviderError::Azure(e) => Some(e),
ProviderError::Cohere(e) => Some(e),
ProviderError::Ollama(e) => Some(e),
ProviderError::Assistant(e) => Some(e),
ProviderError::Responses(e) => Some(e),
ProviderError::DeepSeek(e) => Some(e),
ProviderError::Qwen(e) => Some(e),
ProviderError::Moonshot(e) => Some(e),
ProviderError::Zhipu(e) => Some(e),
ProviderError::Mistral(e) => Some(e),
ProviderError::OpenAICompatible { source, .. } => Some(source),
ProviderError::Config(_) => None,
ProviderError::Testkit(_) => None,
}
}
}
impl From<OpenAIError> for ProviderError {
fn from(e: OpenAIError) -> Self {
ProviderError::OpenAI(e)
}
}
impl From<AnthropicError> for ProviderError {
fn from(e: AnthropicError) -> Self {
ProviderError::Anthropic(e)
}
}
impl From<GeminiError> for ProviderError {
fn from(e: GeminiError) -> Self {
ProviderError::Gemini(e)
}
}
impl From<OllamaError> for ProviderError {
fn from(e: OllamaError) -> Self {
ProviderError::Ollama(e)
}
}
impl From<AssistantError> for ProviderError {
fn from(e: AssistantError) -> Self {
ProviderError::Assistant(e)
}
}
impl From<ResponsesError> for ProviderError {
fn from(e: ResponsesError) -> Self {
ProviderError::Responses(e)
}
}
impl From<AzureOpenAIError> for ProviderError {
fn from(e: AzureOpenAIError) -> Self {
ProviderError::Azure(e)
}
}
impl From<CohereError> for ProviderError {
fn from(e: CohereError) -> Self {
ProviderError::Cohere(e)
}
}
impl From<String> for ProviderError {
fn from(msg: String) -> Self {
ProviderError::Testkit(msg)
}
}
impl From<ProviderError> for lc_core::LcelError {
fn from(err: ProviderError) -> Self {
lc_core::LcelError::Provider(err.to_string())
}
}
impl From<OpenAIError> for lc_core::LcelError {
fn from(err: OpenAIError) -> Self {
lc_core::LcelError::Provider(err.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn openai_error_into_lcel_error() {
let e = OpenAIError::Api("rate limited".to_string());
let lcel: lc_core::LcelError = e.into();
assert!(matches!(
lcel,
lc_core::LcelError::Provider(ref msg) if msg.contains("API error: rate limited")
));
}
#[test]
fn qwen_provider_error_into_lcel_error() {
let e = ProviderError::Qwen(OpenAIError::Http("timeout".to_string()));
let lcel: lc_core::LcelError = e.into();
assert!(matches!(
lcel,
lc_core::LcelError::Provider(ref msg) if msg.contains("Qwen error") && msg.contains("timeout")
));
}
#[test]
fn deepseek_provider_error_into_lcel_error() {
let e = ProviderError::DeepSeek(OpenAIError::Parse("bad json".to_string()));
let lcel: lc_core::LcelError = e.into();
assert!(matches!(
lcel,
lc_core::LcelError::Provider(ref msg) if msg.contains("DeepSeek error")
));
}
#[test]
fn openai_compatible_error_label_and_source() {
let e = ProviderError::OpenAICompatible {
provider: "groq".to_string(),
source: OpenAIError::Api("HTTP 429: slow down".to_string()),
};
let text = e.to_string();
assert!(text.contains("groq"), "{text}");
assert!(text.contains("OpenAI-compatible"), "{text}");
assert!(text.contains("429"), "{text}");
assert!(std::error::Error::source(&e).is_some());
let lcel: lc_core::LcelError = e.into();
assert!(matches!(
lcel,
lc_core::LcelError::Provider(ref msg) if msg.contains("groq")
));
}
}