MemoryOS 0.2.1__tar.gz → 1.0.0__tar.gz

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.

Potentially problematic release.


This version of MemoryOS might be problematic. Click here for more details.

Files changed (184) hide show
  1. {memoryos-0.2.1 → memoryos-1.0.0}/PKG-INFO +7 -1
  2. {memoryos-0.2.1 → memoryos-1.0.0}/README.md +5 -0
  3. {memoryos-0.2.1 → memoryos-1.0.0}/pyproject.toml +2 -1
  4. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/__init__.py +1 -1
  5. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/api/config.py +158 -69
  6. memoryos-1.0.0/src/memos/api/context/context.py +147 -0
  7. memoryos-1.0.0/src/memos/api/context/dependencies.py +101 -0
  8. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/api/product_models.py +5 -1
  9. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/api/routers/product_router.py +54 -26
  10. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/configs/graph_db.py +49 -1
  11. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/configs/internet_retriever.py +19 -0
  12. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/configs/mem_os.py +5 -0
  13. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/configs/mem_reader.py +9 -0
  14. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/configs/mem_scheduler.py +54 -18
  15. memoryos-1.0.0/src/memos/configs/mem_user.py +58 -0
  16. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/graph_dbs/base.py +38 -3
  17. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/graph_dbs/factory.py +2 -0
  18. memoryos-1.0.0/src/memos/graph_dbs/nebular.py +1612 -0
  19. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/graph_dbs/neo4j.py +18 -9
  20. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/log.py +6 -1
  21. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_cube/utils.py +13 -6
  22. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_os/core.py +157 -37
  23. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_os/main.py +2 -2
  24. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_os/product.py +252 -201
  25. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_os/utils/default_config.py +1 -1
  26. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_os/utils/format_utils.py +281 -70
  27. memoryos-1.0.0/src/memos/mem_os/utils/reference_utils.py +133 -0
  28. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_reader/simple_struct.py +13 -5
  29. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_scheduler/base_scheduler.py +239 -266
  30. {memoryos-0.2.1/src/memos/mem_scheduler/modules → memoryos-1.0.0/src/memos/mem_scheduler/general_modules}/base.py +4 -5
  31. {memoryos-0.2.1/src/memos/mem_scheduler/modules → memoryos-1.0.0/src/memos/mem_scheduler/general_modules}/dispatcher.py +57 -21
  32. memoryos-1.0.0/src/memos/mem_scheduler/general_modules/misc.py +104 -0
  33. {memoryos-0.2.1/src/memos/mem_scheduler/modules → memoryos-1.0.0/src/memos/mem_scheduler/general_modules}/rabbitmq_service.py +12 -10
  34. {memoryos-0.2.1/src/memos/mem_scheduler/modules → memoryos-1.0.0/src/memos/mem_scheduler/general_modules}/redis_service.py +1 -1
  35. memoryos-1.0.0/src/memos/mem_scheduler/general_modules/retriever.py +199 -0
  36. memoryos-1.0.0/src/memos/mem_scheduler/general_modules/scheduler_logger.py +261 -0
  37. memoryos-1.0.0/src/memos/mem_scheduler/general_scheduler.py +349 -0
  38. memoryos-1.0.0/src/memos/mem_scheduler/monitors/dispatcher_monitor.py +305 -0
  39. memoryos-0.2.1/src/memos/mem_scheduler/modules/monitor.py → memoryos-1.0.0/src/memos/mem_scheduler/monitors/general_monitor.py +106 -57
  40. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_scheduler/mos_for_test_scheduler.py +23 -20
  41. memoryos-1.0.0/src/memos/mem_scheduler/schemas/general_schemas.py +44 -0
  42. memoryos-1.0.0/src/memos/mem_scheduler/schemas/message_schemas.py +149 -0
  43. memoryos-1.0.0/src/memos/mem_scheduler/schemas/monitor_schemas.py +337 -0
  44. memoryos-1.0.0/src/memos/mem_scheduler/utils/filter_utils.py +176 -0
  45. memoryos-1.0.0/src/memos/mem_scheduler/utils/misc_utils.py +102 -0
  46. memoryos-1.0.0/src/memos/mem_user/factory.py +94 -0
  47. memoryos-1.0.0/src/memos/mem_user/mysql_persistent_user_manager.py +271 -0
  48. memoryos-1.0.0/src/memos/mem_user/mysql_user_manager.py +500 -0
  49. memoryos-1.0.0/src/memos/mem_user/persistent_factory.py +96 -0
  50. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_user/user_manager.py +4 -4
  51. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/activation/item.py +5 -1
  52. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/activation/kv.py +20 -8
  53. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/textual/base.py +2 -2
  54. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/textual/general.py +36 -92
  55. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/textual/item.py +5 -33
  56. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/textual/tree.py +13 -7
  57. memoryos-0.2.1/src/memos/memories/textual/tree_text_memory/organize/conflict.py → memoryos-1.0.0/src/memos/memories/textual/tree_text_memory/organize/handler.py +34 -50
  58. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/textual/tree_text_memory/organize/manager.py +8 -96
  59. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/textual/tree_text_memory/organize/relation_reason_detector.py +49 -43
  60. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/textual/tree_text_memory/organize/reorganizer.py +107 -142
  61. memoryos-1.0.0/src/memos/memories/textual/tree_text_memory/retrieve/bochasearch.py +229 -0
  62. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/textual/tree_text_memory/retrieve/internet_retriever.py +6 -3
  63. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/textual/tree_text_memory/retrieve/internet_retriever_factory.py +11 -0
  64. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/textual/tree_text_memory/retrieve/recall.py +15 -8
  65. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/textual/tree_text_memory/retrieve/reranker.py +1 -1
  66. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/textual/tree_text_memory/retrieve/retrieval_mid_structs.py +2 -0
  67. memoryos-1.0.0/src/memos/memories/textual/tree_text_memory/retrieve/searcher.py +284 -0
  68. memoryos-1.0.0/src/memos/memories/textual/tree_text_memory/retrieve/task_goal_parser.py +100 -0
  69. memoryos-1.0.0/src/memos/memories/textual/tree_text_memory/retrieve/utils.py +52 -0
  70. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/textual/tree_text_memory/retrieve/xinyusearch.py +62 -58
  71. memoryos-1.0.0/src/memos/memos_tools/dinding_report_bot.py +422 -0
  72. memoryos-1.0.0/src/memos/memos_tools/lockfree_dict.py +120 -0
  73. memoryos-1.0.0/src/memos/memos_tools/notification_service.py +44 -0
  74. memoryos-1.0.0/src/memos/memos_tools/notification_utils.py +96 -0
  75. memoryos-1.0.0/src/memos/memos_tools/thread_safe_dict.py +288 -0
  76. memoryos-1.0.0/src/memos/parsers/__init__.py +0 -0
  77. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/settings.py +3 -1
  78. memoryos-1.0.0/src/memos/templates/__init__.py +0 -0
  79. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/templates/mem_reader_prompts.py +4 -1
  80. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/templates/mem_scheduler_prompts.py +62 -15
  81. memoryos-1.0.0/src/memos/templates/mos_prompts.py +179 -0
  82. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/templates/tree_reorganize_prompts.py +24 -17
  83. memoryos-1.0.0/src/memos/utils.py +19 -0
  84. memoryos-1.0.0/src/memos/vec_dbs/__init__.py +0 -0
  85. memoryos-0.2.1/src/memos/mem_scheduler/general_scheduler.py +0 -186
  86. memoryos-0.2.1/src/memos/mem_scheduler/modules/misc.py +0 -39
  87. memoryos-0.2.1/src/memos/mem_scheduler/modules/retriever.py +0 -268
  88. memoryos-0.2.1/src/memos/mem_scheduler/modules/schemas.py +0 -328
  89. memoryos-0.2.1/src/memos/mem_scheduler/utils.py +0 -75
  90. memoryos-0.2.1/src/memos/memories/textual/tree_text_memory/organize/redundancy.py +0 -193
  91. memoryos-0.2.1/src/memos/memories/textual/tree_text_memory/retrieve/searcher.py +0 -209
  92. memoryos-0.2.1/src/memos/memories/textual/tree_text_memory/retrieve/task_goal_parser.py +0 -68
  93. memoryos-0.2.1/src/memos/memories/textual/tree_text_memory/retrieve/utils.py +0 -48
  94. memoryos-0.2.1/src/memos/templates/mos_prompts.py +0 -63
  95. {memoryos-0.2.1 → memoryos-1.0.0}/LICENSE +0 -0
  96. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/api/exceptions.py +0 -0
  97. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/api/mcp_serve.py +0 -0
  98. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/api/product_api.py +0 -0
  99. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/api/routers/__init__.py +0 -0
  100. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/api/start_api.py +0 -0
  101. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/chunkers/__init__.py +0 -0
  102. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/chunkers/base.py +0 -0
  103. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/chunkers/factory.py +0 -0
  104. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/chunkers/sentence_chunker.py +0 -0
  105. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/cli.py +0 -0
  106. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/configs/__init__.py +0 -0
  107. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/configs/base.py +0 -0
  108. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/configs/chunker.py +0 -0
  109. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/configs/embedder.py +0 -0
  110. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/configs/llm.py +0 -0
  111. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/configs/mem_chat.py +0 -0
  112. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/configs/mem_cube.py +0 -0
  113. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/configs/memory.py +0 -0
  114. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/configs/parser.py +0 -0
  115. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/configs/utils.py +0 -0
  116. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/configs/vec_db.py +0 -0
  117. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/dependency.py +0 -0
  118. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/deprecation.py +0 -0
  119. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/embedders/__init__.py +0 -0
  120. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/embedders/ark.py +0 -0
  121. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/embedders/base.py +0 -0
  122. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/embedders/factory.py +0 -0
  123. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/embedders/ollama.py +0 -0
  124. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/embedders/sentence_transformer.py +0 -0
  125. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/embedders/universal_api.py +0 -0
  126. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/exceptions.py +0 -0
  127. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/graph_dbs/__init__.py +0 -0
  128. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/graph_dbs/item.py +0 -0
  129. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/graph_dbs/neo4j_community.py +0 -0
  130. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/hello_world.py +0 -0
  131. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/llms/__init__.py +0 -0
  132. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/llms/base.py +0 -0
  133. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/llms/deepseek.py +0 -0
  134. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/llms/factory.py +0 -0
  135. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/llms/hf.py +0 -0
  136. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/llms/hf_singleton.py +0 -0
  137. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/llms/ollama.py +0 -0
  138. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/llms/openai.py +0 -0
  139. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/llms/qwen.py +0 -0
  140. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/llms/utils.py +0 -0
  141. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/llms/vllm.py +0 -0
  142. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_chat/__init__.py +0 -0
  143. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_chat/base.py +0 -0
  144. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_chat/factory.py +0 -0
  145. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_chat/simple.py +0 -0
  146. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_cube/__init__.py +0 -0
  147. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_cube/base.py +0 -0
  148. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_cube/general.py +0 -0
  149. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_os/client.py +0 -0
  150. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_reader/__init__.py +0 -0
  151. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_reader/base.py +0 -0
  152. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_reader/factory.py +0 -0
  153. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_reader/memory.py +0 -0
  154. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_scheduler/__init__.py +0 -0
  155. {memoryos-0.2.1/src/memos/mem_scheduler/modules → memoryos-1.0.0/src/memos/mem_scheduler/general_modules}/__init__.py +0 -0
  156. {memoryos-0.2.1/src/memos/memories → memoryos-1.0.0/src/memos/mem_scheduler/monitors}/__init__.py +0 -0
  157. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_scheduler/scheduler_factory.py +0 -0
  158. {memoryos-0.2.1/src/memos/memories/activation → memoryos-1.0.0/src/memos/mem_scheduler/schemas}/__init__.py +0 -0
  159. {memoryos-0.2.1/src/memos/memories/parametric → memoryos-1.0.0/src/memos/mem_scheduler/utils}/__init__.py +0 -0
  160. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/mem_user/persistent_user_manager.py +0 -0
  161. {memoryos-0.2.1/src/memos/memories/textual → memoryos-1.0.0/src/memos/memories}/__init__.py +0 -0
  162. {memoryos-0.2.1/src/memos/memories/textual/tree_text_memory → memoryos-1.0.0/src/memos/memories/activation}/__init__.py +0 -0
  163. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/activation/base.py +0 -0
  164. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/activation/vllmkv.py +0 -0
  165. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/base.py +0 -0
  166. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/factory.py +0 -0
  167. {memoryos-0.2.1/src/memos/memories/textual/tree_text_memory/organize → memoryos-1.0.0/src/memos/memories/parametric}/__init__.py +0 -0
  168. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/parametric/base.py +0 -0
  169. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/parametric/item.py +0 -0
  170. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/parametric/lora.py +0 -0
  171. {memoryos-0.2.1/src/memos/memories/textual/tree_text_memory/retrieve → memoryos-1.0.0/src/memos/memories/textual}/__init__.py +0 -0
  172. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/textual/naive.py +0 -0
  173. {memoryos-0.2.1/src/memos/parsers → memoryos-1.0.0/src/memos/memories/textual/tree_text_memory}/__init__.py +0 -0
  174. {memoryos-0.2.1/src/memos/templates → memoryos-1.0.0/src/memos/memories/textual/tree_text_memory/organize}/__init__.py +0 -0
  175. {memoryos-0.2.1/src/memos/vec_dbs → memoryos-1.0.0/src/memos/memories/textual/tree_text_memory/retrieve}/__init__.py +0 -0
  176. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/memories/textual/tree_text_memory/retrieve/reasoner.py +0 -0
  177. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/parsers/base.py +0 -0
  178. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/parsers/factory.py +0 -0
  179. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/parsers/markitdown.py +0 -0
  180. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/types.py +0 -0
  181. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/vec_dbs/base.py +0 -0
  182. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/vec_dbs/factory.py +0 -0
  183. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/vec_dbs/item.py +0 -0
  184. {memoryos-0.2.1 → memoryos-1.0.0}/src/memos/vec_dbs/qdrant.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: MemoryOS
3
- Version: 0.2.1
3
+ Version: 1.0.0
4
4
  Summary: Intelligence Begins with Memory
5
5
  License: Apache-2.0
6
6
  Keywords: memory,llm,language model,memoryOS,agent,kv cache,lora
@@ -35,6 +35,7 @@ Requires-Dist: ollama (>=0.4.8,<0.5.0)
35
35
  Requires-Dist: openai (>=1.77.0,<2.0.0)
36
36
  Requires-Dist: pika (>=1.3.2,<2.0.0) ; extra == "all"
37
37
  Requires-Dist: pika (>=1.3.2,<2.0.0) ; extra == "mem-scheduler"
38
+ Requires-Dist: python-dateutil (>=2.9.0.post0,<3.0.0)
38
39
  Requires-Dist: qdrant-client (>=1.14.2,<2.0.0) ; extra == "all"
39
40
  Requires-Dist: redis (>=6.2.0,<7.0.0) ; extra == "all"
40
41
  Requires-Dist: redis (>=6.2.0,<7.0.0) ; extra == "mem-scheduler"
@@ -309,6 +310,11 @@ MemOS is licensed under the [Apache 2.0 License](./LICENSE).
309
310
 
310
311
  Stay up to date with the latest MemOS announcements, releases, and community highlights.
311
312
 
313
+
314
+ - **2025-08-07** - 🎉 *MemOS v1.0.0 (MemCube Release)*: First MemCube with word game demo, LongMemEval evaluation, BochaAISearchRetriever integration, NebulaGraph support, enhanced search capabilities, and official Playground launch.
315
+ - **2025-07-29** – 🎉 *MemOS v0.2.2 (Nebula Update)*: Internet search+Nebula DB integration, refactored memory scheduler, KV Cache stress tests, MemCube Cookbook release (CN/EN), and 4b/1.7b/0.6b memory ops models.
316
+ - **2025-07-21** – 🎉 *MemOS v0.2.1 (Neo Release)*: Lightweight Neo version with plaintext+KV Cache functionality, Docker/multi-tenant support, MCP expansion, and new Cookbook/Mud game examples.
317
+ - **2025-07-11** – 🎉 *MemOS v0.2.0 (Cross-Platform)*: Added doc search/bilingual UI, MemReader-4B (local deploy), full Win/Mac/Linux support, and playground end-to-end connection.
312
318
  - **2025-07-07** – 🎉 *MemOS 1.0 (Stellar) Preview Release*: A SOTA Memory OS for LLMs is now open-sourced.
313
319
  - **2025-07-04** – 🎉 *MemOS Paper Released*: [MemOS: A Memory OS for AI System](https://arxiv.org/abs/2507.03724) was published on arXiv.
314
320
  - **2025-05-28** – 🎉 *Short Paper Uploaded*: [MemOS: An Operating System for Memory-Augmented Generation (MAG) in Large Language Models](https://arxiv.org/abs/2505.22101) was published on arXiv.
@@ -251,6 +251,11 @@ MemOS is licensed under the [Apache 2.0 License](./LICENSE).
251
251
 
252
252
  Stay up to date with the latest MemOS announcements, releases, and community highlights.
253
253
 
254
+
255
+ - **2025-08-07** - 🎉 *MemOS v1.0.0 (MemCube Release)*: First MemCube with word game demo, LongMemEval evaluation, BochaAISearchRetriever integration, NebulaGraph support, enhanced search capabilities, and official Playground launch.
256
+ - **2025-07-29** – 🎉 *MemOS v0.2.2 (Nebula Update)*: Internet search+Nebula DB integration, refactored memory scheduler, KV Cache stress tests, MemCube Cookbook release (CN/EN), and 4b/1.7b/0.6b memory ops models.
257
+ - **2025-07-21** – 🎉 *MemOS v0.2.1 (Neo Release)*: Lightweight Neo version with plaintext+KV Cache functionality, Docker/multi-tenant support, MCP expansion, and new Cookbook/Mud game examples.
258
+ - **2025-07-11** – 🎉 *MemOS v0.2.0 (Cross-Platform)*: Added doc search/bilingual UI, MemReader-4B (local deploy), full Win/Mac/Linux support, and playground end-to-end connection.
254
259
  - **2025-07-07** – 🎉 *MemOS 1.0 (Stellar) Preview Release*: A SOTA Memory OS for LLMs is now open-sourced.
255
260
  - **2025-07-04** – 🎉 *MemOS Paper Released*: [MemOS: A Memory OS for AI System](https://arxiv.org/abs/2507.03724) was published on arXiv.
256
261
  - **2025-05-28** – 🎉 *Short Paper Uploaded*: [MemOS: An Operating System for Memory-Augmented Generation (MAG) in Large Language Models](https://arxiv.org/abs/2505.22101) was published on arXiv.
@@ -4,7 +4,7 @@
4
4
  ##############################################################################
5
5
 
6
6
  name = "MemoryOS"
7
- version = "0.2.1"
7
+ version = "1.0.0"
8
8
  description = "Intelligence Begins with Memory"
9
9
  license = {text = "Apache-2.0"}
10
10
  readme = "README.md"
@@ -44,6 +44,7 @@ dependencies = [
44
44
  "sqlalchemy (>=2.0.41,<3.0.0)", # SQL toolkit
45
45
  "scikit-learn (>=1.7.0,<2.0.0)", # Machine learning
46
46
  "fastmcp (>=2.10.5,<3.0.0)",
47
+ "python-dateutil (>=2.9.0.post0,<3.0.0)",
47
48
  ]
48
49
 
49
50
  [project.urls]
@@ -1,4 +1,4 @@
1
- __version__ = "0.2.1"
1
+ __version__ = "1.0.0"
2
2
 
3
3
  from memos.configs.mem_cube import GeneralMemCubeConfig
4
4
  from memos.configs.mem_os import MOSConfig
@@ -1,3 +1,4 @@
1
+ import json
1
2
  import os
2
3
 
3
4
  from typing import Any
@@ -99,9 +100,9 @@ class APIConfig:
99
100
  "backend": "universal_api",
100
101
  "config": {
101
102
  "provider": os.getenv("MOS_EMBEDDER_PROVIDER", "openai"),
102
- "api_key": os.getenv("OPENAI_API_KEY", "sk-xxxx"),
103
+ "api_key": os.getenv("MOS_EMBEDDER_API_KEY", "sk-xxxx"),
103
104
  "model_name_or_path": os.getenv("MOS_EMBEDDER_MODEL", "text-embedding-3-large"),
104
- "base_url": os.getenv("OPENAI_API_BASE", "http://openai.com"),
105
+ "base_url": os.getenv("MOS_EMBEDDER_API_BASE", "http://openai.com"),
105
106
  },
106
107
  }
107
108
  else: # ollama
@@ -115,6 +116,47 @@ class APIConfig:
115
116
  },
116
117
  }
117
118
 
119
+ @staticmethod
120
+ def get_internet_config() -> dict[str, Any]:
121
+ """Get embedder configuration."""
122
+ return {
123
+ "backend": "bocha",
124
+ "config": {
125
+ "api_key": os.getenv("BOCHA_API_KEY"),
126
+ "max_results": 15,
127
+ "num_per_request": 10,
128
+ "reader": {
129
+ "backend": "simple_struct",
130
+ "config": {
131
+ "llm": {
132
+ "backend": "openai",
133
+ "config": {
134
+ "model_name_or_path": os.getenv("MEMRADER_MODEL"),
135
+ "temperature": 0.6,
136
+ "max_tokens": 5000,
137
+ "top_p": 0.95,
138
+ "top_k": 20,
139
+ "api_key": os.getenv("MEMRADER_API_KEY", "EMPTY"),
140
+ "api_base": os.getenv("MEMRADER_API_BASE"),
141
+ "remove_think_prefix": True,
142
+ "extra_body": {"chat_template_kwargs": {"enable_thinking": False}},
143
+ },
144
+ },
145
+ "embedder": APIConfig.get_embedder_config(),
146
+ "chunker": {
147
+ "backend": "sentence",
148
+ "config": {
149
+ "tokenizer_or_token_counter": "gpt2",
150
+ "chunk_size": 512,
151
+ "chunk_overlap": 128,
152
+ "min_sentences_per_chunk": 1,
153
+ },
154
+ },
155
+ },
156
+ },
157
+ },
158
+ }
159
+
118
160
  @staticmethod
119
161
  def get_neo4j_community_config(user_id: str | None = None) -> dict[str, Any]:
120
162
  """Get Neo4j community configuration."""
@@ -126,14 +168,14 @@ class APIConfig:
126
168
  "user_name": f"memos{user_id.replace('-', '')}",
127
169
  "auto_create": True,
128
170
  "use_multi_db": False,
129
- "embedding_dimension": 3072,
171
+ "embedding_dimension": int(os.getenv("EMBEDDING_DIMENSION", 3072)),
130
172
  "vec_config": {
131
173
  # Pass nested config to initialize external vector DB
132
174
  # If you use qdrant, please use Server instead of local mode.
133
175
  "backend": "qdrant",
134
176
  "config": {
135
177
  "collection_name": "neo4j_vec_db",
136
- "vector_dimension": 3072,
178
+ "vector_dimension": int(os.getenv("EMBEDDING_DIMENSION", 3072)),
137
179
  "distance_metric": "cosine",
138
180
  "host": "localhost",
139
181
  "port": 6333,
@@ -159,7 +201,7 @@ class APIConfig:
159
201
  "password": os.getenv("NEO4J_PASSWORD", "12345678"),
160
202
  "auto_create": True,
161
203
  "use_multi_db": True,
162
- "embedding_dimension": 3072,
204
+ "embedding_dimension": int(os.getenv("EMBEDDING_DIMENSION", 3072)),
163
205
  }
164
206
 
165
207
  @staticmethod
@@ -173,7 +215,33 @@ class APIConfig:
173
215
  "user_name": f"memos{user_id.replace('-', '')}",
174
216
  "auto_create": True,
175
217
  "use_multi_db": False,
176
- "embedding_dimension": 3072,
218
+ "embedding_dimension": int(os.getenv("EMBEDDING_DIMENSION", 3072)),
219
+ }
220
+
221
+ @staticmethod
222
+ def get_nebular_config(user_id: str | None = None) -> dict[str, Any]:
223
+ """Get Nebular configuration."""
224
+ return {
225
+ "uri": json.loads(os.getenv("NEBULAR_HOSTS", '["localhost"]')),
226
+ "user": os.getenv("NEBULAR_USER", "root"),
227
+ "password": os.getenv("NEBULAR_PASSWORD", "xxxxxx"),
228
+ "space": os.getenv("NEBULAR_SPACE", "shared-tree-textual-memory"),
229
+ "user_name": f"memos{user_id.replace('-', '')}",
230
+ "use_multi_db": False,
231
+ "auto_create": True,
232
+ "embedding_dimension": int(os.getenv("EMBEDDING_DIMENSION", 3072)),
233
+ }
234
+
235
+ @staticmethod
236
+ def get_mysql_config() -> dict[str, Any]:
237
+ """Get MySQL configuration."""
238
+ return {
239
+ "host": os.getenv("MYSQL_HOST", "localhost"),
240
+ "port": int(os.getenv("MYSQL_PORT", "3306")),
241
+ "username": os.getenv("MYSQL_USERNAME", "root"),
242
+ "password": os.getenv("MYSQL_PASSWORD", "12345678"),
243
+ "database": os.getenv("MYSQL_DATABASE", "memos_users"),
244
+ "charset": os.getenv("MYSQL_CHARSET", "utf8mb4"),
177
245
  }
178
246
 
179
247
  @staticmethod
@@ -183,7 +251,6 @@ class APIConfig:
183
251
  "backend": "general_scheduler",
184
252
  "config": {
185
253
  "top_k": int(os.getenv("MOS_SCHEDULER_TOP_K", "10")),
186
- "top_n": int(os.getenv("MOS_SCHEDULER_TOP_N", "5")),
187
254
  "act_mem_update_interval": int(
188
255
  os.getenv("MOS_SCHEDULER_ACT_MEM_UPDATE_INTERVAL", "300")
189
256
  ),
@@ -198,7 +265,7 @@ class APIConfig:
198
265
  "MOS_SCHEDULER_ENABLE_PARALLEL_DISPATCH", "true"
199
266
  ).lower()
200
267
  == "true",
201
- "enable_act_memory_update": True,
268
+ "enable_activation_memory": True,
202
269
  },
203
270
  }
204
271
 
@@ -212,6 +279,34 @@ class APIConfig:
212
279
  """Check if default cube config is enabled via environment variable."""
213
280
  return os.getenv("MOS_ENABLE_DEFAULT_CUBE_CONFIG", "false").lower() == "true"
214
281
 
282
+ @staticmethod
283
+ def is_dingding_bot_enabled() -> bool:
284
+ """Check if DingDing bot is enabled via environment variable."""
285
+ return os.getenv("ENABLE_DINGDING_BOT", "false").lower() == "true"
286
+
287
+ @staticmethod
288
+ def get_dingding_bot_config() -> dict[str, Any] | None:
289
+ """Get DingDing bot configuration if enabled."""
290
+ if not APIConfig.is_dingding_bot_enabled():
291
+ return None
292
+
293
+ return {
294
+ "enabled": True,
295
+ "access_token_user": os.getenv("DINGDING_ACCESS_TOKEN_USER", ""),
296
+ "secret_user": os.getenv("DINGDING_SECRET_USER", ""),
297
+ "access_token_error": os.getenv("DINGDING_ACCESS_TOKEN_ERROR", ""),
298
+ "secret_error": os.getenv("DINGDING_SECRET_ERROR", ""),
299
+ "robot_code": os.getenv("DINGDING_ROBOT_CODE", ""),
300
+ "app_key": os.getenv("DINGDING_APP_KEY", ""),
301
+ "app_secret": os.getenv("DINGDING_APP_SECRET", ""),
302
+ "oss_endpoint": os.getenv("OSS_ENDPOINT", ""),
303
+ "oss_region": os.getenv("OSS_REGION", ""),
304
+ "oss_bucket_name": os.getenv("OSS_BUCKET_NAME", ""),
305
+ "oss_access_key_id": os.getenv("OSS_ACCESS_KEY_ID", ""),
306
+ "oss_access_key_secret": os.getenv("OSS_ACCESS_KEY_SECRET", ""),
307
+ "oss_public_base_url": os.getenv("OSS_PUBLIC_BASE_URL", ""),
308
+ }
309
+
215
310
  @staticmethod
216
311
  def get_product_default_config() -> dict[str, Any]:
217
312
  """Get default configuration for Product API."""
@@ -224,6 +319,7 @@ class APIConfig:
224
319
  "vllm": vllm_config,
225
320
  }
226
321
  backend = os.getenv("MOS_CHAT_MODEL_PROVIDER", "openai")
322
+ mysql_config = APIConfig.get_mysql_config()
227
323
  config = {
228
324
  "user_id": os.getenv("MOS_USER_ID", "root"),
229
325
  "chat_model": {"backend": backend, "config": backend_model[backend]},
@@ -260,6 +356,13 @@ class APIConfig:
260
356
  else:
261
357
  config["enable_mem_scheduler"] = False
262
358
 
359
+ # Add user manager configuration if enabled
360
+ if os.getenv("MOS_USER_MANAGER_BACKEND", "sqlite").lower() == "mysql":
361
+ config["user_manager"] = {
362
+ "backend": "mysql",
363
+ "config": mysql_config,
364
+ }
365
+
263
366
  return config
264
367
 
265
368
  @staticmethod
@@ -300,9 +403,9 @@ class APIConfig:
300
403
  def create_user_config(user_name: str, user_id: str) -> tuple[MOSConfig, GeneralMemCube]:
301
404
  """Create configuration for a specific user."""
302
405
  openai_config = APIConfig.get_openai_config()
303
-
304
406
  qwen_config = APIConfig.qwen_config()
305
407
  vllm_config = APIConfig.vllm_config()
408
+ mysql_config = APIConfig.get_mysql_config()
306
409
  backend = os.getenv("MOS_CHAT_MODEL_PROVIDER", "openai")
307
410
  backend_model = {
308
411
  "openai": openai_config,
@@ -341,7 +444,6 @@ class APIConfig:
341
444
  "top_k": 30,
342
445
  "max_turns_window": 20,
343
446
  }
344
-
345
447
  # Add scheduler configuration if enabled
346
448
  if APIConfig.is_scheduler_enabled():
347
449
  config_dict["mem_scheduler"] = APIConfig.get_scheduler_config()
@@ -349,11 +451,32 @@ class APIConfig:
349
451
  else:
350
452
  config_dict["enable_mem_scheduler"] = False
351
453
 
454
+ # Add user manager configuration if enabled
455
+ if os.getenv("MOS_USER_MANAGER_BACKEND", "sqlite").lower() == "mysql":
456
+ config_dict["user_manager"] = {
457
+ "backend": "mysql",
458
+ "config": mysql_config,
459
+ }
460
+
352
461
  default_config = MOSConfig(**config_dict)
353
462
 
354
- if os.getenv("NEO4J_BACKEND", "neo4j_community").lower() == "neo4j_community":
355
- neo4j_community_config = APIConfig.get_neo4j_community_config(user_id)
463
+ neo4j_community_config = APIConfig.get_neo4j_community_config(user_id)
464
+ neo4j_config = APIConfig.get_neo4j_config(user_id)
465
+ nebular_config = APIConfig.get_nebular_config(user_id)
466
+ internet_config = (
467
+ APIConfig.get_internet_config()
468
+ if os.getenv("ENABLE_INTERNET", "false").lower() == "true"
469
+ else None
470
+ )
471
+ graph_db_backend_map = {
472
+ "neo4j-community": neo4j_community_config,
473
+ "neo4j": neo4j_config,
474
+ "nebular": nebular_config,
475
+ }
476
+ graph_db_backend = os.getenv("NEO4J_BACKEND", "neo4j-community").lower()
477
+ if graph_db_backend in graph_db_backend_map:
356
478
  # Create MemCube config
479
+
357
480
  default_cube_config = GeneralMemCubeConfig.model_validate(
358
481
  {
359
482
  "user_id": user_id,
@@ -364,10 +487,11 @@ class APIConfig:
364
487
  "extractor_llm": {"backend": "openai", "config": openai_config},
365
488
  "dispatcher_llm": {"backend": "openai", "config": openai_config},
366
489
  "graph_db": {
367
- "backend": "neo4j-community",
368
- "config": neo4j_community_config,
490
+ "backend": graph_db_backend,
491
+ "config": graph_db_backend_map[graph_db_backend],
369
492
  },
370
493
  "embedder": APIConfig.get_embedder_config(),
494
+ "internet_retriever": internet_config,
371
495
  },
372
496
  },
373
497
  "act_mem": {}
@@ -377,31 +501,7 @@ class APIConfig:
377
501
  }
378
502
  )
379
503
  else:
380
- neo4j_config = APIConfig.get_neo4j_config(user_id)
381
- # Create MemCube config
382
- default_cube_config = GeneralMemCubeConfig.model_validate(
383
- {
384
- "user_id": user_id,
385
- "cube_id": f"{user_name}_default_cube",
386
- "text_mem": {
387
- "backend": "tree_text",
388
- "config": {
389
- "extractor_llm": {"backend": "openai", "config": openai_config},
390
- "dispatcher_llm": {"backend": "openai", "config": openai_config},
391
- "graph_db": {
392
- "backend": "neo4j",
393
- "config": neo4j_config,
394
- },
395
- "embedder": APIConfig.get_embedder_config(),
396
- },
397
- },
398
- "act_mem": {}
399
- if os.getenv("ENABLE_ACTIVATION_MEMORY", "false").lower() == "false"
400
- else APIConfig.get_activation_vllm_config(),
401
- "para_mem": {},
402
- }
403
- )
404
-
504
+ raise ValueError(f"Invalid Neo4j backend: {graph_db_backend}")
405
505
  default_mem_cube = GeneralMemCube(default_cube_config)
406
506
  return default_config, default_mem_cube
407
507
 
@@ -416,9 +516,21 @@ class APIConfig:
416
516
  return None
417
517
 
418
518
  openai_config = APIConfig.get_openai_config()
419
-
420
- if os.getenv("NEO4J_BACKEND", "neo4j_community").lower() == "neo4j_community":
421
- neo4j_community_config = APIConfig.get_neo4j_community_config(user_id="default")
519
+ neo4j_community_config = APIConfig.get_neo4j_community_config(user_id="default")
520
+ neo4j_config = APIConfig.get_neo4j_config(user_id="default")
521
+ nebular_config = APIConfig.get_nebular_config(user_id="default")
522
+ graph_db_backend_map = {
523
+ "neo4j-community": neo4j_community_config,
524
+ "neo4j": neo4j_config,
525
+ "nebular": nebular_config,
526
+ }
527
+ internet_config = (
528
+ APIConfig.get_internet_config()
529
+ if os.getenv("ENABLE_INTERNET", "false").lower() == "true"
530
+ else None
531
+ )
532
+ graph_db_backend = os.getenv("NEO4J_BACKEND", "neo4j-community").lower()
533
+ if graph_db_backend in graph_db_backend_map:
422
534
  return GeneralMemCubeConfig.model_validate(
423
535
  {
424
536
  "user_id": "default",
@@ -429,12 +541,13 @@ class APIConfig:
429
541
  "extractor_llm": {"backend": "openai", "config": openai_config},
430
542
  "dispatcher_llm": {"backend": "openai", "config": openai_config},
431
543
  "graph_db": {
432
- "backend": "neo4j-community",
433
- "config": neo4j_community_config,
544
+ "backend": graph_db_backend,
545
+ "config": graph_db_backend_map[graph_db_backend],
434
546
  },
435
547
  "embedder": APIConfig.get_embedder_config(),
436
548
  "reorganize": os.getenv("MOS_ENABLE_REORGANIZE", "false").lower()
437
549
  == "true",
550
+ "internet_retriever": internet_config,
438
551
  },
439
552
  },
440
553
  "act_mem": {}
@@ -444,28 +557,4 @@ class APIConfig:
444
557
  }
445
558
  )
446
559
  else:
447
- neo4j_config = APIConfig.get_neo4j_config(user_id="default")
448
- return GeneralMemCubeConfig.model_validate(
449
- {
450
- "user_id": "default",
451
- "cube_id": "default_cube",
452
- "text_mem": {
453
- "backend": "tree_text",
454
- "config": {
455
- "extractor_llm": {"backend": "openai", "config": openai_config},
456
- "dispatcher_llm": {"backend": "openai", "config": openai_config},
457
- "graph_db": {
458
- "backend": "neo4j",
459
- "config": neo4j_config,
460
- },
461
- "embedder": APIConfig.get_embedder_config(),
462
- "reorganize": os.getenv("MOS_ENABLE_REORGANIZE", "false").lower()
463
- == "true",
464
- },
465
- },
466
- "act_mem": {}
467
- if os.getenv("ENABLE_ACTIVATION_MEMORY", "false").lower() == "false"
468
- else APIConfig.get_activation_vllm_config(),
469
- "para_mem": {},
470
- }
471
- )
560
+ raise ValueError(f"Invalid Neo4j backend: {graph_db_backend}")
@@ -0,0 +1,147 @@
1
+ """
2
+ Global request context management for trace_id and request-scoped data.
3
+
4
+ This module provides optional trace_id functionality that can be enabled
5
+ when using the API components. It uses ContextVar to ensure thread safety
6
+ and request isolation.
7
+ """
8
+
9
+ import uuid
10
+
11
+ from collections.abc import Callable
12
+ from contextvars import ContextVar
13
+ from typing import Any
14
+
15
+
16
+ # Global context variable for request-scoped data
17
+ _request_context: ContextVar[dict[str, Any] | None] = ContextVar("request_context", default=None)
18
+
19
+
20
+ class RequestContext:
21
+ """
22
+ Request-scoped context object that holds trace_id and other request data.
23
+
24
+ This provides a Flask g-like object for FastAPI applications.
25
+ """
26
+
27
+ def __init__(self, trace_id: str | None = None):
28
+ self.trace_id = trace_id or str(uuid.uuid4())
29
+ self._data: dict[str, Any] = {}
30
+
31
+ def set(self, key: str, value: Any) -> None:
32
+ """Set a value in the context."""
33
+ self._data[key] = value
34
+
35
+ def get(self, key: str, default: Any | None = None) -> Any:
36
+ """Get a value from the context."""
37
+ return self._data.get(key, default)
38
+
39
+ def __setattr__(self, name: str, value: Any) -> None:
40
+ if name.startswith("_") or name == "trace_id":
41
+ super().__setattr__(name, value)
42
+ else:
43
+ if not hasattr(self, "_data"):
44
+ super().__setattr__(name, value)
45
+ else:
46
+ self._data[name] = value
47
+
48
+ def __getattr__(self, name: str) -> Any:
49
+ if hasattr(self, "_data") and name in self._data:
50
+ return self._data[name]
51
+ raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
52
+
53
+ def to_dict(self) -> dict[str, Any]:
54
+ """Convert context to dictionary."""
55
+ return {"trace_id": self.trace_id, "data": self._data.copy()}
56
+
57
+
58
+ def set_request_context(context: RequestContext) -> None:
59
+ """
60
+ Set the current request context.
61
+
62
+ This is typically called by the API dependency injection system.
63
+ """
64
+ _request_context.set(context.to_dict())
65
+
66
+
67
+ def get_current_trace_id() -> str | None:
68
+ """
69
+ Get the current request's trace_id.
70
+
71
+ Returns:
72
+ The trace_id if available, None otherwise.
73
+ """
74
+ context = _request_context.get()
75
+ if context:
76
+ return context.get("trace_id")
77
+ return None
78
+
79
+
80
+ def get_current_context() -> RequestContext | None:
81
+ """
82
+ Get the current request context.
83
+
84
+ Returns:
85
+ The current RequestContext if available, None otherwise.
86
+ """
87
+ context_dict = _request_context.get()
88
+ if context_dict:
89
+ ctx = RequestContext(trace_id=context_dict.get("trace_id"))
90
+ ctx._data = context_dict.get("data", {}).copy()
91
+ return ctx
92
+ return None
93
+
94
+
95
+ def require_context() -> RequestContext:
96
+ """
97
+ Get the current request context, raising an error if not available.
98
+
99
+ Returns:
100
+ The current RequestContext.
101
+
102
+ Raises:
103
+ RuntimeError: If called outside of a request context.
104
+ """
105
+ context = get_current_context()
106
+ if context is None:
107
+ raise RuntimeError(
108
+ "No request context available. This function must be called within a request handler."
109
+ )
110
+ return context
111
+
112
+
113
+ # Type for trace_id getter function
114
+ TraceIdGetter = Callable[[], str | None]
115
+
116
+ # Global variable to hold the trace_id getter function
117
+ _trace_id_getter: TraceIdGetter | None = None
118
+
119
+
120
+ def set_trace_id_getter(getter: TraceIdGetter) -> None:
121
+ """
122
+ Set a custom trace_id getter function.
123
+
124
+ This allows the logging system to retrieve trace_id without importing
125
+ API-specific general_modules.
126
+ """
127
+ global _trace_id_getter
128
+ _trace_id_getter = getter
129
+
130
+
131
+ def get_trace_id_for_logging() -> str | None:
132
+ """
133
+ Get trace_id for logging purposes.
134
+
135
+ This function is used by the logging system and will use either
136
+ the custom getter function or fall back to the default context.
137
+ """
138
+ if _trace_id_getter:
139
+ try:
140
+ return _trace_id_getter()
141
+ except Exception:
142
+ pass
143
+ return get_current_trace_id()
144
+
145
+
146
+ # Initialize the default trace_id getter
147
+ set_trace_id_getter(get_current_trace_id)
@@ -0,0 +1,101 @@
1
+ import logging
2
+ import os
3
+
4
+ from fastapi import Depends, Header, Request
5
+
6
+ from memos.api.context.context import RequestContext, set_request_context
7
+
8
+
9
+ logger = logging.getLogger(__name__)
10
+
11
+ # Type alias for the RequestContext from context module
12
+ G = RequestContext
13
+
14
+
15
+ def get_trace_id_from_header(
16
+ trace_id: str | None = Header(None, alias="trace-id"),
17
+ x_trace_id: str | None = Header(None, alias="x-trace-id"),
18
+ g_trace_id: str | None = Header(None, alias="g-trace-id"),
19
+ ) -> str | None:
20
+ """
21
+ Extract trace_id from various possible headers.
22
+
23
+ Priority: g-trace-id > x-trace-id > trace-id
24
+ """
25
+ return g_trace_id or x_trace_id or trace_id
26
+
27
+
28
+ def generate_trace_id() -> str:
29
+ """
30
+ Get a random trace_id.
31
+ """
32
+ return os.urandom(16).hex()
33
+
34
+
35
+ def get_request_context(
36
+ request: Request, trace_id: str | None = Depends(get_trace_id_from_header)
37
+ ) -> RequestContext:
38
+ """
39
+ Get request context object with trace_id and request metadata.
40
+
41
+ This function creates a RequestContext and automatically sets it
42
+ in the global context for use throughout the request lifecycle.
43
+ """
44
+ # Create context object
45
+ ctx = RequestContext(trace_id=trace_id)
46
+
47
+ # Set the context globally for this request
48
+ set_request_context(ctx)
49
+
50
+ # Log request start
51
+ logger.info(f"Request started with trace_id: {ctx.trace_id}")
52
+
53
+ # Add request metadata to context
54
+ ctx.set("method", request.method)
55
+ ctx.set("path", request.url.path)
56
+ ctx.set("client_ip", request.client.host if request.client else None)
57
+
58
+ return ctx
59
+
60
+
61
+ def get_g_object(trace_id: str | None = Depends(get_trace_id_from_header)) -> G:
62
+ """
63
+ Get Flask g-like object for the current request.
64
+
65
+ This creates a RequestContext and sets it globally for access
66
+ throughout the request lifecycle.
67
+ """
68
+ if trace_id is None:
69
+ trace_id = generate_trace_id()
70
+
71
+ g = RequestContext(trace_id=trace_id)
72
+ set_request_context(g)
73
+ logger.info(f"Request g object created with trace_id: {g.trace_id}")
74
+ return g
75
+
76
+
77
+ def get_current_g() -> G | None:
78
+ """
79
+ Get the current request's g object from anywhere in the application.
80
+
81
+ Returns:
82
+ The current request's g object if available, None otherwise.
83
+ """
84
+ from memos.context import get_current_context
85
+
86
+ return get_current_context()
87
+
88
+
89
+ def require_g() -> G:
90
+ """
91
+ Get the current request's g object, raising an error if not available.
92
+
93
+ Returns:
94
+ The current request's g object.
95
+
96
+ Raises:
97
+ RuntimeError: If called outside of a request context.
98
+ """
99
+ from memos.context import require_context
100
+
101
+ return require_context()