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 super::*;
use crate::config::models::gateway::GatewayConfig;
use crate::core::guardrails::{GuardrailAction, GuardrailEngine, PIIConfig};
use crate::core::models::openai::{ChatChoice, ContentPart};

fn response(content: MessageContent) -> crate::core::models::openai::ChatCompletionResponse {
    crate::core::models::openai::ChatCompletionResponse {
        id: "chatcmpl-test".to_string(),
        object: "chat.completion".to_string(),
        created: 0,
        model: "test-model".to_string(),
        system_fingerprint: None,
        choices: vec![ChatChoice {
            index: 0,
            message: ChatMessage {
                role: MessageRole::Assistant,
                content: Some(content),
                name: None,
                function_call: None,
                tool_calls: None,
                tool_call_id: None,
                audio: None,
            },
            logprobs: None,
            finish_reason: Some("stop".to_string()),
        }],
        usage: None,
    }
}

#[test]
fn guarded_prompt_extracts_text_parts_without_original_fallback() {
    let request = ChatCompletionRequest {
        messages: vec![ChatMessage {
            role: MessageRole::User,
            content: Some(MessageContent::Parts(vec![
                ContentPart::Text {
                    text: "first".to_string(),
                },
                ContentPart::ImageUrl {
                    image_url: crate::core::models::openai::ImageUrl {
                        url: "https://example.com/image.png".to_string(),
                        detail: None,
                    },
                },
                ContentPart::Text {
                    text: "second".to_string(),
                },
            ])),
            name: None,
            function_call: None,
            tool_calls: None,
            tool_call_id: None,
            audio: None,
        }],
        ..ChatCompletionRequest::default()
    };

    assert_eq!(
        guarded_completion_prompt(&request).expect("text parts should project"),
        "first\nsecond"
    );
}

#[tokio::test]
async fn echo_is_masked_by_the_output_policy_after_transformation() {
    let mut config = GatewayConfig::default().guardrails;
    config.check_input = false;
    config.pii = Some(PIIConfig {
        enabled: true,
        action: GuardrailAction::Mask,
        mask_pattern: Some("[MASKED]".to_string()),
        ..PIIConfig::default()
    });
    let engine = GuardrailEngine::new(config).expect("PII policy must compile");
    let echoed = chat_response_with_completion_echo(
        response(MessageContent::Text("safe response".to_string())),
        "user@example.com ",
    );

    let guarded = crate::server::guardrails::apply_output_with_engine(&engine, &echoed)
        .await
        .expect("echoed response should be masked");

    assert_eq!(
        completion_text_from_message(guarded.choices[0].message.content.as_ref(), "", false),
        "[MASKED] safe response"
    );
}