crabtalk_runtime/memory/
tool.rs1use 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 pub query: String,
14 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 pub name: String,
27 pub description: String,
29 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 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 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}