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,410 @@
1
+ import json
2
+ import os
3
+
4
+ from collections import OrderedDict
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ from memos.api.product_models import APISearchRequest
8
+ from memos.configs.mem_scheduler import GeneralSchedulerConfig
9
+ from memos.log import get_logger
10
+ from memos.mem_cube.general import GeneralMemCube
11
+ from memos.mem_cube.navie import NaiveMemCube
12
+ from memos.mem_scheduler.general_modules.api_misc import SchedulerAPIModule
13
+ from memos.mem_scheduler.general_scheduler import GeneralScheduler
14
+ from memos.mem_scheduler.schemas.message_schemas import ScheduleMessageItem
15
+ from memos.mem_scheduler.schemas.task_schemas import (
16
+ API_MIX_SEARCH_TASK_LABEL,
17
+ )
18
+ from memos.mem_scheduler.utils.api_utils import format_textual_memory_item
19
+ from memos.mem_scheduler.utils.db_utils import get_utc_now
20
+ from memos.mem_scheduler.utils.misc_utils import group_messages_by_user_and_mem_cube
21
+ from memos.memories.textual.tree import TextualMemoryItem, TreeTextMemory
22
+ from memos.types import (
23
+ MemCubeID,
24
+ SearchMode,
25
+ UserContext,
26
+ UserID,
27
+ )
28
+
29
+
30
+ if TYPE_CHECKING:
31
+ from memos.mem_scheduler.schemas.monitor_schemas import MemoryMonitorItem
32
+
33
+ logger = get_logger(__name__)
34
+
35
+
36
+ class OptimizedScheduler(GeneralScheduler):
37
+ """Optimized scheduler with improved working memory management and support for api"""
38
+
39
+ def __init__(self, config: GeneralSchedulerConfig):
40
+ super().__init__(config)
41
+ self.window_size = int(os.getenv("API_SEARCH_WINDOW_SIZE", 5))
42
+ self.history_memory_turns = int(os.getenv("API_SEARCH_HISTORY_TURNS", 5))
43
+ self.session_counter = OrderedDict()
44
+ self.max_session_history = 5
45
+
46
+ if self.config.use_redis_queue:
47
+ self.api_module = SchedulerAPIModule(
48
+ window_size=self.window_size,
49
+ history_memory_turns=self.history_memory_turns,
50
+ )
51
+ else:
52
+ self.api_module = None
53
+
54
+ self.register_handlers(
55
+ {
56
+ API_MIX_SEARCH_TASK_LABEL: self._api_mix_search_message_consumer,
57
+ }
58
+ )
59
+ self.searcher = None
60
+ self.reranker = None
61
+ self.text_mem = None
62
+
63
+ def submit_memory_history_async_task(
64
+ self,
65
+ search_req: APISearchRequest,
66
+ user_context: UserContext,
67
+ memories_to_store: dict | None = None,
68
+ session_id: str | None = None,
69
+ ):
70
+ # Create message for async fine search
71
+ message_content = {
72
+ "search_req": {
73
+ "query": search_req.query,
74
+ "user_id": search_req.user_id,
75
+ "session_id": session_id,
76
+ "top_k": search_req.top_k,
77
+ "internet_search": search_req.internet_search,
78
+ "chat_history": search_req.chat_history,
79
+ },
80
+ "user_context": {"mem_cube_id": user_context.mem_cube_id},
81
+ "memories_to_store": memories_to_store,
82
+ }
83
+
84
+ async_task_id = f"mix_search_{search_req.user_id}_{get_utc_now().timestamp()}"
85
+
86
+ message = ScheduleMessageItem(
87
+ item_id=async_task_id,
88
+ user_id=search_req.user_id,
89
+ mem_cube_id=user_context.mem_cube_id,
90
+ label=API_MIX_SEARCH_TASK_LABEL,
91
+ content=json.dumps(message_content),
92
+ timestamp=get_utc_now(),
93
+ )
94
+
95
+ # Submit async task
96
+ self.memos_message_queue.submit_messages([message])
97
+ logger.info(f"Submitted async fine search task for user {search_req.user_id}")
98
+ return async_task_id
99
+
100
+ def search_memories(
101
+ self,
102
+ search_req: APISearchRequest,
103
+ user_context: UserContext,
104
+ mem_cube: NaiveMemCube,
105
+ mode: SearchMode,
106
+ ):
107
+ """Fine search memories function copied from server_router to avoid circular import"""
108
+ target_session_id = search_req.session_id
109
+ if not target_session_id:
110
+ target_session_id = "default_session"
111
+ search_priority = {"session_id": search_req.session_id} if search_req.session_id else None
112
+ search_filter = search_req.filter
113
+
114
+ # Create MemCube and perform search
115
+ search_results = mem_cube.text_mem.search(
116
+ query=search_req.query,
117
+ user_name=user_context.mem_cube_id,
118
+ top_k=search_req.top_k,
119
+ mode=mode,
120
+ manual_close_internet=not search_req.internet_search,
121
+ search_filter=search_filter,
122
+ search_priority=search_priority,
123
+ info={
124
+ "user_id": search_req.user_id,
125
+ "session_id": target_session_id,
126
+ "chat_history": search_req.chat_history,
127
+ },
128
+ )
129
+ return search_results
130
+
131
+ def mix_search_memories(
132
+ self,
133
+ search_req: APISearchRequest,
134
+ user_context: UserContext,
135
+ ) -> list[dict[str, Any]]:
136
+ """
137
+ Mix search memories: fast search + async fine search
138
+ """
139
+ logger.info(
140
+ f"Mix searching memories for user {search_req.user_id} with query: {search_req.query}"
141
+ )
142
+
143
+ if not self.config.use_redis_queue:
144
+ logger.warning(
145
+ "Redis queue is not enabled. Running in degraded mode: "
146
+ "FAST search only, no history memory reranking, no async updates."
147
+ )
148
+ memories = self.search_memories(
149
+ search_req=search_req,
150
+ user_context=user_context,
151
+ mem_cube=self.mem_cube,
152
+ mode=SearchMode.FAST,
153
+ )
154
+ return [
155
+ format_textual_memory_item(item, include_embedding=search_req.dedup == "sim")
156
+ for item in memories
157
+ ]
158
+
159
+ # Get mem_cube for fast search
160
+ target_session_id = search_req.session_id
161
+ if not target_session_id:
162
+ target_session_id = "default_session"
163
+ search_priority = {"session_id": search_req.session_id} if search_req.session_id else None
164
+ search_filter = search_req.filter
165
+
166
+ # Rerank Memories - reranker expects TextualMemoryItem objects
167
+
168
+ info = {
169
+ "user_id": search_req.user_id,
170
+ "session_id": target_session_id,
171
+ "chat_history": search_req.chat_history,
172
+ }
173
+
174
+ raw_retrieved_memories = self.searcher.retrieve(
175
+ query=search_req.query,
176
+ user_name=user_context.mem_cube_id,
177
+ top_k=search_req.top_k,
178
+ mode=SearchMode.FINE,
179
+ manual_close_internet=not search_req.internet_search,
180
+ moscube=search_req.moscube,
181
+ search_filter=search_filter,
182
+ search_priority=search_priority,
183
+ info=info,
184
+ search_tool_memory=search_req.search_tool_memory,
185
+ tool_mem_top_k=search_req.tool_mem_top_k,
186
+ )
187
+
188
+ # Try to get pre-computed memories if available
189
+ history_memories = self.api_module.get_history_memories(
190
+ user_id=search_req.user_id,
191
+ mem_cube_id=user_context.mem_cube_id,
192
+ turns=self.history_memory_turns,
193
+ )
194
+ logger.info(f"Found {len(history_memories)} history memories.")
195
+
196
+ # if history memories can directly answer
197
+ sorted_history_memories = self.reranker.rerank(
198
+ query=search_req.query, # Use search_req.query instead of undefined query
199
+ graph_results=history_memories, # Pass TextualMemoryItem objects directly
200
+ top_k=search_req.top_k, # Use search_req.top_k instead of undefined top_k
201
+ search_filter=search_filter,
202
+ )
203
+ logger.info(f"Reranked {len(sorted_history_memories)} history memories.")
204
+ merged_memories = self.searcher.post_retrieve(
205
+ retrieved_results=raw_retrieved_memories + sorted_history_memories,
206
+ top_k=search_req.top_k,
207
+ user_name=user_context.mem_cube_id,
208
+ info=info,
209
+ search_tool_memory=search_req.search_tool_memory,
210
+ tool_mem_top_k=search_req.tool_mem_top_k,
211
+ dedup=search_req.dedup,
212
+ )
213
+ memories = merged_memories[: search_req.top_k]
214
+
215
+ formatted_memories = [
216
+ format_textual_memory_item(item, include_embedding=search_req.dedup == "sim")
217
+ for item in memories
218
+ ]
219
+ self.submit_memory_history_async_task(
220
+ search_req=search_req,
221
+ user_context=user_context,
222
+ memories_to_store={
223
+ "memories": [one.to_dict() for one in memories],
224
+ "formatted_memories": formatted_memories,
225
+ },
226
+ )
227
+ return formatted_memories
228
+
229
+ def update_search_memories_to_redis(
230
+ self,
231
+ messages: list[ScheduleMessageItem],
232
+ ):
233
+ for msg in messages:
234
+ content_dict = json.loads(msg.content)
235
+ search_req = content_dict["search_req"]
236
+ user_context = content_dict["user_context"]
237
+ session_id = search_req.get("session_id")
238
+ if session_id:
239
+ if session_id not in self.session_counter:
240
+ self.session_counter[session_id] = 0
241
+ else:
242
+ self.session_counter[session_id] += 1
243
+ session_turn = self.session_counter[session_id]
244
+
245
+ # Move the current session to the end to mark it as recently used
246
+ self.session_counter.move_to_end(session_id)
247
+
248
+ # If the counter exceeds the max size, remove the oldest item
249
+ if len(self.session_counter) > self.max_session_history:
250
+ self.session_counter.popitem(last=False)
251
+ else:
252
+ session_turn = 0
253
+
254
+ memories_to_store = content_dict["memories_to_store"]
255
+ if memories_to_store is None:
256
+ memories: list[TextualMemoryItem] = self.search_memories(
257
+ search_req=APISearchRequest(**content_dict["search_req"]),
258
+ user_context=UserContext(**content_dict["user_context"]),
259
+ mem_cube=self.mem_cube,
260
+ mode=SearchMode.FAST,
261
+ )
262
+ formatted_memories = [
263
+ format_textual_memory_item(data, include_embedding=search_req.dedup == "sim")
264
+ for data in memories
265
+ ]
266
+ else:
267
+ memories = [
268
+ TextualMemoryItem.from_dict(one) for one in memories_to_store["memories"]
269
+ ]
270
+ formatted_memories = memories_to_store["formatted_memories"]
271
+
272
+ # Sync search data to Redis
273
+ self.api_module.sync_search_data(
274
+ item_id=msg.item_id,
275
+ user_id=search_req["user_id"],
276
+ mem_cube_id=user_context["mem_cube_id"],
277
+ query=search_req["query"],
278
+ memories=memories,
279
+ formatted_memories=formatted_memories,
280
+ session_id=session_id,
281
+ conversation_turn=session_turn,
282
+ )
283
+
284
+ def _api_mix_search_message_consumer(self, messages: list[ScheduleMessageItem]) -> None:
285
+ """
286
+ Process and handle query trigger messages from the queue.
287
+
288
+ Args:
289
+ messages: List of query messages to process
290
+ """
291
+ logger.info(f"Messages {messages} assigned to {API_MIX_SEARCH_TASK_LABEL} handler.")
292
+
293
+ # Process the query in a session turn
294
+ grouped_messages = group_messages_by_user_and_mem_cube(messages)
295
+
296
+ self.validate_schedule_messages(messages=messages, label=API_MIX_SEARCH_TASK_LABEL)
297
+
298
+ for user_id in grouped_messages:
299
+ for mem_cube_id in grouped_messages[user_id]:
300
+ messages = grouped_messages[user_id][mem_cube_id]
301
+ if len(messages) == 0:
302
+ return
303
+ self.update_search_memories_to_redis(messages=messages)
304
+
305
+ def replace_working_memory(
306
+ self,
307
+ user_id: UserID | str,
308
+ mem_cube_id: MemCubeID | str,
309
+ mem_cube: GeneralMemCube,
310
+ original_memory: list[TextualMemoryItem],
311
+ new_memory: list[TextualMemoryItem],
312
+ ) -> None | list[TextualMemoryItem]:
313
+ """Replace working memory with new memories after reranking."""
314
+ text_mem_base = mem_cube.text_mem
315
+ if isinstance(text_mem_base, TreeTextMemory):
316
+ text_mem_base: TreeTextMemory = text_mem_base
317
+
318
+ # process rerank memories with llm
319
+ query_db_manager = self.monitor.query_monitors[user_id][mem_cube_id]
320
+ # Sync with database to get latest query history
321
+ query_db_manager.sync_with_orm()
322
+
323
+ query_history = query_db_manager.obj.get_queries_with_timesort()
324
+ memories_with_new_order, rerank_success_flag = (
325
+ self.retriever.process_and_rerank_memories(
326
+ queries=query_history,
327
+ original_memory=original_memory,
328
+ new_memory=new_memory,
329
+ top_k=self.top_k,
330
+ )
331
+ )
332
+
333
+ # Apply combined filtering (unrelated + redundant)
334
+ logger.info(
335
+ f"[optimized replace_working_memory] Applying combined unrelated and redundant memory filtering to {len(memories_with_new_order)} memories"
336
+ )
337
+ filtered_memories, filtering_success_flag = (
338
+ self.retriever.filter_unrelated_and_redundant_memories(
339
+ query_history=query_history,
340
+ memories=memories_with_new_order,
341
+ )
342
+ )
343
+
344
+ if filtering_success_flag:
345
+ logger.info(
346
+ f"[optimized replace_working_memory] Combined filtering completed successfully. "
347
+ f"Filtered from {len(memories_with_new_order)} to {len(filtered_memories)} memories"
348
+ )
349
+ memories_with_new_order = filtered_memories
350
+ else:
351
+ logger.warning(
352
+ "[optimized replace_working_memory] Combined filtering failed - keeping memories as fallback. "
353
+ f"Count: {len(memories_with_new_order)}"
354
+ )
355
+
356
+ # Update working memory monitors
357
+ query_keywords = query_db_manager.obj.get_keywords_collections()
358
+ logger.info(
359
+ f"[optimized replace_working_memory] Processing {len(memories_with_new_order)} memories with {len(query_keywords)} query keywords"
360
+ )
361
+ new_working_memory_monitors = self.transform_working_memories_to_monitors(
362
+ query_keywords=query_keywords,
363
+ memories=memories_with_new_order,
364
+ )
365
+
366
+ if not rerank_success_flag:
367
+ for one in new_working_memory_monitors:
368
+ one.sorting_score = 0
369
+
370
+ self.monitor.update_working_memory_monitors(
371
+ new_working_memory_monitors=new_working_memory_monitors,
372
+ user_id=user_id,
373
+ mem_cube_id=mem_cube_id,
374
+ mem_cube=mem_cube,
375
+ )
376
+ logger.info(
377
+ f"[optimized replace_working_memory] update {len(new_working_memory_monitors)} working_memory_monitors"
378
+ )
379
+ try:
380
+ # Use the filtered and reranked memories directly
381
+ text_mem_base.replace_working_memory(
382
+ memories=memories_with_new_order, user_name=mem_cube_id
383
+ )
384
+ except Exception:
385
+ logger.error(
386
+ "[optimized replace_working_memory] text_mem_base.replace_working_memory failed!",
387
+ stack_info=True,
388
+ )
389
+ # Update monitor after replacing working memory
390
+ mem_monitors: list[MemoryMonitorItem] = self.monitor.working_memory_monitors[user_id][
391
+ mem_cube_id
392
+ ].obj.get_sorted_mem_monitors(reverse=True)
393
+ new_working_memories = [mem_monitor.tree_memory_item for mem_monitor in mem_monitors]
394
+
395
+ logger.info(
396
+ f"[optimized replace_working_memory] The working memory has been replaced with {len(memories_with_new_order)} new memories."
397
+ )
398
+ self.log_working_memory_replacement(
399
+ original_memory=original_memory,
400
+ new_memory=new_working_memories,
401
+ user_id=user_id,
402
+ mem_cube_id=mem_cube_id,
403
+ mem_cube=mem_cube,
404
+ log_func_callback=self._submit_web_logs,
405
+ )
406
+ else:
407
+ logger.error("memory_base is not supported")
408
+ memories_with_new_order = new_memory
409
+
410
+ return memories_with_new_order
File without changes