Skip to main content

crabtalk_runtime/memory/
tool.rs

1//! Tool schemas and dispatch for built-in memory tools.
2
3use crate::{RuntimeHook, bridge::RuntimeBridge};
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<B: RuntimeBridge> RuntimeHook<B> {
67    pub async fn dispatch_recall(&self, args: &str) -> String {
68        let input: Recall = match serde_json::from_str(args) {
69            Ok(v) => v,
70            Err(e) => return format!("invalid arguments: {e}"),
71        };
72        match self.memory {
73            Some(ref mem) => mem.recall(&input.query, input.limit.unwrap_or(5)),
74            None => "memory not available".to_owned(),
75        }
76    }
77
78    pub async fn dispatch_remember(&self, args: &str) -> String {
79        let input: Remember = match serde_json::from_str(args) {
80            Ok(v) => v,
81            Err(e) => return format!("invalid arguments: {e}"),
82        };
83        match self.memory {
84            Some(ref mem) => mem.remember(input.name, input.description, input.content),
85            None => "memory not available".to_owned(),
86        }
87    }
88
89    pub async fn dispatch_forget(&self, args: &str) -> String {
90        let input: Forget = match serde_json::from_str(args) {
91            Ok(v) => v,
92            Err(e) => return format!("invalid arguments: {e}"),
93        };
94        match self.memory {
95            Some(ref mem) => mem.forget(&input.name),
96            None => "memory not available".to_owned(),
97        }
98    }
99
100    pub async fn dispatch_memory(&self, args: &str) -> String {
101        let input: MemoryTool = match serde_json::from_str(args) {
102            Ok(v) => v,
103            Err(e) => return format!("invalid arguments: {e}"),
104        };
105        match self.memory {
106            Some(ref mem) => mem.write_index(&input.content),
107            None => "memory not available".to_owned(),
108        }
109    }
110}