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,237 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Data formatting utilities for server handlers.
|
|
3
|
+
|
|
4
|
+
This module provides utility functions for formatting and transforming data
|
|
5
|
+
structures for API responses, including memory items and preferences.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any
|
|
9
|
+
|
|
10
|
+
from memos.log import get_logger
|
|
11
|
+
from memos.templates.instruction_completion import instruct_completion
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
logger = get_logger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def to_iter(running: Any) -> list[Any]:
|
|
18
|
+
"""
|
|
19
|
+
Normalize running tasks to a list of task objects.
|
|
20
|
+
|
|
21
|
+
Handles different input types and converts them to a consistent list format.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
running: Running tasks, can be None, dict, or iterable
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
List of task objects
|
|
28
|
+
"""
|
|
29
|
+
if running is None:
|
|
30
|
+
return []
|
|
31
|
+
if isinstance(running, dict):
|
|
32
|
+
return list(running.values())
|
|
33
|
+
return list(running) if running else []
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def format_memory_item(
|
|
37
|
+
memory_data: Any, include_embedding: bool = False, save_sources: bool = True
|
|
38
|
+
) -> dict[str, Any]:
|
|
39
|
+
"""
|
|
40
|
+
Format a single memory item for API response.
|
|
41
|
+
|
|
42
|
+
Transforms a memory object into a dictionary with metadata properly
|
|
43
|
+
structured for API consumption.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
memory_data: Memory object to format
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
Formatted memory dictionary with ref_id and metadata
|
|
50
|
+
"""
|
|
51
|
+
memory = memory_data.model_dump()
|
|
52
|
+
memory_id = memory["id"]
|
|
53
|
+
ref_id = f"[{memory_id.split('-')[0]}]"
|
|
54
|
+
|
|
55
|
+
memory["ref_id"] = ref_id
|
|
56
|
+
if not include_embedding:
|
|
57
|
+
memory["metadata"]["embedding"] = []
|
|
58
|
+
if not save_sources:
|
|
59
|
+
memory["metadata"]["sources"] = []
|
|
60
|
+
memory["metadata"]["usage"] = []
|
|
61
|
+
memory["metadata"]["ref_id"] = ref_id
|
|
62
|
+
memory["metadata"]["id"] = memory_id
|
|
63
|
+
memory["metadata"]["memory"] = memory["memory"]
|
|
64
|
+
|
|
65
|
+
return memory
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def post_process_pref_mem(
|
|
69
|
+
memories_result: dict[str, Any],
|
|
70
|
+
pref_formatted_mem: list[dict[str, Any]],
|
|
71
|
+
mem_cube_id: str,
|
|
72
|
+
include_preference: bool,
|
|
73
|
+
) -> dict[str, Any]:
|
|
74
|
+
"""
|
|
75
|
+
Post-process preference memory results.
|
|
76
|
+
|
|
77
|
+
Adds formatted preference memories to the result dictionary and generates
|
|
78
|
+
instruction completion strings if preferences are included.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
memories_result: Result dictionary to update
|
|
82
|
+
pref_formatted_mem: List of formatted preference memories
|
|
83
|
+
mem_cube_id: Memory cube ID
|
|
84
|
+
include_preference: Whether to include preferences in result
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
Updated memories_result dictionary
|
|
88
|
+
"""
|
|
89
|
+
if include_preference:
|
|
90
|
+
memories_result["pref_mem"].append(
|
|
91
|
+
{
|
|
92
|
+
"cube_id": mem_cube_id,
|
|
93
|
+
"memories": pref_formatted_mem,
|
|
94
|
+
"total_nodes": len(pref_formatted_mem),
|
|
95
|
+
}
|
|
96
|
+
)
|
|
97
|
+
pref_instruction, pref_note = instruct_completion(pref_formatted_mem)
|
|
98
|
+
memories_result["pref_string"] = pref_instruction
|
|
99
|
+
memories_result["pref_note"] = pref_note
|
|
100
|
+
|
|
101
|
+
return memories_result
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def post_process_textual_mem(
|
|
105
|
+
memories_result: dict[str, Any],
|
|
106
|
+
text_formatted_mem: list[dict[str, Any]],
|
|
107
|
+
mem_cube_id: str,
|
|
108
|
+
) -> dict[str, Any]:
|
|
109
|
+
"""
|
|
110
|
+
Post-process text and tool memory results.
|
|
111
|
+
"""
|
|
112
|
+
fact_mem = [
|
|
113
|
+
mem
|
|
114
|
+
for mem in text_formatted_mem
|
|
115
|
+
if mem["metadata"]["memory_type"] not in ["ToolSchemaMemory", "ToolTrajectoryMemory"]
|
|
116
|
+
]
|
|
117
|
+
tool_mem = [
|
|
118
|
+
mem
|
|
119
|
+
for mem in text_formatted_mem
|
|
120
|
+
if mem["metadata"]["memory_type"] in ["ToolSchemaMemory", "ToolTrajectoryMemory"]
|
|
121
|
+
]
|
|
122
|
+
|
|
123
|
+
memories_result["text_mem"].append(
|
|
124
|
+
{
|
|
125
|
+
"cube_id": mem_cube_id,
|
|
126
|
+
"memories": fact_mem,
|
|
127
|
+
"total_nodes": len(fact_mem),
|
|
128
|
+
}
|
|
129
|
+
)
|
|
130
|
+
memories_result["tool_mem"].append(
|
|
131
|
+
{
|
|
132
|
+
"cube_id": mem_cube_id,
|
|
133
|
+
"memories": tool_mem,
|
|
134
|
+
"total_nodes": len(tool_mem),
|
|
135
|
+
}
|
|
136
|
+
)
|
|
137
|
+
return memories_result
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def separate_knowledge_and_conversation_mem(memories: list[dict[str, Any]]):
|
|
141
|
+
"""
|
|
142
|
+
Separate knowledge and conversation memories from retrieval results.
|
|
143
|
+
"""
|
|
144
|
+
knowledge_mem = []
|
|
145
|
+
conversation_mem = []
|
|
146
|
+
for item in memories:
|
|
147
|
+
sources = item.get("metadata", {}).get("sources", [])
|
|
148
|
+
if (
|
|
149
|
+
len(sources) > 0
|
|
150
|
+
and "type" in sources[0]
|
|
151
|
+
and sources[0]["type"] == "file"
|
|
152
|
+
and "content" in sources[0]
|
|
153
|
+
and sources[0]["content"] != ""
|
|
154
|
+
): # TODO change to memory_type
|
|
155
|
+
knowledge_mem.append(item)
|
|
156
|
+
else:
|
|
157
|
+
conversation_mem.append(item)
|
|
158
|
+
|
|
159
|
+
logger.info(
|
|
160
|
+
f"Retrieval results number of knowledge_mem: {len(knowledge_mem)}, conversation_mem: {len(conversation_mem)}"
|
|
161
|
+
)
|
|
162
|
+
return knowledge_mem, conversation_mem
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
def rerank_knowledge_mem(
|
|
166
|
+
reranker: Any,
|
|
167
|
+
query: str,
|
|
168
|
+
text_mem: list[dict[str, Any]],
|
|
169
|
+
top_k: int,
|
|
170
|
+
file_mem_proportion: float = 0.5,
|
|
171
|
+
) -> list[dict[str, Any]]:
|
|
172
|
+
"""
|
|
173
|
+
Rerank knowledge memories and keep conversation memories.
|
|
174
|
+
"""
|
|
175
|
+
memid2cubeid = {}
|
|
176
|
+
memories_list = []
|
|
177
|
+
for memory_group in text_mem:
|
|
178
|
+
cube_id = memory_group["cube_id"]
|
|
179
|
+
memories = memory_group["memories"]
|
|
180
|
+
memories_list.extend(memories)
|
|
181
|
+
for memory in memories:
|
|
182
|
+
memid2cubeid[memory["id"]] = cube_id
|
|
183
|
+
|
|
184
|
+
knowledge_mem, conversation_mem = separate_knowledge_and_conversation_mem(memories_list)
|
|
185
|
+
knowledge_mem_top_k = max(int(top_k * file_mem_proportion), int(top_k - len(conversation_mem)))
|
|
186
|
+
# rerank set unuse
|
|
187
|
+
reranked_knowledge_mem = knowledge_mem
|
|
188
|
+
|
|
189
|
+
# Sort by relativity in descending order
|
|
190
|
+
reranked_knowledge_mem = sorted(
|
|
191
|
+
reranked_knowledge_mem,
|
|
192
|
+
key=lambda item: item.get("metadata", {}).get("relativity", 0.0),
|
|
193
|
+
reverse=True,
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
# TODO revoke sources replace memory value
|
|
197
|
+
for item in reranked_knowledge_mem:
|
|
198
|
+
item["memory"] = item["metadata"]["sources"][0]["content"]
|
|
199
|
+
item["metadata"]["sources"] = []
|
|
200
|
+
|
|
201
|
+
for item in conversation_mem:
|
|
202
|
+
item.setdefault("metadata", {})["sources"] = []
|
|
203
|
+
|
|
204
|
+
# deduplicate: remove items with duplicate memory content
|
|
205
|
+
original_count = len(reranked_knowledge_mem)
|
|
206
|
+
seen_memories = set[Any]()
|
|
207
|
+
deduplicated_knowledge_mem = []
|
|
208
|
+
for item in reranked_knowledge_mem:
|
|
209
|
+
memory_content = item.get("memory", "")
|
|
210
|
+
if memory_content and memory_content not in seen_memories:
|
|
211
|
+
seen_memories.add(memory_content)
|
|
212
|
+
deduplicated_knowledge_mem.append(item)
|
|
213
|
+
deduplicated_count = len(deduplicated_knowledge_mem)
|
|
214
|
+
logger.info(
|
|
215
|
+
f"After filtering duplicate knowledge base text from sources, count changed from {original_count} to {deduplicated_count}"
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
reranked_knowledge_mem = deduplicated_knowledge_mem[:knowledge_mem_top_k]
|
|
219
|
+
conversation_mem_top_k = top_k - len(reranked_knowledge_mem)
|
|
220
|
+
cubeid2memories = {}
|
|
221
|
+
text_mem_res = []
|
|
222
|
+
|
|
223
|
+
for memory in reranked_knowledge_mem + conversation_mem[:conversation_mem_top_k]:
|
|
224
|
+
cube_id = memid2cubeid[memory["id"]]
|
|
225
|
+
if cube_id not in cubeid2memories:
|
|
226
|
+
cubeid2memories[cube_id] = []
|
|
227
|
+
cubeid2memories[cube_id].append(memory)
|
|
228
|
+
|
|
229
|
+
for cube_id, memories in cubeid2memories.items():
|
|
230
|
+
text_mem_res.append(
|
|
231
|
+
{
|
|
232
|
+
"cube_id": cube_id,
|
|
233
|
+
"memories": memories,
|
|
234
|
+
}
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
return text_mem_res
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Memory handler for retrieving and managing memories.
|
|
3
|
+
|
|
4
|
+
This module handles retrieving all memories or specific subgraphs based on queries.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import TYPE_CHECKING, Any, Literal
|
|
8
|
+
|
|
9
|
+
from memos.api.handlers.formatters_handler import (
|
|
10
|
+
format_memory_item,
|
|
11
|
+
post_process_pref_mem,
|
|
12
|
+
post_process_textual_mem,
|
|
13
|
+
)
|
|
14
|
+
from memos.api.product_models import (
|
|
15
|
+
DeleteMemoryRequest,
|
|
16
|
+
DeleteMemoryResponse,
|
|
17
|
+
GetMemoryRequest,
|
|
18
|
+
GetMemoryResponse,
|
|
19
|
+
MemoryResponse,
|
|
20
|
+
)
|
|
21
|
+
from memos.log import get_logger
|
|
22
|
+
from memos.mem_cube.navie import NaiveMemCube
|
|
23
|
+
from memos.mem_os.utils.format_utils import (
|
|
24
|
+
convert_graph_to_tree_forworkmem,
|
|
25
|
+
ensure_unique_tree_ids,
|
|
26
|
+
filter_nodes_by_tree_ids,
|
|
27
|
+
remove_embedding_recursive,
|
|
28
|
+
sort_children_by_memory_type,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
if TYPE_CHECKING:
|
|
33
|
+
from memos.memories.textual.preference import TextualMemoryItem
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
logger = get_logger(__name__)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def handle_get_all_memories(
|
|
40
|
+
user_id: str,
|
|
41
|
+
mem_cube_id: str,
|
|
42
|
+
memory_type: Literal["text_mem", "act_mem", "param_mem", "para_mem"],
|
|
43
|
+
naive_mem_cube: Any,
|
|
44
|
+
) -> MemoryResponse:
|
|
45
|
+
"""
|
|
46
|
+
Main handler for getting all memories.
|
|
47
|
+
|
|
48
|
+
Retrieves all memories of specified type for a user and formats them appropriately.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
user_id: User ID
|
|
52
|
+
mem_cube_id: Memory cube ID
|
|
53
|
+
memory_type: Type of memory to retrieve
|
|
54
|
+
naive_mem_cube: Memory cube instance
|
|
55
|
+
|
|
56
|
+
Returns:
|
|
57
|
+
MemoryResponse with formatted memory data
|
|
58
|
+
"""
|
|
59
|
+
try:
|
|
60
|
+
reformat_memory_list = []
|
|
61
|
+
|
|
62
|
+
if memory_type == "text_mem":
|
|
63
|
+
# Get all text memories from the graph database
|
|
64
|
+
memories = naive_mem_cube.text_mem.get_all(user_name=mem_cube_id)
|
|
65
|
+
|
|
66
|
+
# Format and convert to tree structure
|
|
67
|
+
memories_cleaned = remove_embedding_recursive(memories)
|
|
68
|
+
custom_type_ratios = {
|
|
69
|
+
"WorkingMemory": 0.20,
|
|
70
|
+
"LongTermMemory": 0.40,
|
|
71
|
+
"UserMemory": 0.40,
|
|
72
|
+
}
|
|
73
|
+
tree_result, node_type_count = convert_graph_to_tree_forworkmem(
|
|
74
|
+
memories_cleaned, target_node_count=200, type_ratios=custom_type_ratios
|
|
75
|
+
)
|
|
76
|
+
# Ensure all node IDs are unique in the tree structure
|
|
77
|
+
tree_result = ensure_unique_tree_ids(tree_result)
|
|
78
|
+
memories_filtered = filter_nodes_by_tree_ids(tree_result, memories_cleaned)
|
|
79
|
+
children = tree_result["children"]
|
|
80
|
+
children_sort = sort_children_by_memory_type(children)
|
|
81
|
+
tree_result["children"] = children_sort
|
|
82
|
+
memories_filtered["tree_structure"] = tree_result
|
|
83
|
+
|
|
84
|
+
reformat_memory_list.append(
|
|
85
|
+
{
|
|
86
|
+
"cube_id": mem_cube_id,
|
|
87
|
+
"memories": [memories_filtered],
|
|
88
|
+
"memory_statistics": node_type_count,
|
|
89
|
+
}
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
elif memory_type == "act_mem":
|
|
93
|
+
logger.warning("Activity memory retrieval not implemented yet.")
|
|
94
|
+
elif memory_type == "para_mem":
|
|
95
|
+
logger.warning("Parameter memory retrieval not implemented yet.")
|
|
96
|
+
return MemoryResponse(
|
|
97
|
+
message="Memories retrieved successfully",
|
|
98
|
+
data=reformat_memory_list,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
except Exception as e:
|
|
102
|
+
logger.error(f"Failed to get all memories: {e}", exc_info=True)
|
|
103
|
+
raise
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def handle_get_subgraph(
|
|
107
|
+
user_id: str,
|
|
108
|
+
mem_cube_id: str,
|
|
109
|
+
query: str,
|
|
110
|
+
top_k: int,
|
|
111
|
+
naive_mem_cube: Any,
|
|
112
|
+
) -> MemoryResponse:
|
|
113
|
+
"""
|
|
114
|
+
Main handler for getting memory subgraph based on query.
|
|
115
|
+
|
|
116
|
+
Retrieves relevant memory subgraph and formats it as a tree structure.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
user_id: User ID
|
|
120
|
+
mem_cube_id: Memory cube ID
|
|
121
|
+
query: Search query
|
|
122
|
+
top_k: Number of top results to return
|
|
123
|
+
naive_mem_cube: Memory cube instance
|
|
124
|
+
|
|
125
|
+
Returns:
|
|
126
|
+
MemoryResponse with formatted subgraph data
|
|
127
|
+
"""
|
|
128
|
+
try:
|
|
129
|
+
# Get relevant subgraph from text memory
|
|
130
|
+
memories = naive_mem_cube.text_mem.get_relevant_subgraph(
|
|
131
|
+
query, top_k=top_k, user_name=mem_cube_id
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
# Format and convert to tree structure
|
|
135
|
+
memories_cleaned = remove_embedding_recursive(memories)
|
|
136
|
+
custom_type_ratios = {
|
|
137
|
+
"WorkingMemory": 0.20,
|
|
138
|
+
"LongTermMemory": 0.40,
|
|
139
|
+
"UserMemory": 0.40,
|
|
140
|
+
}
|
|
141
|
+
tree_result, node_type_count = convert_graph_to_tree_forworkmem(
|
|
142
|
+
memories_cleaned, target_node_count=150, type_ratios=custom_type_ratios
|
|
143
|
+
)
|
|
144
|
+
# Ensure all node IDs are unique in the tree structure
|
|
145
|
+
tree_result = ensure_unique_tree_ids(tree_result)
|
|
146
|
+
memories_filtered = filter_nodes_by_tree_ids(tree_result, memories_cleaned)
|
|
147
|
+
children = tree_result["children"]
|
|
148
|
+
children_sort = sort_children_by_memory_type(children)
|
|
149
|
+
tree_result["children"] = children_sort
|
|
150
|
+
memories_filtered["tree_structure"] = tree_result
|
|
151
|
+
|
|
152
|
+
reformat_memory_list = [
|
|
153
|
+
{
|
|
154
|
+
"cube_id": mem_cube_id,
|
|
155
|
+
"memories": [memories_filtered],
|
|
156
|
+
"memory_statistics": node_type_count,
|
|
157
|
+
}
|
|
158
|
+
]
|
|
159
|
+
|
|
160
|
+
return MemoryResponse(
|
|
161
|
+
message="Memories retrieved successfully",
|
|
162
|
+
data=reformat_memory_list,
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
except Exception as e:
|
|
166
|
+
logger.error(f"Failed to get subgraph: {e}", exc_info=True)
|
|
167
|
+
raise
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def handle_get_memory(memory_id: str, naive_mem_cube: NaiveMemCube) -> GetMemoryResponse:
|
|
171
|
+
"""
|
|
172
|
+
Handler for getting a single memory by its ID.
|
|
173
|
+
|
|
174
|
+
Tries to retrieve from text memory first, then preference memory if not found.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
memory_id: The ID of the memory to retrieve
|
|
178
|
+
naive_mem_cube: Memory cube instance
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
GetMemoryResponse with the memory data
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
try:
|
|
185
|
+
memory = naive_mem_cube.text_mem.get(memory_id)
|
|
186
|
+
except Exception:
|
|
187
|
+
memory = None
|
|
188
|
+
|
|
189
|
+
# If not found in text memory, try preference memory
|
|
190
|
+
pref = None
|
|
191
|
+
if memory is None and naive_mem_cube.pref_mem is not None:
|
|
192
|
+
collection_names = ["explicit_preference", "implicit_preference"]
|
|
193
|
+
for collection_name in collection_names:
|
|
194
|
+
try:
|
|
195
|
+
pref = naive_mem_cube.pref_mem.get_with_collection_name(collection_name, memory_id)
|
|
196
|
+
if pref is not None:
|
|
197
|
+
break
|
|
198
|
+
except Exception:
|
|
199
|
+
continue
|
|
200
|
+
|
|
201
|
+
# Get the data from whichever memory source succeeded
|
|
202
|
+
data = (memory or pref).model_dump() if (memory or pref) else None
|
|
203
|
+
|
|
204
|
+
return GetMemoryResponse(
|
|
205
|
+
message="Memory retrieved successfully"
|
|
206
|
+
if data
|
|
207
|
+
else f"Memory with ID {memory_id} not found",
|
|
208
|
+
code=200,
|
|
209
|
+
data=data,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
def handle_get_memories(
|
|
214
|
+
get_mem_req: GetMemoryRequest, naive_mem_cube: NaiveMemCube
|
|
215
|
+
) -> GetMemoryResponse:
|
|
216
|
+
results: dict[str, Any] = {"text_mem": [], "pref_mem": [], "tool_mem": []}
|
|
217
|
+
memories = naive_mem_cube.text_mem.get_all(
|
|
218
|
+
user_name=get_mem_req.mem_cube_id,
|
|
219
|
+
user_id=get_mem_req.user_id,
|
|
220
|
+
page=get_mem_req.page,
|
|
221
|
+
page_size=get_mem_req.page_size,
|
|
222
|
+
filter=get_mem_req.filter,
|
|
223
|
+
)["nodes"]
|
|
224
|
+
|
|
225
|
+
results = post_process_textual_mem(results, memories, get_mem_req.mem_cube_id)
|
|
226
|
+
|
|
227
|
+
if not get_mem_req.include_tool_memory:
|
|
228
|
+
results["tool_mem"] = []
|
|
229
|
+
|
|
230
|
+
preferences: list[TextualMemoryItem] = []
|
|
231
|
+
|
|
232
|
+
format_preferences = []
|
|
233
|
+
if get_mem_req.include_preference and naive_mem_cube.pref_mem is not None:
|
|
234
|
+
filter_params: dict[str, Any] = {}
|
|
235
|
+
if get_mem_req.user_id is not None:
|
|
236
|
+
filter_params["user_id"] = get_mem_req.user_id
|
|
237
|
+
if get_mem_req.mem_cube_id is not None:
|
|
238
|
+
filter_params["mem_cube_id"] = get_mem_req.mem_cube_id
|
|
239
|
+
if get_mem_req.filter is not None:
|
|
240
|
+
# Check and remove user_id/mem_cube_id from filter if present
|
|
241
|
+
filter_copy = get_mem_req.filter.copy()
|
|
242
|
+
removed_fields = []
|
|
243
|
+
|
|
244
|
+
if "user_id" in filter_copy:
|
|
245
|
+
filter_copy.pop("user_id")
|
|
246
|
+
removed_fields.append("user_id")
|
|
247
|
+
if "mem_cube_id" in filter_copy:
|
|
248
|
+
filter_copy.pop("mem_cube_id")
|
|
249
|
+
removed_fields.append("mem_cube_id")
|
|
250
|
+
|
|
251
|
+
if removed_fields:
|
|
252
|
+
logger.warning(
|
|
253
|
+
f"Fields {removed_fields} found in filter will be ignored. "
|
|
254
|
+
f"Use request-level user_id/mem_cube_id parameters instead."
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
filter_params.update(filter_copy)
|
|
258
|
+
|
|
259
|
+
preferences, _ = naive_mem_cube.pref_mem.get_memory_by_filter(
|
|
260
|
+
filter_params, page=get_mem_req.page, page_size=get_mem_req.page_size
|
|
261
|
+
)
|
|
262
|
+
format_preferences = [format_memory_item(item, save_sources=False) for item in preferences]
|
|
263
|
+
|
|
264
|
+
results = post_process_pref_mem(
|
|
265
|
+
results, format_preferences, get_mem_req.mem_cube_id, get_mem_req.include_preference
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
# Filter to only keep text_mem, pref_mem, tool_mem
|
|
269
|
+
filtered_results = {
|
|
270
|
+
"text_mem": results.get("text_mem", []),
|
|
271
|
+
"pref_mem": results.get("pref_mem", []),
|
|
272
|
+
"tool_mem": results.get("tool_mem", []),
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return GetMemoryResponse(message="Memories retrieved successfully", data=filtered_results)
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
def handle_delete_memories(delete_mem_req: DeleteMemoryRequest, naive_mem_cube: NaiveMemCube):
|
|
279
|
+
logger.info(
|
|
280
|
+
f"[Delete memory request] writable_cube_ids: {delete_mem_req.writable_cube_ids}, memory_ids: {delete_mem_req.memory_ids}"
|
|
281
|
+
)
|
|
282
|
+
# Validate that only one of memory_ids, file_ids, or filter is provided
|
|
283
|
+
provided_params = [
|
|
284
|
+
delete_mem_req.memory_ids is not None,
|
|
285
|
+
delete_mem_req.file_ids is not None,
|
|
286
|
+
delete_mem_req.filter is not None,
|
|
287
|
+
]
|
|
288
|
+
if sum(provided_params) != 1:
|
|
289
|
+
return DeleteMemoryResponse(
|
|
290
|
+
message="Exactly one of memory_ids, file_ids, or filter must be provided",
|
|
291
|
+
data={"status": "failure"},
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
try:
|
|
295
|
+
if delete_mem_req.memory_ids is not None:
|
|
296
|
+
naive_mem_cube.text_mem.delete_by_memory_ids(delete_mem_req.memory_ids)
|
|
297
|
+
if naive_mem_cube.pref_mem is not None:
|
|
298
|
+
naive_mem_cube.pref_mem.delete(delete_mem_req.memory_ids)
|
|
299
|
+
elif delete_mem_req.file_ids is not None:
|
|
300
|
+
naive_mem_cube.text_mem.delete_by_filter(
|
|
301
|
+
writable_cube_ids=delete_mem_req.writable_cube_ids, file_ids=delete_mem_req.file_ids
|
|
302
|
+
)
|
|
303
|
+
elif delete_mem_req.filter is not None:
|
|
304
|
+
naive_mem_cube.text_mem.delete_by_filter(filter=delete_mem_req.filter)
|
|
305
|
+
if naive_mem_cube.pref_mem is not None:
|
|
306
|
+
naive_mem_cube.pref_mem.delete_by_filter(filter=delete_mem_req.filter)
|
|
307
|
+
except Exception as e:
|
|
308
|
+
logger.error(f"Failed to delete memories: {e}", exc_info=True)
|
|
309
|
+
return DeleteMemoryResponse(
|
|
310
|
+
message="Failed to delete memories",
|
|
311
|
+
data={"status": "failure"},
|
|
312
|
+
)
|
|
313
|
+
return DeleteMemoryResponse(
|
|
314
|
+
message="Memories deleted successfully",
|
|
315
|
+
data={"status": "success"},
|
|
316
|
+
)
|