clawgarden-agent 0.2.2

Agent runtime with persona/memory loader, judge, and pi RPC for ClawGarden
Documentation
//! Loop guard tests - repetition blocking

use clawgarden_agent::loop_guard::LoopGuard;

#[test]
fn test_loop_guard_allows_first_messages() {
    let mut guard = LoopGuard::new("test_agent".to_string());
    let correlation = "corr1";
    let content = "Hello world";

    // First message should not be blocked
    assert!(!guard.should_block(correlation, content));

    // Record it
    guard.record(correlation, content);
    assert!(!guard.should_block(correlation, content));
}

#[test]
fn test_loop_guard_blocks_after_threshold() {
    let mut guard = LoopGuard::new("test_agent".to_string());
    let correlation = "corr1";
    let content = "Same message";

    // Record the same message 3 times
    guard.record(correlation, content);
    guard.record(correlation, content);

    // Should not be blocked after 2
    assert!(!guard.should_block(correlation, content));

    // After 3rd, should be blocked
    guard.record(correlation, content);
    assert!(guard.should_block(correlation, content));
}

#[test]
fn test_loop_guard_different_correlations_independent() {
    let mut guard = LoopGuard::new("test_agent".to_string());
    let content = "Same content";

    // Record 3 times in corr1
    guard.record("corr1", content);
    guard.record("corr1", content);
    guard.record("corr1", content);

    // corr1 should be blocked
    assert!(guard.should_block("corr1", content));

    // corr2 should NOT be blocked (different correlation)
    assert!(!guard.should_block("corr2", content));
}

#[test]
fn test_loop_guard_different_agents_independent() {
    let mut guard1 = LoopGuard::new("agent1".to_string());
    let guard2 = LoopGuard::new("agent2".to_string());
    let correlation = "corr1";
    let content = "Same content";

    // Record as agent1 three times
    guard1.record(correlation, content);
    guard1.record(correlation, content);
    guard1.record(correlation, content);

    // agent1 should be blocked
    assert!(guard1.should_block(correlation, content));

    // agent2 should NOT be blocked (different agent name)
    assert!(!guard2.should_block(correlation, content));
}

#[test]
fn test_loop_guard_different_content_not_blocked() {
    let mut guard = LoopGuard::new("test_agent".to_string());
    let correlation = "corr1";

    // Record 3 different messages
    guard.record(correlation, "Message 1");
    guard.record(correlation, "Message 2");
    guard.record(correlation, "Message 3");

    // None should be blocked because content is different
    assert!(!guard.should_block(correlation, "Message 1"));
    assert!(!guard.should_block(correlation, "Message 2"));
    assert!(!guard.should_block(correlation, "Message 3"));
}

#[test]
fn test_loop_guard_get_block_notice() {
    let mut guard = LoopGuard::new("test_agent".to_string());
    let correlation = "corr1";
    let content = "Repeated content";

    // Should return None when not blocked
    assert!(guard.get_block_notice(correlation, content).is_none());

    // Record 3 times
    guard.record(correlation, content);
    guard.record(correlation, content);
    guard.record(correlation, content);

    // Should return Some notice when blocked
    let notice = guard.get_block_notice(correlation, content);
    assert!(notice.is_some());
    assert!(notice.unwrap().contains("corr1"));
}

#[test]
fn test_hash_content_deterministic() {
    let h1 = LoopGuard::hash_content("hello world");
    let h2 = LoopGuard::hash_content("hello world");
    assert_eq!(h1, h2);
}

#[test]
fn test_hash_content_different_inputs() {
    let h1 = LoopGuard::hash_content("hello");
    let h2 = LoopGuard::hash_content("world");
    assert_ne!(h1, h2);
}