MemoryOS 0.2.1__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.

Files changed (92) hide show
  1. {memoryos-0.2.1.dist-info → memoryos-1.0.0.dist-info}/METADATA +7 -1
  2. {memoryos-0.2.1.dist-info → memoryos-1.0.0.dist-info}/RECORD +87 -64
  3. memos/__init__.py +1 -1
  4. memos/api/config.py +158 -69
  5. memos/api/context/context.py +147 -0
  6. memos/api/context/dependencies.py +101 -0
  7. memos/api/product_models.py +5 -1
  8. memos/api/routers/product_router.py +54 -26
  9. memos/configs/graph_db.py +49 -1
  10. memos/configs/internet_retriever.py +19 -0
  11. memos/configs/mem_os.py +5 -0
  12. memos/configs/mem_reader.py +9 -0
  13. memos/configs/mem_scheduler.py +54 -18
  14. memos/configs/mem_user.py +58 -0
  15. memos/graph_dbs/base.py +38 -3
  16. memos/graph_dbs/factory.py +2 -0
  17. memos/graph_dbs/nebular.py +1612 -0
  18. memos/graph_dbs/neo4j.py +18 -9
  19. memos/log.py +6 -1
  20. memos/mem_cube/utils.py +13 -6
  21. memos/mem_os/core.py +157 -37
  22. memos/mem_os/main.py +2 -2
  23. memos/mem_os/product.py +252 -201
  24. memos/mem_os/utils/default_config.py +1 -1
  25. memos/mem_os/utils/format_utils.py +281 -70
  26. memos/mem_os/utils/reference_utils.py +133 -0
  27. memos/mem_reader/simple_struct.py +13 -5
  28. memos/mem_scheduler/base_scheduler.py +239 -266
  29. memos/mem_scheduler/{modules → general_modules}/base.py +4 -5
  30. memos/mem_scheduler/{modules → general_modules}/dispatcher.py +57 -21
  31. memos/mem_scheduler/general_modules/misc.py +104 -0
  32. memos/mem_scheduler/{modules → general_modules}/rabbitmq_service.py +12 -10
  33. memos/mem_scheduler/{modules → general_modules}/redis_service.py +1 -1
  34. memos/mem_scheduler/general_modules/retriever.py +199 -0
  35. memos/mem_scheduler/general_modules/scheduler_logger.py +261 -0
  36. memos/mem_scheduler/general_scheduler.py +243 -80
  37. memos/mem_scheduler/monitors/__init__.py +0 -0
  38. memos/mem_scheduler/monitors/dispatcher_monitor.py +305 -0
  39. memos/mem_scheduler/{modules/monitor.py → monitors/general_monitor.py} +106 -57
  40. memos/mem_scheduler/mos_for_test_scheduler.py +23 -20
  41. memos/mem_scheduler/schemas/__init__.py +0 -0
  42. memos/mem_scheduler/schemas/general_schemas.py +44 -0
  43. memos/mem_scheduler/schemas/message_schemas.py +149 -0
  44. memos/mem_scheduler/schemas/monitor_schemas.py +337 -0
  45. memos/mem_scheduler/utils/__init__.py +0 -0
  46. memos/mem_scheduler/utils/filter_utils.py +176 -0
  47. memos/mem_scheduler/utils/misc_utils.py +102 -0
  48. memos/mem_user/factory.py +94 -0
  49. memos/mem_user/mysql_persistent_user_manager.py +271 -0
  50. memos/mem_user/mysql_user_manager.py +500 -0
  51. memos/mem_user/persistent_factory.py +96 -0
  52. memos/mem_user/user_manager.py +4 -4
  53. memos/memories/activation/item.py +5 -1
  54. memos/memories/activation/kv.py +20 -8
  55. memos/memories/textual/base.py +2 -2
  56. memos/memories/textual/general.py +36 -92
  57. memos/memories/textual/item.py +5 -33
  58. memos/memories/textual/tree.py +13 -7
  59. memos/memories/textual/tree_text_memory/organize/{conflict.py → handler.py} +34 -50
  60. memos/memories/textual/tree_text_memory/organize/manager.py +8 -96
  61. memos/memories/textual/tree_text_memory/organize/relation_reason_detector.py +49 -43
  62. memos/memories/textual/tree_text_memory/organize/reorganizer.py +107 -142
  63. memos/memories/textual/tree_text_memory/retrieve/bochasearch.py +229 -0
  64. memos/memories/textual/tree_text_memory/retrieve/internet_retriever.py +6 -3
  65. memos/memories/textual/tree_text_memory/retrieve/internet_retriever_factory.py +11 -0
  66. memos/memories/textual/tree_text_memory/retrieve/recall.py +15 -8
  67. memos/memories/textual/tree_text_memory/retrieve/reranker.py +1 -1
  68. memos/memories/textual/tree_text_memory/retrieve/retrieval_mid_structs.py +2 -0
  69. memos/memories/textual/tree_text_memory/retrieve/searcher.py +191 -116
  70. memos/memories/textual/tree_text_memory/retrieve/task_goal_parser.py +47 -15
  71. memos/memories/textual/tree_text_memory/retrieve/utils.py +11 -7
  72. memos/memories/textual/tree_text_memory/retrieve/xinyusearch.py +62 -58
  73. memos/memos_tools/dinding_report_bot.py +422 -0
  74. memos/memos_tools/lockfree_dict.py +120 -0
  75. memos/memos_tools/notification_service.py +44 -0
  76. memos/memos_tools/notification_utils.py +96 -0
  77. memos/memos_tools/thread_safe_dict.py +288 -0
  78. memos/settings.py +3 -1
  79. memos/templates/mem_reader_prompts.py +4 -1
  80. memos/templates/mem_scheduler_prompts.py +62 -15
  81. memos/templates/mos_prompts.py +116 -0
  82. memos/templates/tree_reorganize_prompts.py +24 -17
  83. memos/utils.py +19 -0
  84. memos/mem_scheduler/modules/misc.py +0 -39
  85. memos/mem_scheduler/modules/retriever.py +0 -268
  86. memos/mem_scheduler/modules/schemas.py +0 -328
  87. memos/mem_scheduler/utils.py +0 -75
  88. memos/memories/textual/tree_text_memory/organize/redundancy.py +0 -193
  89. {memoryos-0.2.1.dist-info → memoryos-1.0.0.dist-info}/LICENSE +0 -0
  90. {memoryos-0.2.1.dist-info → memoryos-1.0.0.dist-info}/WHEEL +0 -0
  91. {memoryos-0.2.1.dist-info → memoryos-1.0.0.dist-info}/entry_points.txt +0 -0
  92. /memos/mem_scheduler/{modules → general_modules}/__init__.py +0 -0
@@ -0,0 +1,120 @@
1
+ """
2
+ Lock-free dictionary implementation using copy-on-write strategy.
3
+ This provides better performance but uses more memory.
4
+ """
5
+
6
+ import threading
7
+
8
+ from collections.abc import ItemsView, Iterator, KeysView, ValuesView
9
+ from typing import Generic, TypeVar
10
+
11
+
12
+ K = TypeVar("K")
13
+ V = TypeVar("V")
14
+
15
+
16
+ class CopyOnWriteDict(Generic[K, V]):
17
+ """
18
+ A lock-free dictionary using copy-on-write strategy.
19
+
20
+ Reads are completely lock-free and very fast.
21
+ Writes create a new copy of the dictionary.
22
+ Uses more memory but provides excellent read performance.
23
+ """
24
+
25
+ def __init__(self, initial_dict: dict[K, V] | None = None):
26
+ """Initialize with optional initial dictionary."""
27
+ self._dict = initial_dict.copy() if initial_dict else {}
28
+ self._write_lock = threading.Lock() # Only for writes
29
+
30
+ def __getitem__(self, key: K) -> V:
31
+ """Get item by key - completely lock-free."""
32
+ return self._dict[key]
33
+
34
+ def __setitem__(self, key: K, value: V) -> None:
35
+ """Set item by key - uses copy-on-write."""
36
+ with self._write_lock:
37
+ # Create a new dictionary with the update
38
+ new_dict = self._dict.copy()
39
+ new_dict[key] = value
40
+ # Atomic replacement
41
+ self._dict = new_dict
42
+
43
+ def __delitem__(self, key: K) -> None:
44
+ """Delete item by key - uses copy-on-write."""
45
+ with self._write_lock:
46
+ new_dict = self._dict.copy()
47
+ del new_dict[key]
48
+ self._dict = new_dict
49
+
50
+ def __contains__(self, key: K) -> bool:
51
+ """Check if key exists - completely lock-free."""
52
+ return key in self._dict
53
+
54
+ def __len__(self) -> int:
55
+ """Get length - completely lock-free."""
56
+ return len(self._dict)
57
+
58
+ def __bool__(self) -> bool:
59
+ """Check if not empty - completely lock-free."""
60
+ return bool(self._dict)
61
+
62
+ def __iter__(self) -> Iterator[K]:
63
+ """Iterate over keys - completely lock-free."""
64
+ return iter(self._dict.keys())
65
+
66
+ def get(self, key: K, default: V | None = None) -> V:
67
+ """Get with default - completely lock-free."""
68
+ return self._dict.get(key, default)
69
+
70
+ def keys(self) -> KeysView[K]:
71
+ """Get keys - completely lock-free."""
72
+ return self._dict.keys()
73
+
74
+ def values(self) -> ValuesView[V]:
75
+ """Get values - completely lock-free."""
76
+ return self._dict.values()
77
+
78
+ def items(self) -> ItemsView[K, V]:
79
+ """Get items - completely lock-free."""
80
+ return self._dict.items()
81
+
82
+ def copy(self) -> dict[K, V]:
83
+ """Create a copy - completely lock-free."""
84
+ return self._dict.copy()
85
+
86
+ def update(self, *args, **kwargs) -> None:
87
+ """Update dictionary - uses copy-on-write."""
88
+ with self._write_lock:
89
+ new_dict = self._dict.copy()
90
+ new_dict.update(*args, **kwargs)
91
+ self._dict = new_dict
92
+
93
+ def clear(self) -> None:
94
+ """Clear all items."""
95
+ with self._write_lock:
96
+ self._dict = {}
97
+
98
+ def pop(self, key: K, *args) -> V:
99
+ """Pop item by key."""
100
+ with self._write_lock:
101
+ new_dict = self._dict.copy()
102
+ result = new_dict.pop(key, *args)
103
+ self._dict = new_dict
104
+ return result
105
+
106
+ def setdefault(self, key: K, default: V | None = None) -> V:
107
+ """Set default value for key if not exists."""
108
+ # Fast path for existing keys
109
+ if key in self._dict:
110
+ return self._dict[key]
111
+
112
+ with self._write_lock:
113
+ # Double-check after acquiring lock
114
+ if key in self._dict:
115
+ return self._dict[key]
116
+
117
+ new_dict = self._dict.copy()
118
+ result = new_dict.setdefault(key, default)
119
+ self._dict = new_dict
120
+ return result
@@ -0,0 +1,44 @@
1
+ """
2
+ Simple online_bot integration utility.
3
+ """
4
+
5
+ import logging
6
+
7
+ from collections.abc import Callable
8
+
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ def get_online_bot_function() -> Callable | None:
14
+ """
15
+ Get online_bot function if available, otherwise return None.
16
+
17
+ Returns:
18
+ online_bot function if available, None otherwise
19
+ """
20
+ try:
21
+ from memos.memos_tools.dinding_report_bot import online_bot
22
+
23
+ logger.info("online_bot function loaded successfully")
24
+ return online_bot
25
+ except ImportError as e:
26
+ logger.warning(f"Failed to import online_bot: {e}, returning None")
27
+ return None
28
+
29
+
30
+ def get_error_bot_function() -> Callable | None:
31
+ """
32
+ Get error_bot function if available, otherwise return None.
33
+
34
+ Returns:
35
+ error_bot function if available, None otherwise
36
+ """
37
+ try:
38
+ from memos.memos_tools.dinding_report_bot import error_bot
39
+
40
+ logger.info("error_bot function loaded successfully")
41
+ return error_bot
42
+ except ImportError as e:
43
+ logger.warning(f"Failed to import error_bot: {e}, returning None")
44
+ return None
@@ -0,0 +1,96 @@
1
+ """
2
+ Notification utilities for MemOS product.
3
+ """
4
+
5
+ import logging
6
+
7
+ from collections.abc import Callable
8
+ from typing import Any
9
+
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ def send_online_bot_notification(
15
+ online_bot: Callable | None,
16
+ header_name: str,
17
+ sub_title_name: str,
18
+ title_color: str,
19
+ other_data1: dict[str, Any],
20
+ other_data2: dict[str, Any],
21
+ emoji: dict[str, str],
22
+ ) -> None:
23
+ """
24
+ Send notification via online_bot if available.
25
+
26
+ Args:
27
+ online_bot: The online_bot function or None
28
+ header_name: Header name for the report
29
+ sub_title_name: Subtitle for the report
30
+ title_color: Title color
31
+ other_data1: First data dict
32
+ other_data2: Second data dict
33
+ emoji: Emoji configuration dict
34
+ """
35
+ if online_bot is None:
36
+ return
37
+
38
+ try:
39
+ online_bot(
40
+ header_name=header_name,
41
+ sub_title_name=sub_title_name,
42
+ title_color=title_color,
43
+ other_data1=other_data1,
44
+ other_data2=other_data2,
45
+ emoji=emoji,
46
+ )
47
+
48
+ logger.info(f"Online bot notification sent successfully: {header_name}")
49
+
50
+ except Exception as e:
51
+ logger.warning(f"Failed to send online bot notification: {e}")
52
+
53
+
54
+ def send_error_bot_notification(
55
+ error_bot: Callable | None,
56
+ err: str,
57
+ title: str = "MemOS Error",
58
+ level: str = "P2",
59
+ user_ids: list | None = None,
60
+ ) -> None:
61
+ """
62
+ Send error alert if error_bot is available.
63
+
64
+ Args:
65
+ error_bot: The error_bot function or None
66
+ err: Error message
67
+ title: Alert title
68
+ level: Alert level (P0, P1, P2)
69
+ user_ids: List of user IDs to notify
70
+ """
71
+ if error_bot is None:
72
+ return
73
+
74
+ try:
75
+ error_bot(
76
+ err=err,
77
+ title=title,
78
+ level=level,
79
+ user_ids=user_ids or [],
80
+ )
81
+ logger.info(f"Error alert sent successfully: {title}")
82
+ except Exception as e:
83
+ logger.warning(f"Failed to send error alert: {e}")
84
+
85
+
86
+ # Keep backward compatibility
87
+ def send_error_alert(
88
+ error_bot: Callable | None,
89
+ error_message: str,
90
+ title: str = "MemOS Error",
91
+ level: str = "P2",
92
+ ) -> None:
93
+ """
94
+ Send error alert if error_bot is available (backward compatibility).
95
+ """
96
+ send_error_bot_notification(error_bot, error_message, title, level)
@@ -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)
memos/settings.py CHANGED
@@ -1,7 +1,9 @@
1
+ import os
2
+
1
3
  from pathlib import Path
2
4
 
3
5
 
4
- MEMOS_DIR = Path.cwd() / ".memos"
6
+ MEMOS_DIR = Path(os.getenv("MEMOS_BASE_PATH", Path.cwd())) / ".memos"
5
7
  DEBUG = False
6
8
 
7
9
  # "memos" or "memos.submodules" ... to filter logs from specific packages
@@ -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.
@@ -16,6 +18,7 @@ For example, write "The user felt exhausted..." instead of "I felt exhausted..."
16
18
  - Include all key experiences, thoughts, emotional responses, and plans — even if they seem minor.
17
19
  - Prioritize completeness and fidelity over conciseness.
18
20
  - Do not generalize or skip details that could be personally meaningful to user.
21
+ 5. Please avoid any content that violates national laws and regulations or involves politically sensitive information in the memories you extract.
19
22
 
20
23
  Return a single valid JSON object with the following structure:
21
24
 
@@ -150,7 +153,7 @@ Output:
150
153
  "summary": "Tom is currently focused on managing a new project with a tight schedule. After a team meeting on June 25, 2025, he realized the original deadline of December 15 might not be feasible due to backend delays. Concerned about insufficient testing time, he welcomed Jerry’s suggestion of proposing an extension. Tom plans to raise the idea of shifting the deadline to January 5, 2026 in the next morning’s meeting. His actions reflect both stress about timelines and a proactive, team-oriented problem-solving approach."
151
154
  }
152
155
 
153
- Another Example in Chinese (注意: 你的输出必须和输入的user语言一致):
156
+ Another Example in Chinese (注意: user的语言为中文时,你就需要也输出中文):
154
157
  {
155
158
  "memory list": [
156
159
  {