use g3_core::ContextWindow; use g3_providers::{Message, MessageRole}; #[test] fn test_thinning_thresholds() { let mut context = ContextWindow::new(10000); // At 0%, should not thin assert!(!context.should_thin()); // Simulate reaching 50% usage context.used_tokens = 5000; assert!(context.should_thin()); // After thinning at 50%, should not thin again until next threshold context.last_thinning_percentage = 50; assert!(!context.should_thin()); // At 60%, should thin again context.used_tokens = 6000; assert!(context.should_thin()); // After thinning at 60%, should not thin context.last_thinning_percentage = 60; assert!(!context.should_thin()); // At 70%, should thin context.used_tokens = 7000; assert!(context.should_thin()); // At 80%, should thin context.last_thinning_percentage = 70; context.used_tokens = 8000; assert!(context.should_thin()); // After 80%, should not thin (compaction takes over) context.last_thinning_percentage = 80; context.used_tokens = 8500; assert!(!context.should_thin()); } #[test] fn test_thin_context_basic() { let mut context = ContextWindow::new(10000); // Add some messages to the first third for i in 0..9 { if i % 2 == 0 { context.add_message(Message::new( MessageRole::Assistant, format!("Assistant message {}", i), )); } else { // Add tool results with varying sizes let content = if i == 1 { // Large tool result (> 1000 chars) format!("Tool result: {}", "x".repeat(1500)) } else if i == 3 { // Another large tool result format!("Tool result: {}", "y".repeat(2000)) } else { // Small tool result (< 1000 chars) format!("Tool result: small result {}", i) }; context.add_message(Message::new(MessageRole::User, content)); } } // Trigger thinning at 50% context.used_tokens = 5000; let result = context.thin_context(None); println!("Thinning result: {:?}", result); // Should have made changes assert!(result.had_changes, "Expected thinning to make changes"); assert!(result.chars_saved > 0, "Expected chars to be saved"); // Check that the large tool results were replaced let first_third_end = context.conversation_history.len() / 3; for i in 0..first_third_end { if let Some(msg) = context.conversation_history.get(i) { if matches!(msg.role, MessageRole::User) && msg.content.starts_with("Tool result:") { if msg.content.len() > 1000 { panic!("Found un-thinned large tool result at index {}", i); } } } } } #[test] fn test_thin_write_file_tool_calls() { let mut context = ContextWindow::new(10000); // Add some messages including a write_file tool call with large content context.add_message(Message::new( MessageRole::User, "Please create a large file".to_string(), )); // Add an assistant message with a write_file tool call containing large content let large_content = "x".repeat(1500); let tool_call_json = format!( r#"{{"tool": "write_file", "args": {{"file_path": "test.txt", "content": "{}"}}}}"#, large_content ); context.add_message(Message::new( MessageRole::Assistant, format!("I'll create that file.\n\n{}", tool_call_json), )); context.add_message(Message::new( MessageRole::User, "Tool result: ✅ Successfully wrote 1500 lines".to_string(), )); // Add more messages to ensure we have enough for "first third" logic for i in 0..6 { context.add_message(Message::new( MessageRole::Assistant, format!("Response {}", i), )); } // Trigger thinning at 50% context.used_tokens = 5000; let result = context.thin_context(None); println!("Thinning result: {:?}", result); // Should have made changes assert!(result.had_changes, "Expected thinning to make changes"); assert!(result.chars_saved > 0, "Expected chars to be saved"); // Check that the large content was replaced with a file reference let first_third_end = context.conversation_history.len() / 3; for i in 0..first_third_end { if let Some(msg) = context.conversation_history.get(i) { if matches!(msg.role, MessageRole::Assistant) && msg.content.contains("write_file") { // The content should now reference an external file assert!(msg.content.contains(" 0, "Expected chars to be saved"); // Check that the large diff was replaced with a file reference let first_third_end = context.conversation_history.len() / 3; for i in 0..first_third_end { if let Some(msg) = context.conversation_history.get(i) { if matches!(msg.role, MessageRole::Assistant) && msg.content.contains("str_replace") { // The diff should now reference an external file assert!(msg.content.contains(" 1000, "Message at index {} should not have been thinned", i ); } } } } }