feat: auto-append memory to memory index and don't necessarily require the LLM to remember to do it after a write

This commit is contained in:
2026-06-10 21:31:37 -06:00
parent 7143b50d98
commit 73c4449e7f
+77 -4
View File
@@ -1,6 +1,6 @@
use std::collections::HashSet;
use std::env;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::{env, fs};
use anyhow::{Context, Result, anyhow, bail};
use indexmap::IndexMap;
@@ -192,17 +192,21 @@ pub fn handle_memory_tool(ctx: &mut RequestContext, cmd_name: &str, args: &Value
path: target_dir.join(format!("{name}.md")),
frontmatter: MemoryFrontmatter {
name: name.clone(),
description: Some(description),
description: Some(description.clone()),
kind,
},
body: content,
};
file.save()?;
let index_path = target_dir.join("MEMORY.md");
let index_updated = ensure_index_entry(&index_path, &name, &description)?;
Ok(json!({
"status": "ok",
"path": file.path.display().to_string(),
"reminder": "Update MEMORY.md to keep the index accurate.",
"index_path": index_path.display().to_string(),
"index_updated": index_updated,
}))
}
"lint" => lint_memory(&store),
@@ -210,6 +214,32 @@ pub fn handle_memory_tool(ctx: &mut RequestContext, cmd_name: &str, args: &Value
}
}
fn ensure_index_entry(index_path: &Path, name: &str, description: &str) -> Result<bool> {
let existing = fs::read_to_string(index_path).unwrap_or_default();
let already_referenced =
existing.contains(&format!("[[{name}]]")) || existing.contains(&format!("{name}.md"));
if already_referenced {
return Ok(false);
}
let entry = format!("- [[{name}]]: {description}\n");
let new_content = if existing.is_empty() {
format!("# Memory Index\n\n{entry}")
} else if existing.ends_with('\n') {
format!("{existing}{entry}")
} else {
format!("{existing}\n{entry}")
};
if let Some(parent) = index_path.parent() {
fs::create_dir_all(parent)?;
}
fs::write(index_path, new_content)?;
Ok(true)
}
fn arg_str(args: &Value, key: &str) -> Result<String> {
args.get(key)
.and_then(Value::as_str)
@@ -339,6 +369,49 @@ mod tests {
assert!(extract_wikilinks("nothing here").is_empty());
}
#[test]
fn ensure_index_entry_appends_when_missing() {
let root = temp_root("index_append");
let index = root.join("MEMORY.md");
fs::write(&index, "# Memory Index\n\n- [[existing]] — already here\n").unwrap();
let updated = ensure_index_entry(&index, "new_one", "newly added").unwrap();
assert!(updated);
let content = fs::read_to_string(&index).unwrap();
assert!(content.contains("- [[existing]] — already here"));
assert!(content.contains("- [[new_one]] — newly added"));
let _ = fs::remove_dir_all(&root);
}
#[test]
fn ensure_index_entry_skips_when_referenced() {
let root = temp_root("index_skip");
let index = root.join("MEMORY.md");
let original = "# Memory Index\n\n- [[existing]] — already here\n";
fs::write(&index, original).unwrap();
let updated = ensure_index_entry(&index, "existing", "different description").unwrap();
assert!(!updated);
assert_eq!(fs::read_to_string(&index).unwrap(), original);
let _ = fs::remove_dir_all(&root);
}
#[test]
fn ensure_index_entry_creates_index_when_absent() {
let root = temp_root("index_create");
let index = root.join("memory").join("MEMORY.md");
let updated = ensure_index_entry(&index, "first", "first ever").unwrap();
assert!(updated);
let content = fs::read_to_string(&index).unwrap();
assert!(content.starts_with("# Memory Index"));
assert!(content.contains("- [[first]] — first ever"));
let _ = fs::remove_dir_all(&root);
}
#[test]
fn workspace_write_dir_returns_structured_dir_directly() {
let root = temp_root("ws_structured");