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,455 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import time
|
|
3
|
+
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from typing import Literal
|
|
6
|
+
|
|
7
|
+
from memos.context.context import ContextThread
|
|
8
|
+
from memos.llms.base import BaseLLM
|
|
9
|
+
from memos.log import get_logger
|
|
10
|
+
from memos.mem_cube.navie import NaiveMemCube
|
|
11
|
+
from memos.mem_os.product import _format_mem_block
|
|
12
|
+
from memos.mem_reader.base import BaseMemReader
|
|
13
|
+
from memos.memories.textual.item import TextualMemoryItem
|
|
14
|
+
from memos.templates.mos_prompts import (
|
|
15
|
+
get_memos_prompt,
|
|
16
|
+
)
|
|
17
|
+
from memos.types import MessageList
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
logger = get_logger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class MOSServer:
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
mem_reader: BaseMemReader | None = None,
|
|
27
|
+
llm: BaseLLM | None = None,
|
|
28
|
+
online_bot: bool = False,
|
|
29
|
+
):
|
|
30
|
+
self.mem_reader = mem_reader
|
|
31
|
+
self.chat_llm = llm
|
|
32
|
+
self.online_bot = online_bot
|
|
33
|
+
|
|
34
|
+
def chat(
|
|
35
|
+
self,
|
|
36
|
+
query: str,
|
|
37
|
+
user_id: str,
|
|
38
|
+
cube_id: str | None = None,
|
|
39
|
+
mem_cube: NaiveMemCube | None = None,
|
|
40
|
+
history: MessageList | None = None,
|
|
41
|
+
base_prompt: str | None = None,
|
|
42
|
+
internet_search: bool = False,
|
|
43
|
+
moscube: bool = False,
|
|
44
|
+
top_k: int = 10,
|
|
45
|
+
threshold: float = 0.5,
|
|
46
|
+
session_id: str | None = None,
|
|
47
|
+
) -> str:
|
|
48
|
+
"""
|
|
49
|
+
Chat with LLM with memory references and complete response.
|
|
50
|
+
"""
|
|
51
|
+
time_start = time.time()
|
|
52
|
+
memories_result = mem_cube.text_mem.search(
|
|
53
|
+
query=query,
|
|
54
|
+
user_name=cube_id,
|
|
55
|
+
top_k=top_k,
|
|
56
|
+
mode="fine",
|
|
57
|
+
manual_close_internet=not internet_search,
|
|
58
|
+
moscube=moscube,
|
|
59
|
+
info={
|
|
60
|
+
"user_id": user_id,
|
|
61
|
+
"session_id": session_id,
|
|
62
|
+
"chat_history": history,
|
|
63
|
+
},
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
memories_list = []
|
|
67
|
+
if memories_result:
|
|
68
|
+
memories_list = self._filter_memories_by_threshold(memories_result, threshold)
|
|
69
|
+
new_memories_list = []
|
|
70
|
+
for m in memories_list:
|
|
71
|
+
m.metadata.embedding = []
|
|
72
|
+
new_memories_list.append(m)
|
|
73
|
+
memories_list = new_memories_list
|
|
74
|
+
system_prompt = self._build_system_prompt(memories_list, base_prompt)
|
|
75
|
+
|
|
76
|
+
history_info = []
|
|
77
|
+
if history:
|
|
78
|
+
history_info = history[-20:]
|
|
79
|
+
current_messages = [
|
|
80
|
+
{"role": "system", "content": system_prompt},
|
|
81
|
+
*history_info,
|
|
82
|
+
{"role": "user", "content": query},
|
|
83
|
+
]
|
|
84
|
+
response = self.chat_llm.generate(current_messages)
|
|
85
|
+
time_end = time.time()
|
|
86
|
+
self._start_post_chat_processing(
|
|
87
|
+
user_id=user_id,
|
|
88
|
+
cube_id=cube_id,
|
|
89
|
+
session_id=session_id,
|
|
90
|
+
query=query,
|
|
91
|
+
full_response=response,
|
|
92
|
+
system_prompt=system_prompt,
|
|
93
|
+
time_start=time_start,
|
|
94
|
+
time_end=time_end,
|
|
95
|
+
speed_improvement=0.0,
|
|
96
|
+
current_messages=current_messages,
|
|
97
|
+
mem_cube=mem_cube,
|
|
98
|
+
history=history,
|
|
99
|
+
)
|
|
100
|
+
return response, memories_list
|
|
101
|
+
|
|
102
|
+
def add(
|
|
103
|
+
self,
|
|
104
|
+
user_id: str,
|
|
105
|
+
cube_id: str,
|
|
106
|
+
mem_cube: NaiveMemCube,
|
|
107
|
+
messages: MessageList,
|
|
108
|
+
session_id: str | None = None,
|
|
109
|
+
history: MessageList | None = None,
|
|
110
|
+
) -> list[str]:
|
|
111
|
+
memories = self.mem_reader.get_memory(
|
|
112
|
+
[messages],
|
|
113
|
+
type="chat",
|
|
114
|
+
info={
|
|
115
|
+
"user_id": user_id,
|
|
116
|
+
"session_id": session_id,
|
|
117
|
+
"chat_history": history,
|
|
118
|
+
},
|
|
119
|
+
)
|
|
120
|
+
flattened_memories = [mm for m in memories for mm in m]
|
|
121
|
+
mem_id_list: list[str] = mem_cube.text_mem.add(
|
|
122
|
+
flattened_memories,
|
|
123
|
+
user_name=cube_id,
|
|
124
|
+
)
|
|
125
|
+
return mem_id_list
|
|
126
|
+
|
|
127
|
+
def search(
|
|
128
|
+
self,
|
|
129
|
+
user_id: str,
|
|
130
|
+
cube_id: str,
|
|
131
|
+
session_id: str | None = None,
|
|
132
|
+
) -> None:
|
|
133
|
+
NotImplementedError("Not implemented")
|
|
134
|
+
|
|
135
|
+
def _filter_memories_by_threshold(
|
|
136
|
+
self,
|
|
137
|
+
memories: list[TextualMemoryItem],
|
|
138
|
+
threshold: float = 0.30,
|
|
139
|
+
min_num: int = 3,
|
|
140
|
+
memory_type: Literal["OuterMemory"] = "OuterMemory",
|
|
141
|
+
) -> list[TextualMemoryItem]:
|
|
142
|
+
"""
|
|
143
|
+
Filter memories by threshold and type, at least min_num memories for Non-OuterMemory.
|
|
144
|
+
Args:
|
|
145
|
+
memories: list[TextualMemoryItem],
|
|
146
|
+
threshold: float,
|
|
147
|
+
min_num: int,
|
|
148
|
+
memory_type: Literal["OuterMemory"],
|
|
149
|
+
Returns:
|
|
150
|
+
list[TextualMemoryItem]
|
|
151
|
+
"""
|
|
152
|
+
sorted_memories = sorted(memories, key=lambda m: m.metadata.relativity, reverse=True)
|
|
153
|
+
filtered_person = [m for m in memories if m.metadata.memory_type != memory_type]
|
|
154
|
+
filtered_outer = [m for m in memories if m.metadata.memory_type == memory_type]
|
|
155
|
+
filtered = []
|
|
156
|
+
per_memory_count = 0
|
|
157
|
+
for m in sorted_memories:
|
|
158
|
+
if m.metadata.relativity >= threshold:
|
|
159
|
+
if m.metadata.memory_type != memory_type:
|
|
160
|
+
per_memory_count += 1
|
|
161
|
+
filtered.append(m)
|
|
162
|
+
if len(filtered) < min_num:
|
|
163
|
+
filtered = filtered_person[:min_num] + filtered_outer[:min_num]
|
|
164
|
+
else:
|
|
165
|
+
if per_memory_count < min_num:
|
|
166
|
+
filtered += filtered_person[per_memory_count:min_num]
|
|
167
|
+
filtered_memory = sorted(filtered, key=lambda m: m.metadata.relativity, reverse=True)
|
|
168
|
+
return filtered_memory
|
|
169
|
+
|
|
170
|
+
def _build_base_system_prompt(
|
|
171
|
+
self,
|
|
172
|
+
base_prompt: str | None = None,
|
|
173
|
+
tone: str = "friendly",
|
|
174
|
+
verbosity: str = "mid",
|
|
175
|
+
mode: str = "enhance",
|
|
176
|
+
) -> str:
|
|
177
|
+
"""
|
|
178
|
+
Build base system prompt without memory references.
|
|
179
|
+
"""
|
|
180
|
+
now = datetime.now()
|
|
181
|
+
formatted_date = now.strftime("%Y-%m-%d (%A)")
|
|
182
|
+
sys_body = get_memos_prompt(date=formatted_date, tone=tone, verbosity=verbosity, mode=mode)
|
|
183
|
+
prefix = (base_prompt.strip() + "\n\n") if base_prompt else ""
|
|
184
|
+
return prefix + sys_body
|
|
185
|
+
|
|
186
|
+
def _build_system_prompt(
|
|
187
|
+
self,
|
|
188
|
+
memories: list[TextualMemoryItem] | list[str] | None = None,
|
|
189
|
+
base_prompt: str | None = None,
|
|
190
|
+
**kwargs,
|
|
191
|
+
) -> str:
|
|
192
|
+
"""Build system prompt with optional memories context."""
|
|
193
|
+
if base_prompt is None:
|
|
194
|
+
base_prompt = (
|
|
195
|
+
"You are a knowledgeable and helpful AI assistant. "
|
|
196
|
+
"You have access to conversation memories that help you provide more personalized responses. "
|
|
197
|
+
"Use the memories to understand the user's context, preferences, and past interactions. "
|
|
198
|
+
"If memories are provided, reference them naturally when relevant, but don't explicitly mention having memories."
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
memory_context = ""
|
|
202
|
+
if memories:
|
|
203
|
+
memory_list = []
|
|
204
|
+
for i, memory in enumerate(memories, 1):
|
|
205
|
+
if isinstance(memory, TextualMemoryItem):
|
|
206
|
+
text_memory = memory.memory
|
|
207
|
+
else:
|
|
208
|
+
if not isinstance(memory, str):
|
|
209
|
+
logger.error("Unexpected memory type.")
|
|
210
|
+
text_memory = memory
|
|
211
|
+
memory_list.append(f"{i}. {text_memory}")
|
|
212
|
+
memory_context = "\n".join(memory_list)
|
|
213
|
+
|
|
214
|
+
if "{memories}" in base_prompt:
|
|
215
|
+
return base_prompt.format(memories=memory_context)
|
|
216
|
+
elif base_prompt and memories:
|
|
217
|
+
# For backward compatibility, append memories if no placeholder is found
|
|
218
|
+
memory_context_with_header = "\n\n## Memories:\n" + memory_context
|
|
219
|
+
return base_prompt + memory_context_with_header
|
|
220
|
+
return base_prompt
|
|
221
|
+
|
|
222
|
+
def _build_memory_context(
|
|
223
|
+
self,
|
|
224
|
+
memories_all: list[TextualMemoryItem],
|
|
225
|
+
mode: str = "enhance",
|
|
226
|
+
) -> str:
|
|
227
|
+
"""
|
|
228
|
+
Build memory context to be included in user message.
|
|
229
|
+
"""
|
|
230
|
+
if not memories_all:
|
|
231
|
+
return ""
|
|
232
|
+
|
|
233
|
+
mem_block_o, mem_block_p = _format_mem_block(memories_all)
|
|
234
|
+
|
|
235
|
+
if mode == "enhance":
|
|
236
|
+
return (
|
|
237
|
+
"# Memories\n## PersonalMemory (ordered)\n"
|
|
238
|
+
+ mem_block_p
|
|
239
|
+
+ "\n## OuterMemory (ordered)\n"
|
|
240
|
+
+ mem_block_o
|
|
241
|
+
+ "\n\n"
|
|
242
|
+
)
|
|
243
|
+
else:
|
|
244
|
+
mem_block = mem_block_o + "\n" + mem_block_p
|
|
245
|
+
return "# Memories\n## PersonalMemory & OuterMemory (ordered)\n" + mem_block + "\n\n"
|
|
246
|
+
|
|
247
|
+
def _extract_references_from_response(self, response: str) -> tuple[str, list[dict]]:
|
|
248
|
+
"""
|
|
249
|
+
Extract reference information from the response and return clean text.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
response (str): The complete response text.
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
tuple[str, list[dict]]: A tuple containing:
|
|
256
|
+
- clean_text: Text with reference markers removed
|
|
257
|
+
- references: List of reference information
|
|
258
|
+
"""
|
|
259
|
+
import re
|
|
260
|
+
|
|
261
|
+
try:
|
|
262
|
+
references = []
|
|
263
|
+
# Pattern to match [refid:memoriesID]
|
|
264
|
+
pattern = r"\[(\d+):([^\]]+)\]"
|
|
265
|
+
|
|
266
|
+
matches = re.findall(pattern, response)
|
|
267
|
+
for ref_number, memory_id in matches:
|
|
268
|
+
references.append({"memory_id": memory_id, "reference_number": int(ref_number)})
|
|
269
|
+
|
|
270
|
+
# Remove all reference markers from the text to get clean text
|
|
271
|
+
clean_text = re.sub(pattern, "", response)
|
|
272
|
+
|
|
273
|
+
# Clean up any extra whitespace that might be left after removing markers
|
|
274
|
+
clean_text = re.sub(r"\s+", " ", clean_text).strip()
|
|
275
|
+
|
|
276
|
+
return clean_text, references
|
|
277
|
+
except Exception as e:
|
|
278
|
+
logger.error(f"Error extracting references from response: {e}", exc_info=True)
|
|
279
|
+
return response, []
|
|
280
|
+
|
|
281
|
+
async def _post_chat_processing(
|
|
282
|
+
self,
|
|
283
|
+
user_id: str,
|
|
284
|
+
cube_id: str,
|
|
285
|
+
query: str,
|
|
286
|
+
full_response: str,
|
|
287
|
+
system_prompt: str,
|
|
288
|
+
time_start: float,
|
|
289
|
+
time_end: float,
|
|
290
|
+
speed_improvement: float,
|
|
291
|
+
current_messages: list,
|
|
292
|
+
mem_cube: NaiveMemCube | None = None,
|
|
293
|
+
session_id: str | None = None,
|
|
294
|
+
history: MessageList | None = None,
|
|
295
|
+
) -> None:
|
|
296
|
+
"""
|
|
297
|
+
Asynchronous processing of logs, notifications and memory additions
|
|
298
|
+
"""
|
|
299
|
+
try:
|
|
300
|
+
logger.info(
|
|
301
|
+
f"user_id: {user_id}, cube_id: {cube_id}, current_messages: {current_messages}"
|
|
302
|
+
)
|
|
303
|
+
logger.info(f"user_id: {user_id}, cube_id: {cube_id}, full_response: {full_response}")
|
|
304
|
+
|
|
305
|
+
clean_response, extracted_references = self._extract_references_from_response(
|
|
306
|
+
full_response
|
|
307
|
+
)
|
|
308
|
+
logger.info(f"Extracted {len(extracted_references)} references from response")
|
|
309
|
+
|
|
310
|
+
# Send chat report notifications asynchronously
|
|
311
|
+
if self.online_bot:
|
|
312
|
+
try:
|
|
313
|
+
from memos.memos_tools.notification_utils import (
|
|
314
|
+
send_online_bot_notification_async,
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
# Prepare notification data
|
|
318
|
+
chat_data = {
|
|
319
|
+
"query": query,
|
|
320
|
+
"user_id": user_id,
|
|
321
|
+
"cube_id": cube_id,
|
|
322
|
+
"system_prompt": system_prompt,
|
|
323
|
+
"full_response": full_response,
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
system_data = {
|
|
327
|
+
"references": extracted_references,
|
|
328
|
+
"time_start": time_start,
|
|
329
|
+
"time_end": time_end,
|
|
330
|
+
"speed_improvement": speed_improvement,
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
emoji_config = {"chat": "💬", "system_info": "📊"}
|
|
334
|
+
|
|
335
|
+
await send_online_bot_notification_async(
|
|
336
|
+
online_bot=self.online_bot,
|
|
337
|
+
header_name="MemOS Chat Report",
|
|
338
|
+
sub_title_name="chat_with_references",
|
|
339
|
+
title_color="#00956D",
|
|
340
|
+
other_data1=chat_data,
|
|
341
|
+
other_data2=system_data,
|
|
342
|
+
emoji=emoji_config,
|
|
343
|
+
)
|
|
344
|
+
except Exception as e:
|
|
345
|
+
logger.warning(f"Failed to send chat notification (async): {e}")
|
|
346
|
+
|
|
347
|
+
self.add(
|
|
348
|
+
user_id=user_id,
|
|
349
|
+
cube_id=cube_id,
|
|
350
|
+
mem_cube=mem_cube,
|
|
351
|
+
session_id=session_id,
|
|
352
|
+
history=history,
|
|
353
|
+
messages=[
|
|
354
|
+
{
|
|
355
|
+
"role": "user",
|
|
356
|
+
"content": query,
|
|
357
|
+
"chat_time": str(datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
"role": "assistant",
|
|
361
|
+
"content": clean_response, # Store clean text without reference markers
|
|
362
|
+
"chat_time": str(datetime.now().strftime("%Y-%m-%d %H:%M:%S")),
|
|
363
|
+
},
|
|
364
|
+
],
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
logger.info(f"Post-chat processing completed for user {user_id}")
|
|
368
|
+
|
|
369
|
+
except Exception as e:
|
|
370
|
+
logger.error(f"Error in post-chat processing for user {user_id}: {e}", exc_info=True)
|
|
371
|
+
|
|
372
|
+
def _start_post_chat_processing(
|
|
373
|
+
self,
|
|
374
|
+
user_id: str,
|
|
375
|
+
cube_id: str,
|
|
376
|
+
query: str,
|
|
377
|
+
full_response: str,
|
|
378
|
+
system_prompt: str,
|
|
379
|
+
time_start: float,
|
|
380
|
+
time_end: float,
|
|
381
|
+
speed_improvement: float,
|
|
382
|
+
current_messages: list,
|
|
383
|
+
mem_cube: NaiveMemCube | None = None,
|
|
384
|
+
session_id: str | None = None,
|
|
385
|
+
history: MessageList | None = None,
|
|
386
|
+
) -> None:
|
|
387
|
+
"""
|
|
388
|
+
Asynchronous processing of logs, notifications and memory additions, handle synchronous and asynchronous environments
|
|
389
|
+
"""
|
|
390
|
+
|
|
391
|
+
def run_async_in_thread():
|
|
392
|
+
"""Running asynchronous tasks in a new thread"""
|
|
393
|
+
try:
|
|
394
|
+
loop = asyncio.new_event_loop()
|
|
395
|
+
asyncio.set_event_loop(loop)
|
|
396
|
+
try:
|
|
397
|
+
loop.run_until_complete(
|
|
398
|
+
self._post_chat_processing(
|
|
399
|
+
user_id=user_id,
|
|
400
|
+
cube_id=cube_id,
|
|
401
|
+
query=query,
|
|
402
|
+
full_response=full_response,
|
|
403
|
+
system_prompt=system_prompt,
|
|
404
|
+
time_start=time_start,
|
|
405
|
+
time_end=time_end,
|
|
406
|
+
speed_improvement=speed_improvement,
|
|
407
|
+
current_messages=current_messages,
|
|
408
|
+
mem_cube=mem_cube,
|
|
409
|
+
session_id=session_id,
|
|
410
|
+
history=history,
|
|
411
|
+
)
|
|
412
|
+
)
|
|
413
|
+
finally:
|
|
414
|
+
loop.close()
|
|
415
|
+
except Exception as e:
|
|
416
|
+
logger.error(
|
|
417
|
+
f"Error in thread-based post-chat processing for user {user_id}: {e}",
|
|
418
|
+
exc_info=True,
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
try:
|
|
422
|
+
# Try to get the current event loop
|
|
423
|
+
asyncio.get_running_loop()
|
|
424
|
+
# Create task and store reference to prevent garbage collection
|
|
425
|
+
task = asyncio.create_task(
|
|
426
|
+
self._post_chat_processing(
|
|
427
|
+
user_id=user_id,
|
|
428
|
+
cube_id=cube_id,
|
|
429
|
+
query=query,
|
|
430
|
+
full_response=full_response,
|
|
431
|
+
system_prompt=system_prompt,
|
|
432
|
+
time_start=time_start,
|
|
433
|
+
time_end=time_end,
|
|
434
|
+
speed_improvement=speed_improvement,
|
|
435
|
+
current_messages=current_messages,
|
|
436
|
+
)
|
|
437
|
+
)
|
|
438
|
+
# Add exception handling for the background task
|
|
439
|
+
task.add_done_callback(
|
|
440
|
+
lambda t: logger.error(
|
|
441
|
+
f"Error in background post-chat processing for user {user_id}: {t.exception()}",
|
|
442
|
+
exc_info=True,
|
|
443
|
+
)
|
|
444
|
+
if t.exception()
|
|
445
|
+
else None
|
|
446
|
+
)
|
|
447
|
+
except RuntimeError:
|
|
448
|
+
# No event loop, run in a new thread with context propagation
|
|
449
|
+
thread = ContextThread(
|
|
450
|
+
target=run_async_in_thread,
|
|
451
|
+
name=f"PostChatProcessing-{user_id}",
|
|
452
|
+
# Set as a daemon thread to avoid blocking program exit
|
|
453
|
+
daemon=True,
|
|
454
|
+
)
|
|
455
|
+
thread.start()
|