lean_ctx/tools/
ctx_summary.rs1use crate::core::session::SessionState;
4use crate::core::session_summary;
5
6pub fn handle(
8 project_root: &str,
9 session: Option<&SessionState>,
10 action: &str,
11 query: Option<&str>,
12 top_k: usize,
13) -> String {
14 match action.trim() {
15 "" | "recall" => render_recall(project_root, query, top_k),
16 "record" => render_record(project_root, session),
17 "list" => render_list(project_root),
18 other => {
19 format!("ERR: unknown summary action '{other}'. Use: recall <query> | record | list")
20 }
21 }
22}
23
24fn render_recall(project_root: &str, query: Option<&str>, top_k: usize) -> String {
25 let Some(query) = query.map(str::trim).filter(|q| !q.is_empty()) else {
26 return "ERR: recall requires a query (e.g. \"what did I do on the graph?\")".to_string();
27 };
28 let hits = session_summary::recall(project_root, query, top_k.clamp(1, 20));
29 if hits.is_empty() {
30 return format!("No session summaries match '{query}'.");
31 }
32 let mode = hits.first().map_or("lexical", |h| h.mode);
33 let mut out = format!(
34 "session summaries for '{query}' ({} hits, {mode}):\n",
35 hits.len()
36 );
37 for h in hits {
38 let when = h.record.created_at.format("%Y-%m-%d %H:%M");
39 out.push_str(&format!(
40 "\n[{}] {} — {} (score {:.2})\n{}\n",
41 h.record.id, when, h.record.title, h.score, h.record.body
42 ));
43 }
44 out
45}
46
47fn render_record(project_root: &str, session: Option<&SessionState>) -> String {
48 let Some(session) = session else {
49 return "ERR: no active session to summarize".to_string();
50 };
51 let candidate = session_summary::build_candidate(session);
52 match session_summary::record_now(project_root, candidate) {
53 Ok(title) => format!("summary recorded: {title}"),
54 Err(e) => format!("summary: {e}"),
55 }
56}
57
58fn render_list(project_root: &str) -> String {
59 let summaries = session_summary::list(project_root);
60 if summaries.is_empty() {
61 return "No session summaries yet.".to_string();
62 }
63 let mut out = format!("session summaries ({}):\n", summaries.len());
64 for s in summaries.iter().rev() {
65 let when = s.created_at.format("%Y-%m-%d %H:%M");
66 out.push_str(&format!(
67 " [{}] {} — {} ({} files, {} tool calls)\n",
68 s.id,
69 when,
70 s.title,
71 s.files.len(),
72 s.tool_calls
73 ));
74 }
75 out
76}