recall
Retrieve relevant memories via semantic search with keyword fallback, searching working and long-term memory tiers to support AI agent decision-making.
Instructions
Retrieve relevant memories via semantic search (falls back to keyword). Searches working + long_term tiers. Pass userId to blend in cross-session user facts.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| sessionId | Yes | Session identifier | |
| query | Yes | Search query | |
| limit | No | Max results (default 10) | |
| userId | No | Optional: also blend in this user's cross-session memories | |
| tiers | No | Comma-separated tiers to search: working,long_term,archived (default: working,long_term) |
Implementation Reference
- src/index.ts:52-66 (registration)Tool registration for 'recall' - defines the tool name, description, and inputSchema with sessionId, query, limit, userId, and tiers parameters
{ name: 'recall', description: 'Retrieve relevant memories via semantic search (falls back to keyword). Searches working + long_term tiers. Pass userId to blend in cross-session user facts.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Session identifier' }, query: { type: 'string', description: 'Search query' }, limit: { type: 'number', description: 'Max results (default 10)', default: 10 }, userId: { type: 'string', description: 'Optional: also blend in this user\'s cross-session memories' }, tiers: { type: 'string', description: 'Comma-separated tiers to search: working,long_term,archived (default: working,long_term)' }, }, required: ['sessionId', 'query'], }, }, - src/index.ts:216-230 (handler)Handler for 'recall' tool - parses tier arguments, calls memory.recall() with sessionId, query, limit, and options (tiers, userId), returns JSON results
case 'recall': { const tiers = args.tiers ? (args.tiers as string).split(',').map(t => t.trim()) as any : undefined; const entries = await memory.recall( args.sessionId as string, args.query as string, (args.limit as number) || 10, { tiers, userId: args.userId as string | undefined, } ); return { content: [{ type: 'text', text: JSON.stringify(entries, null, 2) }] }; } - engram.ts:207-292 (handler)Core recall implementation in Engram class - performs semantic search using Ollama embeddings with cosine similarity ranking, falls back to keyword search if embeddings unavailable. Queries SQLite database for memories matching session.
async recall( sessionId: string, query?: string, limit: number = 10, options: RecallOptions = {} ): Promise<MemoryEntry[]> { await this.init(); // Build base query let sql = ` SELECT id, session_id, content, role, timestamp, metadata, embedding FROM memories WHERE session_id = ? `; const params: (string | number)[] = [sessionId]; if (options.role) { sql += ` AND role = ?`; params.push(options.role); } if (options.after) { sql += ` AND timestamp >= ?`; params.push(options.after.getTime()); } if (options.before) { sql += ` AND timestamp <= ?`; params.push(options.before.getTime()); } // Try semantic search if (query && query.trim() && this.semanticSearch) { const queryVector = await this.embed(query); if (queryVector) { sql += ` ORDER BY timestamp DESC`; const rows = await this.db.all(sql, params); // Score each row by cosine similarity const scored = rows .map((row: any) => { let similarity = 0; if (row.embedding) { try { const vec: number[] = JSON.parse(row.embedding); similarity = this.cosineSimilarity(queryVector, vec); } catch { /* malformed, skip */ } } return { row, similarity }; }) .sort((a, b) => b.similarity - a.similarity) .slice(0, limit); return scored.map(({ row, similarity }) => ({ id: row.id, sessionId: row.session_id, content: row.content, role: row.role, timestamp: new Date(row.timestamp), metadata: row.metadata ? JSON.parse(row.metadata) : undefined, similarity })); } // Ollama unreachable — fall through to keyword search } // Keyword fallback if (query && query.trim()) { const keywords = query.toLowerCase().split(/\s+/).filter(k => k.length > 2); if (keywords.length > 0) { sql += ` AND (` + keywords.map(() => `LOWER(content) LIKE ?`).join(' OR ') + `)`; params.push(...keywords.map(k => `%${k}%`)); } } sql += ` ORDER BY timestamp DESC LIMIT ?`; params.push(limit); const rows = await this.db.all(sql, params); return rows.map((row: any) => ({ id: row.id, sessionId: row.session_id, content: row.content, role: row.role, timestamp: new Date(row.timestamp), metadata: row.metadata ? JSON.parse(row.metadata) : undefined })); } - engram.ts:14-19 (schema)RecallOptions interface defining optional parameters: limit, before/after date filters, and role filter for memory retrieval
export interface RecallOptions { limit?: number; before?: Date; after?: Date; role?: 'user' | 'assistant' | 'system'; }