"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.toolDefinition = exports.SearchMessagesInputSchema = void 0; exports.toolHandler = toolHandler; const zod_1 = require("zod"); const date_fns_1 = require("date-fns"); const locale_1 = require("date-fns/locale"); // Input schema for the search_messages tool exports.SearchMessagesInputSchema = zod_1.z.object({ query: zod_1.z.string().describe('The natural language query to search for messages.'), threadId: zod_1.z.string().optional().describe('Optional: The ID of the thread to search within. If not provided, searches the current active thread.'), topK: zod_1.z.number().int().min(1).default(5).optional().describe('Optional: The maximum number of similar messages to return. Defaults to 5.'), minScore: zod_1.z.number().min(0).max(1).default(0.6).optional().describe('Optional: The minimum similarity score (0-1) for results to be included. Defaults to 0.6.'), }); // Tool definition for MCP exports.toolDefinition = { name: 'search_messages', description: 'Semantically searches for relevant messages in the conversation history based on a natural language query.', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'The natural language query to search for messages.' }, threadId: { type: 'string', description: 'Optional: The ID of the thread to search within. If not provided, searches the current active thread.' }, topK: { type: 'number', description: 'Optional: The maximum number of similar messages to return. Defaults to 5.' }, minScore: { type: 'number', description: 'Optional: The minimum similarity score (0-1) for results to be included. Defaults to 0.6.' }, }, required: ['query'], }, }; // Tool handler function async function toolHandler(toolInvocation, threadManager) { const parsedInput = exports.SearchMessagesInputSchema.safeParse(toolInvocation.input); if (!parsedInput.success) { return { message: `Invalid input for search_messages: ${parsedInput.error.errors.map(e => e.message).join(', ')}`, isError: true, }; } const { query, threadId, topK, minScore } = parsedInput.data; try { // Determine the thread ID to search within let targetThreadId = threadId; if (!targetThreadId) { const activeThread = await threadManager.getCurrentThread(); if (activeThread.thread) { targetThreadId = activeThread.thread.id; } else { return { message: 'No active thread found and no threadId provided. Cannot perform search.', isError: true, }; } } // Perform the search const results = await threadManager.messagesDAOInstance.searchSimilar(query, { threadId: targetThreadId, topK, minScore, }); // Format the results for display const formatted = results.map(msg => ({ id: msg.id, role: msg.role, content: msg.content.substring(0, 200) + (msg.content.length > 200 ? '...' : ''), timestamp: (0, date_fns_1.formatDistanceToNow)(msg.timestamp, { locale: locale_1.zhCN, addSuffix: true }), score: msg.score.toFixed(3), threadId: msg.threadId })); const message = formatSearchResults(query, formatted); return { message, info: JSON.stringify({ resultCount: results.length, avgScore: results.length > 0 ? (results.reduce((sum, r) => sum + r.score, 0) / results.length).toFixed(3) : '0.000' }, null, 2) // 格式化为可读的 JSON 字符串 }; } catch (error) { return { message: `Error performing search: ${error.message}`, isError: true, }; } } /** * Formats search results into a human-readable Markdown string. */ function formatSearchResults(query, results) { if (results.length === 0) { return `🔍 未找到与 "${query}" 相关的消息。`; } let output = `### 🔍 搜索结果: "${query}"\n\n`; output += `找到 ${results.length} 条相关消息:\n\n`; results.forEach((result, index) => { const icon = result.role === 'user' ? '👤' : '🤖'; const shortId = result.id.substring(0, 8); output += `**${index + 1}. ${icon} ${result.role}** (相似度: ${result.score}) - ID: \`${shortId}\`\n`; output += `🕒 ${result.timestamp}\n`; output += `> ${result.content}\n\n`; }); return output; }