MemoryOS 1.0.0__py3-none-any.whl → 1.1.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.
- {memoryos-1.0.0.dist-info → memoryos-1.1.1.dist-info}/METADATA +8 -2
- {memoryos-1.0.0.dist-info → memoryos-1.1.1.dist-info}/RECORD +92 -69
- {memoryos-1.0.0.dist-info → memoryos-1.1.1.dist-info}/WHEEL +1 -1
- memos/__init__.py +1 -1
- memos/api/client.py +109 -0
- memos/api/config.py +35 -8
- memos/api/context/dependencies.py +15 -66
- memos/api/middleware/request_context.py +63 -0
- memos/api/product_api.py +5 -2
- memos/api/product_models.py +107 -16
- memos/api/routers/product_router.py +62 -19
- memos/api/start_api.py +13 -0
- memos/configs/graph_db.py +4 -0
- memos/configs/mem_scheduler.py +38 -3
- memos/configs/memory.py +13 -0
- memos/configs/reranker.py +18 -0
- memos/context/context.py +255 -0
- memos/embedders/factory.py +2 -0
- memos/graph_dbs/base.py +4 -2
- memos/graph_dbs/nebular.py +368 -223
- memos/graph_dbs/neo4j.py +49 -13
- memos/graph_dbs/neo4j_community.py +13 -3
- memos/llms/factory.py +2 -0
- memos/llms/openai.py +74 -2
- memos/llms/vllm.py +2 -0
- memos/log.py +128 -4
- memos/mem_cube/general.py +3 -1
- memos/mem_os/core.py +89 -23
- memos/mem_os/main.py +3 -6
- memos/mem_os/product.py +418 -154
- memos/mem_os/utils/reference_utils.py +20 -0
- memos/mem_reader/factory.py +2 -0
- memos/mem_reader/simple_struct.py +204 -82
- memos/mem_scheduler/analyzer/__init__.py +0 -0
- memos/mem_scheduler/analyzer/mos_for_test_scheduler.py +569 -0
- memos/mem_scheduler/analyzer/scheduler_for_eval.py +280 -0
- memos/mem_scheduler/base_scheduler.py +126 -56
- memos/mem_scheduler/general_modules/dispatcher.py +2 -2
- memos/mem_scheduler/general_modules/misc.py +99 -1
- memos/mem_scheduler/general_modules/scheduler_logger.py +17 -11
- memos/mem_scheduler/general_scheduler.py +40 -88
- memos/mem_scheduler/memory_manage_modules/__init__.py +5 -0
- memos/mem_scheduler/memory_manage_modules/memory_filter.py +308 -0
- memos/mem_scheduler/{general_modules → memory_manage_modules}/retriever.py +34 -7
- memos/mem_scheduler/monitors/dispatcher_monitor.py +9 -8
- memos/mem_scheduler/monitors/general_monitor.py +119 -39
- memos/mem_scheduler/optimized_scheduler.py +124 -0
- memos/mem_scheduler/orm_modules/__init__.py +0 -0
- memos/mem_scheduler/orm_modules/base_model.py +635 -0
- memos/mem_scheduler/orm_modules/monitor_models.py +261 -0
- memos/mem_scheduler/scheduler_factory.py +2 -0
- memos/mem_scheduler/schemas/monitor_schemas.py +96 -29
- memos/mem_scheduler/utils/config_utils.py +100 -0
- memos/mem_scheduler/utils/db_utils.py +33 -0
- memos/mem_scheduler/utils/filter_utils.py +1 -1
- memos/mem_scheduler/webservice_modules/__init__.py +0 -0
- memos/mem_user/mysql_user_manager.py +4 -2
- memos/memories/activation/kv.py +2 -1
- memos/memories/textual/item.py +96 -17
- memos/memories/textual/naive.py +1 -1
- memos/memories/textual/tree.py +57 -3
- memos/memories/textual/tree_text_memory/organize/handler.py +4 -2
- memos/memories/textual/tree_text_memory/organize/manager.py +28 -14
- memos/memories/textual/tree_text_memory/organize/relation_reason_detector.py +1 -2
- memos/memories/textual/tree_text_memory/organize/reorganizer.py +75 -23
- memos/memories/textual/tree_text_memory/retrieve/bochasearch.py +10 -6
- memos/memories/textual/tree_text_memory/retrieve/internet_retriever.py +6 -2
- memos/memories/textual/tree_text_memory/retrieve/internet_retriever_factory.py +2 -0
- memos/memories/textual/tree_text_memory/retrieve/recall.py +119 -21
- memos/memories/textual/tree_text_memory/retrieve/searcher.py +172 -44
- memos/memories/textual/tree_text_memory/retrieve/utils.py +6 -4
- memos/memories/textual/tree_text_memory/retrieve/xinyusearch.py +5 -4
- memos/memos_tools/notification_utils.py +46 -0
- memos/memos_tools/singleton.py +174 -0
- memos/memos_tools/thread_safe_dict.py +22 -0
- memos/memos_tools/thread_safe_dict_segment.py +382 -0
- memos/parsers/factory.py +2 -0
- memos/reranker/__init__.py +4 -0
- memos/reranker/base.py +24 -0
- memos/reranker/concat.py +59 -0
- memos/reranker/cosine_local.py +96 -0
- memos/reranker/factory.py +48 -0
- memos/reranker/http_bge.py +312 -0
- memos/reranker/noop.py +16 -0
- memos/templates/mem_reader_prompts.py +289 -40
- memos/templates/mem_scheduler_prompts.py +242 -0
- memos/templates/mos_prompts.py +133 -60
- memos/types.py +4 -1
- memos/api/context/context.py +0 -147
- memos/mem_scheduler/mos_for_test_scheduler.py +0 -146
- {memoryos-1.0.0.dist-info → memoryos-1.1.1.dist-info}/entry_points.txt +0 -0
- {memoryos-1.0.0.dist-info → memoryos-1.1.1.dist-info/licenses}/LICENSE +0 -0
- /memos/mem_scheduler/{general_modules → webservice_modules}/rabbitmq_service.py +0 -0
- /memos/mem_scheduler/{general_modules → webservice_modules}/redis_service.py +0 -0
|
@@ -2,11 +2,18 @@ from datetime import datetime
|
|
|
2
2
|
from threading import Lock
|
|
3
3
|
from typing import Any
|
|
4
4
|
|
|
5
|
+
from sqlalchemy.engine import Engine
|
|
6
|
+
|
|
5
7
|
from memos.configs.mem_scheduler import BaseSchedulerConfig
|
|
6
8
|
from memos.llms.base import BaseLLM
|
|
7
9
|
from memos.log import get_logger
|
|
8
10
|
from memos.mem_cube.general import GeneralMemCube
|
|
9
11
|
from memos.mem_scheduler.general_modules.base import BaseSchedulerModule
|
|
12
|
+
from memos.mem_scheduler.orm_modules.base_model import BaseDBManager
|
|
13
|
+
from memos.mem_scheduler.orm_modules.monitor_models import (
|
|
14
|
+
DBManagerForMemoryMonitorManager,
|
|
15
|
+
DBManagerForQueryMonitorQueue,
|
|
16
|
+
)
|
|
10
17
|
from memos.mem_scheduler.schemas.general_schemas import (
|
|
11
18
|
DEFAULT_ACTIVATION_MEM_MONITOR_SIZE_LIMIT,
|
|
12
19
|
DEFAULT_WEIGHT_VECTOR_FOR_RANKING,
|
|
@@ -19,7 +26,6 @@ from memos.mem_scheduler.schemas.general_schemas import (
|
|
|
19
26
|
from memos.mem_scheduler.schemas.monitor_schemas import (
|
|
20
27
|
MemoryMonitorItem,
|
|
21
28
|
MemoryMonitorManager,
|
|
22
|
-
QueryMonitorItem,
|
|
23
29
|
QueryMonitorQueue,
|
|
24
30
|
)
|
|
25
31
|
from memos.mem_scheduler.utils.misc_utils import extract_json_dict
|
|
@@ -32,7 +38,9 @@ logger = get_logger(__name__)
|
|
|
32
38
|
class SchedulerGeneralMonitor(BaseSchedulerModule):
|
|
33
39
|
"""Monitors and manages scheduling operations with LLM integration."""
|
|
34
40
|
|
|
35
|
-
def __init__(
|
|
41
|
+
def __init__(
|
|
42
|
+
self, process_llm: BaseLLM, config: BaseSchedulerConfig, db_engine: Engine | None = None
|
|
43
|
+
):
|
|
36
44
|
super().__init__()
|
|
37
45
|
|
|
38
46
|
# hyper-parameters
|
|
@@ -49,12 +57,22 @@ class SchedulerGeneralMonitor(BaseSchedulerModule):
|
|
|
49
57
|
"activation_mem_monitor_capacity", DEFAULT_ACTIVATION_MEM_MONITOR_SIZE_LIMIT
|
|
50
58
|
)
|
|
51
59
|
|
|
52
|
-
#
|
|
53
|
-
|
|
54
|
-
self.
|
|
60
|
+
# ORM-based monitor managers
|
|
61
|
+
self.db_engine = db_engine
|
|
62
|
+
if self.db_engine is None:
|
|
63
|
+
logger.warning(
|
|
64
|
+
"No database engine provided; falling back to default temporary SQLite engine. "
|
|
65
|
+
"This is intended for testing only. Consider providing a configured engine for production use."
|
|
66
|
+
)
|
|
67
|
+
self.db_engine = BaseDBManager.create_default_engine()
|
|
55
68
|
|
|
56
|
-
self.
|
|
57
|
-
self.
|
|
69
|
+
self.query_monitors: dict[UserID, dict[MemCubeID, DBManagerForQueryMonitorQueue]] = {}
|
|
70
|
+
self.working_memory_monitors: dict[
|
|
71
|
+
UserID, dict[MemCubeID, DBManagerForMemoryMonitorManager]
|
|
72
|
+
] = {}
|
|
73
|
+
self.activation_memory_monitors: dict[
|
|
74
|
+
UserID, dict[MemCubeID, DBManagerForMemoryMonitorManager]
|
|
75
|
+
] = {}
|
|
58
76
|
|
|
59
77
|
# Lifecycle monitor
|
|
60
78
|
self.last_activation_mem_update_time = datetime.min
|
|
@@ -96,40 +114,47 @@ class SchedulerGeneralMonitor(BaseSchedulerModule):
|
|
|
96
114
|
if user_id not in self.query_monitors:
|
|
97
115
|
self.query_monitors[user_id] = {}
|
|
98
116
|
if mem_cube_id not in self.query_monitors[user_id]:
|
|
99
|
-
self.
|
|
100
|
-
|
|
101
|
-
|
|
117
|
+
if self.db_engine:
|
|
118
|
+
# Create ORM manager with initial QueryMonitorQueue
|
|
119
|
+
initial_queue = QueryMonitorQueue(maxsize=self.config.context_window_size)
|
|
120
|
+
db_manager = DBManagerForQueryMonitorQueue(
|
|
121
|
+
engine=self.db_engine,
|
|
122
|
+
user_id=str(user_id),
|
|
123
|
+
mem_cube_id=str(mem_cube_id),
|
|
124
|
+
obj=initial_queue,
|
|
125
|
+
)
|
|
126
|
+
self.query_monitors[user_id][mem_cube_id] = db_manager
|
|
127
|
+
else:
|
|
128
|
+
# Fallback to in-memory (this shouldn't happen with proper config)
|
|
129
|
+
logger.warning("ORM persistence disabled, using in-memory fallback")
|
|
130
|
+
# For backward compatibility, we'll need to handle this case differently
|
|
131
|
+
raise RuntimeError("ORM persistence is required but not properly configured")
|
|
102
132
|
|
|
103
133
|
def register_memory_manager_if_not_exists(
|
|
104
134
|
self,
|
|
105
135
|
user_id: UserID | str,
|
|
106
136
|
mem_cube_id: MemCubeID | str,
|
|
107
|
-
memory_monitors: dict[UserID, dict[MemCubeID,
|
|
137
|
+
memory_monitors: dict[UserID, dict[MemCubeID, DBManagerForMemoryMonitorManager]],
|
|
108
138
|
max_capacity: int,
|
|
109
139
|
) -> None:
|
|
110
140
|
"""
|
|
111
|
-
Register a new MemoryMonitorManager for the given user and memory cube if it doesn't exist.
|
|
141
|
+
Register a new MemoryMonitorManager ORM manager for the given user and memory cube if it doesn't exist.
|
|
112
142
|
Thread-safe implementation using double-checked locking pattern.
|
|
113
143
|
|
|
114
|
-
Checks if a MemoryMonitorManager already exists for the specified user_id and mem_cube_id.
|
|
115
|
-
If not, creates a new
|
|
144
|
+
Checks if a MemoryMonitorManager ORM manager already exists for the specified user_id and mem_cube_id.
|
|
145
|
+
If not, creates a new ORM manager with appropriate capacity settings and registers it.
|
|
116
146
|
|
|
117
147
|
Args:
|
|
118
148
|
user_id: The ID of the user to associate with the memory manager
|
|
119
149
|
mem_cube_id: The ID of the memory cube to monitor
|
|
120
|
-
memory_monitors: Dictionary storing existing memory monitor managers
|
|
150
|
+
memory_monitors: Dictionary storing existing memory monitor ORM managers
|
|
121
151
|
max_capacity: Maximum capacity for the new memory monitor manager
|
|
122
|
-
lock: Threading lock to ensure safe concurrent access
|
|
123
|
-
|
|
124
|
-
Note:
|
|
125
|
-
This function will update the loose_max_working_memory_capacity based on the current
|
|
126
|
-
WorkingMemory size plus partial retention number before creating a new manager.
|
|
127
152
|
"""
|
|
128
153
|
# First check (lock-free, fast path)
|
|
129
154
|
# Quickly verify existence without lock overhead
|
|
130
155
|
if user_id in memory_monitors and mem_cube_id in memory_monitors[user_id]:
|
|
131
156
|
logger.info(
|
|
132
|
-
f"MemoryMonitorManager already exists for user_id={user_id}, "
|
|
157
|
+
f"MemoryMonitorManager ORM manager already exists for user_id={user_id}, "
|
|
133
158
|
f"mem_cube_id={mem_cube_id} in the provided memory_monitors dictionary"
|
|
134
159
|
)
|
|
135
160
|
return
|
|
@@ -140,22 +165,33 @@ class SchedulerGeneralMonitor(BaseSchedulerModule):
|
|
|
140
165
|
# Re-check after acquiring lock, as another thread might have created it
|
|
141
166
|
if user_id in memory_monitors and mem_cube_id in memory_monitors[user_id]:
|
|
142
167
|
logger.info(
|
|
143
|
-
f"MemoryMonitorManager already exists for user_id={user_id}, "
|
|
168
|
+
f"MemoryMonitorManager ORM manager already exists for user_id={user_id}, "
|
|
144
169
|
f"mem_cube_id={mem_cube_id} in the provided memory_monitors dictionary"
|
|
145
170
|
)
|
|
146
171
|
return
|
|
147
172
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
173
|
+
if self.db_engine:
|
|
174
|
+
# Initialize MemoryMonitorManager with user ID, memory cube ID, and max capacity
|
|
175
|
+
monitor_manager = MemoryMonitorManager(
|
|
176
|
+
user_id=user_id, mem_cube_id=mem_cube_id, max_capacity=max_capacity
|
|
177
|
+
)
|
|
152
178
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
179
|
+
# Create ORM manager
|
|
180
|
+
db_manager = DBManagerForMemoryMonitorManager(
|
|
181
|
+
engine=self.db_engine,
|
|
182
|
+
user_id=str(user_id),
|
|
183
|
+
mem_cube_id=str(mem_cube_id),
|
|
184
|
+
obj=monitor_manager,
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Safely register the new ORM manager in the nested dictionary structure
|
|
188
|
+
memory_monitors.setdefault(user_id, {})[mem_cube_id] = db_manager
|
|
189
|
+
logger.info(
|
|
190
|
+
f"Registered new MemoryMonitorManager ORM manager for user_id={user_id},"
|
|
191
|
+
f" mem_cube_id={mem_cube_id} with max_capacity={max_capacity}"
|
|
192
|
+
)
|
|
193
|
+
else:
|
|
194
|
+
raise RuntimeError("ORM persistence is required but not properly configured")
|
|
159
195
|
|
|
160
196
|
def update_working_memory_monitors(
|
|
161
197
|
self,
|
|
@@ -182,10 +218,14 @@ class SchedulerGeneralMonitor(BaseSchedulerModule):
|
|
|
182
218
|
max_capacity=self.working_mem_monitor_capacity,
|
|
183
219
|
)
|
|
184
220
|
|
|
185
|
-
|
|
221
|
+
# Get the ORM manager and update memories with database sync
|
|
222
|
+
db_manager = self.working_memory_monitors[user_id][mem_cube_id]
|
|
223
|
+
db_manager.obj.update_memories(
|
|
186
224
|
new_memory_monitors=new_working_memory_monitors,
|
|
187
225
|
partial_retention_number=self.partial_retention_number,
|
|
188
226
|
)
|
|
227
|
+
# Sync with database
|
|
228
|
+
db_manager.sync_with_orm(size_limit=self.working_mem_monitor_capacity)
|
|
189
229
|
|
|
190
230
|
def update_activation_memory_monitors(
|
|
191
231
|
self, user_id: str, mem_cube_id: str, mem_cube: GeneralMemCube
|
|
@@ -199,17 +239,21 @@ class SchedulerGeneralMonitor(BaseSchedulerModule):
|
|
|
199
239
|
|
|
200
240
|
# === update activation memory monitors ===
|
|
201
241
|
# Sort by importance_score in descending order and take top k
|
|
242
|
+
working_db_manager = self.working_memory_monitors[user_id][mem_cube_id]
|
|
202
243
|
top_k_memories = sorted(
|
|
203
|
-
|
|
244
|
+
working_db_manager.obj.memories,
|
|
204
245
|
key=lambda m: m.get_importance_score(weight_vector=DEFAULT_WEIGHT_VECTOR_FOR_RANKING),
|
|
205
246
|
reverse=True,
|
|
206
247
|
)[: self.activation_mem_monitor_capacity]
|
|
207
248
|
|
|
208
249
|
# Update the activation memory monitors with these important memories
|
|
209
|
-
self.activation_memory_monitors[user_id][mem_cube_id]
|
|
250
|
+
activation_db_manager = self.activation_memory_monitors[user_id][mem_cube_id]
|
|
251
|
+
activation_db_manager.obj.update_memories(
|
|
210
252
|
new_memory_monitors=top_k_memories,
|
|
211
253
|
partial_retention_number=self.partial_retention_number,
|
|
212
254
|
)
|
|
255
|
+
# Sync with database
|
|
256
|
+
activation_db_manager.sync_with_orm(size_limit=self.activation_mem_monitor_capacity)
|
|
213
257
|
|
|
214
258
|
def timed_trigger(self, last_time: datetime, interval_seconds: float) -> bool:
|
|
215
259
|
now = datetime.utcnow()
|
|
@@ -255,9 +299,12 @@ class SchedulerGeneralMonitor(BaseSchedulerModule):
|
|
|
255
299
|
)
|
|
256
300
|
return []
|
|
257
301
|
|
|
258
|
-
|
|
302
|
+
db_manager: DBManagerForMemoryMonitorManager = monitor_dict[user_id][mem_cube_id]
|
|
303
|
+
# Load latest data from database before accessing
|
|
304
|
+
db_manager.sync_with_orm()
|
|
305
|
+
|
|
259
306
|
# Sort memories by recording_count in descending order and return top_k items
|
|
260
|
-
sorted_memory_monitors =
|
|
307
|
+
sorted_memory_monitors = db_manager.obj.get_sorted_mem_monitors(reverse=True)
|
|
261
308
|
sorted_text_memories = [m.memory_text for m in sorted_memory_monitors[:top_k]]
|
|
262
309
|
return sorted_text_memories
|
|
263
310
|
|
|
@@ -273,16 +320,19 @@ class SchedulerGeneralMonitor(BaseSchedulerModule):
|
|
|
273
320
|
return {}
|
|
274
321
|
|
|
275
322
|
info_dict = {}
|
|
276
|
-
for
|
|
323
|
+
for db_manager in [
|
|
277
324
|
self.working_memory_monitors[user_id][mem_cube_id],
|
|
278
325
|
self.activation_memory_monitors[user_id][mem_cube_id],
|
|
279
326
|
]:
|
|
327
|
+
# Sync with database to get latest data
|
|
328
|
+
db_manager.sync_with_orm()
|
|
329
|
+
manager = db_manager.obj
|
|
280
330
|
info_dict[str(type(manager))] = {
|
|
281
331
|
"user_id": user_id,
|
|
282
332
|
"mem_cube_id": mem_cube_id,
|
|
283
333
|
"memory_count": manager.memory_size,
|
|
284
334
|
"max_capacity": manager.max_capacity,
|
|
285
|
-
"top_memories": self.
|
|
335
|
+
"top_memories": self.get_monitor_memories(user_id, mem_cube_id, top_k=1),
|
|
286
336
|
}
|
|
287
337
|
return info_dict
|
|
288
338
|
|
|
@@ -308,3 +358,33 @@ class SchedulerGeneralMonitor(BaseSchedulerModule):
|
|
|
308
358
|
logger.error(f"Fail to extract json dict from response: {response}")
|
|
309
359
|
response = {"trigger_retrieval": False, "missing_evidences": q_list}
|
|
310
360
|
return response
|
|
361
|
+
|
|
362
|
+
def close(self):
|
|
363
|
+
"""Close all database connections and clean up resources"""
|
|
364
|
+
logger.info("Closing database connections for all monitors")
|
|
365
|
+
|
|
366
|
+
# Close all query monitor database managers
|
|
367
|
+
for user_monitors in self.query_monitors.values():
|
|
368
|
+
for db_manager in user_monitors.values():
|
|
369
|
+
try:
|
|
370
|
+
db_manager.close()
|
|
371
|
+
except Exception as e:
|
|
372
|
+
logger.error(f"Error closing query monitor DB manager: {e}")
|
|
373
|
+
|
|
374
|
+
# Close all working memory monitor database managers
|
|
375
|
+
for user_monitors in self.working_memory_monitors.values():
|
|
376
|
+
for db_manager in user_monitors.values():
|
|
377
|
+
try:
|
|
378
|
+
db_manager.close()
|
|
379
|
+
except Exception as e:
|
|
380
|
+
logger.error(f"Error closing working memory monitor DB manager: {e}")
|
|
381
|
+
|
|
382
|
+
# Close all activation memory monitor database managers
|
|
383
|
+
for user_monitors in self.activation_memory_monitors.values():
|
|
384
|
+
for db_manager in user_monitors.values():
|
|
385
|
+
try:
|
|
386
|
+
db_manager.close()
|
|
387
|
+
except Exception as e:
|
|
388
|
+
logger.error(f"Error closing activation memory monitor DB manager: {e}")
|
|
389
|
+
|
|
390
|
+
logger.info("All database connections closed")
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
from memos.configs.mem_scheduler import GeneralSchedulerConfig
|
|
4
|
+
from memos.log import get_logger
|
|
5
|
+
from memos.mem_cube.general import GeneralMemCube
|
|
6
|
+
from memos.mem_scheduler.general_scheduler import GeneralScheduler
|
|
7
|
+
from memos.mem_scheduler.schemas.general_schemas import (
|
|
8
|
+
MemCubeID,
|
|
9
|
+
UserID,
|
|
10
|
+
)
|
|
11
|
+
from memos.memories.textual.tree import TextualMemoryItem, TreeTextMemory
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from memos.mem_scheduler.schemas.monitor_schemas import MemoryMonitorItem
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
logger = get_logger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class OptimizedScheduler(GeneralScheduler):
|
|
22
|
+
"""Optimized scheduler with improved working memory management"""
|
|
23
|
+
|
|
24
|
+
def __init__(self, config: GeneralSchedulerConfig):
|
|
25
|
+
super().__init__(config)
|
|
26
|
+
|
|
27
|
+
def replace_working_memory(
|
|
28
|
+
self,
|
|
29
|
+
user_id: UserID | str,
|
|
30
|
+
mem_cube_id: MemCubeID | str,
|
|
31
|
+
mem_cube: GeneralMemCube,
|
|
32
|
+
original_memory: list[TextualMemoryItem],
|
|
33
|
+
new_memory: list[TextualMemoryItem],
|
|
34
|
+
) -> None | list[TextualMemoryItem]:
|
|
35
|
+
"""Replace working memory with new memories after reranking."""
|
|
36
|
+
text_mem_base = mem_cube.text_mem
|
|
37
|
+
if isinstance(text_mem_base, TreeTextMemory):
|
|
38
|
+
text_mem_base: TreeTextMemory = text_mem_base
|
|
39
|
+
|
|
40
|
+
# process rerank memories with llm
|
|
41
|
+
query_db_manager = self.monitor.query_monitors[user_id][mem_cube_id]
|
|
42
|
+
# Sync with database to get latest query history
|
|
43
|
+
query_db_manager.sync_with_orm()
|
|
44
|
+
|
|
45
|
+
query_history = query_db_manager.obj.get_queries_with_timesort()
|
|
46
|
+
memories_with_new_order, rerank_success_flag = (
|
|
47
|
+
self.retriever.process_and_rerank_memories(
|
|
48
|
+
queries=query_history,
|
|
49
|
+
original_memory=original_memory,
|
|
50
|
+
new_memory=new_memory,
|
|
51
|
+
top_k=self.top_k,
|
|
52
|
+
)
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Apply combined filtering (unrelated + redundant)
|
|
56
|
+
logger.info(
|
|
57
|
+
f"Applying combined unrelated and redundant memory filtering to {len(memories_with_new_order)} memories"
|
|
58
|
+
)
|
|
59
|
+
filtered_memories, filtering_success_flag = (
|
|
60
|
+
self.retriever.filter_unrelated_and_redundant_memories(
|
|
61
|
+
query_history=query_history,
|
|
62
|
+
memories=memories_with_new_order,
|
|
63
|
+
)
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
if filtering_success_flag:
|
|
67
|
+
logger.info(
|
|
68
|
+
f"Combined filtering completed successfully. "
|
|
69
|
+
f"Filtered from {len(memories_with_new_order)} to {len(filtered_memories)} memories"
|
|
70
|
+
)
|
|
71
|
+
memories_with_new_order = filtered_memories
|
|
72
|
+
else:
|
|
73
|
+
logger.warning(
|
|
74
|
+
"Combined filtering failed - keeping memories as fallback. "
|
|
75
|
+
f"Count: {len(memories_with_new_order)}"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Update working memory monitors
|
|
79
|
+
query_keywords = query_db_manager.obj.get_keywords_collections()
|
|
80
|
+
logger.info(
|
|
81
|
+
f"Processing {len(memories_with_new_order)} memories with {len(query_keywords)} query keywords"
|
|
82
|
+
)
|
|
83
|
+
new_working_memory_monitors = self.transform_working_memories_to_monitors(
|
|
84
|
+
query_keywords=query_keywords,
|
|
85
|
+
memories=memories_with_new_order,
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
if not rerank_success_flag:
|
|
89
|
+
for one in new_working_memory_monitors:
|
|
90
|
+
one.sorting_score = 0
|
|
91
|
+
|
|
92
|
+
logger.info(f"update {len(new_working_memory_monitors)} working_memory_monitors")
|
|
93
|
+
self.monitor.update_working_memory_monitors(
|
|
94
|
+
new_working_memory_monitors=new_working_memory_monitors,
|
|
95
|
+
user_id=user_id,
|
|
96
|
+
mem_cube_id=mem_cube_id,
|
|
97
|
+
mem_cube=mem_cube,
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# Use the filtered and reranked memories directly
|
|
101
|
+
text_mem_base.replace_working_memory(memories=memories_with_new_order)
|
|
102
|
+
|
|
103
|
+
# Update monitor after replacing working memory
|
|
104
|
+
mem_monitors: list[MemoryMonitorItem] = self.monitor.working_memory_monitors[user_id][
|
|
105
|
+
mem_cube_id
|
|
106
|
+
].obj.get_sorted_mem_monitors(reverse=True)
|
|
107
|
+
new_working_memories = [mem_monitor.tree_memory_item for mem_monitor in mem_monitors]
|
|
108
|
+
|
|
109
|
+
logger.info(
|
|
110
|
+
f"The working memory has been replaced with {len(memories_with_new_order)} new memories."
|
|
111
|
+
)
|
|
112
|
+
self.log_working_memory_replacement(
|
|
113
|
+
original_memory=original_memory,
|
|
114
|
+
new_memory=new_working_memories,
|
|
115
|
+
user_id=user_id,
|
|
116
|
+
mem_cube_id=mem_cube_id,
|
|
117
|
+
mem_cube=mem_cube,
|
|
118
|
+
log_func_callback=self._submit_web_logs,
|
|
119
|
+
)
|
|
120
|
+
else:
|
|
121
|
+
logger.error("memory_base is not supported")
|
|
122
|
+
memories_with_new_order = new_memory
|
|
123
|
+
|
|
124
|
+
return memories_with_new_order
|
|
File without changes
|