2026-07-20 09:04:57 +07:00
|
|
|
//! Remember a lesson or fact as persistent memory.
|
2026-07-20 15:53:20 +07:00
|
|
|
//!
|
|
|
|
|
//! Constructs a `Memory` struct from tool arguments and persists it
|
|
|
|
|
//! via `MarkdownMemoryRepository` to the memory directory.
|
2026-07-20 09:04:57 +07:00
|
|
|
|
|
|
|
|
use crate::tools::{Tool, ToolCtx};
|
|
|
|
|
use anyhow::Result;
|
|
|
|
|
use serde_json::{json, Value};
|
2026-07-20 15:53:20 +07:00
|
|
|
use tracing::{info, instrument};
|
2026-07-20 09:04:57 +07:00
|
|
|
|
|
|
|
|
use zesdex_domain::cms::{Memory, MemoryRepository};
|
|
|
|
|
|
2026-07-20 15:53:20 +07:00
|
|
|
/// Tool that saves a lesson or fact to persistent memory.
|
|
|
|
|
///
|
|
|
|
|
/// Flow: parse name/description/content/kind → construct a `Memory` struct
|
|
|
|
|
/// with timestamps → instantiate `MarkdownMemoryRepository` → call
|
|
|
|
|
/// `repo.save()` with the memory directory → confirm save.
|
2026-07-20 09:04:57 +07:00
|
|
|
pub struct Remember;
|
|
|
|
|
|
|
|
|
|
impl Tool for Remember {
|
|
|
|
|
fn name(&self) -> &'static str {
|
|
|
|
|
"remember"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn description(&self) -> &'static str {
|
|
|
|
|
"Save a lesson or fact to persistent memory"
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn parameters(&self) -> Value {
|
|
|
|
|
json!({
|
|
|
|
|
"type": "object",
|
|
|
|
|
"properties": {
|
|
|
|
|
"name": {
|
|
|
|
|
"type": "string",
|
|
|
|
|
"description": "Unique name for this memory"
|
|
|
|
|
},
|
|
|
|
|
"description": {
|
|
|
|
|
"type": "string",
|
|
|
|
|
"description": "Short summary of the memory"
|
|
|
|
|
},
|
|
|
|
|
"content": {
|
|
|
|
|
"type": "string",
|
|
|
|
|
"description": "Full content of the memory"
|
|
|
|
|
},
|
|
|
|
|
"kind": {
|
|
|
|
|
"type": "string",
|
|
|
|
|
"enum": ["lesson", "reference", "fact"],
|
|
|
|
|
"description": "Category of memory"
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
"required": ["name", "description", "content"]
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-20 15:53:20 +07:00
|
|
|
#[instrument(skip(self, ctx, args))]
|
2026-07-20 09:04:57 +07:00
|
|
|
fn run(&self, ctx: &ToolCtx, args: &Value) -> Result<String> {
|
|
|
|
|
let name = crate::tools::arg_str(args, "name")?;
|
|
|
|
|
let description = crate::tools::arg_str(args, "description")?;
|
|
|
|
|
let content = crate::tools::arg_str(args, "content")?;
|
|
|
|
|
let kind = args
|
|
|
|
|
.get("kind")
|
|
|
|
|
.and_then(|v| v.as_str())
|
|
|
|
|
.unwrap_or("reference")
|
|
|
|
|
.to_string();
|
|
|
|
|
|
2026-07-20 15:53:20 +07:00
|
|
|
info!(name, kind, "remember invoked");
|
|
|
|
|
|
2026-07-20 09:04:57 +07:00
|
|
|
let memory = Memory {
|
|
|
|
|
name: name.clone(),
|
|
|
|
|
description,
|
|
|
|
|
content,
|
|
|
|
|
kind,
|
|
|
|
|
created_at: chrono::Utc::now().timestamp(),
|
|
|
|
|
updated_at: chrono::Utc::now().timestamp(),
|
|
|
|
|
outcome: None,
|
|
|
|
|
lifecycle: "active".to_string(),
|
|
|
|
|
scope: None,
|
|
|
|
|
before_snippet: None,
|
|
|
|
|
after_snippet: None,
|
|
|
|
|
provenances: Vec::new(),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let repo = crate::persistence::cms::memory_repo::MarkdownMemoryRepository::new();
|
|
|
|
|
repo.save(&ctx.memory_dir, &memory)?;
|
|
|
|
|
|
2026-07-20 15:53:20 +07:00
|
|
|
info!(name, "memory saved");
|
2026-07-20 09:04:57 +07:00
|
|
|
Ok(format!("Memory '{}' saved", name))
|
|
|
|
|
}
|
|
|
|
|
}
|