Skip to main content

crabtalk_runtime/memory/
tool.rs

1//! Tool schemas and dispatch for built-in memory tools.
2
3use crate::{Env, host::Host};
4use serde::Deserialize;
5use wcore::{
6    agent::{AsTool, ToolDescription},
7    model::Tool,
8};
9
10#[derive(Deserialize, schemars::JsonSchema)]
11pub struct Recall {
12    /// Keyword or phrase to search your memory entries for.
13    pub query: String,
14    /// Maximum number of results to return. Defaults to 5.
15    pub limit: Option<usize>,
16}
17
18impl ToolDescription for Recall {
19    const DESCRIPTION: &'static str =
20        "Search your memory entries by keyword. Returns ranked results.";
21}
22
23#[derive(Deserialize, schemars::JsonSchema)]
24pub struct Remember {
25    /// Short name for this memory entry (used as identifier).
26    pub name: String,
27    /// One-line description — determines search relevance.
28    pub description: String,
29    /// The content to remember.
30    pub content: String,
31}
32
33impl ToolDescription for Remember {
34    const DESCRIPTION: &'static str = "Save or update a memory entry. Creates a persistent file with the given name, description, and content.";
35}
36
37#[derive(Deserialize, schemars::JsonSchema)]
38pub struct Forget {
39    /// Name of the memory entry to delete.
40    pub name: String,
41}
42
43impl ToolDescription for Forget {
44    const DESCRIPTION: &'static str = "Delete a memory entry by name.";
45}
46
47#[derive(Deserialize, schemars::JsonSchema)]
48pub struct MemoryTool {
49    /// The full content to write to MEMORY.md — your curated overview.
50    pub content: String,
51}
52
53impl ToolDescription for MemoryTool {
54    const DESCRIPTION: &'static str = "Overwrite MEMORY.md — your curated overview injected every session. Read it before overwriting.";
55}
56
57pub fn tools() -> Vec<Tool> {
58    vec![
59        Recall::as_tool(),
60        Remember::as_tool(),
61        Forget::as_tool(),
62        MemoryTool::as_tool(),
63    ]
64}
65
66impl<H: Host> Env<H> {
67    pub async fn dispatch_recall(&self, args: &str) -> Result<String, String> {
68        let input: Recall =
69            serde_json::from_str(args).map_err(|e| format!("invalid arguments: {e}"))?;
70        let mem = self.memory.as_ref().ok_or("memory not available")?;
71        Ok(mem.recall(&input.query, input.limit.unwrap_or(5)))
72    }
73
74    pub async fn dispatch_remember(&self, args: &str) -> Result<String, String> {
75        let input: Remember =
76            serde_json::from_str(args).map_err(|e| format!("invalid arguments: {e}"))?;
77        let mem = self.memory.as_ref().ok_or("memory not available")?;
78        Ok(mem.remember(input.name, input.description, input.content))
79    }
80
81    pub async fn dispatch_forget(&self, args: &str) -> Result<String, String> {
82        let input: Forget =
83            serde_json::from_str(args).map_err(|e| format!("invalid arguments: {e}"))?;
84        let mem = self.memory.as_ref().ok_or("memory not available")?;
85        Ok(mem.forget(&input.name))
86    }
87
88    pub async fn dispatch_memory(&self, args: &str) -> Result<String, String> {
89        let input: MemoryTool =
90            serde_json::from_str(args).map_err(|e| format!("invalid arguments: {e}"))?;
91        let mem = self.memory.as_ref().ok_or("memory not available")?;
92        Ok(mem.write_index(&input.content))
93    }
94}