llmproxy 0.2.2

A simple HTTP proxy server for llm api requests
Documentation
use crate::metrics::calculate_ucb_score;
use crate::state::ProxyServer;

/// Adaptive load balancer using UCB (Upper Confidence Bound) algorithm
/// This is a multi-armed bandit approach that balances exploration and exploitation
///
/// Advantages over weighted random:
/// - Automatically explores underutilized servers
/// - Adapts to changing server performance
/// - Reduces oscillation by considering uncertainty
/// - Theoretical guarantees on regret bounds
pub fn select_server_adaptive<'a>(servers: &'a [&ProxyServer]) -> &'a ProxyServer {
    if servers.is_empty() {
        panic!("Cannot select from empty server list");
    }

    if servers.len() == 1 {
        return servers[0];
    }

    // Calculate total requests across all servers for UCB formula
    let total_requests: u64 = servers.iter().map(|s| s.metrics.total_requests).sum();

    // UCB exploration parameter
    // - Higher c = more exploration (try different servers)
    // - Lower c = more exploitation (prefer best known server)
    // Recommended range: 1.0-2.0
    const UCB_C: f64 = 1.5;

    // Find server with highest UCB score
    let best_server = servers
        .iter()
        .max_by(|a, b| {
            let score_a = calculate_ucb_score(a, total_requests, UCB_C);
            let score_b = calculate_ucb_score(b, total_requests, UCB_C);
            score_a
                .partial_cmp(&score_b)
                .unwrap_or(std::cmp::Ordering::Equal)
        })
        .unwrap();

    best_server
}

/// Find all servers that serve the specified model
pub fn find_servers_for_model<'a>(
    all_servers: &'a [ProxyServer],
    model_name: &str,
) -> Vec<&'a ProxyServer> {
    all_servers
        .iter()
        .filter(|server| server.model_name == model_name)
        .collect()
}