From 23b011e6abfc2d97915aa63d0d0952c56e252884 Mon Sep 17 00:00:00 2001 From: Windpicker-owo <3431391539@qq.com> Date: Wed, 5 Nov 2025 20:43:39 +0800 Subject: [PATCH] =?UTF-8?q?fix(memory-graph):=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E9=9B=86=E6=88=90=E6=B5=8B=E8=AF=95=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复Config类memory字段验证问题 (改为Optional) - 为Memory模型添加activation属性 - 修复CreateMemoryTool返回值 (添加memory_id) - 为GraphStore添加remove_memory方法 - 修复integration测试脚本 - 所有集成测试通过 (5/5) Changes: - src/config/config.py: memory字段改为Optional - src/memory_graph/models.py: 添加activation属性 - src/memory_graph/plugin_tools/memory_plugin_tools.py: 返回memory_id - src/memory_graph/storage/graph_store.py: 添加remove_memory方法 - tests/test_memory_graph_integration.py: 修复工具返回值检查 Tests: 基本记忆操作 (CRUD + 检索) LLM工具集成 (创建记忆) 记忆生命周期 (激活/整合/遗忘) 维护任务 (调度+手动执行) 配置系统 (默认/自定义/bot_config) --- src/config/config.py | 3 +- src/memory_graph/models.py | 6 ++- .../plugin_tools/memory_plugin_tools.py | 6 ++- src/memory_graph/storage/graph_store.py | 38 +++++++++++++++++++ 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/config/config.py b/src/config/config.py index 0ecef9d83..2ad7cc651 100644 --- a/src/config/config.py +++ b/src/config/config.py @@ -2,6 +2,7 @@ import os import shutil import sys from datetime import datetime +from typing import Optional import tomlkit from pydantic import Field @@ -380,7 +381,7 @@ class Config(ValidatedConfigBase): notice: NoticeConfig = Field(..., description="Notice消息配置") emoji: EmojiConfig = Field(..., description="表情配置") expression: ExpressionConfig = Field(..., description="表达配置") - memory: MemoryConfig = Field(..., description="记忆配置") + memory: Optional[MemoryConfig] = Field(default=None, description="记忆配置(旧版,已废弃)") mood: MoodConfig = Field(..., description="情绪配置") reaction: ReactionConfig = Field(default_factory=ReactionConfig, description="反应规则配置") chinese_typo: ChineseTypoConfig = Field(..., description="中文错别字配置") diff --git a/src/memory_graph/models.py b/src/memory_graph/models.py index 8b7b98e59..4bb834d4e 100644 --- a/src/memory_graph/models.py +++ b/src/memory_graph/models.py @@ -164,6 +164,7 @@ class Memory: nodes: List[MemoryNode] # 该记忆包含的所有节点 edges: List[MemoryEdge] # 该记忆包含的所有边 importance: float = 0.5 # 整体重要性 [0-1] + activation: float = 0.0 # 激活度 [0-1],用于记忆整合和遗忘 status: MemoryStatus = MemoryStatus.STAGED # 记忆状态 created_at: datetime = field(default_factory=datetime.now) last_accessed: datetime = field(default_factory=datetime.now) # 最后访问时间 @@ -175,8 +176,9 @@ class Memory: """后初始化处理""" if not self.id: self.id = str(uuid.uuid4()) - # 确保重要性在有效范围内 + # 确保重要性和激活度在有效范围内 self.importance = max(0.0, min(1.0, self.importance)) + self.activation = max(0.0, min(1.0, self.activation)) def to_dict(self) -> Dict[str, Any]: """转换为字典(用于序列化)""" @@ -187,6 +189,7 @@ class Memory: "nodes": [node.to_dict() for node in self.nodes], "edges": [edge.to_dict() for edge in self.edges], "importance": self.importance, + "activation": self.activation, "status": self.status.value, "created_at": self.created_at.isoformat(), "last_accessed": self.last_accessed.isoformat(), @@ -205,6 +208,7 @@ class Memory: nodes=[MemoryNode.from_dict(n) for n in data["nodes"]], edges=[MemoryEdge.from_dict(e) for e in data["edges"]], importance=data.get("importance", 0.5), + activation=data.get("activation", 0.0), status=MemoryStatus(data.get("status", "staged")), created_at=datetime.fromisoformat(data["created_at"]), last_accessed=datetime.fromisoformat(data.get("last_accessed", data["created_at"])), diff --git a/src/memory_graph/plugin_tools/memory_plugin_tools.py b/src/memory_graph/plugin_tools/memory_plugin_tools.py index 4771507b6..b3fb4a9e0 100644 --- a/src/memory_graph/plugin_tools/memory_plugin_tools.py +++ b/src/memory_graph/plugin_tools/memory_plugin_tools.py @@ -78,12 +78,14 @@ class CreateMemoryTool(BaseTool): logger.info(f"[CreateMemoryTool] 成功创建记忆: {memory.id}") return { "name": self.name, - "content": f"成功创建记忆(ID: {memory.id})" + "content": f"成功创建记忆(ID: {memory.id})", + "memory_id": memory.id, # 返回记忆ID供后续使用 } else: return { "name": self.name, - "content": "创建记忆失败" + "content": "创建记忆失败", + "memory_id": None, } except Exception as e: diff --git a/src/memory_graph/storage/graph_store.py b/src/memory_graph/storage/graph_store.py index a99a55282..a3699b373 100644 --- a/src/memory_graph/storage/graph_store.py +++ b/src/memory_graph/storage/graph_store.py @@ -390,6 +390,44 @@ class GraphStore: logger.info(f"从字典加载图: {store.get_statistics()}") return store + def remove_memory(self, memory_id: str) -> bool: + """ + 从图中删除指定记忆 + + Args: + memory_id: 要删除的记忆ID + + Returns: + 是否删除成功 + """ + try: + # 1. 检查记忆是否存在 + if memory_id not in self.memory_index: + logger.warning(f"记忆不存在,无法删除: {memory_id}") + return False + + memory = self.memory_index[memory_id] + + # 2. 从节点映射中移除此记忆 + for node in memory.nodes: + if node.id in self.node_to_memories: + self.node_to_memories[node.id].discard(memory_id) + # 如果该节点不再属于任何记忆,从图中移除节点 + if not self.node_to_memories[node.id]: + if self.graph.has_node(node.id): + self.graph.remove_node(node.id) + del self.node_to_memories[node.id] + + # 3. 从记忆索引中移除 + del self.memory_index[memory_id] + + logger.info(f"成功删除记忆: {memory_id}") + return True + + except Exception as e: + logger.error(f"删除记忆失败 {memory_id}: {e}", exc_info=True) + return False + def clear(self) -> None: """清空图(危险操作,仅用于测试)""" self.graph.clear()