#!/usr/bin/env python3 """ memory-md-learning 学习记录脚本 记录陷阱、教训和解决方案到长期记忆和 MEMORY.md """ import os import re import sys import argparse from datetime import datetime from pathlib import Path # 配置 MEMORY_FILE = Path.home() / ".openclaw" / "workspace" / "MEMORY.md" ARCHIVE_THRESHOLD_KB = 50 def read_memory_file(): """读取 memory.md 文件内容""" if not MEMORY_FILE.exists(): return "" return MEMORY_FILE.read_text(encoding='utf-8') def write_memory_file(content): """写入 memory.md 文件""" MEMORY_FILE.parent.mkdir(parents=True, exist_ok=True) MEMORY_FILE.write_text(content, encoding='utf-8') def get_file_size(): """获取文件大小(字节)""" if not MEMORY_FILE.exists(): return 0 return MEMORY_FILE.stat().st_size def extract_learning_entries(content): """从内容中提取学习事件条目""" learning_events = [] lines = content.split('\n') in_learning = False for line in lines: stripped = line.strip() # 检测学习事件区块 if '学习事件' in stripped and stripped.startswith('#'): in_learning = True continue elif stripped.startswith('#') and in_learning: in_learning = False # 收集学习事件 if in_learning and (stripped.startswith('-') or stripped.startswith('*')): if len(stripped) > 10: learning_events.append(line) return learning_events def store_technical_memory(trap, cause, fix, prevent): """ 存储技术层记忆 格式:陷阱:[现象]。原因:[根本原因]。修复:[解决方案]。预防:[如何避免] """ content = f"陷阱:{trap}。原因:{cause}。修复:{fix}。预防:{prevent}" # 使用 memory_store 工具存储 # 注意:实际调用需要通过外部机制,这里返回内容供调用方使用 return { 'content': content, 'category': 'fact', 'importance': 0.8, 'keywords': extract_keywords(content) } def store_principle_memory(principle, trigger, action, tag): """ 存储原则层记忆 格式:决策原则([标签]):[行为准则]。触发条件:[何时]。行动:[做什么] """ content = f"决策原则({tag}):{principle}。触发条件:{trigger}。行动:{action}" return { 'content': content, 'category': 'decision', 'importance': 0.85, 'keywords': extract_keywords(content) } def extract_keywords(text): """从文本中提取关键词""" # 简单实现:提取中文字符和英文单词 import re chinese_chars = re.findall(r'[\u4e00-\u9fff]{2,}', text) english_words = re.findall(r'[a-zA-Z]{3,}', text) return list(set(chinese_chars + english_words))[:10] # 最多10个关键词 def verify_memory_recall(keywords, timeout=5): """ 验证记忆是否能被正确召回 返回: {'verified': bool, 'results': list} """ # 实际实现中需要调用 memory_recall # 这里返回模拟结果 return { 'verified': True, 'results': [], 'message': '记忆召回验证需要调用 memory_recall 工具' } def update_memory_md_learning(summary, keywords): """ 更新 MEMORY.md 的学习事件区块 """ content = read_memory_file() if not content: # 如果文件不存在,先创建一个基础结构 content = generate_base_content() # 检查是否已有学习事件区块 if '## 📚 学习事件' not in content: # 在学习事件区块不存在时,在文件末尾添加 learning_section = f""" --- ## 📚 学习事件 > 记录从陷阱和教训中学习的经验。 > 所有学习记录永久保留,可使用 memory-md-archive 技能归档瘦身。 """ # 在归档提示之前插入 if '---' in content and '*文件大小:' in content: # 找到最后一个分隔符之前 last_sep = content.rfind('---\n\n*文件大小:') if last_sep > 0: content = content[:last_sep] + learning_section + content[last_sep:] else: content = content + learning_section else: content = content + learning_section # 提取现有的学习事件 existing_events = extract_learning_entries(content) # 添加新的学习事件 now = datetime.now() date_str = now.strftime('%Y-%m-%d') time_str = now.strftime('%H:%M') new_event = f"- {date_str} {time_str} | {summary} | {keywords}" # 检查是否已存在 if any(new_event.strip() in existing.strip() for existing in existing_events): return {'added': False, 'message': '学习事件已存在'} # 找到学习事件区块并插入新事件 lines = content.split('\n') new_lines = [] in_learning = False learning_inserted = False for i, line in enumerate(lines): stripped = line.strip() # 检测学习事件区块开始 if '## 📚 学习事件' in stripped: in_learning = True new_lines.append(line) continue # 检测学习事件区块结束(遇到下一个标题或文件末尾信息) if in_learning and stripped.startswith('#') and '学习事件' not in stripped: if not learning_inserted: new_lines.append(new_event) learning_inserted = True in_learning = False new_lines.append(line) continue # 在学习事件区块内,跳过空行后插入新事件 if in_learning and not learning_inserted: if stripped == '' and i > 0 and '记录从陷阱' not in lines[i-1] and '所有学习记录' not in lines[i-1]: new_lines.append(new_event) new_lines.append('') learning_inserted = True continue new_lines.append(line) # 如果在文件末尾,确保插入了事件 if in_learning and not learning_inserted: new_lines.append(new_event) # 更新文件大小信息 new_content = '\n'.join(new_lines) # 更新文件大小统计 write_memory_file(new_content) new_size = get_file_size() size_kb = round(new_size / 1024, 2) # 更新底部统计信息 new_content = update_footer_stats(new_content, size_kb) write_memory_file(new_content) return { 'added': True, 'event': new_event, 'size_kb': size_kb, 'archive_suggested': size_kb > ARCHIVE_THRESHOLD_KB } def update_footer_stats(content, size_kb): """更新文件底部的统计信息""" # 统计学习事件数量 learning_events = extract_learning_entries(content) learning_count = len(learning_events) # 替换或添加归档提示 if '*归档提示:' in content: # 替换现有提示 content = re.sub( r'\*归档提示:.*\*', f"*归档提示: 文件较大时请使用 memory-md-archive 技能归档(当前 {size_kb}KB,{learning_count} 条学习事件)*", content ) elif '---' in content and '*文件大小:' in content: # 在文件大小行后添加 content = content.replace( '*维护脚本:', f"*归档提示: 文件较大时请使用 memory-md-archive 技能归档(当前 {size_kb}KB,{learning_count} 条学习事件)*\n*维护脚本:" ) return content def generate_base_content(): """生成基础的 memory.md 内容""" today = datetime.now().strftime('%Y-%m-%d') return f"""# MEMORY.md - 热记忆 / 活跃记忆 > 本文件记录近期发生的重要事情,详细信息可通过记忆检索获取。 --- ## 🔔 重要事件 > 记录具有全局长期性影响的重要决策和事件。 > 添加重要事件时会告知用户。 --- ## 📅 事件流水 > 按天分组,每天主要事情的概要。 > 所有记录永久保留,可使用 memory-md-archive 技能归档瘦身。 ### {today} - {today} --:-- | 暂无记录 | -- --- *文件大小: ~0.5KB | 事件数: 0* *维护脚本: `memory-md-hot/scripts/daily_maintenance.py`* *归档提示: 文件较大时请使用 memory-md-archive 技能归档* """ def record_learning(trap, cause, fix, prevent, principle, trigger, action, tag, summary, keywords): """ 记录学习的主函数 Returns: dict: 操作结果 """ result = { 'success': False, 'technical_memory': None, 'principle_memory': None, 'learning_event': None, 'recall_verified': False, 'messages': [] } # 1. 准备技术层记忆 technical = store_technical_memory(trap, cause, fix, prevent) result['technical_memory'] = technical result['messages'].append(f"技术层记忆已准备: {technical['content'][:50]}...") # 2. 准备原则层记忆 principle_mem = store_principle_memory(principle, trigger, action, tag) result['principle_memory'] = principle_mem result['messages'].append(f"原则层记忆已准备: {principle_mem['content'][:50]}...") # 3. 更新 MEMORY.md 学习事件 learning_result = update_memory_md_learning(summary, keywords) result['learning_event'] = learning_result if learning_result['added']: result['messages'].append(f"学习事件已记录: {learning_result['event']}") else: result['messages'].append(f"学习事件: {learning_result['message']}") # 4. 验证记忆召回(模拟) all_keywords = technical['keywords'] + principle_mem['keywords'] verify_result = verify_memory_recall(all_keywords) result['recall_verified'] = verify_result['verified'] result['messages'].append(f"记忆召回验证: {verify_result['message']}") # 5. 归档提示 if learning_result.get('archive_suggested'): result['messages'].append(f"提示: 文件大小 {learning_result['size_kb']}KB,建议使用 memory-md-archive 技能归档") result['success'] = True return result def main(): """主函数 - 供命令行调用""" parser = argparse.ArgumentParser(description='记录学习成果') parser.add_argument('--trap', required=True, help='陷阱现象描述') parser.add_argument('--cause', required=True, help='根本原因分析') parser.add_argument('--fix', required=True, help='解决方案') parser.add_argument('--prevent', required=True, help='预防措施') parser.add_argument('--principle', required=True, help='行为准则') parser.add_argument('--trigger', required=True, help='触发条件') parser.add_argument('--action', required=True, help='具体行动') parser.add_argument('--tag', required=True, help='原则标签') parser.add_argument('--summary', required=True, help='一句话概要') parser.add_argument('--keywords', required=True, help='关键词,逗号分隔') args = parser.parse_args() result = record_learning( trap=args.trap, cause=args.cause, fix=args.fix, prevent=args.prevent, principle=args.principle, trigger=args.trigger, action=args.action, tag=args.tag, summary=args.summary, keywords=args.keywords ) if result['success']: print("✅ 学习记录完成") print(f"\n技术层记忆:") print(f" {result['technical_memory']['content']}") print(f"\n原则层记忆:") print(f" {result['principle_memory']['content']}") print(f"\n学习事件:") if result['learning_event']['added']: print(f" {result['learning_event']['event']}") else: print(f" {result['learning_event']['message']}") print(f"\n记忆召回验证: {'通过' if result['recall_verified'] else '待验证'}") print("\n注意:技术层和原则层记忆需要调用 memory_store 工具实际存储到长期记忆") for msg in result['messages']: if '提示' in msg: print(f"\n{msg}") else: print("❌ 学习记录失败") for msg in result['messages']: print(f" - {msg}") sys.exit(1) if __name__ == "__main__": main()