log_conversation
Logs AI conversations in structured markdown format, recording user requests, execution plans, summaries, and file operations. Enhances project continuity and provides searchable history for better context management.
Instructions
记录AI对话 - 所有会话都要记录
使用规范: • userRequest: 用户原始需求+上传文件说明 • aiTodoList: 你的执行计划清单(即使只是查看也要列出) • aiSummary: 你的操作总结(3-5句话,包括解释、分析等) • fileOperations: 文件操作总结,格式:"动作 文件路径 - 说明"(可为空) • title: 对话标题(可选) • tags: 标签数组(可选)
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| aiSummary | Yes | AI的操作总结(3-5句话,包括解释、分析等) | |
| aiTodoList | Yes | AI的执行计划清单(即使只是查看也要列出) | |
| fileOperations | No | 文件操作总结,格式:"动作 文件路径 - 说明"(可为空) | |
| project | No | 项目名(可选,自动检测) | |
| tags | No | 标签数组(可选) | |
| title | No | 对话标题(可选) | |
| userRequest | Yes | 用户原始需求 + 上传文件说明 |
Implementation Reference
- src/tools/conversationLogger.ts:25-115 (handler)Core handler function that validates input using validateLogConversation, detects project, formats and appends conversation entry to daily Markdown log file, returns success/error message.async logConversation(params: unknown): Promise<{ content: Array<{ type: string; text: string }> }> { try { const validatedParams = validateLogConversation(params); const { userRequest, aiTodoList, aiSummary, fileOperations, title, tags, platform } = validatedParams; // Auto-detect project from current working directory const projectInfo = await this.fileManager.getProjectInfo(); const projectName = projectInfo.name; await this.fileManager.initializeProject(); const now = new Date(); // Use zero-padded date format for better sorting (2025-08-07 instead of 2025-8-7) const year = now.getFullYear(); const month = String(now.getMonth() + 1).padStart(2, '0'); const day = String(now.getDate()).padStart(2, '0'); const dateStr = `${year}-${month}-${day}`; const conversationEntry: ConversationEntry = { id: randomUUID(), timestamp: now.toISOString(), project: projectName, platform: platform || CONSTANTS.PLATFORMS.UNKNOWN, userRequest: userRequest.trim(), aiTodoList: aiTodoList || [], aiSummary: aiSummary.trim(), fileOperations: fileOperations || [], title: title?.trim() || undefined, tags: tags || [] }; const dailyLogPath = await this.fileManager.getDailyLogPath(projectName, dateStr); let existingContent = await this.fileManager.readFile(dailyLogPath); // Calculate conversation number const existingConversationCount = (existingContent.match(/## 对话/g) || []).length; const conversationNumber = existingConversationCount + 1; // Generate the conversation markdown const conversationMarkdown = MarkdownFormatter.formatConversationEntry(conversationEntry, conversationNumber); if (!existingContent) { // New file: create header + new conversation const header = MarkdownFormatter.formatDailyLogHeader(projectName, dateStr, projectInfo.root); const finalContent = header + conversationMarkdown; await this.fileManager.writeFile(dailyLogPath, finalContent); } else { // Existing file: just append new conversation const finalContent = existingContent + conversationMarkdown; await this.fileManager.writeFile(dailyLogPath, finalContent); } return { content: [ { type: 'text', text: `✅ 对话已成功记录到项目 "${projectName}"!\n\n` + `📁 文件位置: ${dailyLogPath}\n` + `💻 项目目录: ${projectInfo.root || '未检测到项目'}\n` + `🕒 时间: ${now.toLocaleString('zh-CN')}\n` + `🏷️ 标签: ${(tags && tags.length > 0) ? tags.join(', ') : '无'}\n` + `⚡ 执行任务: ${aiTodoList?.length || 0}\n` + `📂 文件操作: ${fileOperations?.length || 0}\n` + `📝 对话编号: 对话${conversationNumber}` } ] }; } catch (error) { const errorMessage = error instanceof ValidationError ? `参数验证失败: ${error.message}` : error instanceof FileOperationError ? `文件操作失败: ${error.message} (文件: ${error.filePath})` : `记录对话时出错: ${String(error)}`; return { content: [ { type: 'text', text: `❌ ${errorMessage}` } ] }; } }
- src/validation/schemas.ts:19-33 (schema)Zod schema for validating log_conversation input parameters including userRequest, aiTodoList, aiSummary, etc.export const LogConversationSchema = z.object({ project: z.string().optional(), // 项目名称(可选,自动检测) userRequest: z.string().min(1, '用户需求不能为空'), aiTodoList: z.array(z.string()).min(1, 'AI执行计划不能为空'), aiSummary: z.string().min(1, 'AI总结不能为空'), fileOperations: z.array(z.string()).optional(), title: z.string().optional(), tags: z.array(z.string()).optional(), platform: z.string().default(CONSTANTS.PLATFORMS.CLAUDE_CODE) }).transform((data) => ({ ...data, tags: data.tags || [], fileOperations: data.fileOperations || [], platform: data.platform || CONSTANTS.PLATFORMS.CLAUDE_CODE }));
- src/index.ts:38-78 (registration)Tool registration in MCP listTools handler, defining name, description, and inputSchema for log_conversation.{ name: 'log_conversation', description: '记录AI对话 - 所有会话都要记录\n\n使用规范:\n• userRequest: 用户原始需求+上传文件说明\n• aiTodoList: 你的执行计划清单(即使只是查看也要列出)\n• aiSummary: 你的操作总结(3-5句话,包括解释、分析等)\n• fileOperations: 文件操作总结,格式:"动作 文件路径 - 说明"(可为空)\n• title: 对话标题(可选)\n• tags: 标签数组(可选)', inputSchema: { type: 'object', properties: { userRequest: { type: 'string', description: '用户原始需求 + 上传文件说明' }, aiTodoList: { type: 'array', items: { type: 'string' }, description: 'AI的执行计划清单(即使只是查看也要列出)' }, aiSummary: { type: 'string', description: 'AI的操作总结(3-5句话,包括解释、分析等)' }, fileOperations: { type: 'array', items: { type: 'string' }, description: '文件操作总结,格式:"动作 文件路径 - 说明"(可为空)' }, title: { type: 'string', description: '对话标题(可选)' }, tags: { type: 'array', items: { type: 'string' }, description: '标签数组(可选)' }, project: { type: 'string', description: '项目名(可选,自动检测)' } }, required: ['userRequest', 'aiTodoList', 'aiSummary'] } },
- src/index.ts:161-162 (registration)Dispatch handler in MCP callTool switch statement that routes log_conversation calls to ConversationLogger.logConversation method.case 'log_conversation': return await this.conversationLogger.logConversation(args || {});
- src/validation/schemas.ts:119-126 (schema)Validator function that uses LogConversationSchema to parse and validate input parameters for the tool.export const validateLogConversation = (data: unknown): LogConversationParams => { const result = LogConversationSchema.safeParse(data); if (!result.success) { const errorMessages = result.error.errors.map(err => `${err.path.join('.')}: ${err.message}`).join('; '); throw new Error(`${CONSTANTS.ERROR_MESSAGES.INVALID_PARAMETERS}: ${errorMessages}`); } return result.data as LogConversationParams; };