agent_code_lib/memory/
session_notes.rs1use std::path::PathBuf;
10
11const TEMPLATE: &str = "\
13# Session Notes
14
15## Current State
16_What is actively being worked on right now?_
17
18## Task
19_What did the user ask to do?_
20
21## Key Files
22_Important files and their relevance_
23
24## Workflow
25_Commands run and their results_
26
27## Errors
28_Errors encountered and how they were fixed_
29
30## Learnings
31_What worked well? What didn't?_
32
33## Results
34_Key outputs or deliverables_
35
36## Log
37_Step by step, what was attempted and done_
38";
39
40pub fn session_notes_path(session_id: &str) -> Option<PathBuf> {
42 let dir = dirs::config_dir()?.join("agent-code").join("session-notes");
43 let _ = std::fs::create_dir_all(&dir);
44 Some(dir.join(format!("{session_id}.md")))
45}
46
47pub fn init_session_notes(session_id: &str) -> Option<PathBuf> {
49 let path = session_notes_path(session_id)?;
50 if !path.exists() {
51 let _ = std::fs::write(&path, TEMPLATE);
52 }
53 Some(path)
54}
55
56pub fn read_session_notes(session_id: &str) -> Option<String> {
58 let path = session_notes_path(session_id)?;
59 std::fs::read_to_string(path).ok()
60}
61
62pub fn has_content(session_id: &str) -> bool {
64 match read_session_notes(session_id) {
65 Some(content) => {
66 content
68 .lines()
69 .any(|line| !line.is_empty() && !line.starts_with('#') && !line.starts_with('_'))
70 }
71 None => false,
72 }
73}
74
75pub fn build_update_prompt(session_id: &str, recent_messages: &str) -> String {
77 let existing = read_session_notes(session_id).unwrap_or_else(|| TEMPLATE.to_string());
78
79 format!(
80 "Update the session notes below based on the recent conversation. \
81 Fill in sections that apply, leave others with their placeholder text. \
82 Be concise — these notes are for quick reference, not detailed logs. \
83 Keep the markdown structure intact.\n\n\
84 Current notes:\n```\n{existing}\n```\n\n\
85 Recent conversation:\n{recent_messages}\n\n\
86 Write the updated session notes (full markdown document):"
87 )
88}
89
90pub fn cleanup_old_notes() {
92 let dir = match dirs::config_dir() {
93 Some(d) => d.join("agent-code").join("session-notes"),
94 None => return,
95 };
96
97 if !dir.is_dir() {
98 return;
99 }
100
101 let cutoff = std::time::SystemTime::now() - std::time::Duration::from_secs(7 * 24 * 60 * 60);
102
103 if let Ok(entries) = std::fs::read_dir(&dir) {
104 for entry in entries.flatten() {
105 if let Ok(meta) = entry.metadata()
106 && let Ok(modified) = meta.modified()
107 && modified < cutoff
108 {
109 let _ = std::fs::remove_file(entry.path());
110 }
111 }
112 }
113}