Coverage for memory / long_term.py: 22%

59 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-03-29 02:55 +0800

1""" 

2中期记忆模块 

3 

4使用 Markdown 文件存储重要信息,Agent 可以主动写入和读取。 

5特点: 

6- 持久化存储在本地文件 

7- Agent 可以主动管理记忆 

8- 启动时自动加载并注入到 system prompt 

9""" 

10 

11from pathlib import Path 

12from datetime import datetime 

13from qrclaw.logger import get_logger 

14 

15logger = get_logger("qrclaw.memory.long_term") 

16 

17 

18class LongTermMemory: 

19 """长期记忆管理器""" 

20 

21 def __init__(self, memory_file: Path): 

22 """ 

23 初始化长期记忆。 

24 

25 Args: 

26 memory_file: 记忆文件路径(由 Workspace 提供) 

27 """ 

28 self.memory_file = memory_file 

29 self._ensure_file() 

30 logger.info(f"中期记忆初始化: {self.memory_file}") 

31 

32 def _ensure_file(self): 

33 """确保记忆文件存在""" 

34 self.memory_file.parent.mkdir(parents=True, exist_ok=True) 

35 if not self.memory_file.exists(): 

36 self.memory_file.write_text("# QRClaw 中期记忆\n\n", encoding="utf-8") 

37 logger.debug("创建中期记忆文件") 

38 

39 def load(self) -> str: 

40 """ 

41 加载记忆内容 

42 

43 Returns: 

44 str: 记忆内容(Markdown 格式) 

45 """ 

46 try: 

47 content = self.memory_file.read_text(encoding="utf-8") 

48 logger.info(f"加载中期记忆: {len(content)} 字符") 

49 return content 

50 except Exception as e: 

51 logger.error(f"加载中期记忆失败: {e}", exc_info=True) 

52 return "" 

53 

54 def save(self, content: str) -> bool: 

55 """ 

56 保存记忆内容(覆盖) 

57 

58 Args: 

59 content: 要保存的内容 

60 

61 Returns: 

62 bool: 是否成功 

63 """ 

64 try: 

65 self.memory_file.write_text(content, encoding="utf-8") 

66 logger.info(f"保存中期记忆: {len(content)} 字符") 

67 return True 

68 except Exception as e: 

69 logger.error(f"保存中期记忆失败: {e}", exc_info=True) 

70 return False 

71 

72 def append(self, content: str, title: str = None) -> bool: 

73 """ 

74 追加记忆内容 

75 

76 Args: 

77 content: 要追加的内容 

78 title: 可选的标题 

79 

80 Returns: 

81 bool: 是否成功 

82 """ 

83 try: 

84 timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") 

85 

86 # 构建追加内容 

87 append_text = f"\n---\n\n" 

88 if title: 

89 append_text += f"## {title}\n\n" 

90 append_text += f"**时间**: {timestamp}\n\n" 

91 append_text += f"{content}\n" 

92 

93 # 追加到文件 

94 with open(self.memory_file, "a", encoding="utf-8") as f: 

95 f.write(append_text) 

96 

97 logger.info(f"追加中期记忆: {title or '无标题'}, {len(content)} 字符") 

98 return True 

99 except Exception as e: 

100 logger.error(f"追加中期记忆失败: {e}", exc_info=True) 

101 return False 

102 

103 def clear(self) -> bool: 

104 """ 

105 清空记忆(保留标题) 

106 

107 Returns: 

108 bool: 是否成功 

109 """ 

110 try: 

111 self.memory_file.write_text("# QRClaw 中期记忆\n\n", encoding="utf-8") 

112 logger.info("清空中期记忆") 

113 return True 

114 except Exception as e: 

115 logger.error(f"清空中期记忆失败: {e}", exc_info=True) 

116 return False 

117 

118 def exists(self) -> bool: 

119 """检查记忆文件是否存在""" 

120 return self.memory_file.exists() 

121 

122 def size(self) -> int: 

123 """获取记忆文件大小(字符数)""" 

124 if self.exists(): 

125 return len(self.load()) 

126 return 0