mindforge-memory 6.4.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. MindForge.py +20 -0
  2. mindforge/__init__.py +111 -0
  3. mindforge/adapters/__init__.py +18 -0
  4. mindforge/adapters/claude_adapter.py +84 -0
  5. mindforge/adapters/crewai_memory.py +76 -0
  6. mindforge/adapters/generic_api.py +183 -0
  7. mindforge/adapters/langgraph_store.py +463 -0
  8. mindforge/adapters/openclaw_adapter.py +91 -0
  9. mindforge/api/__init__.py +1 -0
  10. mindforge/api/server.py +1567 -0
  11. mindforge/cli/__init__.py +1 -0
  12. mindforge/cli/main.py +13607 -0
  13. mindforge/core/__init__.py +37 -0
  14. mindforge/core/embedding.py +847 -0
  15. mindforge/core/encryption.py +597 -0
  16. mindforge/core/indexer.py +363 -0
  17. mindforge/core/mindforge.py +6298 -0
  18. mindforge/core/paths.py +43 -0
  19. mindforge/core/query.py +501 -0
  20. mindforge/core/storage.py +18656 -0
  21. mindforge/core/types.py +314 -0
  22. mindforge/core/version.py +56 -0
  23. mindforge/daemon/__init__.py +0 -0
  24. mindforge/daemon/server.py +277 -0
  25. mindforge/mcp/__init__.py +4 -0
  26. mindforge/mcp/server.py +2559 -0
  27. mindforge/modules/__init__.py +138 -0
  28. mindforge/modules/categorizer.py +151 -0
  29. mindforge/modules/conflict_detector.py +356 -0
  30. mindforge/modules/connectors.py +331 -0
  31. mindforge/modules/context_window.py +337 -0
  32. mindforge/modules/event_bus.py +572 -0
  33. mindforge/modules/evolution.py +210 -0
  34. mindforge/modules/experience.py +402 -0
  35. mindforge/modules/federated.py +722 -0
  36. mindforge/modules/federated_acl.py +393 -0
  37. mindforge/modules/follow_up.py +315 -0
  38. mindforge/modules/hybrid_search.py +565 -0
  39. mindforge/modules/importer.py +374 -0
  40. mindforge/modules/integrator.py +196 -0
  41. mindforge/modules/intent_router.py +359 -0
  42. mindforge/modules/knowledge_graph.py +395 -0
  43. mindforge/modules/memory_compressor.py +592 -0
  44. mindforge/modules/memory_decay.py +474 -0
  45. mindforge/modules/memory_passport.py +250 -0
  46. mindforge/modules/multi_agent.py +534 -0
  47. mindforge/modules/multimodal.py +304 -0
  48. mindforge/modules/outcome_learning.py +186 -0
  49. mindforge/modules/personality.py +275 -0
  50. mindforge/modules/principled_forgetting.py +258 -0
  51. mindforge/modules/privacy.py +736 -0
  52. mindforge/modules/recall.py +263 -0
  53. mindforge/modules/session_focus.py +305 -0
  54. mindforge/modules/share_conflict.py +521 -0
  55. mindforge/modules/skill_extractor.py +340 -0
  56. mindforge/modules/skill_pack.py +205 -0
  57. mindforge/modules/timeline_viz.py +206 -0
  58. mindforge/modules/v6.py +931 -0
  59. mindforge_memory-6.4.1.dist-info/METADATA +281 -0
  60. mindforge_memory-6.4.1.dist-info/RECORD +64 -0
  61. mindforge_memory-6.4.1.dist-info/WHEEL +5 -0
  62. mindforge_memory-6.4.1.dist-info/entry_points.txt +3 -0
  63. mindforge_memory-6.4.1.dist-info/licenses/LICENSE +21 -0
  64. mindforge_memory-6.4.1.dist-info/top_level.txt +2 -0
@@ -0,0 +1,250 @@
1
+ """
2
+ MindForge v6.0.0 功能 6:记忆护照(跨模型迁移)
3
+
4
+ 花半年教会一个 AI 的记忆,一次授权、记忆跟你走、随时可撤销。
5
+
6
+ - export_passport(): 导出结构化记忆护照(schema + 记忆 + 偏好 + 技能)
7
+ - import_passport(): 导入护照(merge/replace),标记来源 passport_id
8
+ - revoke_passport(): 撤销导入——删除来源标记的记忆,可逆
9
+ - passport_status(): 当前护照导入来源状态
10
+
11
+ 安全约束:
12
+ - 护照含 schema 标识 mindforge-memory-passport/1.0 与 passport_id
13
+ - 导入时校验格式;单条失败不中断
14
+ - revoke 只删除带该 passport_id 来源标记的记忆(不动用户已有数据)
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import json
20
+ import time
21
+ import uuid
22
+ from typing import Any, Dict, List, Optional
23
+
24
+ PASSPORT_FORMAT = "mindforge-memory-passport"
25
+ FORMAT_VERSION = 1
26
+ MAX_MEMORIES = 10000
27
+ MAX_PREFERENCES = 500
28
+
29
+ # 写入 memories 时用于标记来源的 metadata key
30
+ _PASSPORT_KEY = "passport_id"
31
+
32
+
33
+ def _ensure_columns(conn) -> None:
34
+ try:
35
+ conn.execute("ALTER TABLE memories ADD COLUMN passport_id TEXT DEFAULT ''")
36
+ except Exception:
37
+ pass
38
+
39
+
40
+ def _collect_memories(mf, max_memories: int) -> List[Dict[str, Any]]:
41
+ """收集记忆(不含 STRICT 隐私;不含明文之外的敏感字段)"""
42
+ out = []
43
+ try:
44
+ conn = mf._storage._get_conn()
45
+ rows = conn.execute(
46
+ "SELECT id, content, category, tags, importance, layer, privacy, "
47
+ "source_agent, source_session, created_at, valid_from, valid_to, "
48
+ "metadata FROM memories WHERE privacy != 'STRICT' ORDER BY created_at "
49
+ "LIMIT ?", (max(1, min(MAX_MEMORIES, int(max_memories))),)).fetchall()
50
+ except Exception:
51
+ rows = []
52
+ for r in rows:
53
+ tags = r[3]
54
+ try:
55
+ tags = json.loads(tags) if tags and tags.startswith("[") else []
56
+ except Exception:
57
+ tags = []
58
+ out.append({
59
+ "id": r[0], "content": r[1], "category": r[2] or "general",
60
+ "tags": tags, "importance": r[4] or "MEDIUM", "layer": r[5] or "short_term",
61
+ "privacy": r[6] or "INTERNAL", "source_agent": r[7] or "",
62
+ "source_session": r[8] or "", "created_at": r[9] or 0.0,
63
+ "valid_from": r[10] or 0.0, "valid_to": r[11] or 0.0,
64
+ })
65
+ return out
66
+
67
+
68
+ def _collect_preferences(mf) -> List[Dict[str, Any]]:
69
+ """收集偏好类记忆(category=preference 或带 user_preference 标签)"""
70
+ prefs = []
71
+ for m in _collect_memories(mf, MAX_MEMORIES):
72
+ if (m["category"] == "preference"
73
+ or any("user_preference" in (t or "") for t in m["tags"])):
74
+ prefs.append({
75
+ "content": m["content"], "tags": m["tags"][:10],
76
+ "importance": m["importance"], "created_at": m["created_at"],
77
+ })
78
+ if len(prefs) >= MAX_PREFERENCES:
79
+ break
80
+ return prefs
81
+
82
+
83
+ def export_passport(mf, include_skills: bool = True,
84
+ include_preferences: bool = True,
85
+ max_memories: int = 5000) -> Dict[str, Any]:
86
+ """导出记忆护照"""
87
+ passport_id = f"passport_{uuid.uuid4().hex[:12]}"
88
+ memories = _collect_memories(mf, max_memories)
89
+ passport = {
90
+ "format": PASSPORT_FORMAT,
91
+ "format_version": FORMAT_VERSION,
92
+ "passport_id": passport_id,
93
+ "exported_at": round(time.time(), 3),
94
+ "counts": {"memories": len(memories)},
95
+ "memories": memories,
96
+ }
97
+ if include_preferences:
98
+ prefs = _collect_preferences(mf)
99
+ passport["preferences"] = prefs
100
+ passport["counts"]["preferences"] = len(prefs)
101
+ if include_skills:
102
+ try:
103
+ skills = mf.skill_list(limit=200)
104
+ passport["skills"] = skills
105
+ passport["counts"]["skills"] = len(skills)
106
+ except Exception:
107
+ passport["skills"] = []
108
+ return {"success": True, "passport_id": passport_id,
109
+ "passport": passport, "counts": passport["counts"]}
110
+
111
+
112
+ def _validate(passport: Any) -> Dict[str, Any]:
113
+ errors = []
114
+ if not isinstance(passport, dict):
115
+ return {"valid": False, "errors": ["护照必须是 JSON 对象"]}
116
+ if passport.get("format") != PASSPORT_FORMAT:
117
+ errors.append("格式标识错误")
118
+ if passport.get("format_version") != FORMAT_VERSION:
119
+ errors.append("版本不支持")
120
+ if not passport.get("passport_id"):
121
+ errors.append("缺少 passport_id")
122
+ mems = passport.get("memories")
123
+ if not isinstance(mems, list):
124
+ errors.append("缺少 memories 列表")
125
+ elif len(mems) > MAX_MEMORIES:
126
+ errors.append(f"记忆数超过上限 {MAX_MEMORIES}")
127
+ return {"valid": not errors, "errors": errors}
128
+
129
+
130
+ def import_passport(mf, passport: Any, mode: str = "merge",
131
+ actor: str = "", session_id: str = "") -> Dict[str, Any]:
132
+ """导入记忆护照。mode: merge(合并)/ replace(先删旧来源再写)"""
133
+ v = _validate(passport)
134
+ if not v["valid"]:
135
+ return {"success": False, "errors": v["errors"]}
136
+ passport_id = passport["passport_id"]
137
+
138
+ conn = mf._storage._get_conn()
139
+ _ensure_columns(conn)
140
+
141
+ if mode == "replace":
142
+ # v6.1.2 修复:此前裸 DELETE 不做级联清理,会在 memory_versions/
143
+ # links/notes/embeddings/review_schedules/graph_relations 及 FTS 索引
144
+ # 留下孤儿数据(FTS 孤儿词条在 rowid 复用后会导致搜索串台)。
145
+ # 改走存储层 _delete_memory_cascade,保证子表与 FTS 同步清理。
146
+ for (old_id,) in conn.execute(
147
+ "SELECT id FROM memories WHERE passport_id = ?", (passport_id,)
148
+ ).fetchall():
149
+ mf._storage._delete_memory_cascade(conn, old_id)
150
+ conn.commit()
151
+
152
+ imported = 0
153
+ skipped = 0
154
+ for m in (passport.get("memories") or [])[:MAX_MEMORIES]:
155
+ if not isinstance(m, dict):
156
+ continue
157
+ content = (m.get("content") or "").strip()
158
+ if not content:
159
+ skipped += 1
160
+ continue
161
+ try:
162
+ meta = json.loads(m.get("metadata", "{}")) if isinstance(m.get("metadata"), str) else dict(m.get("metadata") or {})
163
+ except Exception:
164
+ meta = {}
165
+ meta[_PASSPORT_KEY] = passport_id
166
+ try:
167
+ entry = mf.add(
168
+ content=content,
169
+ category=m.get("category") or "general",
170
+ tags=list(m.get("tags", []) or [])[:20],
171
+ importance=m.get("importance") or "MEDIUM",
172
+ layer=m.get("layer") or "short_term",
173
+ privacy=m.get("privacy") or "INTERNAL",
174
+ source_agent=m.get("source_agent") or f"passport:{passport_id}",
175
+ source_session=m.get("source_session") or "",
176
+ metadata=meta,
177
+ )
178
+ try:
179
+ conn.execute("UPDATE memories SET passport_id = ? WHERE id = ?",
180
+ (passport_id, entry.id))
181
+ conn.commit()
182
+ except Exception:
183
+ pass
184
+ imported += 1
185
+ except Exception:
186
+ skipped += 1
187
+ # 偏好导入(合并为 preference 记忆)
188
+ pref_imported = 0
189
+ for p in (passport.get("preferences") or [])[:MAX_PREFERENCES]:
190
+ if not isinstance(p, dict):
191
+ continue
192
+ try:
193
+ entry = mf.add(
194
+ content=(p.get("content") or "").strip() or "偏好",
195
+ category="preference",
196
+ tags=list(set((p.get("tags") or [])[:10]) | {"user_preference"}),
197
+ importance=p.get("importance") or "HIGH",
198
+ metadata={_PASSPORT_KEY: passport_id},
199
+ )
200
+ try:
201
+ conn.execute("UPDATE memories SET passport_id = ? WHERE id = ?",
202
+ (passport_id, entry.id))
203
+ conn.commit()
204
+ except Exception:
205
+ pass
206
+ pref_imported += 1
207
+ except Exception:
208
+ pass
209
+ mf._storage._add_audit(
210
+ "passport_import", "", actor or "", session_id or "", "",
211
+ {"passport_id": passport_id, "memories": imported, "prefs": pref_imported})
212
+ return {"success": True, "passport_id": passport_id,
213
+ "memories_imported": imported, "preferences_imported": pref_imported,
214
+ "skipped": skipped}
215
+
216
+
217
+ def revoke_passport(mf, passport_id: str, actor: str = "",
218
+ session_id: str = "") -> Dict[str, Any]:
219
+ """撤销护照导入:删除该护照来源的记忆与偏好,恢复原状。"""
220
+ if not passport_id or len(passport_id) > 128:
221
+ return {"success": False, "error": "passport_id 无效"}
222
+ conn = mf._storage._get_conn()
223
+ _ensure_columns(conn)
224
+ # v6.1.2 修复:裸 DELETE 无级联无 FTS 清理,改走存储层级联删除
225
+ old_ids = [r[0] for r in conn.execute(
226
+ "SELECT id FROM memories WHERE passport_id = ?", (passport_id,)
227
+ ).fetchall()]
228
+ for old_id in old_ids:
229
+ mf._storage._delete_memory_cascade(conn, old_id)
230
+ conn.commit()
231
+ removed = len(old_ids)
232
+ mf._storage._add_audit(
233
+ "passport_revoke", "", actor or "", session_id or "", "",
234
+ {"passport_id": passport_id, "removed": removed})
235
+ return {"success": True, "passport_id": passport_id, "memories_removed": removed}
236
+
237
+
238
+ def passport_status(mf) -> Dict[str, Any]:
239
+ """护照来源状态:列出已导入的护照及其记忆数"""
240
+ conn = mf._storage._get_conn()
241
+ _ensure_columns(conn)
242
+ try:
243
+ rows = conn.execute(
244
+ "SELECT passport_id, COUNT(*) FROM memories "
245
+ "WHERE passport_id != '' GROUP BY passport_id").fetchall()
246
+ except Exception:
247
+ rows = []
248
+ sources = [{"passport_id": r[0], "memories": r[1]} for r in rows]
249
+ return {"sources": sources, "total_sources": len(sources),
250
+ "total_imported": sum(r[1] for r in rows)}