litellm-rs 0.8.2

A high-performance AI Gateway written in Rust, providing OpenAI-compatible APIs with intelligent routing, load balancing, and enterprise features
Documentation
use crate::core::providers::unified_provider::ProviderError;

use super::types::{ErrorCategory, ErrorUtils};

impl ErrorUtils {
    pub fn format_error_for_user(error: &ProviderError) -> String {
        match error {
            ProviderError::Authentication { message, .. } => {
                format!("Authentication failed: {}", message)
            }
            ProviderError::InvalidRequest { message, .. } => {
                format!("Request validation failed: {}", message)
            }
            ProviderError::RateLimit { message, .. } => {
                format!("Rate limit exceeded: {}", message)
            }
            ProviderError::QuotaExceeded { message, .. } => {
                format!("Quota exceeded: {}", message)
            }
            ProviderError::ModelNotFound { model, .. } => {
                format!("Model not supported: {}", model)
            }
            ProviderError::Timeout { message, .. } => {
                format!("Request timeout: {}", message)
            }
            ProviderError::Other { message, .. } => {
                format!("Provider error: {}", message)
            }
            ProviderError::Network { message, .. } => {
                format!("Network error: {}", message)
            }
            ProviderError::ProviderUnavailable { message, .. } => {
                format!("Provider unavailable: {}", message)
            }
            ProviderError::Serialization { message, .. } => {
                format!("Parsing error: {}", message)
            }
            _ => {
                format!("Provider error: {}", error)
            }
        }
    }

    pub fn get_error_category(error: &ProviderError) -> ErrorCategory {
        match error {
            ProviderError::InvalidRequest { .. } => ErrorCategory::ClientError,
            ProviderError::Authentication { .. } => ErrorCategory::ClientError,
            ProviderError::ModelNotFound { .. } => ErrorCategory::ClientError,
            ProviderError::RateLimit { .. } => ErrorCategory::TransientError,
            ProviderError::QuotaExceeded { .. } => ErrorCategory::ClientError,
            ProviderError::Network { .. } => ErrorCategory::TransientError,
            ProviderError::Timeout { .. } => ErrorCategory::TransientError,
            ProviderError::ProviderUnavailable { .. } => ErrorCategory::TransientError,
            ProviderError::Configuration { .. } => ErrorCategory::PermanentError,
            ProviderError::NotSupported { .. } => ErrorCategory::PermanentError,
            ProviderError::NotImplemented { .. } => ErrorCategory::PermanentError,
            _ => ErrorCategory::ServerError,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::core::providers::unified_provider::ProviderError;

    #[test]
    fn test_format_error_for_user_authentication() {
        let error = ProviderError::Authentication {
            provider: "openai",
            message: "Invalid API key".to_string(),
        };
        let formatted = ErrorUtils::format_error_for_user(&error);
        assert_eq!(formatted, "Authentication failed: Invalid API key");
    }

    #[test]
    fn test_format_error_for_user_invalid_request() {
        let error = ProviderError::InvalidRequest {
            provider: "openai",
            message: "Missing required field".to_string(),
        };
        let formatted = ErrorUtils::format_error_for_user(&error);
        assert_eq!(
            formatted,
            "Request validation failed: Missing required field"
        );
    }

    #[test]
    fn test_format_error_for_user_rate_limit() {
        let error = ProviderError::RateLimit {
            provider: "openai",
            message: "Too many requests".to_string(),
            retry_after: Some(60),
            rpm_limit: None,
            tpm_limit: None,
            current_usage: None,
        };
        let formatted = ErrorUtils::format_error_for_user(&error);
        assert_eq!(formatted, "Rate limit exceeded: Too many requests");
    }

    #[test]
    fn test_format_error_for_user_quota_exceeded() {
        let error = ProviderError::QuotaExceeded {
            provider: "openai",
            message: "Monthly quota exceeded".to_string(),
        };
        let formatted = ErrorUtils::format_error_for_user(&error);
        assert_eq!(formatted, "Quota exceeded: Monthly quota exceeded");
    }

    #[test]
    fn test_format_error_for_user_model_not_found() {
        let error = ProviderError::ModelNotFound {
            provider: "openai",
            model: "gpt-unknown".to_string(),
        };
        let formatted = ErrorUtils::format_error_for_user(&error);
        assert_eq!(formatted, "Model not supported: gpt-unknown");
    }

    #[test]
    fn test_format_error_for_user_timeout() {
        let error = ProviderError::Timeout {
            provider: "openai",
            message: "Request timed out after 30s".to_string(),
        };
        let formatted = ErrorUtils::format_error_for_user(&error);
        assert_eq!(formatted, "Request timeout: Request timed out after 30s");
    }

    #[test]
    fn test_format_error_for_user_network() {
        let error = ProviderError::Network {
            provider: "openai",
            message: "Connection refused".to_string(),
        };
        let formatted = ErrorUtils::format_error_for_user(&error);
        assert_eq!(formatted, "Network error: Connection refused");
    }

    #[test]
    fn test_format_error_for_user_provider_unavailable() {
        let error = ProviderError::ProviderUnavailable {
            provider: "openai",
            message: "Service is down".to_string(),
        };
        let formatted = ErrorUtils::format_error_for_user(&error);
        assert_eq!(formatted, "Provider unavailable: Service is down");
    }

    #[test]
    fn test_format_error_for_user_serialization() {
        let error = ProviderError::Serialization {
            provider: "openai",
            message: "Failed to parse JSON".to_string(),
        };
        let formatted = ErrorUtils::format_error_for_user(&error);
        assert_eq!(formatted, "Parsing error: Failed to parse JSON");
    }

    #[test]
    fn test_format_error_for_user_other() {
        let error = ProviderError::Other {
            provider: "openai",
            message: "Unknown error".to_string(),
        };
        let formatted = ErrorUtils::format_error_for_user(&error);
        assert_eq!(formatted, "Provider error: Unknown error");
    }

    #[test]
    fn test_get_error_category_client_errors() {
        assert_eq!(
            ErrorUtils::get_error_category(&ProviderError::InvalidRequest {
                provider: "test",
                message: "test".to_string()
            }),
            ErrorCategory::ClientError
        );
        assert_eq!(
            ErrorUtils::get_error_category(&ProviderError::Authentication {
                provider: "test",
                message: "test".to_string()
            }),
            ErrorCategory::ClientError
        );
        assert_eq!(
            ErrorUtils::get_error_category(&ProviderError::ModelNotFound {
                provider: "test",
                model: "test".to_string()
            }),
            ErrorCategory::ClientError
        );
        assert_eq!(
            ErrorUtils::get_error_category(&ProviderError::QuotaExceeded {
                provider: "test",
                message: "test".to_string()
            }),
            ErrorCategory::ClientError
        );
    }

    #[test]
    fn test_get_error_category_transient_errors() {
        assert_eq!(
            ErrorUtils::get_error_category(&ProviderError::RateLimit {
                provider: "test",
                message: "test".to_string(),
                retry_after: None,
                rpm_limit: None,
                tpm_limit: None,
                current_usage: None,
            }),
            ErrorCategory::TransientError
        );
        assert_eq!(
            ErrorUtils::get_error_category(&ProviderError::Network {
                provider: "test",
                message: "test".to_string()
            }),
            ErrorCategory::TransientError
        );
        assert_eq!(
            ErrorUtils::get_error_category(&ProviderError::Timeout {
                provider: "test",
                message: "test".to_string()
            }),
            ErrorCategory::TransientError
        );
        assert_eq!(
            ErrorUtils::get_error_category(&ProviderError::ProviderUnavailable {
                provider: "test",
                message: "test".to_string()
            }),
            ErrorCategory::TransientError
        );
    }

    #[test]
    fn test_get_error_category_permanent_errors() {
        assert_eq!(
            ErrorUtils::get_error_category(&ProviderError::Configuration {
                provider: "test",
                message: "test".to_string()
            }),
            ErrorCategory::PermanentError
        );
        assert_eq!(
            ErrorUtils::get_error_category(&ProviderError::NotSupported {
                provider: "test",
                feature: "test".to_string()
            }),
            ErrorCategory::PermanentError
        );
        assert_eq!(
            ErrorUtils::get_error_category(&ProviderError::NotImplemented {
                provider: "test",
                feature: "test".to_string()
            }),
            ErrorCategory::PermanentError
        );
    }

    #[test]
    fn test_get_error_category_server_error_default() {
        assert_eq!(
            ErrorUtils::get_error_category(&ProviderError::Other {
                provider: "test",
                message: "test".to_string()
            }),
            ErrorCategory::ServerError
        );
    }
}