loopd: compaction threshold and the fallback summary
Co-Authored-By: ornith-1.5-35b-a3b <agent@wntrmute.dev>
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
//! Compaction: when a session starts a new epoch, the summary call, and writing the next files
|
||||
//! (M5d spec, section 3). Later tasks fill the call and the write.
|
||||
|
||||
use bxcore::{LogRecord, Usage};
|
||||
|
||||
/// True when `cache_n + prompt_n` is at or above `threshold * n_ctx`.
|
||||
pub fn due(usage: &Usage, threshold: f64, n_ctx: u64) -> bool {
|
||||
let total = usage.cache_n.saturating_add(usage.prompt_n) as f64;
|
||||
total >= threshold * (n_ctx as f64)
|
||||
}
|
||||
|
||||
/// The epoch's `User` texts, newest last, joined with `"\n\n"`, then `cap_chars`.
|
||||
pub fn fallback_summary(records: &[LogRecord], summary_chars: usize) -> String {
|
||||
let contents: Vec<&str> = records
|
||||
.iter()
|
||||
.filter_map(|r| match r {
|
||||
LogRecord::User { content, .. } => Some(content.as_str()),
|
||||
_ => None,
|
||||
})
|
||||
.collect();
|
||||
let joined = contents
|
||||
.iter()
|
||||
.rev()
|
||||
.cloned()
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n\n");
|
||||
cap_chars(&joined, summary_chars)
|
||||
}
|
||||
|
||||
pub(crate) fn cap_chars(s: &str, n: usize) -> String {
|
||||
s.chars().take(n).collect()
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
pub mod baseline;
|
||||
pub mod broker_port;
|
||||
pub mod channel;
|
||||
pub mod compact;
|
||||
pub mod config;
|
||||
pub mod http;
|
||||
pub mod llama;
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
//! Tests for when compaction is due and for the fallback summary. Do not edit.
|
||||
|
||||
use bxcore::{Epoch, Hash32, LogRecord, SessionId, Timestamp, Usage};
|
||||
use loopd::compact::{due, fallback_summary};
|
||||
|
||||
fn usage(cache_n: u64, prompt_n: u64) -> Usage {
|
||||
Usage {
|
||||
cache_n,
|
||||
prompt_n,
|
||||
predicted_n: 0,
|
||||
reasoning_tokens: 0,
|
||||
thinking_capped: false,
|
||||
}
|
||||
}
|
||||
|
||||
fn user(content: &str) -> LogRecord {
|
||||
LogRecord::User {
|
||||
time: Timestamp::parse("2026-09-18T08:00:00.000Z").unwrap(),
|
||||
content: content.to_string(),
|
||||
speaker: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn due_at_the_threshold_and_not_below() {
|
||||
assert!(!due(&usage(400, 449), 0.85, 1_000), "849 < 850");
|
||||
assert!(due(&usage(400, 450), 0.85, 1_000), "850 == 0.85 * 1000");
|
||||
assert!(due(&usage(0, 851), 0.85, 1_000));
|
||||
assert!(!due(&usage(0, 0), 0.85, 1_000));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn due_uses_this_agents_n_ctx() {
|
||||
// 0.85 * 262144 = 222822.4, so 222823 is the first integer at or above.
|
||||
assert!(!due(&usage(0, 222_822), 0.85, 262_144));
|
||||
assert!(due(&usage(0, 222_823), 0.85, 262_144));
|
||||
assert!(due(&usage(200_000, 22_823), 0.85, 262_144));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_threshold_of_one_is_the_full_window() {
|
||||
assert!(!due(&usage(99, 0), 1.0, 100));
|
||||
assert!(due(&usage(100, 0), 1.0, 100));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fallback_is_user_texts_newest_last() {
|
||||
let records = vec![
|
||||
LogRecord::SessionStart {
|
||||
time: Timestamp::parse("2026-09-18T08:00:00.000Z").unwrap(),
|
||||
session: SessionId::new("a").unwrap(),
|
||||
epoch: Epoch(0),
|
||||
slot: 0,
|
||||
baseline: Hash32::ZERO,
|
||||
},
|
||||
user("first"),
|
||||
user("second"),
|
||||
user("third"),
|
||||
];
|
||||
assert_eq!(
|
||||
fallback_summary(&records, 4_000),
|
||||
"third\n\nsecond\n\nfirst"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fallback_is_cut_to_summary_chars_on_a_character_boundary() {
|
||||
let records = vec![user("café"), user("ab")];
|
||||
assert_eq!(fallback_summary(&records, 3), "ab\n");
|
||||
assert_eq!(fallback_summary(&records, 1), "a");
|
||||
assert_eq!(fallback_summary(&records, 0), "");
|
||||
let long = user("ååå");
|
||||
assert_eq!(fallback_summary(&[long], 2), "åå");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fallback_with_no_users_is_empty() {
|
||||
assert_eq!(fallback_summary(&[], 100), "");
|
||||
}
|
||||
Reference in New Issue
Block a user