litellm-rs 0.4.16

A high-performance AI Gateway written in Rust, providing OpenAI-compatible APIs with intelligent routing, load balancing, and enterprise features
Documentation
//! Custom HTTPX Provider Implementation

crate::define_http_provider_with_hooks!(
    provider: super::PROVIDER_NAME,
    struct_name: CustomHttpxProvider,
    config: super::config::CustomHttpxConfig,
    error_mapper: super::error_mapper::CustomApiErrorMapper,
    model_info: super::model_info::get_supported_models,
    capabilities: &[
        crate::core::types::model::ProviderCapability::ChatCompletion,
        crate::core::types::model::ProviderCapability::ChatCompletionStream,
    ],
    url_builder: |provider: &CustomHttpxProvider| -> String { provider.config.endpoint_url.clone() },
    request_builder: |provider: &CustomHttpxProvider, url: &str| -> reqwest::RequestBuilder {
        match provider.config.http_method.to_uppercase().as_str() {
            "GET" => provider.http_client.get(url),
            "POST" => provider.http_client.post(url),
            "PUT" => provider.http_client.put(url),
            _ => provider.http_client.post(url),
        }
    },
    supported_params: ["temperature", "max_tokens", "top_p", "stream", "stop"],
    build_headers: |provider: &CustomHttpxProvider,
                    headers: &mut std::collections::HashMap<String, String>| {
        if let Some(api_key) = &provider.config.base.api_key {
            headers.insert("Authorization".to_string(), format!("Bearer {}", api_key));
        }

        headers.insert("Content-Type".to_string(), "application/json".to_string());
    },
    with_api_key: |api_key: String| -> Result<CustomHttpxProvider, crate::core::providers::unified_provider::ProviderError> {
        let _ = api_key;
        Err(crate::core::providers::unified_provider::ProviderError::not_supported(
            "custom_httpx",
            "with_api_key is not supported; use with_endpoint",
        ))
    },
    request_transform: |provider: &CustomHttpxProvider,
                        request: crate::core::types::chat::ChatRequest|
     -> Result<serde_json::Value, crate::core::providers::unified_provider::ProviderError> {
        if let Some(template) = &provider.config.request_template {
            let req_str = template.replace("{model}", &request.model).replace(
                "{messages}",
                &serde_json::to_string(&request.messages).map_err(|e| {
                    crate::core::providers::unified_provider::ProviderError::serialization(
                        "custom_httpx",
                        e.to_string(),
                    )
                })?,
            );

            serde_json::from_str(&req_str).map_err(|e| {
                crate::core::providers::unified_provider::ProviderError::serialization(
                    "custom_httpx",
                    e.to_string(),
                )
            })
        } else {
            let mut req = serde_json::json!({
                "model": request.model,
                "messages": request.messages,
            });

            if let Some(max_tokens) = request.max_tokens {
                req["max_tokens"] = serde_json::Value::Number(max_tokens.into());
            }

            if let Some(temperature) = request.temperature {
                req["temperature"] = serde_json::to_value(temperature).map_err(|e| {
                    crate::core::providers::unified_provider::ProviderError::serialization(
                        "custom_httpx",
                        e.to_string(),
                    )
                })?;
            }

            Ok(req)
        }
    },
    response_transform: |_provider: &CustomHttpxProvider,
                         raw_response: &[u8],
                         _model: &str,
                         _request_id: &str|
     -> Result<crate::core::types::responses::ChatResponse, crate::core::providers::unified_provider::ProviderError> {
        let response_text = String::from_utf8_lossy(raw_response);
        let response: crate::core::types::responses::ChatResponse =
            serde_json::from_str(&response_text).map_err(|e| {
                crate::core::providers::unified_provider::ProviderError::serialization(
                    "custom_httpx",
                    e.to_string(),
                )
            })?;
        Ok(response)
    },
    error_map: |_provider: &CustomHttpxProvider,
                status: u16,
                error_text: String,
                request: &crate::core::types::chat::ChatRequest|
     -> crate::core::providers::unified_provider::ProviderError {
        match status {
            401 => crate::core::providers::unified_provider::ProviderError::authentication(
                "custom_httpx",
                error_text,
            ),
            429 => crate::core::providers::unified_provider::ProviderError::rate_limit(
                "custom_httpx",
                None,
            ),
            404 => crate::core::providers::unified_provider::ProviderError::model_not_found(
                "custom_httpx",
                request.model.as_str(),
            ),
            _ => crate::core::providers::base::HttpErrorMapper::map_status_code(
                "custom_httpx",
                status,
                &error_text,
            ),
        }
    },
    health_check: |_provider: &CustomHttpxProvider| async {
        crate::core::types::health::HealthStatus::Healthy
    },
    streaming_error: "Streaming not yet implemented",
);

impl CustomHttpxProvider {
    pub fn with_endpoint(
        endpoint_url: impl Into<String>,
    ) -> Result<Self, crate::core::providers::unified_provider::ProviderError> {
        let config = super::config::CustomHttpxConfig::new(endpoint_url);
        Self::new(config)
    }
}