//! Tool for reading a single memory entry or listing the whole memory index. use serde_json::{json, Value}; use anyhow::{Result, anyhow}; use super::super::Tool; use super::super::ToolCtx; use crate::model::memory::Memory; /// Tool that reads one memory entry by name, or lists all entries when name is omitted. pub struct Recall; impl Tool for Recall { fn name(&self) -> &'static str { "recall" } fn description(&self) -> &'static str { "Read memory entries. Pass a name to read a specific entry, or omit name to list all entries in the memory index. Use this to find stored lessons, references, and project conventions." } fn parameters(&self) -> Value { json!({ "type": "object", "properties": { "name": { "type": "string", "description": "Optional: exact name of a specific memory entry to read. If omitted, lists all entries." } } }) } /// Read a specific memory entry, or fall back to listing all entries. /// /// Flow: if `name` present and non-empty → `Memory::read` and format as frontmatter /// + body; otherwise → `list_all`. /// /// Return: formatted memory content, or the full index listing. fn run(&self, ctx: &ToolCtx, args: &Value) -> Result { if let Some(name) = args.get("name").and_then(|v| v.as_str()) { if name.is_empty() { return list_all(ctx); } let memory = Memory::read(&ctx.memory_dir, name) .map_err(|e| anyhow!("memory '{}' not found: {}", name, e))?; Ok(format!( "---\nname: {}\ndescription: {}\nkind: {}\nlifecycle: {}\n---\n\n{}", memory.name, memory.description, memory.kind, memory.lifecycle, memory.content, )) } else { list_all(ctx) } } } /// List every memory entry in `ctx.memory_dir` as a one-line summary index. /// /// Flow: `Memory::list` names → for each, try `Memory::read` for kind/description → /// fall back to bare name if the file can't be parsed. /// /// Return: `Ok` with the formatted index (never fails; missing dir yields "(no memory entries)"). fn list_all(ctx: &ToolCtx) -> Result { let names = Memory::list(&ctx.memory_dir); if names.is_empty() { return Ok("(no memory entries)".to_string()); } let mut lines = format!("Memory index ({} entries):\n", names.len()); for name in &names { if let Ok(mem) = Memory::read(&ctx.memory_dir, name) { lines.push_str(&format!("- {} [{}]: {}\n", name, mem.kind, mem.description)); } else { lines.push_str(&format!("- {}\n", name)); } } Ok(lines) }