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,5 @@
1
+ from .memory_filter import MemoryFilter
2
+ from .retriever import SchedulerRetriever
3
+
4
+
5
+ __all__ = ["MemoryFilter", "SchedulerRetriever"]
@@ -0,0 +1,306 @@
1
+ from memos.configs.mem_scheduler import BaseSchedulerConfig
2
+ from memos.llms.base import BaseLLM
3
+ from memos.log import get_logger
4
+ from memos.mem_scheduler.general_modules.base import BaseSchedulerModule
5
+ from memos.mem_scheduler.utils.misc_utils import extract_json_obj
6
+ from memos.memories.textual.tree import TextualMemoryItem
7
+
8
+
9
+ logger = get_logger(__name__)
10
+
11
+
12
+ class MemoryFilter(BaseSchedulerModule):
13
+ def __init__(self, process_llm: BaseLLM, config: BaseSchedulerConfig):
14
+ super().__init__()
15
+ self.config: BaseSchedulerConfig = config
16
+ self.process_llm = process_llm
17
+
18
+ def filter_unrelated_memories(
19
+ self,
20
+ query_history: list[str],
21
+ memories: list[TextualMemoryItem],
22
+ ) -> (list[TextualMemoryItem], bool):
23
+ """
24
+ Filter out memories that are completely unrelated to the query history using LLM.
25
+
26
+ Args:
27
+ query_history: List of query strings to determine relevance
28
+ memories: List of TextualMemoryItem objects to be filtered
29
+
30
+ Returns:
31
+ Tuple of (filtered_memories, success_flag)
32
+ - filtered_memories: List of TextualMemoryItem objects that are relevant to queries
33
+ - success_flag: Boolean indicating if LLM filtering was successful
34
+
35
+ Note:
36
+ If LLM filtering fails, returns all memories (conservative approach)
37
+ """
38
+ success_flag = False
39
+
40
+ if not memories:
41
+ logger.info("No memories to filter - returning empty list")
42
+ return [], True
43
+
44
+ if not query_history:
45
+ logger.info("No query history provided - keeping all memories")
46
+ return memories, True
47
+
48
+ logger.info(
49
+ f"Starting memory filtering for {len(memories)} memories against {len(query_history)} queries"
50
+ )
51
+
52
+ # Extract memory texts for LLM processing
53
+ memory_texts = [mem.memory for mem in memories]
54
+
55
+ # Build LLM prompt for memory filtering
56
+ prompt = self.build_prompt(
57
+ "memory_filtering",
58
+ query_history=[f"[{i}] {query}" for i, query in enumerate(query_history)],
59
+ memories=[f"[{i}] {mem}" for i, mem in enumerate(memory_texts)],
60
+ )
61
+ logger.debug(f"Generated filtering prompt: {prompt[:200]}...") # Log first 200 chars
62
+
63
+ # Get LLM response
64
+ response = self.process_llm.generate([{"role": "user", "content": prompt}])
65
+ logger.debug(f"Received LLM filtering response: {response[:200]}...") # Log first 200 chars
66
+
67
+ try:
68
+ # Parse JSON response
69
+ response = extract_json_obj(response)
70
+ logger.debug(f"Parsed JSON response: {response}")
71
+ relevant_indices = response["relevant_memories"]
72
+ filtered_count = response["filtered_count"]
73
+ reasoning = response["reasoning"]
74
+
75
+ # Validate indices
76
+ if not isinstance(relevant_indices, list):
77
+ raise ValueError("relevant_memories must be a list")
78
+
79
+ # Filter memories based on relevant indices
80
+ filtered_memories = []
81
+ for idx in relevant_indices:
82
+ if isinstance(idx, int) and 0 <= idx < len(memories):
83
+ filtered_memories.append(memories[idx])
84
+ else:
85
+ logger.warning(f"Invalid memory index {idx} - skipping")
86
+
87
+ logger.info(
88
+ f"Successfully filtered memories. Kept {len(filtered_memories)} out of {len(memories)} memories. "
89
+ f"Filtered out {filtered_count} unrelated memories. "
90
+ f"Filtering reasoning: {reasoning}"
91
+ )
92
+ success_flag = True
93
+
94
+ except Exception as e:
95
+ logger.error(
96
+ f"Failed to filter memories with LLM. Exception: {e}. Raw response: {response}",
97
+ exc_info=True,
98
+ )
99
+ # Conservative approach: keep all memories if filtering fails
100
+ filtered_memories = memories
101
+ success_flag = False
102
+
103
+ return filtered_memories, success_flag
104
+
105
+ def filter_redundant_memories(
106
+ self,
107
+ query_history: list[str],
108
+ memories: list[TextualMemoryItem],
109
+ ) -> (list[TextualMemoryItem], bool):
110
+ """
111
+ Filter out redundant memories using LLM analysis.
112
+
113
+ This function removes redundant memories by keeping the most informative
114
+ version when multiple memories contain similar information relevant to queries.
115
+
116
+ Args:
117
+ query_history: List of query strings to determine relevance and value
118
+ memories: List of TextualMemoryItem objects to be filtered
119
+
120
+ Returns:
121
+ Tuple of (filtered_memories, success_flag)
122
+ - filtered_memories: List of TextualMemoryItem objects after redundancy filtering
123
+ - success_flag: Boolean indicating if LLM filtering was successful
124
+
125
+ Note:
126
+ If LLM filtering fails, returns all memories (conservative approach)
127
+ """
128
+ success_flag = False
129
+
130
+ if not memories:
131
+ logger.info("No memories to filter for redundancy - returning empty list")
132
+ return [], True
133
+
134
+ if not query_history:
135
+ logger.info("No query history provided - keeping all memories")
136
+ return memories, True
137
+
138
+ if len(memories) <= 1:
139
+ logger.info("Only one memory - no redundancy to filter")
140
+ return memories, True
141
+
142
+ logger.info(
143
+ f"Starting redundancy filtering for {len(memories)} memories against {len(query_history)} queries"
144
+ )
145
+
146
+ # Extract memory texts for LLM processing
147
+ memory_texts = [mem.memory for mem in memories]
148
+
149
+ # Build LLM prompt for redundancy filtering
150
+ prompt = self.build_prompt(
151
+ "memory_redundancy_filtering",
152
+ query_history=[f"[{i}] {query}" for i, query in enumerate(query_history)],
153
+ memories=[f"[{i}] {mem}" for i, mem in enumerate(memory_texts)],
154
+ )
155
+ logger.debug(
156
+ f"Generated redundancy filtering prompt: {prompt[:200]}..."
157
+ ) # Log first 200 chars
158
+
159
+ # Get LLM response
160
+ response = self.process_llm.generate([{"role": "user", "content": prompt}])
161
+ logger.debug(
162
+ f"Received LLM redundancy filtering response: {response[:200]}..."
163
+ ) # Log first 200 chars
164
+
165
+ try:
166
+ # Parse JSON response
167
+ response = extract_json_obj(response)
168
+ logger.debug(f"Parsed JSON response: {response}")
169
+ kept_indices = response["kept_memories"]
170
+ redundant_groups = response.get("redundant_groups", [])
171
+ reasoning = response["reasoning"]
172
+
173
+ # Validate indices
174
+ if not isinstance(kept_indices, list):
175
+ raise ValueError("kept_memories must be a list")
176
+
177
+ # Filter memories based on kept indices
178
+ filtered_memories = []
179
+ for idx in kept_indices:
180
+ if isinstance(idx, int) and 0 <= idx < len(memories):
181
+ filtered_memories.append(memories[idx])
182
+ else:
183
+ logger.warning(f"Invalid memory index {idx} - skipping")
184
+
185
+ logger.info(
186
+ f"Successfully filtered redundant memories. "
187
+ f"Kept {len(filtered_memories)} out of {len(memories)} memories. "
188
+ f"Removed {len(memories) - len(filtered_memories)} redundant memories. "
189
+ f"Redundant groups identified: {len(redundant_groups)}. "
190
+ f"Filtering reasoning: {reasoning}"
191
+ )
192
+ success_flag = True
193
+
194
+ except Exception as e:
195
+ logger.error(
196
+ f"Failed to filter redundant memories with LLM. Exception: {e}. Raw response: {response}",
197
+ exc_info=True,
198
+ )
199
+ # Conservative approach: keep all memories if filtering fails
200
+ filtered_memories = memories
201
+ success_flag = False
202
+
203
+ return filtered_memories, success_flag
204
+
205
+ def filter_unrelated_and_redundant_memories(
206
+ self,
207
+ query_history: list[str],
208
+ memories: list[TextualMemoryItem],
209
+ ) -> (list[TextualMemoryItem], bool):
210
+ """
211
+ Filter out both unrelated and redundant memories using LLM analysis.
212
+
213
+ This function performs two types of filtering in sequence:
214
+ 1. Remove memories that are completely unrelated to the query history
215
+ 2. Remove redundant memories by keeping the most informative version
216
+
217
+ Args:
218
+ query_history: List of query strings to determine relevance and value
219
+ memories: List of TextualMemoryItem objects to be filtered
220
+
221
+ Returns:
222
+ Tuple of (filtered_memories, success_flag)
223
+ - filtered_memories: List of TextualMemoryItem objects after both filtering steps
224
+ - success_flag: Boolean indicating if LLM filtering was successful
225
+
226
+ Note:
227
+ If LLM filtering fails, returns all memories (conservative approach)
228
+ """
229
+ if not memories:
230
+ logger.info("No memories to filter for unrelated and redundant - returning empty list")
231
+ return [], True
232
+
233
+ if not query_history:
234
+ logger.info("No query history provided - keeping all memories")
235
+ return memories, True
236
+
237
+ if len(memories) <= 1:
238
+ logger.info("Only one memory - no filtering needed")
239
+ return memories, True
240
+
241
+ logger.info(
242
+ f"Starting combined unrelated and redundant filtering for {len(memories)} memories against {len(query_history)} queries"
243
+ )
244
+
245
+ # Extract memory texts for LLM processing
246
+ memory_texts = [mem.memory for mem in memories]
247
+
248
+ # Build LLM prompt for combined filtering
249
+ prompt = self.build_prompt(
250
+ "memory_combined_filtering",
251
+ query_history=[f"[{i}] {query}" for i, query in enumerate(query_history)],
252
+ memories=[f"[{i}] {mem}" for i, mem in enumerate(memory_texts)],
253
+ )
254
+ logger.debug(
255
+ f"Generated combined filtering prompt: {prompt[:200]}..."
256
+ ) # Log first 200 chars
257
+
258
+ # Get LLM response
259
+ response = self.process_llm.generate([{"role": "user", "content": prompt}])
260
+ logger.debug(
261
+ f"Received LLM combined filtering response: {response[:200]}..."
262
+ ) # Log first 200 chars
263
+
264
+ try:
265
+ # Parse JSON response
266
+ response = extract_json_obj(response)
267
+ logger.debug(f"Parsed JSON response: {response}")
268
+ kept_indices = response["kept_memories"]
269
+ unrelated_removed_count = response.get("unrelated_removed_count", 0)
270
+ redundant_removed_count = response.get("redundant_removed_count", 0)
271
+ redundant_groups = response.get("redundant_groups", [])
272
+ reasoning = response["reasoning"]
273
+
274
+ # Validate indices
275
+ if not isinstance(kept_indices, list):
276
+ raise ValueError("kept_memories must be a list")
277
+
278
+ # Filter memories based on kept indices
279
+ filtered_memories = []
280
+ for idx in kept_indices:
281
+ if isinstance(idx, int) and 0 <= idx < len(memories):
282
+ filtered_memories.append(memories[idx])
283
+ else:
284
+ logger.warning(f"Invalid memory index {idx} - skipping")
285
+
286
+ logger.info(
287
+ f"Successfully filtered unrelated and redundant memories. "
288
+ f"Kept {len(filtered_memories)} out of {len(memories)} memories. "
289
+ f"Removed {len(memories) - len(filtered_memories)} memories total. "
290
+ f"Unrelated removed: {unrelated_removed_count}. "
291
+ f"Redundant removed: {redundant_removed_count}. "
292
+ f"Redundant groups identified: {len(redundant_groups)}. "
293
+ f"Filtering reasoning: {reasoning}"
294
+ )
295
+ success_flag = True
296
+
297
+ except Exception as e:
298
+ logger.error(
299
+ f"Failed to filter unrelated and redundant memories with LLM. Exception: {e}. Raw response: {response}",
300
+ exc_info=True,
301
+ )
302
+ # Conservative approach: keep all memories if filtering fails
303
+ filtered_memories = memories
304
+ success_flag = False
305
+
306
+ return filtered_memories, success_flag