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,23 @@
1
+ from typing import Any, ClassVar
2
+
3
+ from memos.configs.mem_scheduler import SchedulerConfigFactory
4
+ from memos.mem_scheduler.base_scheduler import BaseScheduler
5
+ from memos.mem_scheduler.general_scheduler import GeneralScheduler
6
+ from memos.mem_scheduler.optimized_scheduler import OptimizedScheduler
7
+
8
+
9
+ class SchedulerFactory(BaseScheduler):
10
+ """Factory class for creating scheduler instances."""
11
+
12
+ backend_to_class: ClassVar[dict[str, Any]] = {
13
+ "general_scheduler": GeneralScheduler,
14
+ "optimized_scheduler": OptimizedScheduler,
15
+ }
16
+
17
+ @classmethod
18
+ def from_config(cls, config_factory: SchedulerConfigFactory) -> GeneralScheduler:
19
+ backend = config_factory.backend
20
+ if backend not in cls.backend_to_class:
21
+ raise ValueError(f"Invalid backend: {backend}")
22
+ mem_scheduler_class = cls.backend_to_class[backend]
23
+ return mem_scheduler_class(config_factory.config)
File without changes
@@ -0,0 +1,52 @@
1
+ import json
2
+
3
+ from pathlib import Path
4
+ from typing import Any
5
+
6
+ from pydantic import BaseModel, Field
7
+
8
+ from memos.log import get_logger
9
+
10
+
11
+ logger = get_logger(__name__)
12
+
13
+ FILE_PATH = Path(__file__).absolute()
14
+ BASE_DIR = FILE_PATH.parent.parent.parent.parent.parent
15
+
16
+
17
+ class BasicRecordingCase(BaseModel):
18
+ # Conversation identification
19
+ conv_id: str = Field(description="Conversation identifier for this evaluation case")
20
+ user_id: str = Field(description="User identifier for this evaluation case")
21
+ memcube_id: str = Field(description="Memcube identifier for this evaluation case")
22
+
23
+ # Query and answer information
24
+ query: str = Field(description="The current question/query being evaluated")
25
+
26
+ answer: str = Field(description="The generated answer for the query")
27
+
28
+ golden_answer: str | None = Field(
29
+ default=None, description="Ground truth answer for evaluation"
30
+ )
31
+
32
+ def to_dict(self) -> dict[str, Any]:
33
+ return self.dict()
34
+
35
+ def to_json(self, indent: int = 2) -> str:
36
+ return self.json(indent=indent, ensure_ascii=False)
37
+
38
+ @classmethod
39
+ def from_dict(cls, data: dict[str, Any]) -> "BasicRecordingCase":
40
+ return cls(**data)
41
+
42
+ @classmethod
43
+ def from_json(cls, json_str: str) -> "BasicRecordingCase":
44
+ data = json.loads(json_str)
45
+ return cls.from_dict(data)
46
+
47
+ class Config:
48
+ """Pydantic configuration"""
49
+
50
+ extra = "allow" # Allow additional fields not defined in the schema
51
+ validate_assignment = True # Validate on assignment
52
+ use_enum_values = True # Use enum values instead of enum names
@@ -0,0 +1,233 @@
1
+ from datetime import datetime
2
+ from enum import Enum
3
+ from typing import Any
4
+ from uuid import uuid4
5
+
6
+ from pydantic import BaseModel, ConfigDict, Field, field_serializer
7
+
8
+ from memos.log import get_logger
9
+ from memos.mem_scheduler.general_modules.misc import DictConversionMixin
10
+ from memos.mem_scheduler.utils.db_utils import get_utc_now
11
+ from memos.memories.textual.item import TextualMemoryItem
12
+
13
+
14
+ logger = get_logger(__name__)
15
+
16
+
17
+ class TaskRunningStatus(str, Enum):
18
+ """Enumeration for task running status values."""
19
+
20
+ RUNNING = "running"
21
+ COMPLETED = "completed"
22
+
23
+
24
+ class APIMemoryHistoryEntryItem(BaseModel, DictConversionMixin):
25
+ """Data class for search entry items stored in Redis."""
26
+
27
+ item_id: str = Field(
28
+ description="Unique identifier for the task", default_factory=lambda: str(uuid4())
29
+ )
30
+ query: str = Field(..., description="Search query string")
31
+ formatted_memories: Any = Field(..., description="Formatted search results")
32
+ memories: list[TextualMemoryItem] = Field(
33
+ default_factory=list, description="List of TextualMemoryItem objects"
34
+ )
35
+ task_status: str = Field(
36
+ default="running", description="Task status: running, completed, failed"
37
+ )
38
+ session_id: str | None = Field(default=None, description="Optional conversation identifier")
39
+ created_time: datetime = Field(description="Entry creation time", default_factory=get_utc_now)
40
+ timestamp: datetime | None = Field(default=None, description="Timestamp for the entry")
41
+ conversation_turn: int = Field(default=0, description="Turn count for the same session_id")
42
+
43
+ model_config = ConfigDict(
44
+ arbitrary_types_allowed=True,
45
+ validate_assignment=True,
46
+ )
47
+
48
+ @field_serializer("created_time")
49
+ def serialize_created_time(self, value: datetime) -> str:
50
+ """Serialize datetime to ISO format string."""
51
+ return value.isoformat()
52
+
53
+ def get(self, key: str, default: Any | None = None) -> Any:
54
+ """
55
+ Get attribute value by key name, similar to dict.get().
56
+
57
+ Args:
58
+ key: The attribute name to retrieve
59
+ default: Default value to return if attribute doesn't exist
60
+
61
+ Returns:
62
+ The attribute value or default if not found
63
+ """
64
+ return getattr(self, key, default)
65
+
66
+
67
+ class APISearchHistoryManager(BaseModel, DictConversionMixin):
68
+ """
69
+ Data structure for managing search history with separate completed and running entries.
70
+ Supports window_size to limit the number of completed entries.
71
+ """
72
+
73
+ window_size: int = Field(default=5, description="Maximum number of completed entries to keep")
74
+ completed_entries: list[APIMemoryHistoryEntryItem] = Field(
75
+ default_factory=list, description="List of completed search entries"
76
+ )
77
+ running_item_ids: list[str] = Field(
78
+ default_factory=list, description="List of running task ids"
79
+ )
80
+
81
+ model_config = ConfigDict(
82
+ arbitrary_types_allowed=True,
83
+ validate_assignment=True,
84
+ )
85
+
86
+ def complete_entry(self, task_id: str) -> bool:
87
+ """
88
+ Remove task_id from running list when completed.
89
+ Note: The actual entry data should be managed separately.
90
+
91
+ Args:
92
+ task_id: The task ID to complete
93
+
94
+ Returns:
95
+ True if task_id was found and removed, False otherwise
96
+ """
97
+ if task_id in self.running_item_ids:
98
+ self.running_item_ids.remove(task_id)
99
+ logger.debug(f"Completed task_id: {task_id}")
100
+ return True
101
+
102
+ logger.warning(f"Task ID {task_id} not found in running task ids")
103
+ return False
104
+
105
+ def get_running_item_ids(self) -> list[str]:
106
+ """Get all running task IDs"""
107
+ return self.running_item_ids.copy()
108
+
109
+ def get_completed_entries(self) -> list[APIMemoryHistoryEntryItem]:
110
+ """Get all completed entries"""
111
+ return self.completed_entries.copy()
112
+
113
+ def get_history_memory_entries(
114
+ self, turns: int | None = None
115
+ ) -> list[APIMemoryHistoryEntryItem]:
116
+ """
117
+ Get the most recent n completed search entries, sorted by created_time.
118
+
119
+ Args:
120
+ turns: Number of entries to return. If None, returns all completed entries.
121
+
122
+ Returns:
123
+ List of completed search entries, sorted by created_time (newest first)
124
+ """
125
+ if not self.completed_entries:
126
+ return []
127
+
128
+ # Sort by created_time (newest first)
129
+ sorted_entries = sorted(self.completed_entries, key=lambda x: x.created_time, reverse=True)
130
+
131
+ if turns is None:
132
+ return sorted_entries
133
+
134
+ return sorted_entries[:turns]
135
+
136
+ def get_history_memories(self, turns: int | None = None) -> list[TextualMemoryItem]:
137
+ """
138
+ Get the most recent n completed search entries, sorted by created_time.
139
+
140
+ Args:
141
+ turns: Number of entries to return. If None, returns all completed entries.
142
+
143
+ Returns:
144
+ List of TextualMemoryItem objects from completed entries, sorted by created_time (newest first)
145
+ """
146
+ sorted_entries = self.get_history_memory_entries(turns=turns)
147
+
148
+ memories = []
149
+ for one in sorted_entries:
150
+ memories.extend(one.memories)
151
+ return memories
152
+
153
+ def find_entry_by_item_id(self, item_id: str) -> tuple[dict[str, Any] | None, str]:
154
+ """
155
+ Find an entry by item_id in completed list only.
156
+ Running entries are now just task IDs, so we can only search completed entries.
157
+
158
+ Args:
159
+ item_id: The item ID to search for
160
+
161
+ Returns:
162
+ Tuple of (entry_dict, location) where location is 'completed' or 'not_found'
163
+ """
164
+ # Check completed entries
165
+ for entry in self.completed_entries:
166
+ try:
167
+ if hasattr(entry, "item_id") and entry.item_id == item_id:
168
+ return entry.to_dict(), "completed"
169
+ elif isinstance(entry, dict) and entry.get("item_id") == item_id:
170
+ return entry, "completed"
171
+ except AttributeError as e:
172
+ logger.warning(f"Entry missing item_id attribute: {e}, entry type: {type(entry)}")
173
+ continue
174
+
175
+ return None, "not_found"
176
+
177
+ def update_entry_by_item_id(
178
+ self,
179
+ item_id: str,
180
+ query: str,
181
+ formatted_memories: Any,
182
+ task_status: TaskRunningStatus,
183
+ session_id: str | None = None,
184
+ memories: list[TextualMemoryItem] | None = None,
185
+ ) -> bool:
186
+ """
187
+ Update an existing entry by item_id. Since running entries are now just IDs,
188
+ this method can only update completed entries.
189
+
190
+ Args:
191
+ item_id: The item ID to update
192
+ query: New query string
193
+ formatted_memories: New formatted memories
194
+ task_status: New task status
195
+ session_id: New conversation ID
196
+ memories: List of TextualMemoryItem objects
197
+
198
+ Returns:
199
+ True if entry was found and updated, False otherwise
200
+ """
201
+ # Find the entry in completed list
202
+ for entry in self.completed_entries:
203
+ if entry.item_id == item_id:
204
+ # Update the entry content
205
+ entry.query = query
206
+ entry.formatted_memories = formatted_memories
207
+ entry.task_status = task_status
208
+ if session_id is not None:
209
+ entry.session_id = session_id
210
+ if memories is not None:
211
+ entry.memories = memories
212
+
213
+ logger.debug(f"Updated entry with item_id: {item_id}, new status: {task_status}")
214
+ return True
215
+
216
+ logger.warning(f"Entry with item_id: {item_id} not found in completed entries")
217
+ return False
218
+
219
+ def get_total_count(self) -> dict[str, int]:
220
+ """Get count of entries by status"""
221
+ return {
222
+ "completed": len(self.completed_entries),
223
+ "running": len(self.running_item_ids),
224
+ "total": len(self.completed_entries) + len(self.running_item_ids),
225
+ }
226
+
227
+ def __len__(self) -> int:
228
+ """Return total number of entries (completed + running)"""
229
+ return len(self.completed_entries) + len(self.running_item_ids)
230
+
231
+
232
+ # Alias for easier usage
233
+ SearchHistoryManager = APISearchHistoryManager
@@ -0,0 +1,55 @@
1
+ import os
2
+
3
+ from pathlib import Path
4
+
5
+
6
+ FILE_PATH = Path(__file__).absolute()
7
+ BASE_DIR = FILE_PATH.parent.parent.parent.parent.parent
8
+
9
+ TreeTextMemory_SEARCH_METHOD = "tree_text_memory_search"
10
+ TreeTextMemory_FINE_SEARCH_METHOD = "tree_text_memory_fine_search"
11
+ TextMemory_SEARCH_METHOD = "text_memory_search"
12
+ DIRECT_EXCHANGE_TYPE = "direct"
13
+ FANOUT_EXCHANGE_TYPE = "fanout"
14
+ DEFAULT_WORKING_MEM_MONITOR_SIZE_LIMIT = 30
15
+ DEFAULT_ACTIVATION_MEM_MONITOR_SIZE_LIMIT = 20
16
+ DEFAULT_ACT_MEM_DUMP_PATH = f"{BASE_DIR}/outputs/mem_scheduler/mem_cube_scheduler_test.kv_cache"
17
+ DEFAULT_THREAD_POOL_MAX_WORKERS = 50
18
+ DEFAULT_CONSUME_INTERVAL_SECONDS = 0.01
19
+ DEFAULT_CONSUME_BATCH = 3
20
+ DEFAULT_DISPATCHER_MONITOR_CHECK_INTERVAL = 300
21
+ DEFAULT_DISPATCHER_MONITOR_MAX_FAILURES = 2
22
+ DEFAULT_STUCK_THREAD_TOLERANCE = 10
23
+ DEFAULT_MAX_INTERNAL_MESSAGE_QUEUE_SIZE = -1
24
+ DEFAULT_TOP_K = 5
25
+ DEFAULT_CONTEXT_WINDOW_SIZE = 5
26
+ DEFAULT_USE_REDIS_QUEUE = os.getenv("MEMSCHEDULER_USE_REDIS_QUEUE", "False").lower() == "true"
27
+ DEFAULT_MULTI_TASK_RUNNING_TIMEOUT = 30
28
+ DEFAULT_SCHEDULER_RETRIEVER_BATCH_SIZE = 20
29
+ DEFAULT_SCHEDULER_RETRIEVER_RETRIES = 1
30
+ DEFAULT_STOP_WAIT = False
31
+
32
+ # startup mode configuration
33
+ STARTUP_BY_THREAD = "thread"
34
+ STARTUP_BY_PROCESS = "process"
35
+ DEFAULT_STARTUP_MODE = STARTUP_BY_THREAD # default to thread mode
36
+
37
+ NOT_INITIALIZED = -1
38
+
39
+
40
+ # web log
41
+ LONG_TERM_MEMORY_TYPE = "LongTermMemory"
42
+ USER_MEMORY_TYPE = "UserMemory"
43
+ WORKING_MEMORY_TYPE = "WorkingMemory"
44
+ TEXT_MEMORY_TYPE = "TextMemory"
45
+ ACTIVATION_MEMORY_TYPE = "ActivationMemory"
46
+ PARAMETER_MEMORY_TYPE = "ParameterMemory"
47
+ USER_INPUT_TYPE = "UserInput"
48
+ NOT_APPLICABLE_TYPE = "NotApplicable"
49
+
50
+ # monitors
51
+ MONITOR_WORKING_MEMORY_TYPE = "MonitorWorkingMemoryType"
52
+ MONITOR_ACTIVATION_MEMORY_TYPE = "MonitorActivationMemoryType"
53
+ DEFAULT_MAX_QUERY_KEY_WORDS = 1000
54
+ DEFAULT_WEIGHT_VECTOR_FOR_RANKING = [0.9, 0.05, 0.05]
55
+ DEFAULT_MAX_WEB_LOG_QUEUE_SIZE = 50
@@ -0,0 +1,173 @@
1
+ from datetime import datetime
2
+ from typing import Any
3
+ from uuid import uuid4
4
+
5
+ from pydantic import BaseModel, ConfigDict, Field
6
+ from typing_extensions import TypedDict
7
+
8
+ from memos.context.context import generate_trace_id
9
+ from memos.log import get_logger
10
+ from memos.mem_scheduler.general_modules.misc import DictConversionMixin
11
+ from memos.mem_scheduler.utils.db_utils import get_utc_now
12
+
13
+ from .general_schemas import NOT_INITIALIZED
14
+
15
+
16
+ logger = get_logger(__name__)
17
+
18
+ DEFAULT_MEMORY_SIZES = {
19
+ "long_term_memory_size": NOT_INITIALIZED,
20
+ "user_memory_size": NOT_INITIALIZED,
21
+ "working_memory_size": NOT_INITIALIZED,
22
+ "transformed_act_memory_size": NOT_INITIALIZED,
23
+ "parameter_memory_size": NOT_INITIALIZED,
24
+ }
25
+
26
+ DEFAULT_MEMORY_CAPACITIES = {
27
+ "long_term_memory_capacity": 10000,
28
+ "user_memory_capacity": 10000,
29
+ "working_memory_capacity": 20,
30
+ "transformed_act_memory_capacity": NOT_INITIALIZED,
31
+ "parameter_memory_capacity": NOT_INITIALIZED,
32
+ }
33
+
34
+
35
+ class ScheduleMessageItem(BaseModel, DictConversionMixin):
36
+ item_id: str = Field(description="uuid", default_factory=lambda: str(uuid4()))
37
+ redis_message_id: str = Field(default="", description="the message get from redis stream")
38
+ stream_key: str = Field("", description="stream_key for identifying the queue in line")
39
+ user_id: str = Field(..., description="user id")
40
+ trace_id: str = Field(default_factory=generate_trace_id, description="trace id for logging")
41
+ mem_cube_id: str = Field(..., description="memcube id")
42
+ session_id: str = Field(default="", description="Session ID for soft-filtering memories")
43
+ label: str = Field(..., description="Label of the schedule message")
44
+ content: str = Field(..., description="Content of the schedule message")
45
+ timestamp: datetime = Field(
46
+ default_factory=get_utc_now, description="submit time for schedule_messages"
47
+ )
48
+ user_name: str = Field(
49
+ default="",
50
+ description="user name / display name (optional)",
51
+ )
52
+ info: dict | None = Field(default=None, description="user custom info")
53
+ task_id: str | None = Field(
54
+ default=None,
55
+ description="Optional business-level task ID. Multiple items can share the same task_id.",
56
+ )
57
+
58
+ # Pydantic V2 model configuration
59
+ model_config = ConfigDict(
60
+ # Allows arbitrary Python types as model fields without validation
61
+ # Required when using custom types like GeneralMemCube that aren't Pydantic models
62
+ arbitrary_types_allowed=True,
63
+ # Additional metadata for JSON Schema generation
64
+ json_schema_extra={
65
+ # Example payload demonstrating the expected structure and sample values
66
+ # Used for API documentation, testing, and developer reference
67
+ "example": {
68
+ "item_id": "123e4567-e89b-12d3-a456-426614174000", # Sample UUID
69
+ "user_id": "user123", # Example user identifier
70
+ "mem_cube_id": "cube456", # Sample memory cube ID
71
+ "label": "sample_label", # Demonstration label value
72
+ "content": "sample content", # Example message content
73
+ "timestamp": "2024-07-22T12:00:00Z", # Added timestamp example
74
+ "user_name": "Alice", # Added username example
75
+ }
76
+ },
77
+ )
78
+
79
+ def to_dict(self) -> dict:
80
+ """Convert model to dictionary suitable for Redis Stream"""
81
+ return {
82
+ "item_id": self.item_id,
83
+ "user_id": self.user_id,
84
+ "cube_id": self.mem_cube_id,
85
+ "trace_id": self.trace_id,
86
+ "label": self.label,
87
+ "cube": "Not Applicable", # Custom cube serialization
88
+ "content": self.content,
89
+ "timestamp": self.timestamp.isoformat(),
90
+ "user_name": self.user_name,
91
+ "task_id": self.task_id if self.task_id is not None else "",
92
+ }
93
+
94
+ @classmethod
95
+ def from_dict(cls, data: dict) -> "ScheduleMessageItem":
96
+ """Create model from Redis Stream dictionary"""
97
+ return cls(
98
+ item_id=data.get("item_id", str(uuid4())),
99
+ user_id=data["user_id"],
100
+ mem_cube_id=data["cube_id"],
101
+ trace_id=data.get("trace_id", generate_trace_id()),
102
+ label=data["label"],
103
+ content=data["content"],
104
+ timestamp=datetime.fromisoformat(data["timestamp"]),
105
+ user_name=data.get("user_name"),
106
+ task_id=data.get("task_id"),
107
+ )
108
+
109
+
110
+ class MemorySizes(TypedDict):
111
+ long_term_memory_size: int
112
+ user_memory_size: int
113
+ working_memory_size: int
114
+ transformed_act_memory_size: int
115
+
116
+
117
+ class MemoryCapacities(TypedDict):
118
+ long_term_memory_capacity: int
119
+ user_memory_capacity: int
120
+ working_memory_capacity: int
121
+ transformed_act_memory_capacity: int
122
+
123
+
124
+ class ScheduleLogForWebItem(BaseModel, DictConversionMixin):
125
+ item_id: str = Field(
126
+ description="Unique identifier for the log entry", default_factory=lambda: str(uuid4())
127
+ )
128
+ task_id: str | None = Field(default=None, description="Identifier for the parent task")
129
+ user_id: str = Field(..., description="Identifier for the user associated with the log")
130
+ mem_cube_id: str = Field(
131
+ ..., description="Identifier for the memcube associated with this log entry"
132
+ )
133
+ label: str = Field(..., description="Label categorizing the type of log")
134
+ from_memory_type: str | None = Field(None, description="Source memory type")
135
+ to_memory_type: str | None = Field(None, description="Destination memory type")
136
+ log_content: str = Field(..., description="Detailed content of the log entry")
137
+ current_memory_sizes: MemorySizes = Field(
138
+ default_factory=lambda: dict(DEFAULT_MEMORY_SIZES),
139
+ description="Current utilization of memory partitions",
140
+ )
141
+ memory_capacities: MemoryCapacities = Field(
142
+ default_factory=lambda: dict(DEFAULT_MEMORY_CAPACITIES),
143
+ description="Maximum capacities of memory partitions",
144
+ )
145
+ timestamp: datetime = Field(
146
+ default_factory=get_utc_now,
147
+ description="Timestamp indicating when the log entry was created",
148
+ )
149
+ memcube_log_content: list[dict] | None = Field(
150
+ default=None, description="Structured memcube log content list"
151
+ )
152
+ metadata: list[dict] | None = Field(
153
+ default=None, description="Structured metadata list for each log item"
154
+ )
155
+ memcube_name: str | None = Field(default=None, description="Display name for memcube")
156
+ memory_len: int | None = Field(default=None, description="Count of items involved in the event")
157
+ status: str | None = Field(
158
+ default=None, description="Completion status of the task (e.g., 'completed', 'failed')"
159
+ )
160
+ source_doc_id: str | None = Field(default=None, description="Source document ID")
161
+
162
+ def debug_info(self) -> dict[str, Any]:
163
+ """Return structured debug information for logging purposes."""
164
+ return {
165
+ "content_preview:": self.log_content[:50],
166
+ "item_id": self.item_id,
167
+ "user_id": self.user_id,
168
+ "mem_cube_id": self.mem_cube_id,
169
+ "operation": f"{self.from_memory_type} → {self.to_memory_type}",
170
+ "label": self.label,
171
+ "content_length": len(self.log_content),
172
+ "timestamp": self.timestamp.isoformat(),
173
+ }