add context window monitor
Writes the current context window to logs/current_context_window (uses a symlink to a session ID). This PR was unfortunately generated by a different LLM and did a ton of superficial reformating, it's actually a fairly small and benign change, but I don't want to roll back everything. Hope that's ok.
This commit is contained in:
@@ -4,35 +4,35 @@ 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;
|
||||
@@ -42,7 +42,7 @@ fn test_thinning_thresholds() {
|
||||
#[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 {
|
||||
@@ -62,24 +62,25 @@ fn test_thin_context_basic() {
|
||||
// Small tool result (< 1000 chars)
|
||||
format!("Tool result: small result {}", i)
|
||||
};
|
||||
|
||||
context.add_message(Message::new(
|
||||
MessageRole::User,
|
||||
content,
|
||||
));
|
||||
|
||||
context.add_message(Message::new(MessageRole::User, content));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Trigger thinning at 50%
|
||||
context.used_tokens = 5000;
|
||||
let (summary, _chars_saved) = context.thin_context();
|
||||
|
||||
|
||||
println!("Thinning summary: {}", summary);
|
||||
|
||||
|
||||
// Should have thinned at least 1 large tool result in the first third
|
||||
assert!(summary.contains("1 tool result"), "Summary was: {}", summary);
|
||||
assert!(
|
||||
summary.contains("1 tool result"),
|
||||
"Summary was: {}",
|
||||
summary
|
||||
);
|
||||
assert!(summary.contains("50%"));
|
||||
|
||||
|
||||
// Check that the large tool results were replaced
|
||||
let first_third_end = context.conversation_history.len() / 3;
|
||||
for i in 0..first_third_end {
|
||||
@@ -96,13 +97,13 @@ fn test_thin_context_basic() {
|
||||
#[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!(
|
||||
@@ -113,12 +114,12 @@ fn test_thin_write_file_tool_calls() {
|
||||
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(
|
||||
@@ -126,16 +127,16 @@ fn test_thin_write_file_tool_calls() {
|
||||
format!("Response {}", i),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
// Trigger thinning at 50%
|
||||
context.used_tokens = 5000;
|
||||
let (summary, _chars_saved) = context.thin_context();
|
||||
|
||||
|
||||
println!("Thinning summary: {}", summary);
|
||||
|
||||
|
||||
// Should have thinned the write_file tool call
|
||||
assert!(summary.contains("tool call") || summary.contains("chars 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 {
|
||||
@@ -152,15 +153,19 @@ fn test_thin_write_file_tool_calls() {
|
||||
#[test]
|
||||
fn test_thin_str_replace_tool_calls() {
|
||||
let mut context = ContextWindow::new(10000);
|
||||
|
||||
|
||||
// Add some messages including a str_replace tool call with large diff
|
||||
context.add_message(Message::new(
|
||||
MessageRole::User,
|
||||
"Please update the file".to_string(),
|
||||
));
|
||||
|
||||
|
||||
// Add an assistant message with a str_replace tool call containing large diff
|
||||
let large_diff = format!("--- old\n{}\n+++ new\n{}", "-old line\n".repeat(100), "+new line\n".repeat(100));
|
||||
let large_diff = format!(
|
||||
"--- old\n{}\n+++ new\n{}",
|
||||
"-old line\n".repeat(100),
|
||||
"+new line\n".repeat(100)
|
||||
);
|
||||
let tool_call_json = format!(
|
||||
r#"{{"tool": "str_replace", "args": {{"file_path": "test.txt", "diff": "{}"}}}}"#,
|
||||
large_diff.replace('\n', "\\n")
|
||||
@@ -169,12 +174,12 @@ fn test_thin_str_replace_tool_calls() {
|
||||
MessageRole::Assistant,
|
||||
format!("I'll update that file.\n\n{}", tool_call_json),
|
||||
));
|
||||
|
||||
|
||||
context.add_message(Message::new(
|
||||
MessageRole::User,
|
||||
"Tool result: ✅ applied unified diff".to_string(),
|
||||
));
|
||||
|
||||
|
||||
// Add more messages to ensure we have enough for "first third" logic
|
||||
for i in 0..6 {
|
||||
context.add_message(Message::new(
|
||||
@@ -182,16 +187,16 @@ fn test_thin_str_replace_tool_calls() {
|
||||
format!("Response {}", i),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
// Trigger thinning at 50%
|
||||
context.used_tokens = 5000;
|
||||
let (summary, _chars_saved) = context.thin_context();
|
||||
|
||||
|
||||
println!("Thinning summary: {}", summary);
|
||||
|
||||
|
||||
// Should have thinned the str_replace tool call
|
||||
assert!(summary.contains("tool call") || summary.contains("chars 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 {
|
||||
@@ -209,7 +214,7 @@ fn test_thin_str_replace_tool_calls() {
|
||||
#[test]
|
||||
fn test_thin_context_no_large_results() {
|
||||
let mut context = ContextWindow::new(10000);
|
||||
|
||||
|
||||
// Add only small messages
|
||||
for i in 0..9 {
|
||||
context.add_message(Message::new(
|
||||
@@ -217,10 +222,10 @@ fn test_thin_context_no_large_results() {
|
||||
format!("Tool result: small {}", i),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
context.used_tokens = 5000;
|
||||
let (summary, _chars_saved) = context.thin_context();
|
||||
|
||||
|
||||
// Should report no large results found
|
||||
assert!(summary.contains("no large tool results or tool calls found"));
|
||||
}
|
||||
@@ -228,7 +233,7 @@ fn test_thin_context_no_large_results() {
|
||||
#[test]
|
||||
fn test_thin_context_only_affects_first_third() {
|
||||
let mut context = ContextWindow::new(10000);
|
||||
|
||||
|
||||
// Add 12 messages (first third = 4 messages)
|
||||
for i in 0..12 {
|
||||
let content = if i % 2 == 1 {
|
||||
@@ -237,23 +242,23 @@ fn test_thin_context_only_affects_first_third() {
|
||||
} else {
|
||||
format!("Assistant message {}", i)
|
||||
};
|
||||
|
||||
|
||||
let role = if i % 2 == 1 {
|
||||
MessageRole::User
|
||||
} else {
|
||||
MessageRole::Assistant
|
||||
};
|
||||
|
||||
|
||||
context.add_message(Message::new(role, content));
|
||||
}
|
||||
|
||||
|
||||
context.used_tokens = 5000;
|
||||
let (summary, _chars_saved) = context.thin_context();
|
||||
|
||||
|
||||
// First third is 4 messages (indices 0-3), so only indices 1 and 3 should be thinned
|
||||
// That's 2 tool results
|
||||
assert!(summary.contains("2 tool results"));
|
||||
|
||||
|
||||
// Check that messages after the first third are NOT thinned
|
||||
let first_third_end = context.conversation_history.len() / 3;
|
||||
for i in first_third_end..context.conversation_history.len() {
|
||||
@@ -261,8 +266,11 @@ fn test_thin_context_only_affects_first_third() {
|
||||
if matches!(msg.role, MessageRole::User) && msg.content.starts_with("Tool result:") {
|
||||
// These should still be large (not thinned)
|
||||
if i % 2 == 1 {
|
||||
assert!(msg.content.len() > 1000,
|
||||
"Message at index {} should not have been thinned", i);
|
||||
assert!(
|
||||
msg.content.len() > 1000,
|
||||
"Message at index {} should not have been thinned",
|
||||
i
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user