Download apps/desktop/src/tools/memory.js from aiagentmona/mona-agent: direct link, hf CLI and curl.
- Browser
- Download file 2.52 kB
-
https://huggingface.co/aiagentmona/mona-agent/resolve/main/apps/desktop/src/tools/memory.js
- Command line
-
hf download hf://aiagentmona/mona-agent/apps/desktop/src/tools/memory.js
-
curl -L -o memory.js https://huggingface.co/aiagentmona/mona-agent/resolve/main/apps/desktop/src/tools/memory.js
2.52 kB
| // Persistent memory — the agent remembers across tasks and restarts. | |
| // Plain markdown files under ~/.mona-agent/memory/. | |
| import fs from 'node:fs'; | |
| import path from 'node:path'; | |
| import os from 'node:os'; | |
| const MEM_DIR = process.env.MONA_MEMORY_DIR || path.join(os.homedir(), '.mona-agent', 'memory'); | |
| const MAX_NOTE = 4000; | |
| function ensureDir() { | |
| fs.mkdirSync(MEM_DIR, { recursive: true }); | |
| } | |
| function todayFile() { | |
| const d = new Date(); | |
| const ymd = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; | |
| return path.join(MEM_DIR, `${ymd}.md`); | |
| } | |
| function allFiles() { | |
| ensureDir(); | |
| return fs.readdirSync(MEM_DIR).filter((f) => f.endsWith('.md')).map((f) => path.join(MEM_DIR, f)); | |
| } | |
| export const memory = { | |
| name: 'memory', | |
| description: 'Persistent memory across tasks: remember facts, recall/search them, list recent notes.', | |
| args: { | |
| action: 'string — remember | recall | list', | |
| note: 'string — text to remember (for remember)', | |
| query: 'string — search terms (for recall)', | |
| }, | |
| platform: 'any', | |
| async run(args) { | |
| const action = String(args.action || 'recall').toLowerCase(); | |
| if (action === 'remember') { | |
| const note = String(args.note || '').trim().slice(0, MAX_NOTE); | |
| if (!note) return { error: 'note required' }; | |
| ensureDir(); | |
| const stamp = new Date().toISOString(); | |
| fs.appendFileSync(todayFile(), `\n## ${stamp}\n${note}\n`); | |
| return { ok: true, stored: todayFile(), chars: note.length }; | |
| } | |
| if (action === 'list') { | |
| ensureDir(); | |
| const files = allFiles().map((f) => ({ | |
| file: path.basename(f), | |
| bytes: fs.statSync(f).size, | |
| })); | |
| return { files: files.reverse().slice(0, 14) }; | |
| } | |
| // recall (default): substring search across memory files, newest first | |
| const query = String(args.query || '').trim(); | |
| const files = allFiles().sort().reverse(); | |
| const hits = []; | |
| for (const f of files.slice(0, 40)) { | |
| let content; | |
| try { content = fs.readFileSync(f, 'utf8'); } catch { continue; } | |
| const lines = content.split('\n'); | |
| for (let i = 0; i < lines.length; i++) { | |
| if (!query || lines[i].toLowerCase().includes(query.toLowerCase())) { | |
| hits.push({ file: path.basename(f), line: i + 1, text: lines[i].slice(0, 300) }); | |
| if (hits.length >= 20) break; | |
| } | |
| } | |
| if (hits.length >= 20) break; | |
| } | |
| return { query: query || '(all recent)', hits }; | |
| }, | |
| }; | |