1use std::sync::Arc;
2
3use crate::memory::{MemoryKind, MemoryStore};
4use crate::provider::ToolDefinition;
5
6pub fn definitions() -> Vec<ToolDefinition> {
7 vec![
8 ToolDefinition {
9 name: "core_memory_update".to_string(),
10 description: "Update a core memory block that is always visible in your context. \
11 Use this to persist important facts about the user or yourself. \
12 Available blocks: 'human' (facts about the user) and 'agent' (your persona/preferences)."
13 .to_string(),
14 input_schema: serde_json::json!({
15 "type": "object",
16 "properties": {
17 "block": {
18 "type": "string",
19 "enum": ["human", "agent"],
20 "description": "Which core memory block to update"
21 },
22 "content": {
23 "type": "string",
24 "description": "The full new content for this block (replaces previous content)"
25 }
26 },
27 "required": ["block", "content"]
28 }),
29 },
30 ToolDefinition {
31 name: "memory_search".to_string(),
32 description: "Search your long-term archival memory for relevant information. \
33 Returns ranked results matching the query."
34 .to_string(),
35 input_schema: serde_json::json!({
36 "type": "object",
37 "properties": {
38 "query": {
39 "type": "string",
40 "description": "Search query"
41 },
42 "limit": {
43 "type": "integer",
44 "description": "Max results (default 10)"
45 }
46 },
47 "required": ["query"]
48 }),
49 },
50 ToolDefinition {
51 name: "memory_add".to_string(),
52 description: "Add a new entry to long-term archival memory. Use for facts, preferences, \
53 decisions, or project context worth remembering across sessions."
54 .to_string(),
55 input_schema: serde_json::json!({
56 "type": "object",
57 "properties": {
58 "content": {
59 "type": "string",
60 "description": "The memory to store"
61 },
62 "kind": {
63 "type": "string",
64 "enum": ["fact", "preference", "decision", "project", "entity", "belief"],
65 "description": "Memory category (default: fact)"
66 },
67 "importance": {
68 "type": "number",
69 "description": "Importance 0.0-1.0 (default: 0.5)"
70 }
71 },
72 "required": ["content"]
73 }),
74 },
75 ToolDefinition {
76 name: "memory_delete".to_string(),
77 description: "Delete a memory from archival storage by ID.".to_string(),
78 input_schema: serde_json::json!({
79 "type": "object",
80 "properties": {
81 "id": {
82 "type": "string",
83 "description": "Memory ID to delete"
84 }
85 },
86 "required": ["id"]
87 }),
88 },
89 ToolDefinition {
90 name: "memory_list".to_string(),
91 description: "List recent memories from archival storage, optionally filtered by kind."
92 .to_string(),
93 input_schema: serde_json::json!({
94 "type": "object",
95 "properties": {
96 "kind": {
97 "type": "string",
98 "enum": ["fact", "preference", "decision", "project", "entity", "belief"],
99 "description": "Filter by memory kind"
100 },
101 "limit": {
102 "type": "integer",
103 "description": "Max results (default 20)"
104 }
105 }
106 }),
107 },
108 ]
109}
110
111pub fn handle(
112 name: &str,
113 input: &serde_json::Value,
114 store: &Arc<MemoryStore>,
115 conversation_id: &str,
116) -> Option<(String, bool)> {
117 match name {
118 "core_memory_update" => {
119 let block = input.get("block").and_then(|v| v.as_str()).unwrap_or("");
120 let content = input.get("content").and_then(|v| v.as_str()).unwrap_or("");
121 match store.update_block(block, content) {
122 Ok(()) => Some((format!("Updated core memory block '{block}'."), false)),
123 Err(e) => Some((format!("Error: {e}"), true)),
124 }
125 }
126 "memory_search" => {
127 let query = input.get("query").and_then(|v| v.as_str()).unwrap_or("");
128 let limit = input.get("limit").and_then(|v| v.as_u64()).unwrap_or(10) as usize;
129 match store.search(query, limit) {
130 Ok(results) => {
131 if results.is_empty() {
132 Some(("No memories found matching that query.".to_string(), false))
133 } else {
134 let text = results
135 .iter()
136 .map(|r| {
137 format!(
138 "- [{}] (id={}, importance={:.2}, score={:.3}) {}",
139 r.memory.kind,
140 r.memory.id,
141 r.memory.importance,
142 r.score,
143 r.memory.content,
144 )
145 })
146 .collect::<Vec<_>>()
147 .join("\n");
148 Some((format!("{} results:\n{text}", results.len()), false))
149 }
150 }
151 Err(e) => Some((format!("Search error: {e}"), true)),
152 }
153 }
154 "memory_add" => {
155 let content = input.get("content").and_then(|v| v.as_str()).unwrap_or("");
156 let kind = input.get("kind").and_then(|v| v.as_str()).unwrap_or("fact");
157 let importance = input
158 .get("importance")
159 .and_then(|v| v.as_f64())
160 .unwrap_or(0.5) as f32;
161 let kind = MemoryKind::parse(kind);
162 match store.add(content, &kind, importance, Some(conversation_id)) {
163 Ok(id) => Some((format!("Memory added (id={id})."), false)),
164 Err(e) => Some((format!("Error: {e}"), true)),
165 }
166 }
167 "memory_delete" => {
168 let id = input.get("id").and_then(|v| v.as_str()).unwrap_or("");
169 match store.delete(id) {
170 Ok(()) => Some((format!("Memory '{id}' deleted."), false)),
171 Err(e) => Some((format!("Error: {e}"), true)),
172 }
173 }
174 "memory_list" => {
175 let kind = input
176 .get("kind")
177 .and_then(|v| v.as_str())
178 .map(MemoryKind::parse);
179 let limit = input.get("limit").and_then(|v| v.as_u64()).unwrap_or(20) as usize;
180 match store.list(kind.as_ref(), limit) {
181 Ok(memories) => {
182 if memories.is_empty() {
183 Some(("No memories found.".to_string(), false))
184 } else {
185 let text = memories
186 .iter()
187 .map(|m| {
188 format!(
189 "- [{}] (id={}, importance={:.2}) {}",
190 m.kind, m.id, m.importance, m.content,
191 )
192 })
193 .collect::<Vec<_>>()
194 .join("\n");
195 Some((format!("{} memories:\n{text}", memories.len()), false))
196 }
197 }
198 Err(e) => Some((format!("Error: {e}"), true)),
199 }
200 }
201 _ => None,
202 }
203}