use crate::{MemoryItem, MemoryType};
use std::path::{Path, PathBuf};
const IMPORTANT_THRESHOLD: f32 = 0.7;
pub async fn append(base_dir: &Path, item: &MemoryItem) -> anyhow::Result<()> {
if item.importance >= IMPORTANT_THRESHOLD {
append_to_memory_md(base_dir, item).await?;
}
if item.memory_type == MemoryType::Episodic {
append_to_daily_log(base_dir, item).await?;
}
Ok(())
}
async fn append_to_memory_md(base_dir: &Path, item: &MemoryItem) -> anyhow::Result<()> {
use tokio::io::AsyncWriteExt;
let path = base_dir.join("MEMORY.md");
let entry = format_entry(item);
let mut f = tokio::fs::OpenOptions::new()
.create(true)
.append(true)
.open(&path)
.await
.map_err(|e| anyhow::anyhow!("Cannot open {}: {e}", path.display()))?;
f.write_all(format!("{entry}\n").as_bytes())
.await
.map_err(|e| anyhow::anyhow!("Write to {} failed: {e}", path.display()))?;
Ok(())
}
async fn append_to_daily_log(base_dir: &Path, item: &MemoryItem) -> anyhow::Result<()> {
let date = item.timestamp.format("%Y-%m-%d").to_string();
let dir = base_dir.join("memory");
tokio::fs::create_dir_all(&dir).await?;
let path = dir.join(format!("{date}.md"));
use tokio::io::AsyncWriteExt;
let mut f = tokio::fs::OpenOptions::new()
.create(true)
.append(true)
.open(&path)
.await
.map_err(|e| anyhow::anyhow!("Cannot open {}: {e}", path.display()))?;
f.write_all(format!("{}\n", format_entry(item)).as_bytes())
.await
.map_err(|e| anyhow::anyhow!("Write to {} failed: {e}", path.display()))?;
Ok(())
}
fn format_entry(item: &MemoryItem) -> String {
let ts = item.timestamp.format("%Y-%m-%dT%H:%M:%SZ");
let tags = if item.tags.is_empty() {
String::new()
} else {
format!(" [{}]", item.tags.join(", "))
};
format!(
"## {ts} · {type_} · importance={importance:.2}{tags}\n\n{content}\n",
ts = ts,
type_ = format!("{:?}", item.memory_type).to_lowercase(),
importance = item.importance,
tags = tags,
content = item.content.trim(),
)
}
pub fn list_files(base_dir: &Path) -> Vec<PathBuf> {
let mut out = Vec::new();
let main = base_dir.join("MEMORY.md");
if main.exists() {
out.push(main);
}
let daily_dir = base_dir.join("memory");
if let Ok(rd) = std::fs::read_dir(&daily_dir) {
for entry in rd.flatten() {
let p = entry.path();
if p.extension().is_some_and(|e| e == "md") {
out.push(p);
}
}
}
out
}