Skip to main content
Glama
8b-is
by 8b-is
test_partnership.rs14.7 kB
//! Tests for AI-Human Partnership Features //! //! "You're easy to work with. You just get me." - Let's make sure this actually works! use chrono::{DateTime, Duration, Utc}; use st::context_gatherer::{ collab_session::{AnchorType, CollaborativeOrigin, CollaborativeSessionTracker, SessionType}, cross_session::{CrossSessionBridge, PatternType}, partnership::PartnershipAnalyzer, ContextContent, ContextGatherer, ContextType, GatherConfig, GatheredContext, }; use std::collections::HashMap; use std::path::PathBuf; /// Create a test context with specific properties fn create_test_context( timestamp: DateTime<Utc>, ai_tool: &str, content_type: ContextType, role_pattern: &str, ) -> GatheredContext { let content = if role_pattern == "tandem" { ContextContent::Json(serde_json::json!({ "messages": [ {"role": "user", "content": "Let's work on this together"}, {"role": "assistant", "content": "I'd be happy to help! The task is now complete and works perfectly."} ] })) } else if role_pattern == "user_only" { ContextContent::Json(serde_json::json!({ "messages": [ {"role": "user", "content": "Working on my own here"} ] })) } else { ContextContent::Json(serde_json::json!({ "messages": [ {"role": "assistant", "content": "Processing in the background"} ] })) }; GatheredContext { source_path: PathBuf::from(format!("~/{}/test.json", ai_tool)), ai_tool: ai_tool.to_string(), content_type, content, metadata: HashMap::new(), relevance_score: 0.8, timestamp, } } #[test] fn test_collaborative_session_detection() { let mut tracker = CollaborativeSessionTracker::new(); let now = Utc::now(); // Test 1: Solo human session let context1 = create_test_context(now, "claude", ContextType::ChatHistory, "user_only"); tracker.process_context(&context1).unwrap(); assert!(tracker.active_session.is_some()); let session = tracker.active_session.as_ref().unwrap(); assert_eq!(session.session_type, SessionType::SoloHuman); // Test 2: Transition to tandem let context2 = create_test_context( now + Duration::minutes(2), "claude", ContextType::ChatHistory, "tandem", ); tracker.process_context(&context2).unwrap(); let session = tracker.active_session.as_ref().unwrap(); assert_eq!(session.session_type, SessionType::Tandem); assert_eq!(session.interactions.len(), 1); // New session started due to type change // Test 3: New session after 30+ minute gap let context3 = create_test_context( now + Duration::minutes(35), "claude", ContextType::ChatHistory, "tandem", ); tracker.process_context(&context3).unwrap(); assert_eq!(tracker.session_history.len(), 2); // Two previous sessions ended (SoloHuman + Tandem) let new_session = tracker.active_session.as_ref().unwrap(); assert_eq!(new_session.interactions.len(), 1); // Fresh start } #[test] fn test_flow_state_detection() { let mut tracker = CollaborativeSessionTracker::new(); let now = Utc::now(); // Create rapid back-and-forth (flow state) for i in 0..8 { let context = create_test_context( now + Duration::seconds(30 * i), "claude", ContextType::ChatHistory, "tandem", ); tracker.process_context(&context).unwrap(); } let session = tracker.active_session.as_ref().unwrap(); match &session.flow_state { st::context_gatherer::collab_session::FlowState::Flow { depth, sustained_minutes, } => { assert!(*depth > 0.5); assert!(*sustained_minutes > 0); } _ => panic!("Expected flow state, got {:?}", session.flow_state), } } #[test] fn test_memory_anchoring() { let mut tracker = CollaborativeSessionTracker::new(); // Anchor a collaborative insight let anchor_id = tracker .anchor_memory( CollaborativeOrigin::Tandem { human: "hue".to_string(), ai: "claude".to_string(), }, AnchorType::Solution, "We solved the wave grid dimension issue by separating sensor values".to_string(), vec!["wave".to_string(), "grid".to_string(), "sensor".to_string()], ) .unwrap(); assert!(!anchor_id.is_empty()); // Test retrieval let found = tracker.find_relevant_anchors(&["wave".to_string(), "grid".to_string()]); assert_eq!(found.len(), 1); assert_eq!(found[0].anchor_type, AnchorType::Solution); assert!(found[0].co_created); } #[test] fn test_rapport_index_evolution() { let mut tracker = CollaborativeSessionTracker::new(); let now = Utc::now(); // Simulate multiple successful sessions for day in 0..5 { for hour in 0..3 { let context = create_test_context( now + Duration::days(day) + Duration::hours(hour * 2), "claude", ContextType::ChatHistory, "tandem", ); tracker.process_context(&context).unwrap(); } // End session for the day if tracker.active_session.take().is_some() { tracker.end_active_session(); } } let rapport = tracker.get_rapport("claude").unwrap(); assert!(rapport.overall_score > 0.5); assert!(rapport.trust_level > 0.0); assert!(rapport.evolution_trend >= 0.0); // Should be stable or improving } #[test] fn test_cross_domain_patterns() { let mut bridge = CrossSessionBridge::new(); let now = Utc::now(); // Create contexts with wave decay pattern in different projects let contexts = vec![ GatheredContext { source_path: PathBuf::from("/project1/analysis.json"), ai_tool: "claude".to_string(), content_type: ContextType::CodeSnippets, content: ContextContent::Text( "Implementing wave decay algorithm for memory fadeout".to_string(), ), metadata: HashMap::new(), relevance_score: 0.9, timestamp: now, }, GatheredContext { source_path: PathBuf::from("/project2/memory.json"), ai_tool: "cursor".to_string(), content_type: ContextType::CodeSnippets, content: ContextContent::Text( "Using wave decay pattern for temporal memory".to_string(), ), metadata: HashMap::new(), relevance_score: 0.85, timestamp: now + Duration::days(2), }, GatheredContext { source_path: PathBuf::from("/project3/audio.json"), ai_tool: "windsurf".to_string(), content_type: ContextType::CodeSnippets, content: ContextContent::Text( "Applied wave decay to audio signal processing".to_string(), ), metadata: HashMap::new(), relevance_score: 0.8, timestamp: now + Duration::days(5), }, ]; let _new_patterns = bridge.analyze_for_patterns(&contexts); // Get all patterns from the bridge let all_patterns: Vec<_> = bridge.patterns.values().collect(); assert!(!all_patterns.is_empty()); // Should recognize wave decay as a cross-domain pattern let wave_pattern = all_patterns .iter() .find(|p| p.description.contains("Wave decay")) .expect("Should find wave decay pattern"); assert_eq!(wave_pattern.pattern_type, PatternType::Algorithm); assert_eq!(wave_pattern.occurrences.len(), 3); assert!(wave_pattern.strength > 0.0); } #[test] fn test_partnership_analysis() { let now = Utc::now(); let contexts = vec![ // Productive tandem session create_test_context(now, "claude", ContextType::ChatHistory, "tandem"), create_test_context( now + Duration::minutes(5), "claude", ContextType::ChatHistory, "tandem", ), create_test_context( now + Duration::minutes(10), "claude", ContextType::ChatHistory, "tandem", ), // Learning moment GatheredContext { source_path: PathBuf::from("~/.claude/learning.json"), ai_tool: "claude".to_string(), content_type: ContextType::ChatHistory, content: ContextContent::Json(serde_json::json!({ "messages": [ {"role": "user", "content": "What's a monad?"}, {"role": "assistant", "content": "A monad is a design pattern..."} ] })), metadata: HashMap::new(), relevance_score: 0.9, timestamp: now + Duration::minutes(15), }, ]; let analyzer = PartnershipAnalyzer::new(contexts); let analysis = analyzer.analyze_partnership(); assert!(analysis.total_interactions > 0); assert!(!analysis.collaborative_sessions.is_empty()); assert!(analysis.collaboration_metrics.productivity_rate > 0.0); assert!(analysis.collaboration_metrics.learning_rate > 0.0); // With completion messages, the partnership might be "Thriving" or "Healthy" assert!(["Thriving", "Healthy", "Developing"] .contains(&analysis.partnership_health.status.as_str())); assert!(!analysis.recommendations.is_empty()); } #[test] fn test_co_engagement_heatmap() { use st::context_gatherer::collab_session::CoEngagementHeatmap; let mut tracker = CollaborativeSessionTracker::new(); let now = Utc::now(); // Create tandem sessions at specific times for day in 0..7 { // Create date at start of day, then add hours for specific times let base_date = (now - Duration::days(day)) .date_naive() .and_hms_opt(0, 0, 0) .unwrap() .and_utc(); // Morning session (9 AM) let morning = base_date + Duration::hours(9); let context = create_test_context(morning, "claude", ContextType::ChatHistory, "tandem"); tracker.process_context(&context).unwrap(); // End morning session properly before starting afternoon tracker.end_active_session(); // Afternoon session (2 PM) let afternoon = base_date + Duration::hours(14); let context = create_test_context(afternoon, "claude", ContextType::ChatHistory, "tandem"); tracker.process_context(&context).unwrap(); // End afternoon session tracker.end_active_session(); } let sessions: Vec<_> = tracker.session_history.iter().cloned().collect(); let heatmap = CoEngagementHeatmap::from_sessions(&sessions); assert!(!heatmap.peak_collaboration_zones.is_empty()); assert!(heatmap.collaboration_density > 0.0); // Should identify 9 AM and 2 PM as peak zones let has_morning_peak = heatmap .peak_collaboration_zones .iter() .any(|(hour, _)| *hour == 9); let has_afternoon_peak = heatmap .peak_collaboration_zones .iter() .any(|(hour, _)| *hour == 14); assert!(has_morning_peak || has_afternoon_peak); } #[test] fn test_persona_invitation() { let bridge = CrossSessionBridge::new(); // Test performance-related context let invitation = bridge .invite_persona("Need to optimize the wave calculation performance", 15) .unwrap(); assert_eq!(invitation.persona_name, "The Cheet"); assert!(invitation .expertise_areas .contains(&"Performance optimization".to_string())); assert_eq!(invitation.suggested_duration_minutes, 15); // Test wave-related context let invitation = bridge .invite_persona("Exploring wave interference patterns in memory", 10) .unwrap(); assert_eq!(invitation.persona_name, "Omni"); assert!(invitation .expertise_areas .contains(&"Wave-based thinking".to_string())); } #[test] fn test_insight_generation() { let mut bridge = CrossSessionBridge::new(); let now = Utc::now(); // Create enough occurrences to generate insights let contexts: Vec<_> = (0..5) .map(|i| GatheredContext { source_path: PathBuf::from(format!("/project{}/code.rs", i)), ai_tool: "claude".to_string(), content_type: ContextType::CodeSnippets, content: ContextContent::Text("Using observer pattern for event handling".to_string()), metadata: HashMap::new(), relevance_score: 0.8, timestamp: now + Duration::days(i), }) .collect(); bridge.analyze_for_patterns(&contexts); let insights = bridge.generate_insights(0.1); assert!(!insights.is_empty()); let insight = &insights[0]; assert!(insight.content.contains("appears across")); assert!(insight.content.contains("different contexts")); assert_eq!(insight.source_sessions.len(), 5); } #[cfg(test)] mod integration_tests { use super::*; #[test] fn test_full_context_gathering_flow() { let project_path = PathBuf::from("/tmp/test_project"); let config = GatherConfig { search_dirs: vec![".claude".to_string()], custom_dirs: vec![], extensions: vec!["json".to_string()], project_identifiers: vec!["test_project".to_string()], max_file_size: 1024 * 1024, recursive: true, privacy_mode: true, }; let mut gatherer = ContextGatherer::new(project_path, config); // Even without actual files, we can test the structure assert_eq!(gatherer.contexts().len(), 0); // Test memory anchoring through gatherer let anchor_id = gatherer .anchor_memory( CollaborativeOrigin::Single("human".to_string()), AnchorType::PatternInsight, "Testing is essential for reliability".to_string(), vec!["testing".to_string(), "reliability".to_string()], ) .unwrap(); assert!(!anchor_id.is_empty()); // Test memory retrieval let memories = gatherer.find_relevant_memories(&["testing".to_string()]); assert_eq!(memories.len(), 1); assert!(memories[0].contains("Pattern")); assert!(memories[0].contains("Testing is essential")); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/8b-is/smart-tree'

If you have feedback or need assistance with the MCP directory API, please join our Discord server