forked from Dicklesworthstone/pi_agent_rust
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcompaction_bug.rs
More file actions
77 lines (68 loc) · 2.63 KB
/
Copy pathcompaction_bug.rs
File metadata and controls
77 lines (68 loc) · 2.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use pi::compaction::{ResolvedCompactionSettings, prepare_compaction};
use pi::model::{
AssistantMessage, ContentBlock, Cost, StopReason, TextContent, Usage, UserContent,
};
use pi::session::{EntryBase, MessageEntry, SessionEntry, SessionMessage};
#[test]
fn test_compaction_usage_double_counting_bug() {
// Create an assistant message with specific usage
let usage = Usage {
input: 100, // Total input tokens (includes cached)
output: 10,
cache_read: 20,
cache_write: 30,
total_tokens: 0, // Simulate missing/default total_tokens
cost: Cost::default(),
};
let message = SessionMessage::Assistant {
message: AssistantMessage {
content: vec![ContentBlock::Text(TextContent::new("test"))],
api: "test".to_string(),
provider: "test".to_string(),
model: "test".to_string(),
usage,
stop_reason: StopReason::Stop,
error_message: None,
timestamp: 0,
},
};
let user1 = SessionEntry::Message(MessageEntry {
base: EntryBase::new(None, "u1".to_string()),
message: SessionMessage::User {
content: UserContent::Text("hi".to_string()),
timestamp: None,
},
});
let assistant_entry = SessionEntry::Message(MessageEntry {
base: EntryBase::new(None, "msg1".to_string()),
message,
});
// Add a trailing user message so `estimate_context_tokens` considers it "after" the last
// assistant usage entry, but keep it empty so its token estimate is 0.
let user2 = SessionEntry::Message(MessageEntry {
base: EntryBase::new(None, "u2".to_string()),
message: SessionMessage::User {
content: UserContent::Text(String::new()),
timestamp: None,
},
});
let entries = vec![user1, assistant_entry, user2];
// Force compaction to trigger by setting a zero window. The default 200K window
// is far above the ~110 tokens in these test entries.
let settings = ResolvedCompactionSettings {
context_window_tokens: 0,
reserve_tokens: 0,
keep_recent_tokens: 0,
..Default::default()
};
// prepare_compaction calculates tokens_before using estimate_context_tokens
// which uses calculate_context_tokens
let prep = prepare_compaction(&entries, settings);
assert!(prep.is_some());
let prep = prep.unwrap();
// Correct behavior (assuming `input` includes cached tokens): 100 + 10 = 110.
assert_eq!(
prep.tokens_before, 110,
"Expected 110 tokens (100 input + 10 output), got double-counted tokens"
);
}