search_memories
Search stored memories using advanced filters including keywords, date ranges, and relevance scores to retrieve specific conversation data from the Memory MCP Server.
Instructions
使用高級過濾條件搜索記憶。支持關鍵詞、時間範圍、分數過濾等。
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| conversation_id | Yes | 對話 ID | |
| query | No | 搜索查詢文本(將提取關鍵詞) | |
| keywords | No | 直接指定關鍵詞列表 | |
| date_from | No | 起始日期(ISO 格式) | |
| date_to | No | 結束日期(ISO 格式) | |
| min_score | No | 最低分數 | |
| max_score | No | 最高分數 | |
| limit | No | 返回結果數量限制 | |
| sort_by | No | 排序方式 | relevance |
| order | No | 排序順序 | desc |
| memory_type | No | 搜索的記憶類型 | short_term |
Implementation Reference
- src/tools/search-tools.js:35-107 (handler)The async handler function implementing the core logic of the 'search_memories' tool. It retrieves memories from short-term and/or long-term managers, applies filters using helper functions, sorts results, limits them, and returns formatted results.async handler(args) { const { conversation_id, query, keywords: providedKeywords, date_from, date_to, min_score, max_score, limit, sort_by, order, memory_type } = args; try { const results = []; // 搜索短期記憶 if (memory_type === 'short_term' || memory_type === 'both') { const manager = await getShortTermManager(conversation_id); const memories = manager.getMemories(); const filtered = await filterMemories(memories, { query, providedKeywords, date_from, date_to, min_score, max_score }); results.push(...filtered.map(m => ({ ...m, memory_type: 'short_term' }))); } // 搜索長期記憶 if (memory_type === 'long_term' || memory_type === 'both') { const manager = await getLongTermManager(conversation_id); const memories = manager.getMemories(); const filtered = await filterMemories(memories, { query, providedKeywords, date_from: date_from, date_to: date_to, min_score, max_score, isLongTerm: true }); results.push(...filtered.map(m => ({ ...m, memory_type: 'long_term' }))); } // 排序 sortResults(results, sort_by, order); // 限制結果數量 const limitedResults = results.slice(0, limit); return { success: true, total_found: results.length, returned: limitedResults.length, results: limitedResults.map(formatSearchResult) }; } catch (error) { return { success: false, error: error.message }; } } });
- src/tools/search-tools.js:22-34 (schema)Zod input schema defining parameters for the 'search_memories' tool, including conversation_id, query options, filters, limits, and sorting.inputSchema: z.object({ conversation_id: z.string().describe('對話 ID'), query: z.string().optional().describe('搜索查詢文本(將提取關鍵詞)'), keywords: z.array(z.string()).optional().describe('直接指定關鍵詞列表'), date_from: z.string().optional().describe('起始日期(ISO 格式)'), date_to: z.string().optional().describe('結束日期(ISO 格式)'), min_score: z.number().optional().describe('最低分數'), max_score: z.number().optional().describe('最高分數'), limit: z.number().default(20).describe('返回結果數量限制'), sort_by: z.enum(['relevance', 'score', 'timestamp']).default('relevance').describe('排序方式'), order: z.enum(['asc', 'desc']).default('desc').describe('排序順序'), memory_type: z.enum(['short_term', 'long_term', 'both']).default('short_term').describe('搜索的記憶類型') }),
- src/index.js:164-166 (registration)Registration of search tools, including 'search_memories', by invoking createSearchTools and registering each tool in the toolRegistry.// 註冊高級搜索工具 const searchTools = createSearchTools(getShortTermManager, getLongTermManager); searchTools.forEach(tool => registerTool(tool, 'search'));
- src/tools/search-tools.js:163-228 (helper)Key helper function called by the handler to filter memories based on keyword matching, date ranges, and score thresholds.async function filterMemories(memories, filters) { const { query, providedKeywords, date_from, date_to, min_score, max_score, isLongTerm } = filters; let filtered = [...memories]; // 關鍵詞過濾 if (query || providedKeywords) { let searchKeywords = []; if (query) { const extracted = extractKeywords(query, 10); searchKeywords = extracted.map(kw => kw.word.toLowerCase()); } if (providedKeywords) { searchKeywords = [...searchKeywords, ...providedKeywords.map(k => k.toLowerCase())]; } filtered = filtered.filter(mem => { const memoryKeywords = (mem.keywords || []).map(kw => (kw.word || kw).toLowerCase() ); return searchKeywords.some(sk => memoryKeywords.includes(sk)); }); } // 日期範圍過濾 if (date_from || date_to) { const fromTimestamp = date_from ? new Date(date_from).getTime() : 0; const toTimestamp = date_to ? new Date(date_to).getTime() : Infinity; filtered = filtered.filter(mem => { let timestamp; if (isLongTerm) { timestamp = mem.createdAt ? new Date(mem.createdAt).getTime() : 0; } else { timestamp = mem.time_stamp ? new Date(mem.time_stamp).getTime() : 0; } return timestamp >= fromTimestamp && timestamp <= toTimestamp; }); } // 分數範圍過濾 if (min_score !== undefined || max_score !== undefined) { const minScoreVal = min_score !== undefined ? min_score : -Infinity; const maxScoreVal = max_score !== undefined ? max_score : Infinity; filtered = filtered.filter(mem => { const score = mem.score || 0; return score >= minScoreVal && score <= maxScoreVal; }); } return filtered; }