Skip to content

Commit c584eab

Browse files
committed
feat: implement output collapse pipeline and track savings in session stats
1 parent cffbe41 commit c584eab

9 files changed

Lines changed: 1270 additions & 9 deletions

File tree

src/cli/stats.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,24 @@ pub fn run(args: &[String], store: &Store) -> Result<()> {
181181
.bright_magenta()
182182
);
183183

184+
// Collapse savings
185+
let collapse_stats = store.collapse_aggregate(since);
186+
if let Ok((events, total_original, total_collapsed)) = collapse_stats
187+
&& events > 0
188+
{
189+
println!(
190+
" {:<20} {}",
191+
"Collapse:".bright_black(),
192+
format!(
193+
"{} → {} lines across {} events",
194+
format_number(total_original),
195+
format_number(total_collapsed),
196+
events
197+
)
198+
.bright_green()
199+
);
200+
}
201+
184202
// Filter breakdown
185203
let filters = store.filter_breakdown(since)?;
186204
if !filters.is_empty() {

src/hooks/pipe.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::io::{Read, Write};
44
use std::sync::{Arc, Mutex};
55
use std::time::Instant;
66

7-
use crate::pipeline::{SessionState, classifier, composer, scorer, toml_filter};
7+
use crate::pipeline::{SessionState, classifier, collapse, composer, scorer, toml_filter};
88
use crate::store::sqlite::Store;
99
use crate::store::transcript::{Transcript, TranscriptEntry};
1010

@@ -131,8 +131,13 @@ pub fn run_inner<R: Read, W: Write, E: Write>(
131131
)
132132
} else {
133133
let c = classifier::classify(&input_text);
134+
135+
// Pre-processing: collapse repetitive lines before scoring
136+
let collapse_result = collapse::collapse(&input_text, &c);
137+
let effective_input = collapse_result.collapsed_lines.join("\n");
138+
134139
let scored_segments =
135-
scorer::score_segments(&input_text, &c, active_session_opt.as_deref());
140+
scorer::score_segments(&effective_input, &c, active_session_opt.as_deref());
136141
drop(active_session_opt);
137142

138143
let compose_config = composer::ComposeConfig::default();
@@ -194,6 +199,7 @@ pub fn run_inner<R: Read, W: Write, E: Write>(
194199
rewind_hash: rewind_hash_opt,
195200
segments_kept: kept_count,
196201
segments_dropped: dropped_count,
202+
collapse_savings: None,
197203
};
198204

199205
s.record_distillation(&s_id, &result, command_name.unwrap_or(""));

src/hooks/post_tool.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::distillers;
22
use crate::pipeline::toml_filter;
3-
use crate::pipeline::{DistillResult, Route, SessionState, classifier, composer, scorer};
3+
use crate::pipeline::{DistillResult, Route, SessionState, classifier, collapse, composer, scorer};
44
use crate::store::sqlite::Store;
55
use serde::{Deserialize, Serialize};
66
use std::sync::{Arc, Mutex};
@@ -117,19 +117,23 @@ pub fn process_payload(
117117
// Fallback to Rust distiller pipeline
118118
let ctype = classifier::classify(&content);
119119

120+
// Pre-processing: collapse repetitive lines before scoring
121+
let collapse_result = collapse::collapse(&content, &ctype);
122+
let effective_input = collapse_result.collapsed_lines.join("\n");
123+
120124
let scored_segments = if let Some(ref lock) = session {
121125
if let Ok(state) = lock.lock() {
122-
scorer::score_segments(&content, &ctype, Some(&*state))
126+
scorer::score_segments(&effective_input, &ctype, Some(&*state))
123127
} else {
124-
scorer::score_segments(&content, &ctype, None)
128+
scorer::score_segments(&effective_input, &ctype, None)
125129
}
126130
} else {
127-
scorer::score_segments(&content, &ctype, None)
131+
scorer::score_segments(&effective_input, &ctype, None)
128132
};
129133

130134
let distiller = distillers::get_distiller(&ctype);
131135
let active_ctype = distiller.content_type();
132-
let output = distiller.distill(&scored_segments, &content);
136+
let output = distiller.distill(&scored_segments, &effective_input);
133137
(output, format!("{:?}", active_ctype), Some(active_ctype))
134138
};
135139

@@ -220,6 +224,7 @@ pub fn process_payload(
220224
},
221225
segments_kept: 0,
222226
segments_dropped: 0,
227+
collapse_savings: None,
223228
};
224229
let session_id = session
225230
.as_ref()

0 commit comments

Comments
 (0)