MemoryOS 2.0.3__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 (315) hide show
  1. memoryos-2.0.3.dist-info/METADATA +418 -0
  2. memoryos-2.0.3.dist-info/RECORD +315 -0
  3. memoryos-2.0.3.dist-info/WHEEL +4 -0
  4. memoryos-2.0.3.dist-info/entry_points.txt +3 -0
  5. memoryos-2.0.3.dist-info/licenses/LICENSE +201 -0
  6. memos/__init__.py +20 -0
  7. memos/api/client.py +571 -0
  8. memos/api/config.py +1018 -0
  9. memos/api/context/dependencies.py +50 -0
  10. memos/api/exceptions.py +53 -0
  11. memos/api/handlers/__init__.py +62 -0
  12. memos/api/handlers/add_handler.py +158 -0
  13. memos/api/handlers/base_handler.py +194 -0
  14. memos/api/handlers/chat_handler.py +1401 -0
  15. memos/api/handlers/component_init.py +388 -0
  16. memos/api/handlers/config_builders.py +190 -0
  17. memos/api/handlers/feedback_handler.py +93 -0
  18. memos/api/handlers/formatters_handler.py +237 -0
  19. memos/api/handlers/memory_handler.py +316 -0
  20. memos/api/handlers/scheduler_handler.py +497 -0
  21. memos/api/handlers/search_handler.py +222 -0
  22. memos/api/handlers/suggestion_handler.py +117 -0
  23. memos/api/mcp_serve.py +614 -0
  24. memos/api/middleware/request_context.py +101 -0
  25. memos/api/product_api.py +38 -0
  26. memos/api/product_models.py +1206 -0
  27. memos/api/routers/__init__.py +1 -0
  28. memos/api/routers/product_router.py +477 -0
  29. memos/api/routers/server_router.py +394 -0
  30. memos/api/server_api.py +44 -0
  31. memos/api/start_api.py +433 -0
  32. memos/chunkers/__init__.py +4 -0
  33. memos/chunkers/base.py +24 -0
  34. memos/chunkers/charactertext_chunker.py +41 -0
  35. memos/chunkers/factory.py +24 -0
  36. memos/chunkers/markdown_chunker.py +62 -0
  37. memos/chunkers/sentence_chunker.py +54 -0
  38. memos/chunkers/simple_chunker.py +50 -0
  39. memos/cli.py +113 -0
  40. memos/configs/__init__.py +0 -0
  41. memos/configs/base.py +82 -0
  42. memos/configs/chunker.py +59 -0
  43. memos/configs/embedder.py +88 -0
  44. memos/configs/graph_db.py +236 -0
  45. memos/configs/internet_retriever.py +100 -0
  46. memos/configs/llm.py +151 -0
  47. memos/configs/mem_agent.py +54 -0
  48. memos/configs/mem_chat.py +81 -0
  49. memos/configs/mem_cube.py +105 -0
  50. memos/configs/mem_os.py +83 -0
  51. memos/configs/mem_reader.py +91 -0
  52. memos/configs/mem_scheduler.py +385 -0
  53. memos/configs/mem_user.py +70 -0
  54. memos/configs/memory.py +324 -0
  55. memos/configs/parser.py +38 -0
  56. memos/configs/reranker.py +18 -0
  57. memos/configs/utils.py +8 -0
  58. memos/configs/vec_db.py +80 -0
  59. memos/context/context.py +355 -0
  60. memos/dependency.py +52 -0
  61. memos/deprecation.py +262 -0
  62. memos/embedders/__init__.py +0 -0
  63. memos/embedders/ark.py +95 -0
  64. memos/embedders/base.py +106 -0
  65. memos/embedders/factory.py +29 -0
  66. memos/embedders/ollama.py +77 -0
  67. memos/embedders/sentence_transformer.py +49 -0
  68. memos/embedders/universal_api.py +51 -0
  69. memos/exceptions.py +30 -0
  70. memos/graph_dbs/__init__.py +0 -0
  71. memos/graph_dbs/base.py +274 -0
  72. memos/graph_dbs/factory.py +27 -0
  73. memos/graph_dbs/item.py +46 -0
  74. memos/graph_dbs/nebular.py +1794 -0
  75. memos/graph_dbs/neo4j.py +1942 -0
  76. memos/graph_dbs/neo4j_community.py +1058 -0
  77. memos/graph_dbs/polardb.py +5446 -0
  78. memos/hello_world.py +97 -0
  79. memos/llms/__init__.py +0 -0
  80. memos/llms/base.py +25 -0
  81. memos/llms/deepseek.py +13 -0
  82. memos/llms/factory.py +38 -0
  83. memos/llms/hf.py +443 -0
  84. memos/llms/hf_singleton.py +114 -0
  85. memos/llms/ollama.py +135 -0
  86. memos/llms/openai.py +222 -0
  87. memos/llms/openai_new.py +198 -0
  88. memos/llms/qwen.py +13 -0
  89. memos/llms/utils.py +14 -0
  90. memos/llms/vllm.py +218 -0
  91. memos/log.py +237 -0
  92. memos/mem_agent/base.py +19 -0
  93. memos/mem_agent/deepsearch_agent.py +391 -0
  94. memos/mem_agent/factory.py +36 -0
  95. memos/mem_chat/__init__.py +0 -0
  96. memos/mem_chat/base.py +30 -0
  97. memos/mem_chat/factory.py +21 -0
  98. memos/mem_chat/simple.py +200 -0
  99. memos/mem_cube/__init__.py +0 -0
  100. memos/mem_cube/base.py +30 -0
  101. memos/mem_cube/general.py +240 -0
  102. memos/mem_cube/navie.py +172 -0
  103. memos/mem_cube/utils.py +169 -0
  104. memos/mem_feedback/base.py +15 -0
  105. memos/mem_feedback/feedback.py +1192 -0
  106. memos/mem_feedback/simple_feedback.py +40 -0
  107. memos/mem_feedback/utils.py +230 -0
  108. memos/mem_os/client.py +5 -0
  109. memos/mem_os/core.py +1203 -0
  110. memos/mem_os/main.py +582 -0
  111. memos/mem_os/product.py +1608 -0
  112. memos/mem_os/product_server.py +455 -0
  113. memos/mem_os/utils/default_config.py +359 -0
  114. memos/mem_os/utils/format_utils.py +1403 -0
  115. memos/mem_os/utils/reference_utils.py +162 -0
  116. memos/mem_reader/__init__.py +0 -0
  117. memos/mem_reader/base.py +47 -0
  118. memos/mem_reader/factory.py +53 -0
  119. memos/mem_reader/memory.py +298 -0
  120. memos/mem_reader/multi_modal_struct.py +965 -0
  121. memos/mem_reader/read_multi_modal/__init__.py +43 -0
  122. memos/mem_reader/read_multi_modal/assistant_parser.py +311 -0
  123. memos/mem_reader/read_multi_modal/base.py +273 -0
  124. memos/mem_reader/read_multi_modal/file_content_parser.py +826 -0
  125. memos/mem_reader/read_multi_modal/image_parser.py +359 -0
  126. memos/mem_reader/read_multi_modal/multi_modal_parser.py +252 -0
  127. memos/mem_reader/read_multi_modal/string_parser.py +139 -0
  128. memos/mem_reader/read_multi_modal/system_parser.py +327 -0
  129. memos/mem_reader/read_multi_modal/text_content_parser.py +131 -0
  130. memos/mem_reader/read_multi_modal/tool_parser.py +210 -0
  131. memos/mem_reader/read_multi_modal/user_parser.py +218 -0
  132. memos/mem_reader/read_multi_modal/utils.py +358 -0
  133. memos/mem_reader/simple_struct.py +912 -0
  134. memos/mem_reader/strategy_struct.py +163 -0
  135. memos/mem_reader/utils.py +157 -0
  136. memos/mem_scheduler/__init__.py +0 -0
  137. memos/mem_scheduler/analyzer/__init__.py +0 -0
  138. memos/mem_scheduler/analyzer/api_analyzer.py +714 -0
  139. memos/mem_scheduler/analyzer/eval_analyzer.py +219 -0
  140. memos/mem_scheduler/analyzer/mos_for_test_scheduler.py +571 -0
  141. memos/mem_scheduler/analyzer/scheduler_for_eval.py +280 -0
  142. memos/mem_scheduler/base_scheduler.py +1319 -0
  143. memos/mem_scheduler/general_modules/__init__.py +0 -0
  144. memos/mem_scheduler/general_modules/api_misc.py +137 -0
  145. memos/mem_scheduler/general_modules/base.py +80 -0
  146. memos/mem_scheduler/general_modules/init_components_for_scheduler.py +425 -0
  147. memos/mem_scheduler/general_modules/misc.py +313 -0
  148. memos/mem_scheduler/general_modules/scheduler_logger.py +389 -0
  149. memos/mem_scheduler/general_modules/task_threads.py +315 -0
  150. memos/mem_scheduler/general_scheduler.py +1495 -0
  151. memos/mem_scheduler/memory_manage_modules/__init__.py +5 -0
  152. memos/mem_scheduler/memory_manage_modules/memory_filter.py +306 -0
  153. memos/mem_scheduler/memory_manage_modules/retriever.py +547 -0
  154. memos/mem_scheduler/monitors/__init__.py +0 -0
  155. memos/mem_scheduler/monitors/dispatcher_monitor.py +366 -0
  156. memos/mem_scheduler/monitors/general_monitor.py +394 -0
  157. memos/mem_scheduler/monitors/task_schedule_monitor.py +254 -0
  158. memos/mem_scheduler/optimized_scheduler.py +410 -0
  159. memos/mem_scheduler/orm_modules/__init__.py +0 -0
  160. memos/mem_scheduler/orm_modules/api_redis_model.py +518 -0
  161. memos/mem_scheduler/orm_modules/base_model.py +729 -0
  162. memos/mem_scheduler/orm_modules/monitor_models.py +261 -0
  163. memos/mem_scheduler/orm_modules/redis_model.py +699 -0
  164. memos/mem_scheduler/scheduler_factory.py +23 -0
  165. memos/mem_scheduler/schemas/__init__.py +0 -0
  166. memos/mem_scheduler/schemas/analyzer_schemas.py +52 -0
  167. memos/mem_scheduler/schemas/api_schemas.py +233 -0
  168. memos/mem_scheduler/schemas/general_schemas.py +55 -0
  169. memos/mem_scheduler/schemas/message_schemas.py +173 -0
  170. memos/mem_scheduler/schemas/monitor_schemas.py +406 -0
  171. memos/mem_scheduler/schemas/task_schemas.py +132 -0
  172. memos/mem_scheduler/task_schedule_modules/__init__.py +0 -0
  173. memos/mem_scheduler/task_schedule_modules/dispatcher.py +740 -0
  174. memos/mem_scheduler/task_schedule_modules/local_queue.py +247 -0
  175. memos/mem_scheduler/task_schedule_modules/orchestrator.py +74 -0
  176. memos/mem_scheduler/task_schedule_modules/redis_queue.py +1385 -0
  177. memos/mem_scheduler/task_schedule_modules/task_queue.py +162 -0
  178. memos/mem_scheduler/utils/__init__.py +0 -0
  179. memos/mem_scheduler/utils/api_utils.py +77 -0
  180. memos/mem_scheduler/utils/config_utils.py +100 -0
  181. memos/mem_scheduler/utils/db_utils.py +50 -0
  182. memos/mem_scheduler/utils/filter_utils.py +176 -0
  183. memos/mem_scheduler/utils/metrics.py +125 -0
  184. memos/mem_scheduler/utils/misc_utils.py +290 -0
  185. memos/mem_scheduler/utils/monitor_event_utils.py +67 -0
  186. memos/mem_scheduler/utils/status_tracker.py +229 -0
  187. memos/mem_scheduler/webservice_modules/__init__.py +0 -0
  188. memos/mem_scheduler/webservice_modules/rabbitmq_service.py +485 -0
  189. memos/mem_scheduler/webservice_modules/redis_service.py +380 -0
  190. memos/mem_user/factory.py +94 -0
  191. memos/mem_user/mysql_persistent_user_manager.py +271 -0
  192. memos/mem_user/mysql_user_manager.py +502 -0
  193. memos/mem_user/persistent_factory.py +98 -0
  194. memos/mem_user/persistent_user_manager.py +260 -0
  195. memos/mem_user/redis_persistent_user_manager.py +225 -0
  196. memos/mem_user/user_manager.py +488 -0
  197. memos/memories/__init__.py +0 -0
  198. memos/memories/activation/__init__.py +0 -0
  199. memos/memories/activation/base.py +42 -0
  200. memos/memories/activation/item.py +56 -0
  201. memos/memories/activation/kv.py +292 -0
  202. memos/memories/activation/vllmkv.py +219 -0
  203. memos/memories/base.py +19 -0
  204. memos/memories/factory.py +42 -0
  205. memos/memories/parametric/__init__.py +0 -0
  206. memos/memories/parametric/base.py +19 -0
  207. memos/memories/parametric/item.py +11 -0
  208. memos/memories/parametric/lora.py +41 -0
  209. memos/memories/textual/__init__.py +0 -0
  210. memos/memories/textual/base.py +92 -0
  211. memos/memories/textual/general.py +236 -0
  212. memos/memories/textual/item.py +304 -0
  213. memos/memories/textual/naive.py +187 -0
  214. memos/memories/textual/prefer_text_memory/__init__.py +0 -0
  215. memos/memories/textual/prefer_text_memory/adder.py +504 -0
  216. memos/memories/textual/prefer_text_memory/config.py +106 -0
  217. memos/memories/textual/prefer_text_memory/extractor.py +221 -0
  218. memos/memories/textual/prefer_text_memory/factory.py +85 -0
  219. memos/memories/textual/prefer_text_memory/retrievers.py +177 -0
  220. memos/memories/textual/prefer_text_memory/spliter.py +132 -0
  221. memos/memories/textual/prefer_text_memory/utils.py +93 -0
  222. memos/memories/textual/preference.py +344 -0
  223. memos/memories/textual/simple_preference.py +161 -0
  224. memos/memories/textual/simple_tree.py +69 -0
  225. memos/memories/textual/tree.py +459 -0
  226. memos/memories/textual/tree_text_memory/__init__.py +0 -0
  227. memos/memories/textual/tree_text_memory/organize/__init__.py +0 -0
  228. memos/memories/textual/tree_text_memory/organize/handler.py +184 -0
  229. memos/memories/textual/tree_text_memory/organize/manager.py +518 -0
  230. memos/memories/textual/tree_text_memory/organize/relation_reason_detector.py +238 -0
  231. memos/memories/textual/tree_text_memory/organize/reorganizer.py +622 -0
  232. memos/memories/textual/tree_text_memory/retrieve/__init__.py +0 -0
  233. memos/memories/textual/tree_text_memory/retrieve/advanced_searcher.py +364 -0
  234. memos/memories/textual/tree_text_memory/retrieve/bm25_util.py +186 -0
  235. memos/memories/textual/tree_text_memory/retrieve/bochasearch.py +419 -0
  236. memos/memories/textual/tree_text_memory/retrieve/internet_retriever.py +270 -0
  237. memos/memories/textual/tree_text_memory/retrieve/internet_retriever_factory.py +102 -0
  238. memos/memories/textual/tree_text_memory/retrieve/reasoner.py +61 -0
  239. memos/memories/textual/tree_text_memory/retrieve/recall.py +497 -0
  240. memos/memories/textual/tree_text_memory/retrieve/reranker.py +111 -0
  241. memos/memories/textual/tree_text_memory/retrieve/retrieval_mid_structs.py +16 -0
  242. memos/memories/textual/tree_text_memory/retrieve/retrieve_utils.py +472 -0
  243. memos/memories/textual/tree_text_memory/retrieve/searcher.py +848 -0
  244. memos/memories/textual/tree_text_memory/retrieve/task_goal_parser.py +135 -0
  245. memos/memories/textual/tree_text_memory/retrieve/utils.py +54 -0
  246. memos/memories/textual/tree_text_memory/retrieve/xinyusearch.py +387 -0
  247. memos/memos_tools/dinding_report_bot.py +453 -0
  248. memos/memos_tools/lockfree_dict.py +120 -0
  249. memos/memos_tools/notification_service.py +44 -0
  250. memos/memos_tools/notification_utils.py +142 -0
  251. memos/memos_tools/singleton.py +174 -0
  252. memos/memos_tools/thread_safe_dict.py +310 -0
  253. memos/memos_tools/thread_safe_dict_segment.py +382 -0
  254. memos/multi_mem_cube/__init__.py +0 -0
  255. memos/multi_mem_cube/composite_cube.py +86 -0
  256. memos/multi_mem_cube/single_cube.py +874 -0
  257. memos/multi_mem_cube/views.py +54 -0
  258. memos/parsers/__init__.py +0 -0
  259. memos/parsers/base.py +15 -0
  260. memos/parsers/factory.py +21 -0
  261. memos/parsers/markitdown.py +28 -0
  262. memos/reranker/__init__.py +4 -0
  263. memos/reranker/base.py +25 -0
  264. memos/reranker/concat.py +103 -0
  265. memos/reranker/cosine_local.py +102 -0
  266. memos/reranker/factory.py +72 -0
  267. memos/reranker/http_bge.py +324 -0
  268. memos/reranker/http_bge_strategy.py +327 -0
  269. memos/reranker/noop.py +19 -0
  270. memos/reranker/strategies/__init__.py +4 -0
  271. memos/reranker/strategies/base.py +61 -0
  272. memos/reranker/strategies/concat_background.py +94 -0
  273. memos/reranker/strategies/concat_docsource.py +110 -0
  274. memos/reranker/strategies/dialogue_common.py +109 -0
  275. memos/reranker/strategies/factory.py +31 -0
  276. memos/reranker/strategies/single_turn.py +107 -0
  277. memos/reranker/strategies/singleturn_outmem.py +98 -0
  278. memos/settings.py +10 -0
  279. memos/templates/__init__.py +0 -0
  280. memos/templates/advanced_search_prompts.py +211 -0
  281. memos/templates/cloud_service_prompt.py +107 -0
  282. memos/templates/instruction_completion.py +66 -0
  283. memos/templates/mem_agent_prompts.py +85 -0
  284. memos/templates/mem_feedback_prompts.py +822 -0
  285. memos/templates/mem_reader_prompts.py +1096 -0
  286. memos/templates/mem_reader_strategy_prompts.py +238 -0
  287. memos/templates/mem_scheduler_prompts.py +626 -0
  288. memos/templates/mem_search_prompts.py +93 -0
  289. memos/templates/mos_prompts.py +403 -0
  290. memos/templates/prefer_complete_prompt.py +735 -0
  291. memos/templates/tool_mem_prompts.py +139 -0
  292. memos/templates/tree_reorganize_prompts.py +230 -0
  293. memos/types/__init__.py +34 -0
  294. memos/types/general_types.py +151 -0
  295. memos/types/openai_chat_completion_types/__init__.py +15 -0
  296. memos/types/openai_chat_completion_types/chat_completion_assistant_message_param.py +56 -0
  297. memos/types/openai_chat_completion_types/chat_completion_content_part_image_param.py +27 -0
  298. memos/types/openai_chat_completion_types/chat_completion_content_part_input_audio_param.py +23 -0
  299. memos/types/openai_chat_completion_types/chat_completion_content_part_param.py +43 -0
  300. memos/types/openai_chat_completion_types/chat_completion_content_part_refusal_param.py +16 -0
  301. memos/types/openai_chat_completion_types/chat_completion_content_part_text_param.py +16 -0
  302. memos/types/openai_chat_completion_types/chat_completion_message_custom_tool_call_param.py +27 -0
  303. memos/types/openai_chat_completion_types/chat_completion_message_function_tool_call_param.py +32 -0
  304. memos/types/openai_chat_completion_types/chat_completion_message_param.py +18 -0
  305. memos/types/openai_chat_completion_types/chat_completion_message_tool_call_union_param.py +15 -0
  306. memos/types/openai_chat_completion_types/chat_completion_system_message_param.py +36 -0
  307. memos/types/openai_chat_completion_types/chat_completion_tool_message_param.py +30 -0
  308. memos/types/openai_chat_completion_types/chat_completion_user_message_param.py +34 -0
  309. memos/utils.py +123 -0
  310. memos/vec_dbs/__init__.py +0 -0
  311. memos/vec_dbs/base.py +117 -0
  312. memos/vec_dbs/factory.py +23 -0
  313. memos/vec_dbs/item.py +50 -0
  314. memos/vec_dbs/milvus.py +654 -0
  315. memos/vec_dbs/qdrant.py +355 -0
memos/mem_cube/base.py ADDED
@@ -0,0 +1,30 @@
1
+ from abc import ABC, abstractmethod
2
+ from typing import TYPE_CHECKING
3
+
4
+ from memos.configs.mem_cube import BaseMemCubeConfig
5
+
6
+
7
+ if TYPE_CHECKING:
8
+ from memos.memories.activation.base import BaseActMemory
9
+ from memos.memories.parametric.base import BaseParaMemory
10
+ from memos.memories.textual.base import BaseTextMemory
11
+
12
+
13
+ class BaseMemCube(ABC):
14
+ """Base class for all MemCube implementations."""
15
+
16
+ @abstractmethod
17
+ def __init__(self, config: BaseMemCubeConfig):
18
+ """Initialize the MemCube with the given configuration."""
19
+ self.text_mem: BaseTextMemory
20
+ self.act_mem: BaseActMemory
21
+ self.para_mem: BaseParaMemory
22
+ self.pref_mem: BaseTextMemory
23
+
24
+ @abstractmethod
25
+ def load(self, dir: str) -> None:
26
+ """Load memories from a directory."""
27
+
28
+ @abstractmethod
29
+ def dump(self, dir: str) -> None:
30
+ """Dump memories to a directory."""
@@ -0,0 +1,240 @@
1
+ import os
2
+ import time
3
+
4
+ from typing import Literal
5
+
6
+ from memos.configs.mem_cube import GeneralMemCubeConfig
7
+ from memos.configs.utils import get_json_file_model_schema
8
+ from memos.exceptions import ConfigurationError, MemCubeError
9
+ from memos.log import get_logger
10
+ from memos.mem_cube.base import BaseMemCube
11
+ from memos.mem_cube.utils import download_repo, merge_config_with_default
12
+ from memos.memories.activation.base import BaseActMemory
13
+ from memos.memories.factory import MemoryFactory
14
+ from memos.memories.parametric.base import BaseParaMemory
15
+ from memos.memories.textual.base import BaseTextMemory
16
+
17
+
18
+ logger = get_logger(__name__)
19
+
20
+
21
+ class GeneralMemCube(BaseMemCube):
22
+ """MemCube is a box for loading and dumping three types of memories."""
23
+
24
+ def __init__(self, config: GeneralMemCubeConfig):
25
+ """Initialize the MemCube with a configuration."""
26
+ self.config = config
27
+ time_start = time.time()
28
+ self._text_mem: BaseTextMemory | None = (
29
+ MemoryFactory.from_config(config.text_mem)
30
+ if config.text_mem.backend != "uninitialized"
31
+ else None
32
+ )
33
+ logger.info(f"init_text_mem in {time.time() - time_start} seconds")
34
+ self._act_mem: BaseActMemory | None = (
35
+ MemoryFactory.from_config(config.act_mem)
36
+ if config.act_mem.backend != "uninitialized"
37
+ else None
38
+ )
39
+ self._para_mem: BaseParaMemory | None = (
40
+ MemoryFactory.from_config(config.para_mem)
41
+ if config.para_mem.backend != "uninitialized"
42
+ else None
43
+ )
44
+ self._pref_mem: BaseTextMemory | None = (
45
+ MemoryFactory.from_config(config.pref_mem)
46
+ if config.pref_mem.backend != "uninitialized"
47
+ else None
48
+ )
49
+
50
+ def load(
51
+ self,
52
+ dir: str,
53
+ memory_types: list[Literal["text_mem", "act_mem", "para_mem", "pref_mem"]] | None = None,
54
+ ) -> None:
55
+ """Load memories.
56
+ Args:
57
+ dir (str): The directory containing the memory files.
58
+ memory_types (list[str], optional): List of memory types to load.
59
+ If None, loads all available memory types.
60
+ Options: ["text_mem", "act_mem", "para_mem", "pref_mem"]
61
+ """
62
+ loaded_schema = get_json_file_model_schema(os.path.join(dir, self.config.config_filename))
63
+ if loaded_schema != self.config.model_schema:
64
+ raise ConfigurationError(
65
+ f"Configuration schema mismatch. Expected {self.config.model_schema}, "
66
+ f"but found {loaded_schema}."
67
+ )
68
+
69
+ # If no specific memory types specified, load all
70
+ if memory_types is None:
71
+ memory_types = ["text_mem", "act_mem", "para_mem", "pref_mem"]
72
+
73
+ # Load specified memory types
74
+ if "text_mem" in memory_types and self.text_mem:
75
+ self.text_mem.load(dir)
76
+ logger.debug(f"Loaded text_mem from {dir}")
77
+
78
+ if "act_mem" in memory_types and self.act_mem:
79
+ self.act_mem.load(dir)
80
+ logger.info(f"Loaded act_mem from {dir}")
81
+
82
+ if "para_mem" in memory_types and self.para_mem:
83
+ self.para_mem.load(dir)
84
+ logger.info(f"Loaded para_mem from {dir}")
85
+
86
+ if "pref_mem" in memory_types and self.pref_mem:
87
+ self.pref_mem.load(dir)
88
+ logger.info(f"Loaded pref_mem from {dir}")
89
+
90
+ logger.info(f"MemCube loaded successfully from {dir} (types: {memory_types})")
91
+
92
+ def dump(
93
+ self,
94
+ dir: str,
95
+ memory_types: list[Literal["text_mem", "act_mem", "para_mem", "pref_mem"]] | None = None,
96
+ ) -> None:
97
+ """Dump memories.
98
+ Args:
99
+ dir (str): The directory where the memory files will be saved.
100
+ memory_types (list[str], optional): List of memory types to dump.
101
+ If None, dumps all available memory types.
102
+ Options: ["text_mem", "act_mem", "para_mem", "pref_mem"]
103
+ """
104
+ if os.path.exists(dir) and os.listdir(dir):
105
+ raise MemCubeError(
106
+ f"Directory {dir} is not empty. Please provide an empty directory for dumping."
107
+ )
108
+
109
+ # Always dump config
110
+ self.config.to_json_file(os.path.join(dir, self.config.config_filename))
111
+
112
+ # If no specific memory types specified, dump all
113
+ if memory_types is None:
114
+ memory_types = ["text_mem", "act_mem", "para_mem", "pref_mem"]
115
+
116
+ # Dump specified memory types
117
+ if "text_mem" in memory_types and self.text_mem:
118
+ self.text_mem.dump(dir)
119
+ logger.info(f"Dumped text_mem to {dir}")
120
+
121
+ if "act_mem" in memory_types and self.act_mem:
122
+ self.act_mem.dump(dir)
123
+ logger.info(f"Dumped act_mem to {dir}")
124
+
125
+ if "para_mem" in memory_types and self.para_mem:
126
+ self.para_mem.dump(dir)
127
+ logger.info(f"Dumped para_mem to {dir}")
128
+
129
+ if "pref_mem" in memory_types and self.pref_mem:
130
+ self.pref_mem.dump(dir)
131
+ logger.info(f"Dumped pref_mem to {dir}")
132
+
133
+ logger.info(f"MemCube dumped successfully to {dir} (types: {memory_types})")
134
+
135
+ @staticmethod
136
+ def init_from_dir(
137
+ dir: str,
138
+ memory_types: list[Literal["text_mem", "act_mem", "para_mem", "pref_mem"]] | None = None,
139
+ default_config: GeneralMemCubeConfig | None = None,
140
+ ) -> "GeneralMemCube":
141
+ """Create a MemCube instance from a MemCube directory.
142
+
143
+ Args:
144
+ dir (str): The directory containing the memory files.
145
+ memory_types (list[str], optional): List of memory types to load.
146
+ If None, loads all available memory types.
147
+ default_config (GeneralMemCubeConfig, optional): Default configuration to merge with existing config.
148
+ If provided, will merge general settings while preserving critical user-specific fields.
149
+
150
+ Returns:
151
+ MemCube: An instance of MemCube loaded with memories from the specified directory.
152
+ """
153
+ config_path = os.path.join(dir, "config.json")
154
+ config = GeneralMemCubeConfig.from_json_file(config_path)
155
+
156
+ # Merge with default config if provided
157
+ if default_config is not None:
158
+ config = merge_config_with_default(config, default_config)
159
+ logger.info(f"Applied default config to cube {config.cube_id}")
160
+ mem_cube = GeneralMemCube(config)
161
+ mem_cube.load(dir, memory_types)
162
+ return mem_cube
163
+
164
+ @staticmethod
165
+ def init_from_remote_repo(
166
+ cube_id: str,
167
+ base_url: str = "https://huggingface.co/datasets",
168
+ memory_types: list[Literal["text_mem", "act_mem", "para_mem", "pref_mem"]] | None = None,
169
+ default_config: GeneralMemCubeConfig | None = None,
170
+ ) -> "GeneralMemCube":
171
+ """Create a MemCube instance from a remote repository.
172
+
173
+ Args:
174
+ cube_id (str): The repository name.
175
+ base_url (str): The base URL of the remote repository.
176
+ memory_types (list[str], optional): List of memory types to load.
177
+ If None, loads all available memory types.
178
+ default_config (GeneralMemCubeConfig, optional): Default configuration to merge with existing config.
179
+
180
+ Returns:
181
+ MemCube: An instance of MemCube loaded with memories from the specified remote repository.
182
+ """
183
+ dir = download_repo(cube_id, base_url)
184
+ return GeneralMemCube.init_from_dir(dir, memory_types, default_config)
185
+
186
+ @property
187
+ def text_mem(self) -> "BaseTextMemory | None":
188
+ """Get the textual memory."""
189
+ if self._text_mem is None:
190
+ logger.warning("Textual memory is not initialized. Returning None.")
191
+ return self._text_mem
192
+
193
+ @text_mem.setter
194
+ def text_mem(self, value: BaseTextMemory) -> None:
195
+ """Set the textual memory."""
196
+ if not isinstance(value, BaseTextMemory):
197
+ raise TypeError(f"Expected BaseTextMemory, got {type(value).__name__}")
198
+ self._text_mem = value
199
+
200
+ @property
201
+ def act_mem(self) -> "BaseActMemory | None":
202
+ """Get the activation memory."""
203
+ if self._act_mem is None:
204
+ logger.warning("Activation memory is not initialized. Returning None.")
205
+ return self._act_mem
206
+
207
+ @act_mem.setter
208
+ def act_mem(self, value: BaseActMemory) -> None:
209
+ """Set the activation memory."""
210
+ if not isinstance(value, BaseActMemory):
211
+ raise TypeError(f"Expected BaseActMemory, got {type(value).__name__}")
212
+ self._act_mem = value
213
+
214
+ @property
215
+ def para_mem(self) -> "BaseParaMemory | None":
216
+ """Get the parametric memory."""
217
+ if self._para_mem is None:
218
+ logger.warning("Parametric memory is not initialized. Returning None.")
219
+ return self._para_mem
220
+
221
+ @para_mem.setter
222
+ def para_mem(self, value: BaseParaMemory) -> None:
223
+ """Set the parametric memory."""
224
+ if not isinstance(value, BaseParaMemory):
225
+ raise TypeError(f"Expected BaseParaMemory, got {type(value).__name__}")
226
+ self._para_mem = value
227
+
228
+ @property
229
+ def pref_mem(self) -> "BaseTextMemory | None":
230
+ """Get the preference memory."""
231
+ if self._pref_mem is None:
232
+ logger.warning("Preference memory is not initialized. Returning None.")
233
+ return self._pref_mem
234
+
235
+ @pref_mem.setter
236
+ def pref_mem(self, value: BaseTextMemory) -> None:
237
+ """Set the preference memory."""
238
+ if not isinstance(value, BaseTextMemory):
239
+ raise TypeError(f"Expected BaseTextMemory, got {type(value).__name__}")
240
+ self._pref_mem = value
@@ -0,0 +1,172 @@
1
+ import os
2
+
3
+ from typing import Literal
4
+
5
+ from memos.configs.utils import get_json_file_model_schema
6
+ from memos.exceptions import ConfigurationError, MemCubeError
7
+ from memos.log import get_logger
8
+ from memos.mem_cube.base import BaseMemCube
9
+ from memos.memories.activation.base import BaseActMemory
10
+ from memos.memories.parametric.base import BaseParaMemory
11
+ from memos.memories.textual.base import BaseTextMemory
12
+
13
+
14
+ logger = get_logger(__name__)
15
+
16
+
17
+ class NaiveMemCube(BaseMemCube):
18
+ """MemCube is a box for loading and dumping three types of memories."""
19
+
20
+ def __init__(
21
+ self,
22
+ text_mem: BaseTextMemory | None = None,
23
+ pref_mem: BaseTextMemory | None = None,
24
+ act_mem: BaseActMemory | None = None,
25
+ para_mem: BaseParaMemory | None = None,
26
+ ):
27
+ """Initialize the MemCube with memory instances."""
28
+ self._text_mem: BaseTextMemory = text_mem
29
+ self._act_mem: BaseActMemory | None = act_mem
30
+ self._para_mem: BaseParaMemory | None = para_mem
31
+ self._pref_mem: BaseTextMemory | None = pref_mem
32
+
33
+ def load(
34
+ self,
35
+ dir: str,
36
+ memory_types: list[Literal["text_mem", "act_mem", "para_mem", "pref_mem"]] | None = None,
37
+ ) -> None:
38
+ """Load memories.
39
+ Args:
40
+ dir (str): The directory containing the memory files.
41
+ memory_types (list[str], optional): List of memory types to load.
42
+ If None, loads all available memory types.
43
+ Options: ["text_mem", "act_mem", "para_mem", "pref_mem"]
44
+ """
45
+ loaded_schema = get_json_file_model_schema(os.path.join(dir, self.config.config_filename))
46
+ if loaded_schema != self.config.model_schema:
47
+ raise ConfigurationError(
48
+ f"Configuration schema mismatch. Expected {self.config.model_schema}, "
49
+ f"but found {loaded_schema}."
50
+ )
51
+
52
+ # If no specific memory types specified, load all
53
+ if memory_types is None:
54
+ memory_types = ["text_mem", "act_mem", "para_mem", "pref_mem"]
55
+
56
+ # Load specified memory types
57
+ if "text_mem" in memory_types and self.text_mem:
58
+ self.text_mem.load(dir)
59
+ logger.debug(f"Loaded text_mem from {dir}")
60
+
61
+ if "act_mem" in memory_types and self.act_mem:
62
+ self.act_mem.load(dir)
63
+ logger.info(f"Loaded act_mem from {dir}")
64
+
65
+ if "para_mem" in memory_types and self.para_mem:
66
+ self.para_mem.load(dir)
67
+ logger.info(f"Loaded para_mem from {dir}")
68
+
69
+ if "pref_mem" in memory_types and self.pref_mem:
70
+ self.pref_mem.load(dir)
71
+ logger.info(f"Loaded pref_mem from {dir}")
72
+
73
+ logger.info(f"MemCube loaded successfully from {dir} (types: {memory_types})")
74
+
75
+ def dump(
76
+ self,
77
+ dir: str,
78
+ memory_types: list[Literal["text_mem", "act_mem", "para_mem", "pref_mem"]] | None = None,
79
+ ) -> None:
80
+ """Dump memories.
81
+ Args:
82
+ dir (str): The directory where the memory files will be saved.
83
+ memory_types (list[str], optional): List of memory types to dump.
84
+ If None, dumps all available memory types.
85
+ Options: ["text_mem", "act_mem", "para_mem", "pref_mem"]
86
+ """
87
+ if os.path.exists(dir) and os.listdir(dir):
88
+ raise MemCubeError(
89
+ f"Directory {dir} is not empty. Please provide an empty directory for dumping."
90
+ )
91
+
92
+ # Always dump config
93
+ self.config.to_json_file(os.path.join(dir, self.config.config_filename))
94
+
95
+ # If no specific memory types specified, dump all
96
+ if memory_types is None:
97
+ memory_types = ["text_mem", "act_mem", "para_mem", "pref_mem"]
98
+
99
+ # Dump specified memory types
100
+ if "text_mem" in memory_types and self.text_mem:
101
+ self.text_mem.dump(dir)
102
+ logger.info(f"Dumped text_mem to {dir}")
103
+
104
+ if "act_mem" in memory_types and self.act_mem:
105
+ self.act_mem.dump(dir)
106
+ logger.info(f"Dumped act_mem to {dir}")
107
+
108
+ if "para_mem" in memory_types and self.para_mem:
109
+ self.para_mem.dump(dir)
110
+ logger.info(f"Dumped para_mem to {dir}")
111
+
112
+ if "pref_mem" in memory_types and self.pref_mem:
113
+ self.pref_mem.dump(dir)
114
+ logger.info(f"Dumped pref_mem to {dir}")
115
+
116
+ logger.info(f"MemCube dumped successfully to {dir} (types: {memory_types})")
117
+
118
+ @property
119
+ def text_mem(self) -> "BaseTextMemory | None":
120
+ """Get the textual memory."""
121
+ if self._text_mem is None:
122
+ logger.warning("Textual memory is not initialized. Returning None.")
123
+ return self._text_mem
124
+
125
+ @text_mem.setter
126
+ def text_mem(self, value: BaseTextMemory) -> None:
127
+ """Set the textual memory."""
128
+ if not isinstance(value, BaseTextMemory):
129
+ raise TypeError(f"Expected BaseTextMemory, got {type(value).__name__}")
130
+ self._text_mem = value
131
+
132
+ @property
133
+ def act_mem(self) -> "BaseActMemory | None":
134
+ """Get the activation memory."""
135
+ if self._act_mem is None:
136
+ logger.warning("Activation memory is not initialized. Returning None.")
137
+ return self._act_mem
138
+
139
+ @act_mem.setter
140
+ def act_mem(self, value: BaseActMemory) -> None:
141
+ """Set the activation memory."""
142
+ if not isinstance(value, BaseActMemory):
143
+ raise TypeError(f"Expected BaseActMemory, got {type(value).__name__}")
144
+ self._act_mem = value
145
+
146
+ @property
147
+ def para_mem(self) -> "BaseParaMemory | None":
148
+ """Get the parametric memory."""
149
+ if self._para_mem is None:
150
+ logger.warning("Parametric memory is not initialized. Returning None.")
151
+ return self._para_mem
152
+
153
+ @para_mem.setter
154
+ def para_mem(self, value: BaseParaMemory) -> None:
155
+ """Set the parametric memory."""
156
+ if not isinstance(value, BaseParaMemory):
157
+ raise TypeError(f"Expected BaseParaMemory, got {type(value).__name__}")
158
+ self._para_mem = value
159
+
160
+ @property
161
+ def pref_mem(self) -> "BaseTextMemory | None":
162
+ """Get the preference memory."""
163
+ if self._pref_mem is None:
164
+ logger.warning("Preference memory is not initialized. Returning None.")
165
+ return self._pref_mem
166
+
167
+ @pref_mem.setter
168
+ def pref_mem(self, value: BaseTextMemory) -> None:
169
+ """Set the preference memory."""
170
+ if not isinstance(value, BaseTextMemory):
171
+ raise TypeError(f"Expected BaseTextMemory, got {type(value).__name__}")
172
+ self._pref_mem = value
@@ -0,0 +1,169 @@
1
+ import copy
2
+ import logging
3
+ import subprocess
4
+ import tempfile
5
+
6
+ from memos.configs.mem_cube import GeneralMemCubeConfig
7
+
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+
12
+ def download_repo(repo: str, base_url: str, dir: str | None = None) -> str:
13
+ """Download a repository from a remote source.
14
+
15
+ Args:
16
+ repo (str): The repository name.
17
+ base_url (str): The base URL of the remote repository.
18
+ dir (str, optional): The directory where the repository will be downloaded. If None, a temporary directory will be created.
19
+ If a directory is provided, it will be used instead of creating a temporary one.
20
+
21
+ Returns:
22
+ str: The local directory where the repository is downloaded.
23
+ """
24
+ if dir is None:
25
+ dir = tempfile.mkdtemp()
26
+ repo_url = f"{base_url}/{repo}"
27
+
28
+ # Clone the repo
29
+ subprocess.run(["git", "clone", repo_url, dir], check=True)
30
+
31
+ return dir
32
+
33
+
34
+ def merge_config_with_default(
35
+ existing_config: GeneralMemCubeConfig, default_config: GeneralMemCubeConfig
36
+ ) -> GeneralMemCubeConfig:
37
+ """
38
+ Merge existing cube config with default config, preserving critical fields.
39
+
40
+ This method updates general configuration fields (like API keys, model parameters)
41
+ while preserving critical user-specific fields (like user_id, cube_id, graph_db settings).
42
+
43
+ Args:
44
+ existing_config (GeneralMemCubeConfig): The existing cube configuration loaded from file
45
+ default_config (GeneralMemCubeConfig): The default configuration to merge from
46
+
47
+ Returns:
48
+ GeneralMemCubeConfig: Merged configuration
49
+ """
50
+
51
+ # Convert configs to dictionaries
52
+ existing_dict = existing_config.model_dump(mode="json")
53
+ default_dict = default_config.model_dump(mode="json")
54
+
55
+ logger.info(
56
+ f"Starting config merge for user {existing_config.user_id}, cube {existing_config.cube_id}"
57
+ )
58
+
59
+ # Define fields that should be preserved from existing config
60
+ preserve_fields = {"user_id", "cube_id", "config_filename", "model_schema"}
61
+
62
+ # Preserve graph_db from existing config if it exists, but merge some fields
63
+ preserved_graph_db = None
64
+ if "text_mem" in existing_dict and "text_mem" in default_dict:
65
+ existing_text_config = existing_dict["text_mem"].get("config", {})
66
+ default_text_config = default_dict["text_mem"].get("config", {})
67
+
68
+ if "graph_db" in existing_text_config and "graph_db" in default_text_config:
69
+ existing_graph_config = existing_text_config["graph_db"]["config"]
70
+ default_graph_config = default_text_config["graph_db"]["config"]
71
+ existing_backend = existing_text_config["graph_db"]["backend"]
72
+ default_backend = default_text_config["graph_db"]["backend"]
73
+
74
+ # Detect backend change
75
+ backend_changed = existing_backend != default_backend
76
+
77
+ if backend_changed:
78
+ logger.info(
79
+ f"Detected graph_db backend change: {existing_backend} -> {default_backend}. "
80
+ f"Migrating configuration..."
81
+ )
82
+ # Start with default config as base when backend changes
83
+ merged_graph_config = copy.deepcopy(default_graph_config)
84
+
85
+ # Preserve user-specific fields if they exist in both configs
86
+ preserve_graph_fields = {
87
+ "auto_create",
88
+ "user_name",
89
+ "use_multi_db",
90
+ }
91
+ for field in preserve_graph_fields:
92
+ if field in existing_graph_config:
93
+ merged_graph_config[field] = existing_graph_config[field]
94
+ logger.debug(
95
+ f"Preserved graph_db field '{field}': {existing_graph_config[field]}"
96
+ )
97
+
98
+ # Clean up backend-specific fields that don't exist in the new backend
99
+ # This approach is generic: remove any field from merged config that's not in default config
100
+ # and not in the preserve list
101
+ fields_to_remove = []
102
+ for field in list(merged_graph_config.keys()):
103
+ if field not in default_graph_config and field not in preserve_graph_fields:
104
+ fields_to_remove.append(field)
105
+
106
+ for field in fields_to_remove:
107
+ removed_value = merged_graph_config.pop(field)
108
+ logger.info(
109
+ f"Removed {existing_backend}-specific field '{field}' (value: {removed_value}) "
110
+ f"during migration to {default_backend}"
111
+ )
112
+ else:
113
+ # Same backend: merge configs while preserving user-specific fields
114
+ logger.debug(f"Same graph_db backend ({default_backend}), merging configurations")
115
+ preserve_graph_fields = {
116
+ "auto_create",
117
+ "user_name",
118
+ "use_multi_db",
119
+ }
120
+
121
+ # Start with existing config as base
122
+ merged_graph_config = copy.deepcopy(existing_graph_config)
123
+
124
+ # Update with default config except preserved fields
125
+ for key, value in default_graph_config.items():
126
+ if key not in preserve_graph_fields:
127
+ merged_graph_config[key] = value
128
+ logger.debug(
129
+ f"Updated graph_db field '{key}': {existing_graph_config.get(key)} -> {value}"
130
+ )
131
+
132
+ # Handle use_multi_db transition
133
+ if not default_graph_config.get("use_multi_db", True) and merged_graph_config.get(
134
+ "use_multi_db", True
135
+ ):
136
+ merged_graph_config["use_multi_db"] = False
137
+ # For Neo4j: db_name becomes user_name in single-db mode
138
+ if "neo4j" in default_backend and "db_name" in merged_graph_config:
139
+ merged_graph_config["user_name"] = merged_graph_config.get("db_name")
140
+ merged_graph_config["db_name"] = default_graph_config.get("db_name")
141
+ logger.info("Transitioned to single-db mode (use_multi_db=False)")
142
+
143
+ preserved_graph_db = {
144
+ "backend": default_backend,
145
+ "config": merged_graph_config,
146
+ }
147
+
148
+ # Use default config as base
149
+ merged_dict = copy.deepcopy(default_dict)
150
+
151
+ # Restore preserved fields from existing config
152
+ for field in preserve_fields:
153
+ if field in existing_dict:
154
+ merged_dict[field] = existing_dict[field]
155
+ logger.debug(f"Preserved field '{field}': {existing_dict[field]}")
156
+
157
+ # Restore graph_db if it was preserved
158
+ if preserved_graph_db and "text_mem" in merged_dict:
159
+ merged_dict["text_mem"]["config"]["graph_db"] = preserved_graph_db
160
+ logger.debug(f"Preserved graph_db with merged config: {preserved_graph_db}")
161
+
162
+ # Create new config from merged dictionary
163
+ merged_config = GeneralMemCubeConfig.model_validate(merged_dict)
164
+
165
+ logger.info(
166
+ f"Successfully merged cube config for user {merged_config.user_id}, cube {merged_config.cube_id}"
167
+ )
168
+
169
+ return merged_config
@@ -0,0 +1,15 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from memos.configs.memory import MemFeedbackConfig
4
+
5
+
6
+ class BaseMemFeedback(ABC):
7
+ """MemFeedback interface class for reading information."""
8
+
9
+ @abstractmethod
10
+ def __init__(self, config: MemFeedbackConfig):
11
+ """Initialize the MemFeedback with the given configuration."""
12
+
13
+ @abstractmethod
14
+ def process_feedback(self, data: dict) -> None:
15
+ """Process user's feedback"""