mcpkill 0.1.0

Universal MCP proxy — semantic cache + chunking to kill token waste
Documentation
/// Cosine similarity between two vectors.
pub fn cosine(a: &[f32], b: &[f32]) -> f32 {
    let dot: f32 = a.iter().zip(b.iter()).map(|(x, y)| x * y).sum();
    let norm_a: f32 = a.iter().map(|x| x * x).sum::<f32>().sqrt();
    let norm_b: f32 = b.iter().map(|x| x * x).sum::<f32>().sqrt();
    if norm_a == 0.0 || norm_b == 0.0 {
        return 0.0;
    }
    dot / (norm_a * norm_b)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn identical_vectors_return_one() {
        let v = vec![1.0_f32, 2.0, 3.0];
        let s = cosine(&v, &v);
        assert!((s - 1.0).abs() < 1e-5, "expected ~1.0, got {s}");
    }

    #[test]
    fn orthogonal_vectors_return_zero() {
        let a = vec![1.0_f32, 0.0, 0.0];
        let b = vec![0.0_f32, 1.0, 0.0];
        let s = cosine(&a, &b);
        assert!(s.abs() < 1e-5, "expected ~0.0, got {s}");
    }

    #[test]
    fn opposite_vectors_return_minus_one() {
        let a = vec![1.0_f32, 0.0];
        let b = vec![-1.0_f32, 0.0];
        let s = cosine(&a, &b);
        assert!((s + 1.0).abs() < 1e-5, "expected ~-1.0, got {s}");
    }

    #[test]
    fn zero_vector_returns_zero() {
        let a = vec![0.0_f32, 0.0];
        let b = vec![1.0_f32, 2.0];
        assert_eq!(cosine(&a, &b), 0.0);
        assert_eq!(cosine(&b, &a), 0.0);
    }

    #[test]
    fn similar_vectors_score_high() {
        let a = vec![1.0_f32, 1.0, 0.0];
        let b = vec![1.0_f32, 0.9, 0.1];
        let s = cosine(&a, &b);
        assert!(s > 0.98, "expected > 0.98, got {s}");
    }
}