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
@@ -0,0 +1,455 @@
1
+ import asyncio
2
+ import time
3
+
4
+ from datetime import datetime
5
+ from typing import Literal
6
+
7
+ from memos.context.context import ContextThread
8
+ from memos.llms.base import BaseLLM
9
+ from memos.log import get_logger
10
+ from memos.mem_cube.navie import NaiveMemCube
11
+ from memos.mem_os.product import _format_mem_block
12
+ from memos.mem_reader.base import BaseMemReader
13
+ from memos.memories.textual.item import TextualMemoryItem
14
+ from memos.templates.mos_prompts import (
15
+ get_memos_prompt,
16
+ )
17
+ from memos.types import MessageList
18
+
19
+
20
+ logger = get_logger(__name__)
21
+
22
+
23
+ class MOSServer:
24
+ def __init__(
25
+ self,
26
+ mem_reader: BaseMemReader | None = None,
27
+ llm: BaseLLM | None = None,
28
+ online_bot: bool = False,
29
+ ):
30
+ self.mem_reader = mem_reader
31
+ self.chat_llm = llm
32
+ self.online_bot = online_bot
33
+
34
+ def chat(
35
+ self,
36
+ query: str,
37
+ user_id: str,
38
+ cube_id: str | None = None,
39
+ mem_cube: NaiveMemCube | None = None,
40
+ history: MessageList | None = None,
41
+ base_prompt: str | None = None,
42
+ internet_search: bool = False,
43
+ moscube: bool = False,
44
+ top_k: int = 10,
45
+ threshold: float = 0.5,
46
+ session_id: str | None = None,
47
+ ) -> str:
48
+ """
49
+ Chat with LLM with memory references and complete response.
50
+ """
51
+ time_start = time.time()
52
+ memories_result = mem_cube.text_mem.search(
53
+ query=query,
54
+ user_name=cube_id,
55
+ top_k=top_k,
56
+ mode="fine",
57
+ manual_close_internet=not internet_search,
58
+ moscube=moscube,
59
+ info={
60
+ "user_id": user_id,
61
+ "session_id": session_id,
62
+ "chat_history": history,
63
+ },
64
+ )
65
+
66
+ memories_list = []
67
+ if memories_result:
68
+ memories_list = self._filter_memories_by_threshold(memories_result, threshold)
69
+ new_memories_list = []
70
+ for m in memories_list:
71
+ m.metadata.embedding = []
72
+ new_memories_list.append(m)
73
+ memories_list = new_memories_list
74
+ system_prompt = self._build_system_prompt(memories_list, base_prompt)
75
+
76
+ history_info = []
77
+ if history:
78
+ history_info = history[-20:]
79
+ current_messages = [
80
+ {"role": "system", "content": system_prompt},
81
+ *history_info,
82
+ {"role": "user", "content": query},
83
+ ]
84
+ response = self.chat_llm.generate(current_messages)
85
+ time_end = time.time()
86
+ self._start_post_chat_processing(
87
+ user_id=user_id,
88
+ cube_id=cube_id,
89
+ session_id=session_id,
90
+ query=query,
91
+ full_response=response,
92
+ system_prompt=system_prompt,
93
+ time_start=time_start,
94
+ time_end=time_end,
95
+ speed_improvement=0.0,
96
+ current_messages=current_messages,
97
+ mem_cube=mem_cube,
98
+ history=history,
99
+ )
100
+ return response, memories_list
101
+
102
+ def add(
103
+ self,
104
+ user_id: str,
105
+ cube_id: str,
106
+ mem_cube: NaiveMemCube,
107
+ messages: MessageList,
108
+ session_id: str | None = None,
109
+ history: MessageList | None = None,
110
+ ) -> list[str]:
111
+ memories = self.mem_reader.get_memory(
112
+ [messages],
113
+ type="chat",
114
+ info={
115
+ "user_id": user_id,
116
+ "session_id": session_id,
117
+ "chat_history": history,
118
+ },
119
+ )
120
+ flattened_memories = [mm for m in memories for mm in m]
121
+ mem_id_list: list[str] = mem_cube.text_mem.add(
122
+ flattened_memories,
123
+ user_name=cube_id,
124
+ )
125
+ return mem_id_list
126
+
127
+ def search(
128
+ self,
129
+ user_id: str,
130
+ cube_id: str,
131
+ session_id: str | None = None,
132
+ ) -> None:
133
+ NotImplementedError("Not implemented")
134
+
135
+ def _filter_memories_by_threshold(
136
+ self,
137
+ memories: list[TextualMemoryItem],
138
+ threshold: float = 0.30,
139
+ min_num: int = 3,
140
+ memory_type: Literal["OuterMemory"] = "OuterMemory",
141
+ ) -> list[TextualMemoryItem]:
142
+ """
143
+ Filter memories by threshold and type, at least min_num memories for Non-OuterMemory.
144
+ Args:
145
+ memories: list[TextualMemoryItem],
146
+ threshold: float,
147
+ min_num: int,
148
+ memory_type: Literal["OuterMemory"],
149
+ Returns:
150
+ list[TextualMemoryItem]
151
+ """
152
+ sorted_memories = sorted(memories, key=lambda m: m.metadata.relativity, reverse=True)
153
+ filtered_person = [m for m in memories if m.metadata.memory_type != memory_type]
154
+ filtered_outer = [m for m in memories if m.metadata.memory_type == memory_type]
155
+ filtered = []
156
+ per_memory_count = 0
157
+ for m in sorted_memories:
158
+ if m.metadata.relativity >= threshold:
159
+ if m.metadata.memory_type != memory_type:
160
+ per_memory_count += 1
161
+ filtered.append(m)
162
+ if len(filtered) < min_num:
163
+ filtered = filtered_person[:min_num] + filtered_outer[:min_num]
164
+ else:
165
+ if per_memory_count < min_num:
166
+ filtered += filtered_person[per_memory_count:min_num]
167
+ filtered_memory = sorted(filtered, key=lambda m: m.metadata.relativity, reverse=True)
168
+ return filtered_memory
169
+
170
+ def _build_base_system_prompt(
171
+ self,
172
+ base_prompt: str | None = None,
173
+ tone: str = "friendly",
174
+ verbosity: str = "mid",
175
+ mode: str = "enhance",
176
+ ) -> str:
177
+ """
178
+ Build base system prompt without memory references.
179
+ """
180
+ now = datetime.now()
181
+ formatted_date = now.strftime("%Y-%m-%d (%A)")
182
+ sys_body = get_memos_prompt(date=formatted_date, tone=tone, verbosity=verbosity, mode=mode)
183
+ prefix = (base_prompt.strip() + "\n\n") if base_prompt else ""
184
+ return prefix + sys_body
185
+
186
+ def _build_system_prompt(
187
+ self,
188
+ memories: list[TextualMemoryItem] | list[str] | None = None,
189
+ base_prompt: str | None = None,
190
+ **kwargs,
191
+ ) -> str:
192
+ """Build system prompt with optional memories context."""
193
+ if base_prompt is None:
194
+ base_prompt = (
195
+ "You are a knowledgeable and helpful AI assistant. "
196
+ "You have access to conversation memories that help you provide more personalized responses. "
197
+ "Use the memories to understand the user's context, preferences, and past interactions. "
198
+ "If memories are provided, reference them naturally when relevant, but don't explicitly mention having memories."
199
+ )
200
+
201
+ memory_context = ""
202
+ if memories:
203
+ memory_list = []
204
+ for i, memory in enumerate(memories, 1):
205
+ if isinstance(memory, TextualMemoryItem):
206
+ text_memory = memory.memory
207
+ else:
208
+ if not isinstance(memory, str):
209
+ logger.error("Unexpected memory type.")
210
+ text_memory = memory
211
+ memory_list.append(f"{i}. {text_memory}")
212
+ memory_context = "\n".join(memory_list)
213
+
214
+ if "{memories}" in base_prompt:
215
+ return base_prompt.format(memories=memory_context)
216
+ elif base_prompt and memories:
217
+ # For backward compatibility, append memories if no placeholder is found
218
+ memory_context_with_header = "\n\n## Memories:\n" + memory_context
219
+ return base_prompt + memory_context_with_header
220
+ return base_prompt
221
+
222
+ def _build_memory_context(
223
+ self,
224
+ memories_all: list[TextualMemoryItem],
225
+ mode: str = "enhance",
226
+ ) -> str:
227
+ """
228
+ Build memory context to be included in user message.
229
+ """
230
+ if not memories_all:
231
+ return ""
232
+
233
+ mem_block_o, mem_block_p = _format_mem_block(memories_all)
234
+
235
+ if mode == "enhance":
236
+ return (
237
+ "# Memories\n## PersonalMemory (ordered)\n"
238
+ + mem_block_p
239
+ + "\n## OuterMemory (ordered)\n"
240
+ + mem_block_o
241
+ + "\n\n"
242
+ )
243
+ else:
244
+ mem_block = mem_block_o + "\n" + mem_block_p
245
+ return "# Memories\n## PersonalMemory & OuterMemory (ordered)\n" + mem_block + "\n\n"
246
+
247
+ def _extract_references_from_response(self, response: str) -> tuple[str, list[dict]]:
248
+ """
249
+ Extract reference information from the response and return clean text.
250
+
251
+ Args:
252
+ response (str): The complete response text.
253
+
254
+ Returns:
255
+ tuple[str, list[dict]]: A tuple containing:
256
+ - clean_text: Text with reference markers removed
257
+ - references: List of reference information
258
+ """
259
+ import re
260
+
261
+ try:
262
+ references = []
263
+ # Pattern to match [refid:memoriesID]
264
+ pattern = r"\[(\d+):([^\]]+)\]"
265
+
266
+ matches = re.findall(pattern, response)
267
+ for ref_number, memory_id in matches:
268
+ references.append({"memory_id": memory_id, "reference_number": int(ref_number)})
269
+
270
+ # Remove all reference markers from the text to get clean text
271
+ clean_text = re.sub(pattern, "", response)
272
+
273
+ # Clean up any extra whitespace that might be left after removing markers
274
+ clean_text = re.sub(r"\s+", " ", clean_text).strip()
275
+
276
+ return clean_text, references
277
+ except Exception as e:
278
+ logger.error(f"Error extracting references from response: {e}", exc_info=True)
279
+ return response, []
280
+
281
+ async def _post_chat_processing(
282
+ self,
283
+ user_id: str,
284
+ cube_id: str,
285
+ query: str,
286
+ full_response: str,
287
+ system_prompt: str,
288
+ time_start: float,
289
+ time_end: float,
290
+ speed_improvement: float,
291
+ current_messages: list,
292
+ mem_cube: NaiveMemCube | None = None,
293
+ session_id: str | None = None,
294
+ history: MessageList | None = None,
295
+ ) -> None:
296
+ """
297
+ Asynchronous processing of logs, notifications and memory additions
298
+ """
299
+ try:
300
+ logger.info(
301
+ f"user_id: {user_id}, cube_id: {cube_id}, current_messages: {current_messages}"
302
+ )
303
+ logger.info(f"user_id: {user_id}, cube_id: {cube_id}, full_response: {full_response}")
304
+
305
+ clean_response, extracted_references = self._extract_references_from_response(
306
+ full_response
307
+ )
308
+ logger.info(f"Extracted {len(extracted_references)} references from response")
309
+
310
+ # Send chat report notifications asynchronously
311
+ if self.online_bot:
312
+ try:
313
+ from memos.memos_tools.notification_utils import (
314
+ send_online_bot_notification_async,
315
+ )
316
+
317
+ # Prepare notification data
318
+ chat_data = {
319
+ "query": query,
320
+ "user_id": user_id,
321
+ "cube_id": cube_id,
322
+ "system_prompt": system_prompt,
323
+ "full_response": full_response,
324
+ }
325
+
326
+ system_data = {
327
+ "references": extracted_references,
328
+ "time_start": time_start,
329
+ "time_end": time_end,
330
+ "speed_improvement": speed_improvement,
331
+ }
332
+
333
+ emoji_config = {"chat": "💬", "system_info": "📊"}
334
+
335
+ await send_online_bot_notification_async(
336
+ online_bot=self.online_bot,
337
+ header_name="MemOS Chat Report",
338
+ sub_title_name="chat_with_references",
339
+ title_color="#00956D",
340
+ other_data1=chat_data,
341
+ other_data2=system_data,
342
+ emoji=emoji_config,
343
+ )
344
+ except Exception as e:
345
+ logger.warning(f"Failed to send chat notification (async): {e}")
346
+
347
+ self.add(
348
+ user_id=user_id,
349
+ cube_id=cube_id,
350
+ mem_cube=mem_cube,
351
+ session_id=session_id,
352
+ history=history,
353
+ messages=[
354
+ {
355
+ "role": "user",
356
+ "content": query,
357
+ "chat_time": str(datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
358
+ },
359
+ {
360
+ "role": "assistant",
361
+ "content": clean_response, # Store clean text without reference markers
362
+ "chat_time": str(datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
363
+ },
364
+ ],
365
+ )
366
+
367
+ logger.info(f"Post-chat processing completed for user {user_id}")
368
+
369
+ except Exception as e:
370
+ logger.error(f"Error in post-chat processing for user {user_id}: {e}", exc_info=True)
371
+
372
+ def _start_post_chat_processing(
373
+ self,
374
+ user_id: str,
375
+ cube_id: str,
376
+ query: str,
377
+ full_response: str,
378
+ system_prompt: str,
379
+ time_start: float,
380
+ time_end: float,
381
+ speed_improvement: float,
382
+ current_messages: list,
383
+ mem_cube: NaiveMemCube | None = None,
384
+ session_id: str | None = None,
385
+ history: MessageList | None = None,
386
+ ) -> None:
387
+ """
388
+ Asynchronous processing of logs, notifications and memory additions, handle synchronous and asynchronous environments
389
+ """
390
+
391
+ def run_async_in_thread():
392
+ """Running asynchronous tasks in a new thread"""
393
+ try:
394
+ loop = asyncio.new_event_loop()
395
+ asyncio.set_event_loop(loop)
396
+ try:
397
+ loop.run_until_complete(
398
+ self._post_chat_processing(
399
+ user_id=user_id,
400
+ cube_id=cube_id,
401
+ query=query,
402
+ full_response=full_response,
403
+ system_prompt=system_prompt,
404
+ time_start=time_start,
405
+ time_end=time_end,
406
+ speed_improvement=speed_improvement,
407
+ current_messages=current_messages,
408
+ mem_cube=mem_cube,
409
+ session_id=session_id,
410
+ history=history,
411
+ )
412
+ )
413
+ finally:
414
+ loop.close()
415
+ except Exception as e:
416
+ logger.error(
417
+ f"Error in thread-based post-chat processing for user {user_id}: {e}",
418
+ exc_info=True,
419
+ )
420
+
421
+ try:
422
+ # Try to get the current event loop
423
+ asyncio.get_running_loop()
424
+ # Create task and store reference to prevent garbage collection
425
+ task = asyncio.create_task(
426
+ self._post_chat_processing(
427
+ user_id=user_id,
428
+ cube_id=cube_id,
429
+ query=query,
430
+ full_response=full_response,
431
+ system_prompt=system_prompt,
432
+ time_start=time_start,
433
+ time_end=time_end,
434
+ speed_improvement=speed_improvement,
435
+ current_messages=current_messages,
436
+ )
437
+ )
438
+ # Add exception handling for the background task
439
+ task.add_done_callback(
440
+ lambda t: logger.error(
441
+ f"Error in background post-chat processing for user {user_id}: {t.exception()}",
442
+ exc_info=True,
443
+ )
444
+ if t.exception()
445
+ else None
446
+ )
447
+ except RuntimeError:
448
+ # No event loop, run in a new thread with context propagation
449
+ thread = ContextThread(
450
+ target=run_async_in_thread,
451
+ name=f"PostChatProcessing-{user_id}",
452
+ # Set as a daemon thread to avoid blocking program exit
453
+ daemon=True,
454
+ )
455
+ thread.start()