MemoryOS 2.0.3__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.
- memoryos-2.0.3.dist-info/METADATA +418 -0
- memoryos-2.0.3.dist-info/RECORD +315 -0
- memoryos-2.0.3.dist-info/WHEEL +4 -0
- memoryos-2.0.3.dist-info/entry_points.txt +3 -0
- memoryos-2.0.3.dist-info/licenses/LICENSE +201 -0
- memos/__init__.py +20 -0
- memos/api/client.py +571 -0
- memos/api/config.py +1018 -0
- memos/api/context/dependencies.py +50 -0
- memos/api/exceptions.py +53 -0
- memos/api/handlers/__init__.py +62 -0
- memos/api/handlers/add_handler.py +158 -0
- memos/api/handlers/base_handler.py +194 -0
- memos/api/handlers/chat_handler.py +1401 -0
- memos/api/handlers/component_init.py +388 -0
- memos/api/handlers/config_builders.py +190 -0
- memos/api/handlers/feedback_handler.py +93 -0
- memos/api/handlers/formatters_handler.py +237 -0
- memos/api/handlers/memory_handler.py +316 -0
- memos/api/handlers/scheduler_handler.py +497 -0
- memos/api/handlers/search_handler.py +222 -0
- memos/api/handlers/suggestion_handler.py +117 -0
- memos/api/mcp_serve.py +614 -0
- memos/api/middleware/request_context.py +101 -0
- memos/api/product_api.py +38 -0
- memos/api/product_models.py +1206 -0
- memos/api/routers/__init__.py +1 -0
- memos/api/routers/product_router.py +477 -0
- memos/api/routers/server_router.py +394 -0
- memos/api/server_api.py +44 -0
- memos/api/start_api.py +433 -0
- memos/chunkers/__init__.py +4 -0
- memos/chunkers/base.py +24 -0
- memos/chunkers/charactertext_chunker.py +41 -0
- memos/chunkers/factory.py +24 -0
- memos/chunkers/markdown_chunker.py +62 -0
- memos/chunkers/sentence_chunker.py +54 -0
- memos/chunkers/simple_chunker.py +50 -0
- memos/cli.py +113 -0
- memos/configs/__init__.py +0 -0
- memos/configs/base.py +82 -0
- memos/configs/chunker.py +59 -0
- memos/configs/embedder.py +88 -0
- memos/configs/graph_db.py +236 -0
- memos/configs/internet_retriever.py +100 -0
- memos/configs/llm.py +151 -0
- memos/configs/mem_agent.py +54 -0
- memos/configs/mem_chat.py +81 -0
- memos/configs/mem_cube.py +105 -0
- memos/configs/mem_os.py +83 -0
- memos/configs/mem_reader.py +91 -0
- memos/configs/mem_scheduler.py +385 -0
- memos/configs/mem_user.py +70 -0
- memos/configs/memory.py +324 -0
- memos/configs/parser.py +38 -0
- memos/configs/reranker.py +18 -0
- memos/configs/utils.py +8 -0
- memos/configs/vec_db.py +80 -0
- memos/context/context.py +355 -0
- memos/dependency.py +52 -0
- memos/deprecation.py +262 -0
- memos/embedders/__init__.py +0 -0
- memos/embedders/ark.py +95 -0
- memos/embedders/base.py +106 -0
- memos/embedders/factory.py +29 -0
- memos/embedders/ollama.py +77 -0
- memos/embedders/sentence_transformer.py +49 -0
- memos/embedders/universal_api.py +51 -0
- memos/exceptions.py +30 -0
- memos/graph_dbs/__init__.py +0 -0
- memos/graph_dbs/base.py +274 -0
- memos/graph_dbs/factory.py +27 -0
- memos/graph_dbs/item.py +46 -0
- memos/graph_dbs/nebular.py +1794 -0
- memos/graph_dbs/neo4j.py +1942 -0
- memos/graph_dbs/neo4j_community.py +1058 -0
- memos/graph_dbs/polardb.py +5446 -0
- memos/hello_world.py +97 -0
- memos/llms/__init__.py +0 -0
- memos/llms/base.py +25 -0
- memos/llms/deepseek.py +13 -0
- memos/llms/factory.py +38 -0
- memos/llms/hf.py +443 -0
- memos/llms/hf_singleton.py +114 -0
- memos/llms/ollama.py +135 -0
- memos/llms/openai.py +222 -0
- memos/llms/openai_new.py +198 -0
- memos/llms/qwen.py +13 -0
- memos/llms/utils.py +14 -0
- memos/llms/vllm.py +218 -0
- memos/log.py +237 -0
- memos/mem_agent/base.py +19 -0
- memos/mem_agent/deepsearch_agent.py +391 -0
- memos/mem_agent/factory.py +36 -0
- memos/mem_chat/__init__.py +0 -0
- memos/mem_chat/base.py +30 -0
- memos/mem_chat/factory.py +21 -0
- memos/mem_chat/simple.py +200 -0
- memos/mem_cube/__init__.py +0 -0
- memos/mem_cube/base.py +30 -0
- memos/mem_cube/general.py +240 -0
- memos/mem_cube/navie.py +172 -0
- memos/mem_cube/utils.py +169 -0
- memos/mem_feedback/base.py +15 -0
- memos/mem_feedback/feedback.py +1192 -0
- memos/mem_feedback/simple_feedback.py +40 -0
- memos/mem_feedback/utils.py +230 -0
- memos/mem_os/client.py +5 -0
- memos/mem_os/core.py +1203 -0
- memos/mem_os/main.py +582 -0
- memos/mem_os/product.py +1608 -0
- memos/mem_os/product_server.py +455 -0
- memos/mem_os/utils/default_config.py +359 -0
- memos/mem_os/utils/format_utils.py +1403 -0
- memos/mem_os/utils/reference_utils.py +162 -0
- memos/mem_reader/__init__.py +0 -0
- memos/mem_reader/base.py +47 -0
- memos/mem_reader/factory.py +53 -0
- memos/mem_reader/memory.py +298 -0
- memos/mem_reader/multi_modal_struct.py +965 -0
- memos/mem_reader/read_multi_modal/__init__.py +43 -0
- memos/mem_reader/read_multi_modal/assistant_parser.py +311 -0
- memos/mem_reader/read_multi_modal/base.py +273 -0
- memos/mem_reader/read_multi_modal/file_content_parser.py +826 -0
- memos/mem_reader/read_multi_modal/image_parser.py +359 -0
- memos/mem_reader/read_multi_modal/multi_modal_parser.py +252 -0
- memos/mem_reader/read_multi_modal/string_parser.py +139 -0
- memos/mem_reader/read_multi_modal/system_parser.py +327 -0
- memos/mem_reader/read_multi_modal/text_content_parser.py +131 -0
- memos/mem_reader/read_multi_modal/tool_parser.py +210 -0
- memos/mem_reader/read_multi_modal/user_parser.py +218 -0
- memos/mem_reader/read_multi_modal/utils.py +358 -0
- memos/mem_reader/simple_struct.py +912 -0
- memos/mem_reader/strategy_struct.py +163 -0
- memos/mem_reader/utils.py +157 -0
- memos/mem_scheduler/__init__.py +0 -0
- memos/mem_scheduler/analyzer/__init__.py +0 -0
- memos/mem_scheduler/analyzer/api_analyzer.py +714 -0
- memos/mem_scheduler/analyzer/eval_analyzer.py +219 -0
- memos/mem_scheduler/analyzer/mos_for_test_scheduler.py +571 -0
- memos/mem_scheduler/analyzer/scheduler_for_eval.py +280 -0
- memos/mem_scheduler/base_scheduler.py +1319 -0
- memos/mem_scheduler/general_modules/__init__.py +0 -0
- memos/mem_scheduler/general_modules/api_misc.py +137 -0
- memos/mem_scheduler/general_modules/base.py +80 -0
- memos/mem_scheduler/general_modules/init_components_for_scheduler.py +425 -0
- memos/mem_scheduler/general_modules/misc.py +313 -0
- memos/mem_scheduler/general_modules/scheduler_logger.py +389 -0
- memos/mem_scheduler/general_modules/task_threads.py +315 -0
- memos/mem_scheduler/general_scheduler.py +1495 -0
- memos/mem_scheduler/memory_manage_modules/__init__.py +5 -0
- memos/mem_scheduler/memory_manage_modules/memory_filter.py +306 -0
- memos/mem_scheduler/memory_manage_modules/retriever.py +547 -0
- memos/mem_scheduler/monitors/__init__.py +0 -0
- memos/mem_scheduler/monitors/dispatcher_monitor.py +366 -0
- memos/mem_scheduler/monitors/general_monitor.py +394 -0
- memos/mem_scheduler/monitors/task_schedule_monitor.py +254 -0
- memos/mem_scheduler/optimized_scheduler.py +410 -0
- memos/mem_scheduler/orm_modules/__init__.py +0 -0
- memos/mem_scheduler/orm_modules/api_redis_model.py +518 -0
- memos/mem_scheduler/orm_modules/base_model.py +729 -0
- memos/mem_scheduler/orm_modules/monitor_models.py +261 -0
- memos/mem_scheduler/orm_modules/redis_model.py +699 -0
- memos/mem_scheduler/scheduler_factory.py +23 -0
- memos/mem_scheduler/schemas/__init__.py +0 -0
- memos/mem_scheduler/schemas/analyzer_schemas.py +52 -0
- memos/mem_scheduler/schemas/api_schemas.py +233 -0
- memos/mem_scheduler/schemas/general_schemas.py +55 -0
- memos/mem_scheduler/schemas/message_schemas.py +173 -0
- memos/mem_scheduler/schemas/monitor_schemas.py +406 -0
- memos/mem_scheduler/schemas/task_schemas.py +132 -0
- memos/mem_scheduler/task_schedule_modules/__init__.py +0 -0
- memos/mem_scheduler/task_schedule_modules/dispatcher.py +740 -0
- memos/mem_scheduler/task_schedule_modules/local_queue.py +247 -0
- memos/mem_scheduler/task_schedule_modules/orchestrator.py +74 -0
- memos/mem_scheduler/task_schedule_modules/redis_queue.py +1385 -0
- memos/mem_scheduler/task_schedule_modules/task_queue.py +162 -0
- memos/mem_scheduler/utils/__init__.py +0 -0
- memos/mem_scheduler/utils/api_utils.py +77 -0
- memos/mem_scheduler/utils/config_utils.py +100 -0
- memos/mem_scheduler/utils/db_utils.py +50 -0
- memos/mem_scheduler/utils/filter_utils.py +176 -0
- memos/mem_scheduler/utils/metrics.py +125 -0
- memos/mem_scheduler/utils/misc_utils.py +290 -0
- memos/mem_scheduler/utils/monitor_event_utils.py +67 -0
- memos/mem_scheduler/utils/status_tracker.py +229 -0
- memos/mem_scheduler/webservice_modules/__init__.py +0 -0
- memos/mem_scheduler/webservice_modules/rabbitmq_service.py +485 -0
- memos/mem_scheduler/webservice_modules/redis_service.py +380 -0
- memos/mem_user/factory.py +94 -0
- memos/mem_user/mysql_persistent_user_manager.py +271 -0
- memos/mem_user/mysql_user_manager.py +502 -0
- memos/mem_user/persistent_factory.py +98 -0
- memos/mem_user/persistent_user_manager.py +260 -0
- memos/mem_user/redis_persistent_user_manager.py +225 -0
- memos/mem_user/user_manager.py +488 -0
- memos/memories/__init__.py +0 -0
- memos/memories/activation/__init__.py +0 -0
- memos/memories/activation/base.py +42 -0
- memos/memories/activation/item.py +56 -0
- memos/memories/activation/kv.py +292 -0
- memos/memories/activation/vllmkv.py +219 -0
- memos/memories/base.py +19 -0
- memos/memories/factory.py +42 -0
- memos/memories/parametric/__init__.py +0 -0
- memos/memories/parametric/base.py +19 -0
- memos/memories/parametric/item.py +11 -0
- memos/memories/parametric/lora.py +41 -0
- memos/memories/textual/__init__.py +0 -0
- memos/memories/textual/base.py +92 -0
- memos/memories/textual/general.py +236 -0
- memos/memories/textual/item.py +304 -0
- memos/memories/textual/naive.py +187 -0
- memos/memories/textual/prefer_text_memory/__init__.py +0 -0
- memos/memories/textual/prefer_text_memory/adder.py +504 -0
- memos/memories/textual/prefer_text_memory/config.py +106 -0
- memos/memories/textual/prefer_text_memory/extractor.py +221 -0
- memos/memories/textual/prefer_text_memory/factory.py +85 -0
- memos/memories/textual/prefer_text_memory/retrievers.py +177 -0
- memos/memories/textual/prefer_text_memory/spliter.py +132 -0
- memos/memories/textual/prefer_text_memory/utils.py +93 -0
- memos/memories/textual/preference.py +344 -0
- memos/memories/textual/simple_preference.py +161 -0
- memos/memories/textual/simple_tree.py +69 -0
- memos/memories/textual/tree.py +459 -0
- memos/memories/textual/tree_text_memory/__init__.py +0 -0
- memos/memories/textual/tree_text_memory/organize/__init__.py +0 -0
- memos/memories/textual/tree_text_memory/organize/handler.py +184 -0
- memos/memories/textual/tree_text_memory/organize/manager.py +518 -0
- memos/memories/textual/tree_text_memory/organize/relation_reason_detector.py +238 -0
- memos/memories/textual/tree_text_memory/organize/reorganizer.py +622 -0
- memos/memories/textual/tree_text_memory/retrieve/__init__.py +0 -0
- memos/memories/textual/tree_text_memory/retrieve/advanced_searcher.py +364 -0
- memos/memories/textual/tree_text_memory/retrieve/bm25_util.py +186 -0
- memos/memories/textual/tree_text_memory/retrieve/bochasearch.py +419 -0
- memos/memories/textual/tree_text_memory/retrieve/internet_retriever.py +270 -0
- memos/memories/textual/tree_text_memory/retrieve/internet_retriever_factory.py +102 -0
- memos/memories/textual/tree_text_memory/retrieve/reasoner.py +61 -0
- memos/memories/textual/tree_text_memory/retrieve/recall.py +497 -0
- memos/memories/textual/tree_text_memory/retrieve/reranker.py +111 -0
- memos/memories/textual/tree_text_memory/retrieve/retrieval_mid_structs.py +16 -0
- memos/memories/textual/tree_text_memory/retrieve/retrieve_utils.py +472 -0
- memos/memories/textual/tree_text_memory/retrieve/searcher.py +848 -0
- memos/memories/textual/tree_text_memory/retrieve/task_goal_parser.py +135 -0
- memos/memories/textual/tree_text_memory/retrieve/utils.py +54 -0
- memos/memories/textual/tree_text_memory/retrieve/xinyusearch.py +387 -0
- memos/memos_tools/dinding_report_bot.py +453 -0
- memos/memos_tools/lockfree_dict.py +120 -0
- memos/memos_tools/notification_service.py +44 -0
- memos/memos_tools/notification_utils.py +142 -0
- memos/memos_tools/singleton.py +174 -0
- memos/memos_tools/thread_safe_dict.py +310 -0
- memos/memos_tools/thread_safe_dict_segment.py +382 -0
- memos/multi_mem_cube/__init__.py +0 -0
- memos/multi_mem_cube/composite_cube.py +86 -0
- memos/multi_mem_cube/single_cube.py +874 -0
- memos/multi_mem_cube/views.py +54 -0
- memos/parsers/__init__.py +0 -0
- memos/parsers/base.py +15 -0
- memos/parsers/factory.py +21 -0
- memos/parsers/markitdown.py +28 -0
- memos/reranker/__init__.py +4 -0
- memos/reranker/base.py +25 -0
- memos/reranker/concat.py +103 -0
- memos/reranker/cosine_local.py +102 -0
- memos/reranker/factory.py +72 -0
- memos/reranker/http_bge.py +324 -0
- memos/reranker/http_bge_strategy.py +327 -0
- memos/reranker/noop.py +19 -0
- memos/reranker/strategies/__init__.py +4 -0
- memos/reranker/strategies/base.py +61 -0
- memos/reranker/strategies/concat_background.py +94 -0
- memos/reranker/strategies/concat_docsource.py +110 -0
- memos/reranker/strategies/dialogue_common.py +109 -0
- memos/reranker/strategies/factory.py +31 -0
- memos/reranker/strategies/single_turn.py +107 -0
- memos/reranker/strategies/singleturn_outmem.py +98 -0
- memos/settings.py +10 -0
- memos/templates/__init__.py +0 -0
- memos/templates/advanced_search_prompts.py +211 -0
- memos/templates/cloud_service_prompt.py +107 -0
- memos/templates/instruction_completion.py +66 -0
- memos/templates/mem_agent_prompts.py +85 -0
- memos/templates/mem_feedback_prompts.py +822 -0
- memos/templates/mem_reader_prompts.py +1096 -0
- memos/templates/mem_reader_strategy_prompts.py +238 -0
- memos/templates/mem_scheduler_prompts.py +626 -0
- memos/templates/mem_search_prompts.py +93 -0
- memos/templates/mos_prompts.py +403 -0
- memos/templates/prefer_complete_prompt.py +735 -0
- memos/templates/tool_mem_prompts.py +139 -0
- memos/templates/tree_reorganize_prompts.py +230 -0
- memos/types/__init__.py +34 -0
- memos/types/general_types.py +151 -0
- memos/types/openai_chat_completion_types/__init__.py +15 -0
- memos/types/openai_chat_completion_types/chat_completion_assistant_message_param.py +56 -0
- memos/types/openai_chat_completion_types/chat_completion_content_part_image_param.py +27 -0
- memos/types/openai_chat_completion_types/chat_completion_content_part_input_audio_param.py +23 -0
- memos/types/openai_chat_completion_types/chat_completion_content_part_param.py +43 -0
- memos/types/openai_chat_completion_types/chat_completion_content_part_refusal_param.py +16 -0
- memos/types/openai_chat_completion_types/chat_completion_content_part_text_param.py +16 -0
- memos/types/openai_chat_completion_types/chat_completion_message_custom_tool_call_param.py +27 -0
- memos/types/openai_chat_completion_types/chat_completion_message_function_tool_call_param.py +32 -0
- memos/types/openai_chat_completion_types/chat_completion_message_param.py +18 -0
- memos/types/openai_chat_completion_types/chat_completion_message_tool_call_union_param.py +15 -0
- memos/types/openai_chat_completion_types/chat_completion_system_message_param.py +36 -0
- memos/types/openai_chat_completion_types/chat_completion_tool_message_param.py +30 -0
- memos/types/openai_chat_completion_types/chat_completion_user_message_param.py +34 -0
- memos/utils.py +123 -0
- memos/vec_dbs/__init__.py +0 -0
- memos/vec_dbs/base.py +117 -0
- memos/vec_dbs/factory.py +23 -0
- memos/vec_dbs/item.py +50 -0
- memos/vec_dbs/milvus.py +654 -0
- memos/vec_dbs/qdrant.py +355 -0
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from collections import OrderedDict
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
from memos.api.product_models import APISearchRequest
|
|
8
|
+
from memos.configs.mem_scheduler import GeneralSchedulerConfig
|
|
9
|
+
from memos.log import get_logger
|
|
10
|
+
from memos.mem_cube.general import GeneralMemCube
|
|
11
|
+
from memos.mem_cube.navie import NaiveMemCube
|
|
12
|
+
from memos.mem_scheduler.general_modules.api_misc import SchedulerAPIModule
|
|
13
|
+
from memos.mem_scheduler.general_scheduler import GeneralScheduler
|
|
14
|
+
from memos.mem_scheduler.schemas.message_schemas import ScheduleMessageItem
|
|
15
|
+
from memos.mem_scheduler.schemas.task_schemas import (
|
|
16
|
+
API_MIX_SEARCH_TASK_LABEL,
|
|
17
|
+
)
|
|
18
|
+
from memos.mem_scheduler.utils.api_utils import format_textual_memory_item
|
|
19
|
+
from memos.mem_scheduler.utils.db_utils import get_utc_now
|
|
20
|
+
from memos.mem_scheduler.utils.misc_utils import group_messages_by_user_and_mem_cube
|
|
21
|
+
from memos.memories.textual.tree import TextualMemoryItem, TreeTextMemory
|
|
22
|
+
from memos.types import (
|
|
23
|
+
MemCubeID,
|
|
24
|
+
SearchMode,
|
|
25
|
+
UserContext,
|
|
26
|
+
UserID,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
if TYPE_CHECKING:
|
|
31
|
+
from memos.mem_scheduler.schemas.monitor_schemas import MemoryMonitorItem
|
|
32
|
+
|
|
33
|
+
logger = get_logger(__name__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class OptimizedScheduler(GeneralScheduler):
|
|
37
|
+
"""Optimized scheduler with improved working memory management and support for api"""
|
|
38
|
+
|
|
39
|
+
def __init__(self, config: GeneralSchedulerConfig):
|
|
40
|
+
super().__init__(config)
|
|
41
|
+
self.window_size = int(os.getenv("API_SEARCH_WINDOW_SIZE", 5))
|
|
42
|
+
self.history_memory_turns = int(os.getenv("API_SEARCH_HISTORY_TURNS", 5))
|
|
43
|
+
self.session_counter = OrderedDict()
|
|
44
|
+
self.max_session_history = 5
|
|
45
|
+
|
|
46
|
+
if self.config.use_redis_queue:
|
|
47
|
+
self.api_module = SchedulerAPIModule(
|
|
48
|
+
window_size=self.window_size,
|
|
49
|
+
history_memory_turns=self.history_memory_turns,
|
|
50
|
+
)
|
|
51
|
+
else:
|
|
52
|
+
self.api_module = None
|
|
53
|
+
|
|
54
|
+
self.register_handlers(
|
|
55
|
+
{
|
|
56
|
+
API_MIX_SEARCH_TASK_LABEL: self._api_mix_search_message_consumer,
|
|
57
|
+
}
|
|
58
|
+
)
|
|
59
|
+
self.searcher = None
|
|
60
|
+
self.reranker = None
|
|
61
|
+
self.text_mem = None
|
|
62
|
+
|
|
63
|
+
def submit_memory_history_async_task(
|
|
64
|
+
self,
|
|
65
|
+
search_req: APISearchRequest,
|
|
66
|
+
user_context: UserContext,
|
|
67
|
+
memories_to_store: dict | None = None,
|
|
68
|
+
session_id: str | None = None,
|
|
69
|
+
):
|
|
70
|
+
# Create message for async fine search
|
|
71
|
+
message_content = {
|
|
72
|
+
"search_req": {
|
|
73
|
+
"query": search_req.query,
|
|
74
|
+
"user_id": search_req.user_id,
|
|
75
|
+
"session_id": session_id,
|
|
76
|
+
"top_k": search_req.top_k,
|
|
77
|
+
"internet_search": search_req.internet_search,
|
|
78
|
+
"chat_history": search_req.chat_history,
|
|
79
|
+
},
|
|
80
|
+
"user_context": {"mem_cube_id": user_context.mem_cube_id},
|
|
81
|
+
"memories_to_store": memories_to_store,
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async_task_id = f"mix_search_{search_req.user_id}_{get_utc_now().timestamp()}"
|
|
85
|
+
|
|
86
|
+
message = ScheduleMessageItem(
|
|
87
|
+
item_id=async_task_id,
|
|
88
|
+
user_id=search_req.user_id,
|
|
89
|
+
mem_cube_id=user_context.mem_cube_id,
|
|
90
|
+
label=API_MIX_SEARCH_TASK_LABEL,
|
|
91
|
+
content=json.dumps(message_content),
|
|
92
|
+
timestamp=get_utc_now(),
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Submit async task
|
|
96
|
+
self.memos_message_queue.submit_messages([message])
|
|
97
|
+
logger.info(f"Submitted async fine search task for user {search_req.user_id}")
|
|
98
|
+
return async_task_id
|
|
99
|
+
|
|
100
|
+
def search_memories(
|
|
101
|
+
self,
|
|
102
|
+
search_req: APISearchRequest,
|
|
103
|
+
user_context: UserContext,
|
|
104
|
+
mem_cube: NaiveMemCube,
|
|
105
|
+
mode: SearchMode,
|
|
106
|
+
):
|
|
107
|
+
"""Fine search memories function copied from server_router to avoid circular import"""
|
|
108
|
+
target_session_id = search_req.session_id
|
|
109
|
+
if not target_session_id:
|
|
110
|
+
target_session_id = "default_session"
|
|
111
|
+
search_priority = {"session_id": search_req.session_id} if search_req.session_id else None
|
|
112
|
+
search_filter = search_req.filter
|
|
113
|
+
|
|
114
|
+
# Create MemCube and perform search
|
|
115
|
+
search_results = mem_cube.text_mem.search(
|
|
116
|
+
query=search_req.query,
|
|
117
|
+
user_name=user_context.mem_cube_id,
|
|
118
|
+
top_k=search_req.top_k,
|
|
119
|
+
mode=mode,
|
|
120
|
+
manual_close_internet=not search_req.internet_search,
|
|
121
|
+
search_filter=search_filter,
|
|
122
|
+
search_priority=search_priority,
|
|
123
|
+
info={
|
|
124
|
+
"user_id": search_req.user_id,
|
|
125
|
+
"session_id": target_session_id,
|
|
126
|
+
"chat_history": search_req.chat_history,
|
|
127
|
+
},
|
|
128
|
+
)
|
|
129
|
+
return search_results
|
|
130
|
+
|
|
131
|
+
def mix_search_memories(
|
|
132
|
+
self,
|
|
133
|
+
search_req: APISearchRequest,
|
|
134
|
+
user_context: UserContext,
|
|
135
|
+
) -> list[dict[str, Any]]:
|
|
136
|
+
"""
|
|
137
|
+
Mix search memories: fast search + async fine search
|
|
138
|
+
"""
|
|
139
|
+
logger.info(
|
|
140
|
+
f"Mix searching memories for user {search_req.user_id} with query: {search_req.query}"
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
if not self.config.use_redis_queue:
|
|
144
|
+
logger.warning(
|
|
145
|
+
"Redis queue is not enabled. Running in degraded mode: "
|
|
146
|
+
"FAST search only, no history memory reranking, no async updates."
|
|
147
|
+
)
|
|
148
|
+
memories = self.search_memories(
|
|
149
|
+
search_req=search_req,
|
|
150
|
+
user_context=user_context,
|
|
151
|
+
mem_cube=self.mem_cube,
|
|
152
|
+
mode=SearchMode.FAST,
|
|
153
|
+
)
|
|
154
|
+
return [
|
|
155
|
+
format_textual_memory_item(item, include_embedding=search_req.dedup == "sim")
|
|
156
|
+
for item in memories
|
|
157
|
+
]
|
|
158
|
+
|
|
159
|
+
# Get mem_cube for fast search
|
|
160
|
+
target_session_id = search_req.session_id
|
|
161
|
+
if not target_session_id:
|
|
162
|
+
target_session_id = "default_session"
|
|
163
|
+
search_priority = {"session_id": search_req.session_id} if search_req.session_id else None
|
|
164
|
+
search_filter = search_req.filter
|
|
165
|
+
|
|
166
|
+
# Rerank Memories - reranker expects TextualMemoryItem objects
|
|
167
|
+
|
|
168
|
+
info = {
|
|
169
|
+
"user_id": search_req.user_id,
|
|
170
|
+
"session_id": target_session_id,
|
|
171
|
+
"chat_history": search_req.chat_history,
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
raw_retrieved_memories = self.searcher.retrieve(
|
|
175
|
+
query=search_req.query,
|
|
176
|
+
user_name=user_context.mem_cube_id,
|
|
177
|
+
top_k=search_req.top_k,
|
|
178
|
+
mode=SearchMode.FINE,
|
|
179
|
+
manual_close_internet=not search_req.internet_search,
|
|
180
|
+
moscube=search_req.moscube,
|
|
181
|
+
search_filter=search_filter,
|
|
182
|
+
search_priority=search_priority,
|
|
183
|
+
info=info,
|
|
184
|
+
search_tool_memory=search_req.search_tool_memory,
|
|
185
|
+
tool_mem_top_k=search_req.tool_mem_top_k,
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# Try to get pre-computed memories if available
|
|
189
|
+
history_memories = self.api_module.get_history_memories(
|
|
190
|
+
user_id=search_req.user_id,
|
|
191
|
+
mem_cube_id=user_context.mem_cube_id,
|
|
192
|
+
turns=self.history_memory_turns,
|
|
193
|
+
)
|
|
194
|
+
logger.info(f"Found {len(history_memories)} history memories.")
|
|
195
|
+
|
|
196
|
+
# if history memories can directly answer
|
|
197
|
+
sorted_history_memories = self.reranker.rerank(
|
|
198
|
+
query=search_req.query, # Use search_req.query instead of undefined query
|
|
199
|
+
graph_results=history_memories, # Pass TextualMemoryItem objects directly
|
|
200
|
+
top_k=search_req.top_k, # Use search_req.top_k instead of undefined top_k
|
|
201
|
+
search_filter=search_filter,
|
|
202
|
+
)
|
|
203
|
+
logger.info(f"Reranked {len(sorted_history_memories)} history memories.")
|
|
204
|
+
merged_memories = self.searcher.post_retrieve(
|
|
205
|
+
retrieved_results=raw_retrieved_memories + sorted_history_memories,
|
|
206
|
+
top_k=search_req.top_k,
|
|
207
|
+
user_name=user_context.mem_cube_id,
|
|
208
|
+
info=info,
|
|
209
|
+
search_tool_memory=search_req.search_tool_memory,
|
|
210
|
+
tool_mem_top_k=search_req.tool_mem_top_k,
|
|
211
|
+
dedup=search_req.dedup,
|
|
212
|
+
)
|
|
213
|
+
memories = merged_memories[: search_req.top_k]
|
|
214
|
+
|
|
215
|
+
formatted_memories = [
|
|
216
|
+
format_textual_memory_item(item, include_embedding=search_req.dedup == "sim")
|
|
217
|
+
for item in memories
|
|
218
|
+
]
|
|
219
|
+
self.submit_memory_history_async_task(
|
|
220
|
+
search_req=search_req,
|
|
221
|
+
user_context=user_context,
|
|
222
|
+
memories_to_store={
|
|
223
|
+
"memories": [one.to_dict() for one in memories],
|
|
224
|
+
"formatted_memories": formatted_memories,
|
|
225
|
+
},
|
|
226
|
+
)
|
|
227
|
+
return formatted_memories
|
|
228
|
+
|
|
229
|
+
def update_search_memories_to_redis(
|
|
230
|
+
self,
|
|
231
|
+
messages: list[ScheduleMessageItem],
|
|
232
|
+
):
|
|
233
|
+
for msg in messages:
|
|
234
|
+
content_dict = json.loads(msg.content)
|
|
235
|
+
search_req = content_dict["search_req"]
|
|
236
|
+
user_context = content_dict["user_context"]
|
|
237
|
+
session_id = search_req.get("session_id")
|
|
238
|
+
if session_id:
|
|
239
|
+
if session_id not in self.session_counter:
|
|
240
|
+
self.session_counter[session_id] = 0
|
|
241
|
+
else:
|
|
242
|
+
self.session_counter[session_id] += 1
|
|
243
|
+
session_turn = self.session_counter[session_id]
|
|
244
|
+
|
|
245
|
+
# Move the current session to the end to mark it as recently used
|
|
246
|
+
self.session_counter.move_to_end(session_id)
|
|
247
|
+
|
|
248
|
+
# If the counter exceeds the max size, remove the oldest item
|
|
249
|
+
if len(self.session_counter) > self.max_session_history:
|
|
250
|
+
self.session_counter.popitem(last=False)
|
|
251
|
+
else:
|
|
252
|
+
session_turn = 0
|
|
253
|
+
|
|
254
|
+
memories_to_store = content_dict["memories_to_store"]
|
|
255
|
+
if memories_to_store is None:
|
|
256
|
+
memories: list[TextualMemoryItem] = self.search_memories(
|
|
257
|
+
search_req=APISearchRequest(**content_dict["search_req"]),
|
|
258
|
+
user_context=UserContext(**content_dict["user_context"]),
|
|
259
|
+
mem_cube=self.mem_cube,
|
|
260
|
+
mode=SearchMode.FAST,
|
|
261
|
+
)
|
|
262
|
+
formatted_memories = [
|
|
263
|
+
format_textual_memory_item(data, include_embedding=search_req.dedup == "sim")
|
|
264
|
+
for data in memories
|
|
265
|
+
]
|
|
266
|
+
else:
|
|
267
|
+
memories = [
|
|
268
|
+
TextualMemoryItem.from_dict(one) for one in memories_to_store["memories"]
|
|
269
|
+
]
|
|
270
|
+
formatted_memories = memories_to_store["formatted_memories"]
|
|
271
|
+
|
|
272
|
+
# Sync search data to Redis
|
|
273
|
+
self.api_module.sync_search_data(
|
|
274
|
+
item_id=msg.item_id,
|
|
275
|
+
user_id=search_req["user_id"],
|
|
276
|
+
mem_cube_id=user_context["mem_cube_id"],
|
|
277
|
+
query=search_req["query"],
|
|
278
|
+
memories=memories,
|
|
279
|
+
formatted_memories=formatted_memories,
|
|
280
|
+
session_id=session_id,
|
|
281
|
+
conversation_turn=session_turn,
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
def _api_mix_search_message_consumer(self, messages: list[ScheduleMessageItem]) -> None:
|
|
285
|
+
"""
|
|
286
|
+
Process and handle query trigger messages from the queue.
|
|
287
|
+
|
|
288
|
+
Args:
|
|
289
|
+
messages: List of query messages to process
|
|
290
|
+
"""
|
|
291
|
+
logger.info(f"Messages {messages} assigned to {API_MIX_SEARCH_TASK_LABEL} handler.")
|
|
292
|
+
|
|
293
|
+
# Process the query in a session turn
|
|
294
|
+
grouped_messages = group_messages_by_user_and_mem_cube(messages)
|
|
295
|
+
|
|
296
|
+
self.validate_schedule_messages(messages=messages, label=API_MIX_SEARCH_TASK_LABEL)
|
|
297
|
+
|
|
298
|
+
for user_id in grouped_messages:
|
|
299
|
+
for mem_cube_id in grouped_messages[user_id]:
|
|
300
|
+
messages = grouped_messages[user_id][mem_cube_id]
|
|
301
|
+
if len(messages) == 0:
|
|
302
|
+
return
|
|
303
|
+
self.update_search_memories_to_redis(messages=messages)
|
|
304
|
+
|
|
305
|
+
def replace_working_memory(
|
|
306
|
+
self,
|
|
307
|
+
user_id: UserID | str,
|
|
308
|
+
mem_cube_id: MemCubeID | str,
|
|
309
|
+
mem_cube: GeneralMemCube,
|
|
310
|
+
original_memory: list[TextualMemoryItem],
|
|
311
|
+
new_memory: list[TextualMemoryItem],
|
|
312
|
+
) -> None | list[TextualMemoryItem]:
|
|
313
|
+
"""Replace working memory with new memories after reranking."""
|
|
314
|
+
text_mem_base = mem_cube.text_mem
|
|
315
|
+
if isinstance(text_mem_base, TreeTextMemory):
|
|
316
|
+
text_mem_base: TreeTextMemory = text_mem_base
|
|
317
|
+
|
|
318
|
+
# process rerank memories with llm
|
|
319
|
+
query_db_manager = self.monitor.query_monitors[user_id][mem_cube_id]
|
|
320
|
+
# Sync with database to get latest query history
|
|
321
|
+
query_db_manager.sync_with_orm()
|
|
322
|
+
|
|
323
|
+
query_history = query_db_manager.obj.get_queries_with_timesort()
|
|
324
|
+
memories_with_new_order, rerank_success_flag = (
|
|
325
|
+
self.retriever.process_and_rerank_memories(
|
|
326
|
+
queries=query_history,
|
|
327
|
+
original_memory=original_memory,
|
|
328
|
+
new_memory=new_memory,
|
|
329
|
+
top_k=self.top_k,
|
|
330
|
+
)
|
|
331
|
+
)
|
|
332
|
+
|
|
333
|
+
# Apply combined filtering (unrelated + redundant)
|
|
334
|
+
logger.info(
|
|
335
|
+
f"[optimized replace_working_memory] Applying combined unrelated and redundant memory filtering to {len(memories_with_new_order)} memories"
|
|
336
|
+
)
|
|
337
|
+
filtered_memories, filtering_success_flag = (
|
|
338
|
+
self.retriever.filter_unrelated_and_redundant_memories(
|
|
339
|
+
query_history=query_history,
|
|
340
|
+
memories=memories_with_new_order,
|
|
341
|
+
)
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
if filtering_success_flag:
|
|
345
|
+
logger.info(
|
|
346
|
+
f"[optimized replace_working_memory] Combined filtering completed successfully. "
|
|
347
|
+
f"Filtered from {len(memories_with_new_order)} to {len(filtered_memories)} memories"
|
|
348
|
+
)
|
|
349
|
+
memories_with_new_order = filtered_memories
|
|
350
|
+
else:
|
|
351
|
+
logger.warning(
|
|
352
|
+
"[optimized replace_working_memory] Combined filtering failed - keeping memories as fallback. "
|
|
353
|
+
f"Count: {len(memories_with_new_order)}"
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
# Update working memory monitors
|
|
357
|
+
query_keywords = query_db_manager.obj.get_keywords_collections()
|
|
358
|
+
logger.info(
|
|
359
|
+
f"[optimized replace_working_memory] Processing {len(memories_with_new_order)} memories with {len(query_keywords)} query keywords"
|
|
360
|
+
)
|
|
361
|
+
new_working_memory_monitors = self.transform_working_memories_to_monitors(
|
|
362
|
+
query_keywords=query_keywords,
|
|
363
|
+
memories=memories_with_new_order,
|
|
364
|
+
)
|
|
365
|
+
|
|
366
|
+
if not rerank_success_flag:
|
|
367
|
+
for one in new_working_memory_monitors:
|
|
368
|
+
one.sorting_score = 0
|
|
369
|
+
|
|
370
|
+
self.monitor.update_working_memory_monitors(
|
|
371
|
+
new_working_memory_monitors=new_working_memory_monitors,
|
|
372
|
+
user_id=user_id,
|
|
373
|
+
mem_cube_id=mem_cube_id,
|
|
374
|
+
mem_cube=mem_cube,
|
|
375
|
+
)
|
|
376
|
+
logger.info(
|
|
377
|
+
f"[optimized replace_working_memory] update {len(new_working_memory_monitors)} working_memory_monitors"
|
|
378
|
+
)
|
|
379
|
+
try:
|
|
380
|
+
# Use the filtered and reranked memories directly
|
|
381
|
+
text_mem_base.replace_working_memory(
|
|
382
|
+
memories=memories_with_new_order, user_name=mem_cube_id
|
|
383
|
+
)
|
|
384
|
+
except Exception:
|
|
385
|
+
logger.error(
|
|
386
|
+
"[optimized replace_working_memory] text_mem_base.replace_working_memory failed!",
|
|
387
|
+
stack_info=True,
|
|
388
|
+
)
|
|
389
|
+
# Update monitor after replacing working memory
|
|
390
|
+
mem_monitors: list[MemoryMonitorItem] = self.monitor.working_memory_monitors[user_id][
|
|
391
|
+
mem_cube_id
|
|
392
|
+
].obj.get_sorted_mem_monitors(reverse=True)
|
|
393
|
+
new_working_memories = [mem_monitor.tree_memory_item for mem_monitor in mem_monitors]
|
|
394
|
+
|
|
395
|
+
logger.info(
|
|
396
|
+
f"[optimized replace_working_memory] The working memory has been replaced with {len(memories_with_new_order)} new memories."
|
|
397
|
+
)
|
|
398
|
+
self.log_working_memory_replacement(
|
|
399
|
+
original_memory=original_memory,
|
|
400
|
+
new_memory=new_working_memories,
|
|
401
|
+
user_id=user_id,
|
|
402
|
+
mem_cube_id=mem_cube_id,
|
|
403
|
+
mem_cube=mem_cube,
|
|
404
|
+
log_func_callback=self._submit_web_logs,
|
|
405
|
+
)
|
|
406
|
+
else:
|
|
407
|
+
logger.error("memory_base is not supported")
|
|
408
|
+
memories_with_new_order = new_memory
|
|
409
|
+
|
|
410
|
+
return memories_with_new_order
|
|
File without changes
|