Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion crates/loopal-protocol/src/event_summary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ pub enum CompactPhase {
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CompactionSummary {
pub kept: usize,
pub removed: usize,
/// Message-count reduction (before − after). These were condensed into the
/// summary, NOT discarded — their content survives in the summary plus the
/// re-read (`files_rehydrated`) files.
pub summarized: usize,
pub tokens_before: u32,
pub tokens_after: u32,
pub strategy: String,
Expand Down
4 changes: 2 additions & 2 deletions crates/loopal-protocol/tests/suite/event_lifecycle_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ fn test_turn_completed_wire_format_unchanged() {
fn test_compacted_wire_format_unchanged() {
let event = AgentEvent::root(AgentEventPayload::Compacted(CompactionSummary {
kept: 5,
removed: 10,
summarized: 10,
tokens_before: 1000,
tokens_after: 500,
strategy: "smart".into(),
Expand All @@ -89,7 +89,7 @@ fn test_compacted_wire_format_unchanged() {
}));
let json = serde_json::to_string(&event).unwrap();
assert!(
json.contains(r#""Compacted":{"kept":5,"removed":10"#),
json.contains(r#""Compacted":{"kept":5,"summarized":10"#),
"wire shape regressed: {json}"
);
}
Expand Down
6 changes: 3 additions & 3 deletions crates/loopal-runtime/src/agent_loop/compaction_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,13 @@ impl AgentLoopRunner {
files_rehydrated: usize,
) -> Result<()> {
let after = self.turns.view().len();
let removed = before.saturating_sub(after);
let summarized = before.saturating_sub(after);
let tokens_after = self.turns.view().current_tokens();

self.emit(AgentEventPayload::Compacted(
loopal_protocol::CompactionSummary {
kept: after,
removed,
summarized,
tokens_before,
tokens_after,
strategy: strategy.to_string(),
Expand Down Expand Up @@ -197,7 +197,7 @@ impl AgentLoopRunner {

info!(
before,
after, removed, tokens_before, tokens_after, strategy, "compaction complete"
after, summarized, tokens_before, tokens_after, strategy, "compaction complete"
);
Ok(())
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ async fn compact_falls_back_to_bare_summary_on_llm_failure() {
_ => None,
})
.expect("Compacted event must fire even on LLM failure");
assert!(summary.removed > 0);
assert!(summary.summarized > 0);
assert!(summary.kept > 0);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ async fn compact_event_payload_carries_manual_strategy_label() {
});
let stats = stats.expect("Compacted event must fire");
assert!(stats.kept > 0);
assert!(stats.removed > 0);
assert!(stats.summarized > 0);
assert!(
stats.strategy.starts_with("manual"),
"expected manual-* strategy, got {}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,10 @@ async fn force_compact_emits_compacted_event_with_kept_removed_stats() {

assert_eq!(summary.strategy, "manual");
// before: 5 user messages; after: [summary, ack, last_user_trigger] = 3
// → removed message count = 2. Exact value catches off-by-one regression.
// → summarized message count = 2. Exact value catches off-by-one regression.
assert_eq!(
summary.removed, 2,
"Compacted.removed must reflect message-count delta (5 before → 3 after)"
summary.summarized, 2,
"Compacted.summarized must reflect message-count delta (5 before → 3 after)"
);
assert!(
summary.tokens_before > 0,
Expand Down
2 changes: 1 addition & 1 deletion crates/loopal-tui/tests/suite/e2e_compact_banner_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ fn compacted_event_clears_stale_banner_from_frame() {
app.dispatch_event(AgentEvent::root(AgentEventPayload::Compacted(
CompactionSummary {
kept: 4,
removed: 80,
summarized: 80,
tokens_before: 40_000,
tokens_after: 4_000,
strategy: "auto".into(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ pub fn handle_auto_continuation(conv: &mut AgentConversation, cont: u32, max: u3
pub fn handle_compaction(
conv: &mut AgentConversation,
kept: usize,
removed: usize,
summarized: usize,
tokens_before: u32,
tokens_after: u32,
strategy: &str,
Expand All @@ -69,11 +69,12 @@ pub fn handle_compaction(
} else {
0
};
let before = kept + summarized;
push_system_msg(
conv,
&format!(
"Context compacted ({strategy}): {removed} messages removed, \
{kept} kept. {tokens_before}→{tokens_after} tokens ({pct}% freed).",
"Context compacted ({strategy}): {before}→{kept} messages \
({summarized} summarized), {tokens_before}→{tokens_after} tokens ({pct}% freed).",
),
);
// Self-correct ctx counter from the Compacted event alone, in case the
Expand Down
4 changes: 2 additions & 2 deletions crates/loopal-view-state/src/mutators/interactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ pub(super) fn auto_continuation(
pub(super) fn compacted(
state: &mut SessionViewState,
kept: usize,
removed: usize,
summarized: usize,
tokens_before: u32,
tokens_after: u32,
strategy: &str,
Expand All @@ -85,7 +85,7 @@ pub(super) fn compacted(
conversation_display::handle_compaction(
&mut state.agent.conversation,
kept,
removed,
summarized,
tokens_before,
tokens_after,
strategy,
Expand Down
2 changes: 1 addition & 1 deletion crates/loopal-view-state/src/mutators/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ pub(crate) fn mutate(state: &mut SessionViewState, event: &AgentEventPayload) ->
Compacted(s) => interactive::compacted(
state,
s.kept,
s.removed,
s.summarized,
s.tokens_before,
s.tokens_after,
&s.strategy,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ fn compacted_event_clears_banner() {
assert!(banner_of(&r).is_some());
r.apply(AgentEventPayload::Compacted(CompactionSummary {
kept: 5,
removed: 100,
summarized: 100,
tokens_before: 50_000,
tokens_after: 5_000,
strategy: "smart".into(),
Expand Down Expand Up @@ -119,7 +119,7 @@ fn compacted_event_refreshes_ctx() {
let mut r = ViewStateReducer::new("root");
r.apply(AgentEventPayload::Compacted(CompactionSummary {
kept: 9,
removed: 491,
summarized: 491,
tokens_before: 259_392,
tokens_after: 6_453,
strategy: "manual".into(),
Expand Down
4 changes: 2 additions & 2 deletions crates/loopal-view-state/tests/suite/compact_idle_e2e_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ fn manual_compact_from_idle_keeps_idle_and_refreshes_ctx() {
r.apply(summarize("259392 tokens before"));
r.apply(AgentEventPayload::Compacted(CompactionSummary {
kept: 9,
removed: 491,
summarized: 491,
tokens_before: 259_392,
tokens_after: 6_453,
strategy: "manual".into(),
Expand Down Expand Up @@ -81,7 +81,7 @@ fn manual_compact_idle_without_token_usage_still_consistent() {
r.apply(summarize("259392 tokens before"));
r.apply(AgentEventPayload::Compacted(CompactionSummary {
kept: 9,
removed: 491,
summarized: 491,
tokens_before: 259_392,
tokens_after: 6_453,
strategy: "manual".into(),
Expand Down
Loading