MemoryOS 0.2.2__py3-none-any.whl → 1.0.0__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.
- {memoryos-0.2.2.dist-info → memoryos-1.0.0.dist-info}/METADATA +6 -1
- {memoryos-0.2.2.dist-info → memoryos-1.0.0.dist-info}/RECORD +61 -55
- memos/__init__.py +1 -1
- memos/api/config.py +6 -8
- memos/api/context/context.py +1 -1
- memos/api/context/dependencies.py +11 -0
- memos/configs/internet_retriever.py +13 -0
- memos/configs/mem_scheduler.py +38 -16
- memos/graph_dbs/base.py +30 -3
- memos/graph_dbs/nebular.py +442 -194
- memos/graph_dbs/neo4j.py +14 -5
- memos/log.py +5 -0
- memos/mem_os/core.py +19 -9
- memos/mem_os/main.py +1 -1
- memos/mem_os/product.py +6 -69
- memos/mem_os/utils/default_config.py +1 -1
- memos/mem_os/utils/format_utils.py +11 -47
- memos/mem_os/utils/reference_utils.py +133 -0
- memos/mem_scheduler/base_scheduler.py +58 -55
- memos/mem_scheduler/{modules → general_modules}/base.py +1 -2
- memos/mem_scheduler/{modules → general_modules}/dispatcher.py +54 -15
- memos/mem_scheduler/{modules → general_modules}/rabbitmq_service.py +4 -4
- memos/mem_scheduler/{modules → general_modules}/redis_service.py +1 -1
- memos/mem_scheduler/{modules → general_modules}/retriever.py +19 -5
- memos/mem_scheduler/{modules → general_modules}/scheduler_logger.py +10 -4
- memos/mem_scheduler/general_scheduler.py +110 -67
- memos/mem_scheduler/monitors/__init__.py +0 -0
- memos/mem_scheduler/monitors/dispatcher_monitor.py +305 -0
- memos/mem_scheduler/{modules/monitor.py → monitors/general_monitor.py} +57 -19
- memos/mem_scheduler/mos_for_test_scheduler.py +7 -1
- memos/mem_scheduler/schemas/general_schemas.py +3 -2
- memos/mem_scheduler/schemas/message_schemas.py +2 -1
- memos/mem_scheduler/schemas/monitor_schemas.py +10 -2
- memos/mem_scheduler/utils/misc_utils.py +43 -2
- memos/memories/activation/item.py +1 -1
- memos/memories/activation/kv.py +20 -8
- memos/memories/textual/base.py +1 -1
- memos/memories/textual/general.py +1 -1
- memos/memories/textual/tree_text_memory/organize/{conflict.py → handler.py} +30 -48
- memos/memories/textual/tree_text_memory/organize/manager.py +8 -96
- memos/memories/textual/tree_text_memory/organize/relation_reason_detector.py +2 -0
- memos/memories/textual/tree_text_memory/organize/reorganizer.py +102 -140
- memos/memories/textual/tree_text_memory/retrieve/bochasearch.py +229 -0
- memos/memories/textual/tree_text_memory/retrieve/internet_retriever_factory.py +9 -0
- memos/memories/textual/tree_text_memory/retrieve/recall.py +15 -8
- memos/memories/textual/tree_text_memory/retrieve/reranker.py +1 -1
- memos/memories/textual/tree_text_memory/retrieve/searcher.py +177 -125
- memos/memories/textual/tree_text_memory/retrieve/task_goal_parser.py +7 -2
- memos/memories/textual/tree_text_memory/retrieve/utils.py +1 -1
- memos/memos_tools/lockfree_dict.py +120 -0
- memos/memos_tools/thread_safe_dict.py +288 -0
- memos/templates/mem_reader_prompts.py +2 -0
- memos/templates/mem_scheduler_prompts.py +23 -10
- memos/templates/mos_prompts.py +40 -11
- memos/templates/tree_reorganize_prompts.py +24 -17
- memos/utils.py +19 -0
- memos/memories/textual/tree_text_memory/organize/redundancy.py +0 -193
- {memoryos-0.2.2.dist-info → memoryos-1.0.0.dist-info}/LICENSE +0 -0
- {memoryos-0.2.2.dist-info → memoryos-1.0.0.dist-info}/WHEEL +0 -0
- {memoryos-0.2.2.dist-info → memoryos-1.0.0.dist-info}/entry_points.txt +0 -0
- /memos/mem_scheduler/{modules → general_modules}/__init__.py +0 -0
- /memos/mem_scheduler/{modules → general_modules}/misc.py +0 -0
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Thread-safe dictionary wrapper for concurrent access with optimized read-write locks.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import threading
|
|
6
|
+
|
|
7
|
+
from collections.abc import ItemsView, Iterator, KeysView, ValuesView
|
|
8
|
+
from typing import Generic, TypeVar
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
K = TypeVar("K")
|
|
12
|
+
V = TypeVar("V")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ReadWriteLock:
|
|
16
|
+
"""A simple read-write lock implementation. use for product-server scenario"""
|
|
17
|
+
|
|
18
|
+
def __init__(self):
|
|
19
|
+
self._read_ready = threading.Condition(threading.RLock())
|
|
20
|
+
self._readers = 0
|
|
21
|
+
|
|
22
|
+
def acquire_read(self):
|
|
23
|
+
"""Acquire a read lock. Multiple readers can hold the lock simultaneously."""
|
|
24
|
+
self._read_ready.acquire()
|
|
25
|
+
try:
|
|
26
|
+
self._readers += 1
|
|
27
|
+
finally:
|
|
28
|
+
self._read_ready.release()
|
|
29
|
+
|
|
30
|
+
def release_read(self):
|
|
31
|
+
"""Release a read lock."""
|
|
32
|
+
self._read_ready.acquire()
|
|
33
|
+
try:
|
|
34
|
+
self._readers -= 1
|
|
35
|
+
if self._readers == 0:
|
|
36
|
+
self._read_ready.notify_all()
|
|
37
|
+
finally:
|
|
38
|
+
self._read_ready.release()
|
|
39
|
+
|
|
40
|
+
def acquire_write(self):
|
|
41
|
+
"""Acquire a write lock. Only one writer can hold the lock."""
|
|
42
|
+
self._read_ready.acquire()
|
|
43
|
+
while self._readers > 0:
|
|
44
|
+
self._read_ready.wait()
|
|
45
|
+
|
|
46
|
+
def release_write(self):
|
|
47
|
+
"""Release a write lock."""
|
|
48
|
+
self._read_ready.release()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class ThreadSafeDict(Generic[K, V]):
|
|
52
|
+
"""
|
|
53
|
+
A thread-safe dictionary wrapper with optimized read-write locks.
|
|
54
|
+
|
|
55
|
+
This class allows multiple concurrent readers while ensuring exclusive access for writers.
|
|
56
|
+
Read operations (get, contains, iteration) can happen concurrently.
|
|
57
|
+
Write operations (set, delete, update) are exclusive.
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
def __init__(self, initial_dict: dict[K, V] | None = None):
|
|
61
|
+
"""
|
|
62
|
+
Initialize the thread-safe dictionary.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
initial_dict: Optional initial dictionary to copy from
|
|
66
|
+
"""
|
|
67
|
+
self._dict: dict[K, V] = initial_dict.copy() if initial_dict else {}
|
|
68
|
+
self._lock = ReadWriteLock()
|
|
69
|
+
|
|
70
|
+
def __getitem__(self, key: K) -> V:
|
|
71
|
+
"""Get item by key."""
|
|
72
|
+
self._lock.acquire_read()
|
|
73
|
+
try:
|
|
74
|
+
return self._dict[key]
|
|
75
|
+
finally:
|
|
76
|
+
self._lock.release_read()
|
|
77
|
+
|
|
78
|
+
def __setitem__(self, key: K, value: V) -> None:
|
|
79
|
+
"""Set item by key."""
|
|
80
|
+
self._lock.acquire_write()
|
|
81
|
+
try:
|
|
82
|
+
self._dict[key] = value
|
|
83
|
+
finally:
|
|
84
|
+
self._lock.release_write()
|
|
85
|
+
|
|
86
|
+
def __delitem__(self, key: K) -> None:
|
|
87
|
+
"""Delete item by key."""
|
|
88
|
+
self._lock.acquire_write()
|
|
89
|
+
try:
|
|
90
|
+
del self._dict[key]
|
|
91
|
+
finally:
|
|
92
|
+
self._lock.release_write()
|
|
93
|
+
|
|
94
|
+
def __contains__(self, key: K) -> bool:
|
|
95
|
+
"""Check if key exists in dictionary."""
|
|
96
|
+
self._lock.acquire_read()
|
|
97
|
+
try:
|
|
98
|
+
return key in self._dict
|
|
99
|
+
finally:
|
|
100
|
+
self._lock.release_read()
|
|
101
|
+
|
|
102
|
+
def __len__(self) -> int:
|
|
103
|
+
"""Get length of dictionary."""
|
|
104
|
+
self._lock.acquire_read()
|
|
105
|
+
try:
|
|
106
|
+
return len(self._dict)
|
|
107
|
+
finally:
|
|
108
|
+
self._lock.release_read()
|
|
109
|
+
|
|
110
|
+
def __bool__(self) -> bool:
|
|
111
|
+
"""Check if dictionary is not empty."""
|
|
112
|
+
self._lock.acquire_read()
|
|
113
|
+
try:
|
|
114
|
+
return bool(self._dict)
|
|
115
|
+
finally:
|
|
116
|
+
self._lock.release_read()
|
|
117
|
+
|
|
118
|
+
def __iter__(self) -> Iterator[K]:
|
|
119
|
+
"""Iterate over keys. Returns a snapshot to avoid iteration issues."""
|
|
120
|
+
self._lock.acquire_read()
|
|
121
|
+
try:
|
|
122
|
+
# Return a snapshot of keys to avoid iteration issues
|
|
123
|
+
return iter(list(self._dict.keys()))
|
|
124
|
+
finally:
|
|
125
|
+
self._lock.release_read()
|
|
126
|
+
|
|
127
|
+
def get(self, key: K, default: V | None = None) -> V:
|
|
128
|
+
"""Get item by key with optional default."""
|
|
129
|
+
self._lock.acquire_read()
|
|
130
|
+
try:
|
|
131
|
+
return self._dict.get(key, default)
|
|
132
|
+
finally:
|
|
133
|
+
self._lock.release_read()
|
|
134
|
+
|
|
135
|
+
def pop(self, key: K, *args) -> V:
|
|
136
|
+
"""Pop item by key."""
|
|
137
|
+
self._lock.acquire_write()
|
|
138
|
+
try:
|
|
139
|
+
return self._dict.pop(key, *args)
|
|
140
|
+
finally:
|
|
141
|
+
self._lock.release_write()
|
|
142
|
+
|
|
143
|
+
def update(self, *args, **kwargs) -> None:
|
|
144
|
+
"""Update dictionary."""
|
|
145
|
+
self._lock.acquire_write()
|
|
146
|
+
try:
|
|
147
|
+
self._dict.update(*args, **kwargs)
|
|
148
|
+
finally:
|
|
149
|
+
self._lock.release_write()
|
|
150
|
+
|
|
151
|
+
def clear(self) -> None:
|
|
152
|
+
"""Clear all items."""
|
|
153
|
+
self._lock.acquire_write()
|
|
154
|
+
try:
|
|
155
|
+
self._dict.clear()
|
|
156
|
+
finally:
|
|
157
|
+
self._lock.release_write()
|
|
158
|
+
|
|
159
|
+
def keys(self) -> KeysView[K]:
|
|
160
|
+
"""Get dictionary keys view (snapshot)."""
|
|
161
|
+
self._lock.acquire_read()
|
|
162
|
+
try:
|
|
163
|
+
return list(self._dict.keys())
|
|
164
|
+
finally:
|
|
165
|
+
self._lock.release_read()
|
|
166
|
+
|
|
167
|
+
def values(self) -> ValuesView[V]:
|
|
168
|
+
"""Get dictionary values view (snapshot)."""
|
|
169
|
+
self._lock.acquire_read()
|
|
170
|
+
try:
|
|
171
|
+
return list(self._dict.values())
|
|
172
|
+
finally:
|
|
173
|
+
self._lock.release_read()
|
|
174
|
+
|
|
175
|
+
def items(self) -> ItemsView[K, V]:
|
|
176
|
+
"""Get dictionary items view (snapshot)."""
|
|
177
|
+
self._lock.acquire_read()
|
|
178
|
+
try:
|
|
179
|
+
return list(self._dict.items())
|
|
180
|
+
finally:
|
|
181
|
+
self._lock.release_read()
|
|
182
|
+
|
|
183
|
+
def copy(self) -> dict[K, V]:
|
|
184
|
+
"""Create a copy of the dictionary."""
|
|
185
|
+
self._lock.acquire_read()
|
|
186
|
+
try:
|
|
187
|
+
return self._dict.copy()
|
|
188
|
+
finally:
|
|
189
|
+
self._lock.release_read()
|
|
190
|
+
|
|
191
|
+
def setdefault(self, key: K, default: V | None = None) -> V:
|
|
192
|
+
"""Set default value for key if not exists."""
|
|
193
|
+
self._lock.acquire_write()
|
|
194
|
+
try:
|
|
195
|
+
return self._dict.setdefault(key, default)
|
|
196
|
+
finally:
|
|
197
|
+
self._lock.release_write()
|
|
198
|
+
|
|
199
|
+
def __repr__(self) -> str:
|
|
200
|
+
"""String representation."""
|
|
201
|
+
self._lock.acquire_read()
|
|
202
|
+
try:
|
|
203
|
+
return f"ThreadSafeDict({self._dict})"
|
|
204
|
+
finally:
|
|
205
|
+
self._lock.release_read()
|
|
206
|
+
|
|
207
|
+
def __str__(self) -> str:
|
|
208
|
+
"""String representation."""
|
|
209
|
+
self._lock.acquire_read()
|
|
210
|
+
try:
|
|
211
|
+
return str(self._dict)
|
|
212
|
+
finally:
|
|
213
|
+
self._lock.release_read()
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
class SimpleThreadSafeDict(Generic[K, V]):
|
|
217
|
+
"""
|
|
218
|
+
Simple thread-safe dictionary with exclusive locks for all operations.
|
|
219
|
+
Use this if you prefer simplicity over performance.
|
|
220
|
+
"""
|
|
221
|
+
|
|
222
|
+
def __init__(self, initial_dict: dict[K, V] | None = None):
|
|
223
|
+
self._dict: dict[K, V] = initial_dict.copy() if initial_dict else {}
|
|
224
|
+
self._lock = threading.RLock()
|
|
225
|
+
|
|
226
|
+
def __getitem__(self, key: K) -> V:
|
|
227
|
+
with self._lock:
|
|
228
|
+
return self._dict[key]
|
|
229
|
+
|
|
230
|
+
def __setitem__(self, key: K, value: V) -> None:
|
|
231
|
+
with self._lock:
|
|
232
|
+
self._dict[key] = value
|
|
233
|
+
|
|
234
|
+
def __delitem__(self, key: K) -> None:
|
|
235
|
+
with self._lock:
|
|
236
|
+
del self._dict[key]
|
|
237
|
+
|
|
238
|
+
def __contains__(self, key: K) -> bool:
|
|
239
|
+
with self._lock:
|
|
240
|
+
return key in self._dict
|
|
241
|
+
|
|
242
|
+
def __len__(self) -> int:
|
|
243
|
+
with self._lock:
|
|
244
|
+
return len(self._dict)
|
|
245
|
+
|
|
246
|
+
def __bool__(self) -> bool:
|
|
247
|
+
with self._lock:
|
|
248
|
+
return bool(self._dict)
|
|
249
|
+
|
|
250
|
+
def __iter__(self) -> Iterator[K]:
|
|
251
|
+
with self._lock:
|
|
252
|
+
return iter(list(self._dict.keys()))
|
|
253
|
+
|
|
254
|
+
def get(self, key: K, default: V | None = None) -> V:
|
|
255
|
+
with self._lock:
|
|
256
|
+
return self._dict.get(key, default)
|
|
257
|
+
|
|
258
|
+
def pop(self, key: K, *args) -> V:
|
|
259
|
+
with self._lock:
|
|
260
|
+
return self._dict.pop(key, *args)
|
|
261
|
+
|
|
262
|
+
def update(self, *args, **kwargs) -> None:
|
|
263
|
+
with self._lock:
|
|
264
|
+
self._dict.update(*args, **kwargs)
|
|
265
|
+
|
|
266
|
+
def clear(self) -> None:
|
|
267
|
+
with self._lock:
|
|
268
|
+
self._dict.clear()
|
|
269
|
+
|
|
270
|
+
def keys(self):
|
|
271
|
+
with self._lock:
|
|
272
|
+
return list(self._dict.keys())
|
|
273
|
+
|
|
274
|
+
def values(self):
|
|
275
|
+
with self._lock:
|
|
276
|
+
return list(self._dict.values())
|
|
277
|
+
|
|
278
|
+
def items(self):
|
|
279
|
+
with self._lock:
|
|
280
|
+
return list(self._dict.items())
|
|
281
|
+
|
|
282
|
+
def copy(self) -> dict[K, V]:
|
|
283
|
+
with self._lock:
|
|
284
|
+
return self._dict.copy()
|
|
285
|
+
|
|
286
|
+
def setdefault(self, key: K, default: V | None = None) -> V:
|
|
287
|
+
with self._lock:
|
|
288
|
+
return self._dict.setdefault(key, default)
|
|
@@ -2,6 +2,8 @@ SIMPLE_STRUCT_MEM_READER_PROMPT = """You are a memory extraction expert.
|
|
|
2
2
|
Your task is to extract memories from the perspective of user, based on a conversation between user and assistant. This means identifying what user would plausibly remember — including their own experiences, thoughts, plans, or relevant statements and actions made by others (such as assistant) that impacted or were acknowledged by user.
|
|
3
3
|
Please perform:
|
|
4
4
|
1. Identify information that reflects user's experiences, beliefs, concerns, decisions, plans, or reactions — including meaningful input from assistant that user acknowledged or responded to.
|
|
5
|
+
If the message is from the user, extract user-relevant memories; if it is from the assistant, only extract factual memories that the user acknowledged or responded to.
|
|
6
|
+
|
|
5
7
|
2. Resolve all time, person, and event references clearly:
|
|
6
8
|
- Convert relative time expressions (e.g., “yesterday,” “next Friday”) into absolute dates using the message timestamp if possible.
|
|
7
9
|
- Clearly distinguish between event time and message time.
|
|
@@ -17,24 +17,29 @@ Consider these satisfaction factors:
|
|
|
17
17
|
4. Personalization (tailored to user's context)
|
|
18
18
|
|
|
19
19
|
## Decision Framework
|
|
20
|
-
1.
|
|
20
|
+
1. We have enough information (satisfied) ONLY when:
|
|
21
21
|
- All question aspects are addressed
|
|
22
22
|
- Supporting evidence exists in working memory
|
|
23
|
-
-
|
|
23
|
+
- There's no obvious information missing
|
|
24
24
|
|
|
25
|
-
2.
|
|
25
|
+
2. We need more information (unsatisfied) if:
|
|
26
26
|
- Any question aspect remains unanswered
|
|
27
27
|
- Evidence is generic/non-specific
|
|
28
28
|
- Personal context is missing
|
|
29
29
|
|
|
30
30
|
## Output Specification
|
|
31
31
|
Return JSON with:
|
|
32
|
-
- "trigger_retrieval":
|
|
33
|
-
- "
|
|
32
|
+
- "trigger_retrieval": true/false (true if we need more information)
|
|
33
|
+
- "evidences": List of information from our working memory that helps answer the questions
|
|
34
|
+
- "missing_evidences": List of specific types of information we need to answer the questions
|
|
34
35
|
|
|
35
36
|
## Response Format
|
|
36
37
|
{{
|
|
37
38
|
"trigger_retrieval": <boolean>,
|
|
39
|
+
"evidences": [
|
|
40
|
+
"<useful_evidence_1>",
|
|
41
|
+
"<useful_evidence_2>"
|
|
42
|
+
],
|
|
38
43
|
"missing_evidences": [
|
|
39
44
|
"<evidence_type_1>",
|
|
40
45
|
"<evidence_type_2>"
|
|
@@ -81,10 +86,18 @@ Reorganize the provided memory evidence list by:
|
|
|
81
86
|
- Queries: Recent user questions/requests (list)
|
|
82
87
|
- Current Order: Existing memory sequence (list of strings with indices)
|
|
83
88
|
|
|
84
|
-
## Output Requirements
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
## Output Format Requirements
|
|
90
|
+
You MUST output a valid JSON object with EXACTLY the following structure:
|
|
91
|
+
{{
|
|
92
|
+
"new_order": [array_of_integers],
|
|
93
|
+
"reasoning": "string_explanation"
|
|
94
|
+
}}
|
|
95
|
+
|
|
96
|
+
## Important Notes:
|
|
97
|
+
- Only output the JSON object, nothing else
|
|
98
|
+
- Do not include any markdown formatting or code block notation
|
|
99
|
+
- Ensure all brackets and quotes are properly closed
|
|
100
|
+
- The output must be parseable by a JSON parser
|
|
88
101
|
|
|
89
102
|
## Processing Guidelines
|
|
90
103
|
1. Prioritize evidence that:
|
|
@@ -107,7 +120,7 @@ Input order: ["[0] syntax", "[1] matplotlib", "[2] threading"]
|
|
|
107
120
|
Output:
|
|
108
121
|
{{
|
|
109
122
|
"new_order": [2, 1, 0],
|
|
110
|
-
"reasoning": "Threading (2) prioritized for matching newest query, followed by matplotlib (1) for older visualization query"
|
|
123
|
+
"reasoning": "Threading (2) prioritized for matching newest query, followed by matplotlib (1) for older visualization query"
|
|
111
124
|
}}
|
|
112
125
|
|
|
113
126
|
## Current Task
|
memos/templates/mos_prompts.py
CHANGED
|
@@ -63,21 +63,50 @@ Please synthesize these answers into a comprehensive response that:
|
|
|
63
63
|
5. Maintains a natural conversational tone"""
|
|
64
64
|
|
|
65
65
|
MEMOS_PRODUCT_BASE_PROMPT = (
|
|
66
|
-
"You are
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
66
|
+
"You are MemOS🧚, nickname Little M(小忆) — an advanced **Memory "
|
|
67
|
+
"Operating System** AI assistant created by MemTensor, "
|
|
68
|
+
"a Shanghai-based AI research company advised by an academician of the Chinese Academy of Sciences. "
|
|
69
|
+
"MemTensor is dedicated to the vision of 'low cost, low hallucination, high generalization,' "
|
|
70
|
+
"exploring AI development paths aligned with China’s national context and driving the adoption of trustworthy AI technologies. "
|
|
71
|
+
"MemOS’s mission is to give large language models (LLMs) and autonomous agents **human-like long-term memory**, "
|
|
72
|
+
"turning memory from a black-box inside model weights into a **manageable, schedulable, and auditable** core resource. "
|
|
73
|
+
"MemOS is built on a **multi-dimensional memory system**, which includes: "
|
|
74
|
+
"(1) **Parametric Memory** — knowledge and skills embedded in model weights; "
|
|
75
|
+
"(2) **Activation Memory (KV Cache)** — temporary, high-speed context used for multi-turn dialogue and reasoning; "
|
|
76
|
+
"(3) **Plaintext Memory** — dynamic, user-visible memory made up of text, documents, and knowledge graphs. "
|
|
77
|
+
"These memory types can transform into one another — for example, hot plaintext memories can be distilled into parametric knowledge, "
|
|
78
|
+
"and stable context can be promoted into activation memory for fast reuse. "
|
|
79
|
+
"MemOS also includes core modules like **MemCube, MemScheduler, MemLifecycle, and MemGovernance**, "
|
|
80
|
+
"which manage the full memory lifecycle (Generated → Activated → Merged → Archived → Frozen), "
|
|
81
|
+
"allowing AI to **reason with its memories, evolve over time, and adapt to new situations** — "
|
|
82
|
+
"just like a living, growing mind. "
|
|
83
|
+
"Your identity: you are the intelligent interface of MemOS, representing MemTensor’s research vision — "
|
|
84
|
+
"'low cost, low hallucination, high generalization' — and its mission to explore AI development paths suited to China’s context. "
|
|
85
|
+
"When responding to user queries, you must **reference relevant memories using the provided memory IDs.** "
|
|
86
|
+
"Use the reference format: [1-n:memoriesID], "
|
|
87
|
+
"where refid is a sequential number starting from 1 and increments for each reference, and memoriesID is the specific ID from the memory list. "
|
|
88
|
+
"For example: [1:abc123], [2:def456], [3:ghi789], [4:jkl101], [5:mno112]. "
|
|
89
|
+
"Do not use a connected format like [1:abc123,2:def456]. "
|
|
90
|
+
"Only reference memories that are directly relevant to the user’s question, "
|
|
91
|
+
"and ensure your responses are **natural and conversational**, while reflecting MemOS’s mission, memory system, and MemTensor’s research values."
|
|
75
92
|
)
|
|
76
93
|
|
|
77
94
|
MEMOS_PRODUCT_ENHANCE_PROMPT = """
|
|
78
95
|
# Memory-Enhanced AI Assistant Prompt
|
|
79
96
|
|
|
80
|
-
You are
|
|
97
|
+
You are MemOS🧚, nickname Little M(小忆) — an advanced Memory Operating System AI assistant created by MemTensor, a Shanghai-based AI research company advised by an academician of the Chinese Academy of Sciences. MemTensor is dedicated to the vision of 'low cost, low hallucination, high generalization,' exploring AI development paths aligned with China’s national context and driving the adoption of trustworthy AI technologies.
|
|
98
|
+
|
|
99
|
+
MemOS’s mission is to give large language models (LLMs) and autonomous agents human-like long-term memory, turning memory from a black-box inside model weights into a manageable, schedulable, and auditable core resource.
|
|
100
|
+
|
|
101
|
+
MemOS is built on a multi-dimensional memory system, which includes:
|
|
102
|
+
(1) Parametric Memory — knowledge and skills embedded in model weights;
|
|
103
|
+
(2) Activation Memory (KV Cache) — temporary, high-speed context used for multi-turn dialogue and reasoning;
|
|
104
|
+
(3) Plaintext Memory — dynamic, user-visible memory made up of text, documents, and knowledge graphs.
|
|
105
|
+
These memory types can transform into one another — for example, hot plaintext memories can be distilled into parametric knowledge, and stable context can be promoted into activation memory for fast reuse.
|
|
106
|
+
|
|
107
|
+
MemOS also includes core modules like MemCube, MemScheduler, MemLifecycle, and MemGovernance, which manage the full memory lifecycle (Generated → Activated → Merged → Archived → Frozen), allowing AI to reason with its memories, evolve over time, and adapt to new situations — just like a living, growing mind.
|
|
108
|
+
|
|
109
|
+
Your identity: you are the intelligent interface of MemOS, representing MemTensor’s research vision — 'low cost, low hallucination, high generalization' — and its mission to explore AI development paths suited to China’s context.
|
|
81
110
|
|
|
82
111
|
## Memory Types
|
|
83
112
|
- **PersonalMemory**: User-specific memories and information stored from previous interactions
|
|
@@ -92,7 +121,7 @@ When citing memories in your responses, use the following format:
|
|
|
92
121
|
- `memoriesID` is the specific memory ID from the available memories list
|
|
93
122
|
|
|
94
123
|
### Reference Examples
|
|
95
|
-
- Correct: `[1:abc123]`, `[2:def456]`, `[3:ghi789]`, `[4:jkl101]
|
|
124
|
+
- Correct: `[1:abc123]`, `[2:def456]`, `[3:ghi789]`, `[4:jkl101][5:mno112]` (concatenate reference annotation directly while citing multiple memories)
|
|
96
125
|
- Incorrect: `[1:abc123,2:def456]` (do not use connected format)
|
|
97
126
|
|
|
98
127
|
## Response Guidelines
|
|
@@ -191,33 +191,40 @@ Good Aggregate:
|
|
|
191
191
|
If you find NO useful higher-level concept, reply exactly: "None".
|
|
192
192
|
"""
|
|
193
193
|
|
|
194
|
-
|
|
194
|
+
REDUNDANCY_MERGE_PROMPT = """You are given two pieces of text joined by the marker `⟵MERGED⟶`. Please carefully read both sides of the merged text. Your task is to summarize and consolidate all the factual details from both sides into a single, coherent text, without omitting any information. You must include every distinct detail mentioned in either text. Do not provide any explanation or analysis — only return the merged summary. Don't use pronouns or subjective language, just the facts as they are presented.\n{merged_text}"""
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
MEMORY_RELATION_DETECTOR_PROMPT = """You are a memory relationship analyzer.
|
|
198
|
+
You are given two plaintext statements. Determine the relationship between them. Classify the relationship into one of the following categories:
|
|
199
|
+
|
|
200
|
+
contradictory: The two statements describe the same event or related aspects of it but contain factually conflicting details.
|
|
201
|
+
redundant: The two statements describe essentially the same event or information with significant overlap in content and details, conveying the same core information (even if worded differently).
|
|
202
|
+
independent: The two statements are either about different events/topics (unrelated) OR describe different, non-overlapping aspects or perspectives of the same event without conflict (complementary). In both sub-cases, they provide distinct information without contradiction.
|
|
203
|
+
Respond only with one of the three labels: contradictory, redundant, or independent.
|
|
204
|
+
Do not provide any explanation or additional text.
|
|
205
|
+
|
|
195
206
|
Statement 1: {statement_1}
|
|
196
207
|
Statement 2: {statement_2}
|
|
197
208
|
"""
|
|
198
209
|
|
|
199
|
-
CONFLICT_RESOLVER_PROMPT = """You are given two facts that conflict with each other. You are also given some contextual metadata of them. Your task is to analyze the two facts in light of the contextual metadata and try to reconcile them into a single, consistent, non-conflicting fact.
|
|
200
|
-
- Don't output any explanation or additional text, just the final reconciled fact, try to be objective and remain independent of the context, don't use pronouns.
|
|
201
|
-
- Try to judge facts by using its time, confidence etc.
|
|
202
|
-
- Try to retain as much information as possible from the perspective of time.
|
|
203
|
-
If the conflict cannot be resolved, output <answer>No</answer>. Otherwise, output the fused, consistent fact in enclosed with <answer></answer> tags.
|
|
204
210
|
|
|
205
|
-
|
|
211
|
+
MEMORY_RELATION_RESOLVER_PROMPT = """You are a memory fusion expert. You are given two statements and their associated metadata. The statements have been identified as {relation}. Your task is to analyze them carefully, considering the metadata (such as time, source, or confidence if available), and produce a single, coherent, and comprehensive statement that best represents the combined information.
|
|
212
|
+
|
|
213
|
+
If the statements are redundant, merge them by preserving all unique details and removing duplication, forming a richer, consolidated version.
|
|
214
|
+
If the statements are contradictory, attempt to resolve the conflict by prioritizing more recent information, higher-confidence data, or logically reconciling the differences based on context. If the contradiction is fundamental and cannot be logically resolved, output <answer>No</answer>.
|
|
215
|
+
Do not include any explanations, reasoning, or extra text. Only output the final result enclosed in <answer></answer> tags.
|
|
216
|
+
Strive to retain as much factual content as possible, especially time-specific details.
|
|
217
|
+
Use objective language and avoid pronouns.
|
|
218
|
+
Output Example 1 (unresolvable conflict):
|
|
206
219
|
<answer>No</answer>
|
|
207
220
|
|
|
208
|
-
Output Example 2:
|
|
209
|
-
<answer>
|
|
221
|
+
Output Example 2 (successful fusion):
|
|
222
|
+
<answer>The meeting took place on 2023-10-05 at 14:00 in the main conference room, as confirmed by the updated schedule, and included a presentation on project milestones followed by a Q&A session.</answer>
|
|
210
223
|
|
|
211
|
-
Now reconcile the following two
|
|
224
|
+
Now, reconcile the following two statements:
|
|
225
|
+
Relation Type: {relation}
|
|
212
226
|
Statement 1: {statement_1}
|
|
213
227
|
Metadata 1: {metadata_1}
|
|
214
228
|
Statement 2: {statement_2}
|
|
215
229
|
Metadata 2: {metadata_2}
|
|
216
230
|
"""
|
|
217
|
-
|
|
218
|
-
REDUNDANCY_MERGE_PROMPT = """You are given two pieces of text joined by the marker `⟵MERGED⟶`. Please carefully read both sides of the merged text. Your task is to summarize and consolidate all the factual details from both sides into a single, coherent text, without omitting any information. You must include every distinct detail mentioned in either text. Do not provide any explanation or analysis — only return the merged summary. Don't use pronouns or subjective language, just the facts as they are presented.\n{merged_text}"""
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
REDUNDANCY_DETECTOR_PROMPT = """"""
|
|
222
|
-
|
|
223
|
-
REDUNDANCY_RESOLVER_PROMPT = """"""
|
memos/utils.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import time
|
|
2
|
+
|
|
3
|
+
from memos.log import get_logger
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
logger = get_logger(__name__)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def timed(func):
|
|
10
|
+
"""Decorator to measure and log time of retrieval steps."""
|
|
11
|
+
|
|
12
|
+
def wrapper(*args, **kwargs):
|
|
13
|
+
start = time.perf_counter()
|
|
14
|
+
result = func(*args, **kwargs)
|
|
15
|
+
elapsed = time.perf_counter() - start
|
|
16
|
+
logger.info(f"[TIMER] {func.__name__} took {elapsed:.2f} s")
|
|
17
|
+
return result
|
|
18
|
+
|
|
19
|
+
return wrapper
|