MemoryOS 0.2.0__py3-none-any.whl → 0.2.1__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.

Potentially problematic release.


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

Files changed (80) hide show
  1. {memoryos-0.2.0.dist-info → memoryos-0.2.1.dist-info}/METADATA +66 -26
  2. {memoryos-0.2.0.dist-info → memoryos-0.2.1.dist-info}/RECORD +80 -56
  3. memoryos-0.2.1.dist-info/entry_points.txt +3 -0
  4. memos/__init__.py +1 -1
  5. memos/api/config.py +471 -0
  6. memos/api/exceptions.py +28 -0
  7. memos/api/mcp_serve.py +502 -0
  8. memos/api/product_api.py +35 -0
  9. memos/api/product_models.py +159 -0
  10. memos/api/routers/__init__.py +1 -0
  11. memos/api/routers/product_router.py +358 -0
  12. memos/chunkers/sentence_chunker.py +8 -2
  13. memos/cli.py +113 -0
  14. memos/configs/embedder.py +27 -0
  15. memos/configs/graph_db.py +83 -2
  16. memos/configs/llm.py +47 -0
  17. memos/configs/mem_cube.py +1 -1
  18. memos/configs/mem_scheduler.py +91 -5
  19. memos/configs/memory.py +5 -4
  20. memos/dependency.py +52 -0
  21. memos/embedders/ark.py +92 -0
  22. memos/embedders/factory.py +4 -0
  23. memos/embedders/sentence_transformer.py +8 -2
  24. memos/embedders/universal_api.py +32 -0
  25. memos/graph_dbs/base.py +2 -2
  26. memos/graph_dbs/factory.py +2 -0
  27. memos/graph_dbs/neo4j.py +331 -122
  28. memos/graph_dbs/neo4j_community.py +300 -0
  29. memos/llms/base.py +9 -0
  30. memos/llms/deepseek.py +54 -0
  31. memos/llms/factory.py +10 -1
  32. memos/llms/hf.py +170 -13
  33. memos/llms/hf_singleton.py +114 -0
  34. memos/llms/ollama.py +4 -0
  35. memos/llms/openai.py +67 -1
  36. memos/llms/qwen.py +63 -0
  37. memos/llms/vllm.py +153 -0
  38. memos/mem_cube/general.py +77 -16
  39. memos/mem_cube/utils.py +102 -0
  40. memos/mem_os/core.py +131 -41
  41. memos/mem_os/main.py +93 -11
  42. memos/mem_os/product.py +1098 -35
  43. memos/mem_os/utils/default_config.py +352 -0
  44. memos/mem_os/utils/format_utils.py +1154 -0
  45. memos/mem_reader/simple_struct.py +5 -5
  46. memos/mem_scheduler/base_scheduler.py +467 -36
  47. memos/mem_scheduler/general_scheduler.py +125 -244
  48. memos/mem_scheduler/modules/base.py +9 -0
  49. memos/mem_scheduler/modules/dispatcher.py +68 -2
  50. memos/mem_scheduler/modules/misc.py +39 -0
  51. memos/mem_scheduler/modules/monitor.py +228 -49
  52. memos/mem_scheduler/modules/rabbitmq_service.py +317 -0
  53. memos/mem_scheduler/modules/redis_service.py +32 -22
  54. memos/mem_scheduler/modules/retriever.py +250 -23
  55. memos/mem_scheduler/modules/schemas.py +189 -7
  56. memos/mem_scheduler/mos_for_test_scheduler.py +143 -0
  57. memos/mem_scheduler/utils.py +51 -2
  58. memos/mem_user/persistent_user_manager.py +260 -0
  59. memos/memories/activation/item.py +25 -0
  60. memos/memories/activation/kv.py +10 -3
  61. memos/memories/activation/vllmkv.py +219 -0
  62. memos/memories/factory.py +2 -0
  63. memos/memories/textual/general.py +7 -5
  64. memos/memories/textual/tree.py +9 -5
  65. memos/memories/textual/tree_text_memory/organize/conflict.py +5 -3
  66. memos/memories/textual/tree_text_memory/organize/manager.py +26 -18
  67. memos/memories/textual/tree_text_memory/organize/redundancy.py +25 -44
  68. memos/memories/textual/tree_text_memory/organize/relation_reason_detector.py +11 -13
  69. memos/memories/textual/tree_text_memory/organize/reorganizer.py +73 -51
  70. memos/memories/textual/tree_text_memory/retrieve/recall.py +0 -1
  71. memos/memories/textual/tree_text_memory/retrieve/reranker.py +2 -2
  72. memos/memories/textual/tree_text_memory/retrieve/searcher.py +6 -5
  73. memos/parsers/markitdown.py +8 -2
  74. memos/templates/mem_reader_prompts.py +65 -23
  75. memos/templates/mem_scheduler_prompts.py +96 -47
  76. memos/templates/tree_reorganize_prompts.py +85 -30
  77. memos/vec_dbs/base.py +12 -0
  78. memos/vec_dbs/qdrant.py +46 -20
  79. {memoryos-0.2.0.dist-info → memoryos-0.2.1.dist-info}/LICENSE +0 -0
  80. {memoryos-0.2.0.dist-info → memoryos-0.2.1.dist-info}/WHEEL +0 -0
memos/vec_dbs/qdrant.py CHANGED
@@ -1,17 +1,7 @@
1
1
  from typing import Any
2
2
 
3
- from qdrant_client import QdrantClient
4
- from qdrant_client.http import models
5
- from qdrant_client.http.models import (
6
- Distance,
7
- FieldCondition,
8
- Filter,
9
- MatchValue,
10
- PointStruct,
11
- VectorParams,
12
- )
13
-
14
3
  from memos.configs.vec_db import QdrantVecDBConfig
4
+ from memos.dependency import require_python_package
15
5
  from memos.log import get_logger
16
6
  from memos.vec_dbs.base import BaseVecDB
17
7
  from memos.vec_dbs.item import VecDBItem
@@ -23,8 +13,15 @@ logger = get_logger(__name__)
23
13
  class QdrantVecDB(BaseVecDB):
24
14
  """Qdrant vector database implementation."""
25
15
 
16
+ @require_python_package(
17
+ import_name="qdrant_client",
18
+ install_command="pip install qdrant-client",
19
+ install_link="https://python-client.qdrant.tech/",
20
+ )
26
21
  def __init__(self, config: QdrantVecDBConfig):
27
22
  """Initialize the Qdrant vector database and the collection."""
23
+ from qdrant_client import QdrantClient
24
+
28
25
  self.config = config
29
26
 
30
27
  # If both host and port are None, we are running in local mode
@@ -43,6 +40,7 @@ class QdrantVecDB(BaseVecDB):
43
40
 
44
41
  def create_collection(self) -> None:
45
42
  """Create a new collection with specified parameters."""
43
+ from qdrant_client.http import models
46
44
 
47
45
  if self.collection_exists(self.config.collection_name):
48
46
  collection_info = self.client.get_collection(self.config.collection_name)
@@ -54,14 +52,14 @@ class QdrantVecDB(BaseVecDB):
54
52
 
55
53
  # Map string distance metric to Qdrant Distance enum
56
54
  distance_map = {
57
- "cosine": Distance.COSINE,
58
- "euclidean": Distance.EUCLID,
59
- "dot": Distance.DOT,
55
+ "cosine": models.Distance.COSINE,
56
+ "euclidean": models.Distance.EUCLID,
57
+ "dot": models.Distance.DOT,
60
58
  }
61
59
 
62
60
  self.client.create_collection(
63
61
  collection_name=self.config.collection_name,
64
- vectors_config=VectorParams(
62
+ vectors_config=models.VectorParams(
65
63
  size=self.config.vector_dimension,
66
64
  distance=distance_map[self.config.distance_metric],
67
65
  ),
@@ -122,16 +120,20 @@ class QdrantVecDB(BaseVecDB):
122
120
  for point in response
123
121
  ]
124
122
 
125
- def _dict_to_filter(self, filter_dict: dict[str, Any]) -> Filter:
123
+ def _dict_to_filter(self, filter_dict: dict[str, Any]) -> Any:
124
+ from qdrant_client.http import models
125
+
126
126
  """Convert a dictionary filter to a Qdrant Filter object."""
127
127
  conditions = []
128
128
 
129
129
  for field, value in filter_dict.items():
130
130
  # Simple exact match for now
131
131
  # TODO: Extend this to support more complex conditions
132
- conditions.append(FieldCondition(key=field, match=MatchValue(value=value)))
132
+ conditions.append(
133
+ models.FieldCondition(key=field, match=models.MatchValue(value=value))
134
+ )
133
135
 
134
- return Filter(must=conditions)
136
+ return models.Filter(must=conditions)
135
137
 
136
138
  def get_by_id(self, id: str) -> VecDBItem | None:
137
139
  """Get a single item by ID."""
@@ -235,6 +237,8 @@ class QdrantVecDB(BaseVecDB):
235
237
  return response.count
236
238
 
237
239
  def add(self, data: list[VecDBItem | dict[str, Any]]) -> None:
240
+ from qdrant_client.http import models
241
+
238
242
  """
239
243
  Add data to the vector database.
240
244
 
@@ -249,13 +253,14 @@ class QdrantVecDB(BaseVecDB):
249
253
  if isinstance(item, dict):
250
254
  item = item.copy()
251
255
  item = VecDBItem.from_dict(item)
252
- point = PointStruct(id=item.id, vector=item.vector, payload=item.payload)
256
+ point = models.PointStruct(id=item.id, vector=item.vector, payload=item.payload)
253
257
  points.append(point)
254
258
 
255
259
  self.client.upsert(collection_name=self.config.collection_name, points=points)
256
260
 
257
261
  def update(self, id: str, data: VecDBItem | dict[str, Any]) -> None:
258
262
  """Update an item in the vector database."""
263
+ from qdrant_client.http import models
259
264
 
260
265
  if isinstance(data, dict):
261
266
  data = data.copy()
@@ -265,7 +270,7 @@ class QdrantVecDB(BaseVecDB):
265
270
  # For vector updates (with or without payload), use upsert with the same ID
266
271
  self.client.upsert(
267
272
  collection_name=self.config.collection_name,
268
- points=[PointStruct(id=id, vector=data.vector, payload=data.payload)],
273
+ points=[models.PointStruct(id=id, vector=data.vector, payload=data.payload)],
269
274
  )
270
275
  else:
271
276
  # For payload-only updates
@@ -273,6 +278,25 @@ class QdrantVecDB(BaseVecDB):
273
278
  collection_name=self.config.collection_name, payload=data.payload, points=[id]
274
279
  )
275
280
 
281
+ def ensure_payload_indexes(self, fields: list[str]) -> None:
282
+ """
283
+ Create payload indexes for specified fields in the collection.
284
+ This is idempotent: it will skip if index already exists.
285
+
286
+ Args:
287
+ fields (list[str]): List of field names to index (as keyword).
288
+ """
289
+ for field in fields:
290
+ try:
291
+ self.client.create_payload_index(
292
+ collection_name=self.config.collection_name,
293
+ field_name=field,
294
+ field_schema="keyword", # Could be extended in future
295
+ )
296
+ logger.debug(f"Qdrant payload index on '{field}' ensured.")
297
+ except Exception as e:
298
+ logger.warning(f"Failed to create payload index on '{field}': {e}")
299
+
276
300
  def upsert(self, data: list[VecDBItem | dict[str, Any]]) -> None:
277
301
  """
278
302
  Add or update data in the vector database.
@@ -284,6 +308,8 @@ class QdrantVecDB(BaseVecDB):
284
308
  self.add(data)
285
309
 
286
310
  def delete(self, ids: list[str]) -> None:
311
+ from qdrant_client.http import models
312
+
287
313
  """Delete items from the vector database."""
288
314
  point_ids: list[str | int] = ids
289
315
  self.client.delete(