#!/usr/bin/env node /** * OpenClaw Mem0 Integration Plugin * 将 mem0 拦截器挂载到 OpenClaw 主对话生命周期 */ const fs = require('fs'); const path = require('path'); // Python 子进程执行器 const { spawn } = require('child_process'); class Mem0Plugin { constructor(config) { this.config = config; this.enabled = true; this.pythonPath = config.pythonPath || 'python3'; this.scriptPath = path.join(__dirname, 'mem0_integration.py'); this.initialized = false; } /** * 初始化 mem0(在 OpenClaw 启动时调用) */ async onLoad() { if (!this.enabled) return; console.log('[Mem0] 初始化记忆系统...'); try { // 调用 Python 脚本初始化 mem0 const result = await this._executePython('init'); if (result.success) { this.initialized = true; console.log('🟢 Mem0 生产环境集成完毕,等待 Telegram 消息注入'); } else { console.error('[Mem0] 初始化失败:', result.error); } } catch (error) { console.error('[Mem0] 初始化异常:', error.message); } } /** * Pre-Hook: 在 LLM 生成前检索记忆 */ async preLLM(userMessage, context) { if (!this.enabled || !this.initialized) return null; try { const result = await this._executePython('search', { query: userMessage, user_id: context.user_id || 'default', agent_id: context.agent_id || 'general' }); if (result.success && result.memories && result.memories.length > 0) { console.log(`[Mem0] Pre-Hook: 检索到 ${result.memories.length} 条记忆`); return this._formatMemories(result.memories); } return null; } catch (error) { console.error('[Mem0] Pre-Hook 失败:', error.message); return null; // 静默失败,不影响对话 } } /** * Post-Hook: 在响应后异步写入记忆 */ async postResponse(userMessage, assistantMessage, context) { if (!this.enabled || !this.initialized) return; try { await this._executePython('add', { user_message: userMessage, assistant_message: assistantMessage, user_id: context.user_id || 'default', agent_id: context.agent_id || 'general' }, false); // 不等待结果(异步) console.log('[Mem0] Post-Hook: 已提交对话到记忆队列'); } catch (error) { console.error('[Mem0] Post-Hook 失败:', error.message); // 静默失败 } } /** * 执行 Python 脚本 */ _executePython(action, data = {}, waitForResult = true) { return new Promise((resolve, reject) => { const args = [this.scriptPath, action]; if (data) { args.push(JSON.stringify(data)); } const proc = spawn(this.pythonPath, args, { cwd: __dirname, env: process.env }); let stdout = ''; let stderr = ''; proc.stdout.on('data', (data) => { stdout += data.toString(); }); proc.stderr.on('data', (data) => { stderr += data.toString(); }); proc.on('close', (code) => { if (code === 0) { try { const result = JSON.parse(stdout); resolve({ success: true, ...result }); } catch { resolve({ success: true, raw: stdout }); } } else { resolve({ success: false, error: stderr || `Exit code: ${code}` }); } }); proc.on('error', reject); // 如果不等待结果,立即返回 if (!waitForResult) { resolve({ success: true, async: true }); } }); } /** * 格式化记忆为 Prompt */ _formatMemories(memories) { if (!memories || memories.length === 0) return ''; let prompt = '\n\n=== 相关记忆 ===\n'; memories.forEach((mem, i) => { prompt += `${i + 1}. ${mem.memory}`; if (mem.created_at) { prompt += ` (记录于:${mem.created_at})`; } prompt += '\n'; }); prompt += '===============\n'; return prompt; } } // 导出插件实例 const mem0Plugin = new Mem0Plugin({ pythonPath: process.env.MEM0_PYTHON_PATH || 'python3' }); // OpenClaw 插件生命周期导出 module.exports = { async register(ctx) { console.log('[Mem0] 注册插件...'); await mem0Plugin.onLoad(); return mem0Plugin; }, async activate(ctx) { console.log('[Mem0] 激活插件...'); return mem0Plugin; }, // 导出实例方法供 OpenClaw 调用 preLLM: async (userMessage, context) => await mem0Plugin.preLLM(userMessage, context), postResponse: async (userMessage, assistantMessage, context) => await mem0Plugin.postResponse(userMessage, assistantMessage, context), ...mem0Plugin };