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,385 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Any, ClassVar
|
|
6
|
+
|
|
7
|
+
from pydantic import ConfigDict, Field, field_validator, model_validator
|
|
8
|
+
|
|
9
|
+
from memos.configs.base import BaseConfig
|
|
10
|
+
from memos.mem_scheduler.general_modules.misc import DictConversionMixin, EnvConfigMixin
|
|
11
|
+
from memos.mem_scheduler.schemas.general_schemas import (
|
|
12
|
+
BASE_DIR,
|
|
13
|
+
DEFAULT_ACT_MEM_DUMP_PATH,
|
|
14
|
+
DEFAULT_ACTIVATION_MEM_MONITOR_SIZE_LIMIT,
|
|
15
|
+
DEFAULT_CONSUME_BATCH,
|
|
16
|
+
DEFAULT_CONSUME_INTERVAL_SECONDS,
|
|
17
|
+
DEFAULT_CONTEXT_WINDOW_SIZE,
|
|
18
|
+
DEFAULT_MAX_INTERNAL_MESSAGE_QUEUE_SIZE,
|
|
19
|
+
DEFAULT_MULTI_TASK_RUNNING_TIMEOUT,
|
|
20
|
+
DEFAULT_SCHEDULER_RETRIEVER_BATCH_SIZE,
|
|
21
|
+
DEFAULT_SCHEDULER_RETRIEVER_RETRIES,
|
|
22
|
+
DEFAULT_THREAD_POOL_MAX_WORKERS,
|
|
23
|
+
DEFAULT_TOP_K,
|
|
24
|
+
DEFAULT_USE_REDIS_QUEUE,
|
|
25
|
+
DEFAULT_WORKING_MEM_MONITOR_SIZE_LIMIT,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class BaseSchedulerConfig(BaseConfig):
|
|
30
|
+
"""Base configuration class for mem_scheduler."""
|
|
31
|
+
|
|
32
|
+
top_k: int = Field(
|
|
33
|
+
default=DEFAULT_TOP_K,
|
|
34
|
+
description="Number of top candidates to consider in initial retrieval",
|
|
35
|
+
)
|
|
36
|
+
enable_parallel_dispatch: bool = Field(
|
|
37
|
+
default=True, description="Whether to enable parallel message processing using thread pool"
|
|
38
|
+
)
|
|
39
|
+
thread_pool_max_workers: int = Field(
|
|
40
|
+
default=DEFAULT_THREAD_POOL_MAX_WORKERS,
|
|
41
|
+
gt=1,
|
|
42
|
+
description=f"Maximum worker threads in pool (default: {DEFAULT_THREAD_POOL_MAX_WORKERS})",
|
|
43
|
+
)
|
|
44
|
+
consume_interval_seconds: float = Field(
|
|
45
|
+
default=DEFAULT_CONSUME_INTERVAL_SECONDS,
|
|
46
|
+
gt=0,
|
|
47
|
+
description=f"Interval for consuming messages from queue in seconds (default: {DEFAULT_CONSUME_INTERVAL_SECONDS})",
|
|
48
|
+
)
|
|
49
|
+
consume_batch: int = Field(
|
|
50
|
+
default=DEFAULT_CONSUME_BATCH,
|
|
51
|
+
gt=0,
|
|
52
|
+
description=f"Number of messages to consume in each batch (default: {DEFAULT_CONSUME_BATCH})",
|
|
53
|
+
)
|
|
54
|
+
auth_config_path: str | None = Field(
|
|
55
|
+
default=None,
|
|
56
|
+
description="Path to the authentication configuration file containing private credentials",
|
|
57
|
+
)
|
|
58
|
+
# Redis queue configuration
|
|
59
|
+
use_redis_queue: bool = Field(
|
|
60
|
+
default=DEFAULT_USE_REDIS_QUEUE,
|
|
61
|
+
description="Whether to use Redis queue instead of local memory queue",
|
|
62
|
+
)
|
|
63
|
+
redis_config: dict[str, Any] = Field(
|
|
64
|
+
default_factory=lambda: {"host": "localhost", "port": 6379, "db": 0},
|
|
65
|
+
description="Redis connection configuration",
|
|
66
|
+
)
|
|
67
|
+
max_internal_message_queue_size: int = Field(
|
|
68
|
+
default=DEFAULT_MAX_INTERNAL_MESSAGE_QUEUE_SIZE,
|
|
69
|
+
description="Maximum size of internal message queue when not using Redis",
|
|
70
|
+
)
|
|
71
|
+
multi_task_running_timeout: int = Field(
|
|
72
|
+
default=DEFAULT_MULTI_TASK_RUNNING_TIMEOUT,
|
|
73
|
+
description="Default timeout for multi-task running operations in seconds",
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class GeneralSchedulerConfig(BaseSchedulerConfig):
|
|
78
|
+
model_config = ConfigDict(extra="ignore", strict=True)
|
|
79
|
+
act_mem_update_interval: int | None = Field(
|
|
80
|
+
default=300, description="Interval in seconds for updating activation memory"
|
|
81
|
+
)
|
|
82
|
+
context_window_size: int | None = Field(
|
|
83
|
+
default=DEFAULT_CONTEXT_WINDOW_SIZE,
|
|
84
|
+
description="Size of the context window for conversation history",
|
|
85
|
+
)
|
|
86
|
+
act_mem_dump_path: str | None = Field(
|
|
87
|
+
default=DEFAULT_ACT_MEM_DUMP_PATH, # Replace with DEFAULT_ACT_MEM_DUMP_PATH
|
|
88
|
+
description="File path for dumping activation memory",
|
|
89
|
+
)
|
|
90
|
+
enable_activation_memory: bool = Field(
|
|
91
|
+
default=False, description="Whether to enable automatic activation memory updates"
|
|
92
|
+
)
|
|
93
|
+
working_mem_monitor_capacity: int = Field(
|
|
94
|
+
default=DEFAULT_WORKING_MEM_MONITOR_SIZE_LIMIT,
|
|
95
|
+
description="Capacity of the working memory monitor",
|
|
96
|
+
)
|
|
97
|
+
activation_mem_monitor_capacity: int = Field(
|
|
98
|
+
default=DEFAULT_ACTIVATION_MEM_MONITOR_SIZE_LIMIT,
|
|
99
|
+
description="Capacity of the activation memory monitor",
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
# Memory enhancement concurrency & retries configuration
|
|
103
|
+
enhance_batch_size: int | None = Field(
|
|
104
|
+
default=DEFAULT_SCHEDULER_RETRIEVER_BATCH_SIZE,
|
|
105
|
+
description="Batch size for concurrent memory enhancement; None or <=1 disables batching",
|
|
106
|
+
)
|
|
107
|
+
enhance_retries: int = Field(
|
|
108
|
+
default=DEFAULT_SCHEDULER_RETRIEVER_RETRIES,
|
|
109
|
+
ge=0,
|
|
110
|
+
description="Number of retry attempts per enhancement batch",
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
# Database configuration for ORM persistence
|
|
114
|
+
db_path: str | None = Field(
|
|
115
|
+
default=None,
|
|
116
|
+
description="Path to SQLite database file for ORM persistence. If None, uses default scheduler_orm.db",
|
|
117
|
+
)
|
|
118
|
+
db_url: str | None = Field(
|
|
119
|
+
default=None,
|
|
120
|
+
description="Database URL for ORM persistence (e.g., mysql://user:pass@host/db). Takes precedence over db_path",
|
|
121
|
+
)
|
|
122
|
+
enable_orm_persistence: bool = Field(
|
|
123
|
+
default=True, description="Whether to enable ORM-based persistence for monitors"
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
class OptimizedSchedulerConfig(GeneralSchedulerConfig):
|
|
128
|
+
"""Configuration for the optimized scheduler.
|
|
129
|
+
|
|
130
|
+
This class inherits all fields from `GeneralSchedulerConfig`
|
|
131
|
+
and is used to distinguish optimized scheduling logic via type.
|
|
132
|
+
"""
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class SchedulerConfigFactory(BaseConfig):
|
|
136
|
+
"""Factory class for creating scheduler configurations."""
|
|
137
|
+
|
|
138
|
+
backend: str = Field(..., description="Backend for scheduler")
|
|
139
|
+
config: dict[str, Any] = Field(..., description="Configuration for the scheduler backend")
|
|
140
|
+
|
|
141
|
+
model_config = ConfigDict(extra="forbid", strict=True)
|
|
142
|
+
backend_to_class: ClassVar[dict[str, Any]] = {
|
|
143
|
+
"general_scheduler": GeneralSchedulerConfig,
|
|
144
|
+
"optimized_scheduler": OptimizedSchedulerConfig, # optimized_scheduler uses same config as general_scheduler
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@field_validator("backend")
|
|
148
|
+
@classmethod
|
|
149
|
+
def validate_backend(cls, backend: str) -> str:
|
|
150
|
+
"""Validate the backend field."""
|
|
151
|
+
if backend not in cls.backend_to_class:
|
|
152
|
+
raise ValueError(f"Invalid backend: {backend}")
|
|
153
|
+
return backend
|
|
154
|
+
|
|
155
|
+
@model_validator(mode="after")
|
|
156
|
+
def create_config(self) -> "SchedulerConfigFactory":
|
|
157
|
+
config_class = self.backend_to_class[self.backend]
|
|
158
|
+
self.config = config_class(**self.config)
|
|
159
|
+
return self
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
# ************************* Auth *************************
|
|
163
|
+
class RabbitMQConfig(
|
|
164
|
+
BaseConfig,
|
|
165
|
+
DictConversionMixin,
|
|
166
|
+
EnvConfigMixin,
|
|
167
|
+
):
|
|
168
|
+
host_name: str = Field(default="", description="Endpoint for RabbitMQ instance access")
|
|
169
|
+
user_name: str = Field(default="", description="Static username for RabbitMQ instance")
|
|
170
|
+
password: str = Field(default="", description="Password for the static username")
|
|
171
|
+
virtual_host: str = Field(default="", description="Vhost name for RabbitMQ instance")
|
|
172
|
+
erase_on_connect: bool = Field(
|
|
173
|
+
default=True, description="Whether to clear connection state or buffers upon connecting"
|
|
174
|
+
)
|
|
175
|
+
port: int = Field(
|
|
176
|
+
default=5672,
|
|
177
|
+
description="Port number for RabbitMQ instance access",
|
|
178
|
+
ge=1, # Port must be >= 1
|
|
179
|
+
le=65535, # Port must be <= 65535
|
|
180
|
+
)
|
|
181
|
+
exchange_name: str = Field(
|
|
182
|
+
default="memos-fanout",
|
|
183
|
+
description="Exchange name for RabbitMQ (e.g., memos-fanout, memos-memory-change)",
|
|
184
|
+
)
|
|
185
|
+
exchange_type: str = Field(
|
|
186
|
+
default="fanout", description="Exchange type for RabbitMQ (fanout or direct)"
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class GraphDBAuthConfig(BaseConfig, DictConversionMixin, EnvConfigMixin):
|
|
191
|
+
uri: str = Field(
|
|
192
|
+
default="bolt://localhost:7687",
|
|
193
|
+
description="URI for graph database access (e.g., bolt://host:port)",
|
|
194
|
+
)
|
|
195
|
+
user: str = Field(default="neo4j", description="Username for graph database authentication")
|
|
196
|
+
password: str = Field(
|
|
197
|
+
default="",
|
|
198
|
+
description="Password for graph database authentication",
|
|
199
|
+
min_length=8, # Recommended minimum password length
|
|
200
|
+
)
|
|
201
|
+
db_name: str = Field(default="neo4j", description="Database name to connect to")
|
|
202
|
+
auto_create: bool = Field(
|
|
203
|
+
default=True, description="Whether to automatically create the database if it doesn't exist"
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
class OpenAIConfig(BaseConfig, DictConversionMixin, EnvConfigMixin):
|
|
208
|
+
api_key: str = Field(default="", description="API key for OpenAI service")
|
|
209
|
+
base_url: str = Field(default="", description="Base URL for API endpoint")
|
|
210
|
+
default_model: str = Field(default="", description="Default model to use")
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class AuthConfig(BaseConfig, DictConversionMixin):
|
|
214
|
+
rabbitmq: RabbitMQConfig | None = None
|
|
215
|
+
openai: OpenAIConfig | None = None
|
|
216
|
+
graph_db: GraphDBAuthConfig | None = None
|
|
217
|
+
default_config_path: ClassVar[str] = (
|
|
218
|
+
f"{BASE_DIR}/examples/data/config/mem_scheduler/scheduler_auth.yaml"
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
@model_validator(mode="after")
|
|
222
|
+
def validate_partial_initialization(self) -> "AuthConfig":
|
|
223
|
+
"""
|
|
224
|
+
Validate that at least one configuration component is successfully initialized.
|
|
225
|
+
Log warnings for any failed initializations but allow partial success.
|
|
226
|
+
"""
|
|
227
|
+
logger = logging.getLogger(__name__)
|
|
228
|
+
|
|
229
|
+
initialized_components = []
|
|
230
|
+
failed_components = []
|
|
231
|
+
|
|
232
|
+
if self.rabbitmq is not None:
|
|
233
|
+
initialized_components.append("rabbitmq")
|
|
234
|
+
else:
|
|
235
|
+
failed_components.append("rabbitmq")
|
|
236
|
+
|
|
237
|
+
if self.openai is not None:
|
|
238
|
+
initialized_components.append("openai")
|
|
239
|
+
else:
|
|
240
|
+
failed_components.append("openai")
|
|
241
|
+
|
|
242
|
+
if self.graph_db is not None:
|
|
243
|
+
initialized_components.append("graph_db")
|
|
244
|
+
else:
|
|
245
|
+
failed_components.append("graph_db")
|
|
246
|
+
|
|
247
|
+
# Allow all components to be None for flexibility, but log a warning
|
|
248
|
+
if not initialized_components:
|
|
249
|
+
logger.warning(
|
|
250
|
+
"All configuration components are None. This may indicate missing environment variables or configuration files."
|
|
251
|
+
)
|
|
252
|
+
elif failed_components:
|
|
253
|
+
logger.warning(
|
|
254
|
+
f"Failed to initialize components: {', '.join(failed_components)}. Successfully initialized: {', '.join(initialized_components)}"
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
return self
|
|
258
|
+
|
|
259
|
+
@classmethod
|
|
260
|
+
def from_local_config(cls, config_path: str | Path | None = None) -> "AuthConfig":
|
|
261
|
+
"""
|
|
262
|
+
Load configuration from either a YAML or JSON file based on file extension.
|
|
263
|
+
|
|
264
|
+
Automatically detects file type (YAML or JSON) from the file extension
|
|
265
|
+
and uses the appropriate parser. If no path is provided, uses the default
|
|
266
|
+
configuration path (YAML) or its JSON counterpart.
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
config_path: Optional path to configuration file.
|
|
270
|
+
If not provided, uses default configuration path.
|
|
271
|
+
|
|
272
|
+
Returns:
|
|
273
|
+
AuthConfig instance populated with data from the configuration file.
|
|
274
|
+
|
|
275
|
+
Raises:
|
|
276
|
+
FileNotFoundError: If the specified or default configuration file does not exist.
|
|
277
|
+
ValueError: If file extension is not .yaml/.yml or .json, or if parsing fails.
|
|
278
|
+
"""
|
|
279
|
+
# Determine config path
|
|
280
|
+
if config_path is None:
|
|
281
|
+
config_path = cls.default_config_path
|
|
282
|
+
|
|
283
|
+
# Validate file existence
|
|
284
|
+
config_path_obj = Path(config_path)
|
|
285
|
+
if not config_path_obj.exists():
|
|
286
|
+
raise FileNotFoundError(f"Configuration file not found: {config_path}")
|
|
287
|
+
|
|
288
|
+
# Get file extension and determine parser
|
|
289
|
+
file_ext = config_path_obj.suffix.lower()
|
|
290
|
+
|
|
291
|
+
if file_ext in (".yaml", ".yml"):
|
|
292
|
+
return cls.from_yaml_file(yaml_path=str(config_path_obj))
|
|
293
|
+
elif file_ext == ".json":
|
|
294
|
+
return cls.from_json_file(json_path=str(config_path_obj))
|
|
295
|
+
else:
|
|
296
|
+
raise ValueError(
|
|
297
|
+
f"Unsupported file format: {file_ext}. "
|
|
298
|
+
"Please use YAML (.yaml, .yml) or JSON (.json) files."
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
@classmethod
|
|
302
|
+
def from_local_env(cls) -> "AuthConfig":
|
|
303
|
+
"""Creates an AuthConfig instance by loading configuration from environment variables.
|
|
304
|
+
|
|
305
|
+
This method loads configuration for all nested components (RabbitMQ, OpenAI, GraphDB)
|
|
306
|
+
from their respective environment variables using each component's specific prefix.
|
|
307
|
+
If any component fails to initialize, it will be set to None and a warning will be logged.
|
|
308
|
+
|
|
309
|
+
Returns:
|
|
310
|
+
AuthConfig: Configured instance with values from environment variables
|
|
311
|
+
|
|
312
|
+
Raises:
|
|
313
|
+
ValueError: If all components fail to initialize
|
|
314
|
+
"""
|
|
315
|
+
logger = logging.getLogger(__name__)
|
|
316
|
+
|
|
317
|
+
rabbitmq_config = None
|
|
318
|
+
openai_config = None
|
|
319
|
+
graph_db_config = None
|
|
320
|
+
|
|
321
|
+
# Try to initialize RabbitMQ config - check if any RabbitMQ env vars exist
|
|
322
|
+
try:
|
|
323
|
+
rabbitmq_prefix = RabbitMQConfig.get_env_prefix()
|
|
324
|
+
has_rabbitmq_env = any(key.startswith(rabbitmq_prefix) for key in os.environ)
|
|
325
|
+
if has_rabbitmq_env:
|
|
326
|
+
rabbitmq_config = RabbitMQConfig.from_env()
|
|
327
|
+
logger.info("Successfully initialized RabbitMQ configuration")
|
|
328
|
+
else:
|
|
329
|
+
logger.info(
|
|
330
|
+
"No RabbitMQ environment variables found, skipping RabbitMQ initialization"
|
|
331
|
+
)
|
|
332
|
+
except (ValueError, Exception) as e:
|
|
333
|
+
logger.warning(f"Failed to initialize RabbitMQ config from environment: {e}")
|
|
334
|
+
|
|
335
|
+
# Try to initialize OpenAI config - check if any OpenAI env vars exist
|
|
336
|
+
try:
|
|
337
|
+
openai_prefix = OpenAIConfig.get_env_prefix()
|
|
338
|
+
has_openai_env = any(key.startswith(openai_prefix) for key in os.environ)
|
|
339
|
+
if has_openai_env:
|
|
340
|
+
openai_config = OpenAIConfig.from_env()
|
|
341
|
+
logger.info("Successfully initialized OpenAI configuration")
|
|
342
|
+
else:
|
|
343
|
+
logger.info("No OpenAI environment variables found, skipping OpenAI initialization")
|
|
344
|
+
except (ValueError, Exception) as e:
|
|
345
|
+
logger.warning(f"Failed to initialize OpenAI config from environment: {e}")
|
|
346
|
+
|
|
347
|
+
# Try to initialize GraphDB config - check if any GraphDB env vars exist
|
|
348
|
+
try:
|
|
349
|
+
graphdb_prefix = GraphDBAuthConfig.get_env_prefix()
|
|
350
|
+
has_graphdb_env = any(key.startswith(graphdb_prefix) for key in os.environ)
|
|
351
|
+
if has_graphdb_env:
|
|
352
|
+
graph_db_config = GraphDBAuthConfig.from_env()
|
|
353
|
+
logger.info("Successfully initialized GraphDB configuration")
|
|
354
|
+
else:
|
|
355
|
+
logger.info(
|
|
356
|
+
"No GraphDB environment variables found, skipping GraphDB initialization"
|
|
357
|
+
)
|
|
358
|
+
except (ValueError, Exception) as e:
|
|
359
|
+
logger.warning(f"Failed to initialize GraphDB config from environment: {e}")
|
|
360
|
+
|
|
361
|
+
return cls(
|
|
362
|
+
rabbitmq=rabbitmq_config,
|
|
363
|
+
openai=openai_config,
|
|
364
|
+
graph_db=graph_db_config,
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
def set_openai_config_to_environment(self):
|
|
368
|
+
# Set environment variables only if openai config is available
|
|
369
|
+
if self.openai is not None:
|
|
370
|
+
os.environ["OPENAI_API_KEY"] = self.openai.api_key
|
|
371
|
+
os.environ["OPENAI_BASE_URL"] = self.openai.base_url
|
|
372
|
+
os.environ["MODEL"] = self.openai.default_model
|
|
373
|
+
else:
|
|
374
|
+
logger = logging.getLogger(__name__)
|
|
375
|
+
logger.warning("OpenAI config is not available, skipping environment variable setup")
|
|
376
|
+
|
|
377
|
+
@classmethod
|
|
378
|
+
def default_config_exists(cls) -> bool:
|
|
379
|
+
"""
|
|
380
|
+
Check if the default configuration file exists.
|
|
381
|
+
|
|
382
|
+
Returns:
|
|
383
|
+
bool: True if the default config file exists, False otherwise
|
|
384
|
+
"""
|
|
385
|
+
return Path(cls.default_config_path).exists()
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
from typing import Any, ClassVar
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field, field_validator, model_validator
|
|
4
|
+
|
|
5
|
+
from memos.configs.base import BaseConfig
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class BaseUserManagerConfig(BaseConfig):
|
|
9
|
+
"""Base configuration class for user managers."""
|
|
10
|
+
|
|
11
|
+
user_id: str = Field(default="root", description="Default user ID for initialization")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class SQLiteUserManagerConfig(BaseUserManagerConfig):
|
|
15
|
+
"""SQLite user manager configuration."""
|
|
16
|
+
|
|
17
|
+
db_path: str | None = Field(
|
|
18
|
+
default=None,
|
|
19
|
+
description="Path to SQLite database file. If None, uses default path in MEMOS_DIR",
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class MySQLUserManagerConfig(BaseUserManagerConfig):
|
|
24
|
+
"""MySQL user manager configuration."""
|
|
25
|
+
|
|
26
|
+
host: str = Field(default="localhost", description="MySQL server host")
|
|
27
|
+
port: int = Field(default=3306, description="MySQL server port")
|
|
28
|
+
username: str = Field(default="root", description="MySQL username")
|
|
29
|
+
password: str = Field(default="", description="MySQL password")
|
|
30
|
+
database: str = Field(default="memos_users", description="MySQL database name")
|
|
31
|
+
charset: str = Field(default="utf8mb4", description="MySQL charset")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class RedisUserManagerConfig(BaseUserManagerConfig):
|
|
35
|
+
"""Redis user manager configuration."""
|
|
36
|
+
|
|
37
|
+
host: str = Field(default="localhost", description="Redis server host")
|
|
38
|
+
port: int = Field(default=6379, description="Redis server port")
|
|
39
|
+
username: str = Field(default="root", description="Redis username")
|
|
40
|
+
password: str = Field(default="", description="Redis password")
|
|
41
|
+
database: str = Field(default="memos_users", description="Redis database name")
|
|
42
|
+
charset: str = Field(default="utf8mb4", description="Redis charset")
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class UserManagerConfigFactory(BaseModel):
|
|
46
|
+
"""Factory for user manager configurations."""
|
|
47
|
+
|
|
48
|
+
backend: str = Field(default="sqlite", description="Backend for user manager")
|
|
49
|
+
config: dict[str, Any] = Field(
|
|
50
|
+
default_factory=dict, description="Configuration for the user manager backend"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
backend_to_class: ClassVar[dict[str, Any]] = {
|
|
54
|
+
"sqlite": SQLiteUserManagerConfig,
|
|
55
|
+
"mysql": MySQLUserManagerConfig,
|
|
56
|
+
"redis": RedisUserManagerConfig,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
@field_validator("backend")
|
|
60
|
+
@classmethod
|
|
61
|
+
def validate_backend(cls, backend: str) -> str:
|
|
62
|
+
if backend not in cls.backend_to_class:
|
|
63
|
+
raise ValueError(f"Unsupported user manager backend: {backend}")
|
|
64
|
+
return backend
|
|
65
|
+
|
|
66
|
+
@model_validator(mode="after")
|
|
67
|
+
def instantiate_config(self):
|
|
68
|
+
config_class = self.backend_to_class[self.backend]
|
|
69
|
+
self.config = config_class(**self.config)
|
|
70
|
+
return self
|