ai-agent 0.13.4

Idiomatic agent sdk inspired by the claude code source leak
Documentation
//! Memory system - persistent file-based memory for the agent.
//!
//! This module provides the memory system that allows the agent to remember
//! information across conversations. It follows the TypeScript flavor of the
//! original Claude Code project.

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,
};

/// Entrypoint filename
pub const ENTRYPOINT_NAME: &str = "MEMORY.md";

/// Build the typed-memory behavioral instructions (without MEMORY.md content).
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,
    )
}

/// Build the full memory prompt with MEMORY.md content included.
/// Returns None if auto-memory is disabled.
pub fn build_memory_prompt() -> Option<String> {
    if !is_auto_memory_enabled() {
        return None;
    }

    // Ensure directory exists
    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);

    // Read entrypoint content
    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;

    // Add entrypoint section
    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"))
}

/// Load the memory prompt for inclusion in the system prompt.
/// Returns None if auto-memory is disabled.
pub fn load_memory_prompt() -> Option<String> {
    build_memory_prompt()
}

/// Ensure the memory directory exists (wrapper for memdir_paths)
pub fn ensure_memory_dir_exists(path: &std::path::Path) -> std::io::Result<()> {
    memdir_paths::ensure_memory_dir_exists(path)
}

/// Get the auto-memory directory path (wrapper for memdir_paths)
pub fn get_auto_mem_path() -> std::path::PathBuf {
    memdir_paths::get_auto_mem_path()
}

/// Check if auto-memory is enabled (wrapper for memdir_paths)
pub fn is_auto_memory_enabled() -> bool {
    memdir_paths::is_auto_memory_enabled()
}

/// Check if a path is within the auto-memory directory (wrapper for memdir_paths)
pub fn is_auto_mem_path(path: &std::path::Path) -> bool {
    memdir_paths::is_auto_mem_path(path)
}

/// Get the memory base directory (wrapper for memdir_paths)
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();
        // May be None if directory can't be created
        if let Some(p) = prompt {
            assert!(p.contains("auto memory"));
            assert!(p.contains("MEMORY.md"));
        }
    }
}