pub mod age;
pub mod memdir;
pub mod memdir_paths;
pub mod paths;
pub mod scan;
pub mod types;
pub use age::{memory_age, memory_age_days, memory_freshness_note, memory_freshness_text};
pub use memdir::{
build_memory_lines as build_memory_lines_new, build_memory_prompt as build_memory_prompt_new,
load_memory_prompt as load_memory_prompt_new, truncate_entrypoint_content,
BuildMemoryPromptParams, DIR_EXISTS_GUIDANCE, MAX_ENTRYPOINT_BYTES, MAX_ENTRYPOINT_LINES,
};
pub use memdir_paths::{
ensure_memory_dir_exists as ensure_memory_dir_exists_new, get_auto_mem_daily_log_path,
get_auto_mem_entrypoint, get_auto_mem_path as get_auto_mem_path_new,
get_memory_base_dir as get_memory_base_dir_new, has_auto_mem_path_override,
is_auto_mem_path as is_auto_mem_path_new, is_auto_memory_enabled as is_auto_memory_enabled_new,
sanitize_path_component,
};
pub use paths::{
ensure_memory_dir_exists as ensure_memory_dir_exists_legacy,
get_auto_mem_path as get_auto_mem_path_legacy,
get_memory_base_dir as get_memory_base_dir_legacy, get_memory_entrypoint, get_project_slug,
is_auto_mem_path as is_auto_mem_path_legacy,
is_auto_memory_enabled as is_auto_memory_enabled_legacy,
};
pub use scan::{format_memory_manifest, scan_memory_files, MemoryHeader, MAX_MEMORY_FILES};
pub use types::{
extract_content, parse_frontmatter, EntrypointTruncation, MemoryFrontmatter, MemoryType,
MAX_ENTRYPOINT_LINES as MAX_ENTRYPOINT_LINES_FROM_TYPES,
};
pub const ENTRYPOINT_NAME: &str = "MEMORY.md";
pub fn build_memory_lines(
display_name: &str,
memory_dir: &str,
extra_guidelines: Option<Vec<&str>>,
skip_index: bool,
) -> Vec<String> {
memdir::build_memory_lines(
display_name,
memory_dir,
extra_guidelines.as_deref(),
skip_index,
)
}
pub fn build_memory_prompt() -> Option<String> {
if !is_auto_memory_enabled() {
return None;
}
let _ = ensure_memory_dir_exists(&get_auto_mem_path());
let memory_dir = get_auto_mem_path().to_string_lossy().to_string();
let lines = build_memory_lines("auto memory", &memory_dir, None, false);
let entrypoint_path = get_memory_entrypoint();
let entrypoint_content = if entrypoint_path.exists() {
std::fs::read_to_string(&entrypoint_path).unwrap_or_default()
} else {
String::new()
};
let mut all_lines = lines;
all_lines.push(format!("## {}", ENTRYPOINT_NAME));
all_lines.push(String::new());
if entrypoint_content.trim().is_empty() {
all_lines.push(format!(
"Your {} is currently empty. When you save new memories, they will appear here.",
ENTRYPOINT_NAME
));
} else {
let truncated = truncate_entrypoint_content(&entrypoint_content);
all_lines.push(truncated.content);
}
Some(all_lines.join("\n"))
}
pub fn load_memory_prompt() -> Option<String> {
build_memory_prompt()
}
pub fn ensure_memory_dir_exists(path: &std::path::Path) -> std::io::Result<()> {
memdir_paths::ensure_memory_dir_exists(path)
}
pub fn get_auto_mem_path() -> std::path::PathBuf {
memdir_paths::get_auto_mem_path()
}
pub fn is_auto_memory_enabled() -> bool {
memdir_paths::is_auto_memory_enabled()
}
pub fn is_auto_mem_path(path: &std::path::Path) -> bool {
memdir_paths::is_auto_mem_path(path)
}
pub fn get_memory_base_dir() -> std::path::PathBuf {
memdir_paths::get_memory_base_dir()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_build_memory_lines() {
let lines = build_memory_lines("auto memory", "/tmp/memory", None, false);
assert!(!lines.is_empty());
assert!(lines.iter().any(|l| l.contains("Types of memory")));
assert!(lines.iter().any(|l| l.contains("How to save memories")));
}
#[test]
fn test_load_memory_prompt() {
let prompt = load_memory_prompt();
if let Some(p) = prompt {
assert!(p.contains("auto memory"));
assert!(p.contains("MEMORY.md"));
}
}
}