MemoryOS 0.2.0__py3-none-any.whl → 0.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of MemoryOS might be problematic. Click here for more details.
- {memoryos-0.2.0.dist-info → memoryos-0.2.2.dist-info}/METADATA +67 -26
- memoryos-0.2.2.dist-info/RECORD +169 -0
- memoryos-0.2.2.dist-info/entry_points.txt +3 -0
- memos/__init__.py +1 -1
- memos/api/config.py +562 -0
- memos/api/context/context.py +147 -0
- memos/api/context/dependencies.py +90 -0
- memos/api/exceptions.py +28 -0
- memos/api/mcp_serve.py +502 -0
- memos/api/product_api.py +35 -0
- memos/api/product_models.py +163 -0
- memos/api/routers/__init__.py +1 -0
- memos/api/routers/product_router.py +386 -0
- memos/chunkers/sentence_chunker.py +8 -2
- memos/cli.py +113 -0
- memos/configs/embedder.py +27 -0
- memos/configs/graph_db.py +132 -3
- memos/configs/internet_retriever.py +6 -0
- memos/configs/llm.py +47 -0
- memos/configs/mem_cube.py +1 -1
- memos/configs/mem_os.py +5 -0
- memos/configs/mem_reader.py +9 -0
- memos/configs/mem_scheduler.py +107 -7
- memos/configs/mem_user.py +58 -0
- memos/configs/memory.py +5 -4
- memos/dependency.py +52 -0
- memos/embedders/ark.py +92 -0
- memos/embedders/factory.py +4 -0
- memos/embedders/sentence_transformer.py +8 -2
- memos/embedders/universal_api.py +32 -0
- memos/graph_dbs/base.py +11 -3
- memos/graph_dbs/factory.py +4 -0
- memos/graph_dbs/nebular.py +1364 -0
- memos/graph_dbs/neo4j.py +333 -124
- memos/graph_dbs/neo4j_community.py +300 -0
- memos/llms/base.py +9 -0
- memos/llms/deepseek.py +54 -0
- memos/llms/factory.py +10 -1
- memos/llms/hf.py +170 -13
- memos/llms/hf_singleton.py +114 -0
- memos/llms/ollama.py +4 -0
- memos/llms/openai.py +67 -1
- memos/llms/qwen.py +63 -0
- memos/llms/vllm.py +153 -0
- memos/log.py +1 -1
- memos/mem_cube/general.py +77 -16
- memos/mem_cube/utils.py +109 -0
- memos/mem_os/core.py +251 -51
- memos/mem_os/main.py +94 -12
- memos/mem_os/product.py +1220 -43
- memos/mem_os/utils/default_config.py +352 -0
- memos/mem_os/utils/format_utils.py +1401 -0
- memos/mem_reader/simple_struct.py +18 -10
- memos/mem_scheduler/base_scheduler.py +441 -40
- memos/mem_scheduler/general_scheduler.py +249 -248
- memos/mem_scheduler/modules/base.py +14 -5
- memos/mem_scheduler/modules/dispatcher.py +67 -4
- memos/mem_scheduler/modules/misc.py +104 -0
- memos/mem_scheduler/modules/monitor.py +240 -50
- memos/mem_scheduler/modules/rabbitmq_service.py +319 -0
- memos/mem_scheduler/modules/redis_service.py +32 -22
- memos/mem_scheduler/modules/retriever.py +167 -23
- memos/mem_scheduler/modules/scheduler_logger.py +255 -0
- memos/mem_scheduler/mos_for_test_scheduler.py +140 -0
- memos/mem_scheduler/schemas/__init__.py +0 -0
- memos/mem_scheduler/schemas/general_schemas.py +43 -0
- memos/mem_scheduler/{modules/schemas.py → schemas/message_schemas.py} +63 -61
- memos/mem_scheduler/schemas/monitor_schemas.py +329 -0
- memos/mem_scheduler/utils/__init__.py +0 -0
- memos/mem_scheduler/utils/filter_utils.py +176 -0
- memos/mem_scheduler/utils/misc_utils.py +61 -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 +500 -0
- memos/mem_user/persistent_factory.py +96 -0
- memos/mem_user/persistent_user_manager.py +260 -0
- memos/mem_user/user_manager.py +4 -4
- memos/memories/activation/item.py +29 -0
- memos/memories/activation/kv.py +10 -3
- memos/memories/activation/vllmkv.py +219 -0
- memos/memories/factory.py +2 -0
- memos/memories/textual/base.py +1 -1
- memos/memories/textual/general.py +43 -97
- memos/memories/textual/item.py +5 -33
- memos/memories/textual/tree.py +22 -12
- memos/memories/textual/tree_text_memory/organize/conflict.py +9 -5
- memos/memories/textual/tree_text_memory/organize/manager.py +26 -18
- memos/memories/textual/tree_text_memory/organize/redundancy.py +25 -44
- memos/memories/textual/tree_text_memory/organize/relation_reason_detector.py +50 -48
- memos/memories/textual/tree_text_memory/organize/reorganizer.py +81 -56
- memos/memories/textual/tree_text_memory/retrieve/internet_retriever.py +6 -3
- memos/memories/textual/tree_text_memory/retrieve/internet_retriever_factory.py +2 -0
- memos/memories/textual/tree_text_memory/retrieve/recall.py +0 -1
- memos/memories/textual/tree_text_memory/retrieve/reranker.py +2 -2
- memos/memories/textual/tree_text_memory/retrieve/retrieval_mid_structs.py +2 -0
- memos/memories/textual/tree_text_memory/retrieve/searcher.py +52 -28
- memos/memories/textual/tree_text_memory/retrieve/task_goal_parser.py +42 -15
- memos/memories/textual/tree_text_memory/retrieve/utils.py +11 -7
- memos/memories/textual/tree_text_memory/retrieve/xinyusearch.py +62 -58
- memos/memos_tools/dinding_report_bot.py +422 -0
- memos/memos_tools/notification_service.py +44 -0
- memos/memos_tools/notification_utils.py +96 -0
- memos/parsers/markitdown.py +8 -2
- memos/settings.py +3 -1
- memos/templates/mem_reader_prompts.py +66 -23
- memos/templates/mem_scheduler_prompts.py +126 -43
- memos/templates/mos_prompts.py +87 -0
- memos/templates/tree_reorganize_prompts.py +85 -30
- memos/vec_dbs/base.py +12 -0
- memos/vec_dbs/qdrant.py +46 -20
- memoryos-0.2.0.dist-info/RECORD +0 -128
- memos/mem_scheduler/utils.py +0 -26
- {memoryos-0.2.0.dist-info → memoryos-0.2.2.dist-info}/LICENSE +0 -0
- {memoryos-0.2.0.dist-info → memoryos-0.2.2.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Global request context management for trace_id and request-scoped data.
|
|
3
|
+
|
|
4
|
+
This module provides optional trace_id functionality that can be enabled
|
|
5
|
+
when using the API components. It uses ContextVar to ensure thread safety
|
|
6
|
+
and request isolation.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import uuid
|
|
10
|
+
|
|
11
|
+
from collections.abc import Callable
|
|
12
|
+
from contextvars import ContextVar
|
|
13
|
+
from typing import Any
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# Global context variable for request-scoped data
|
|
17
|
+
_request_context: ContextVar[dict[str, Any] | None] = ContextVar("request_context", default=None)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class RequestContext:
|
|
21
|
+
"""
|
|
22
|
+
Request-scoped context object that holds trace_id and other request data.
|
|
23
|
+
|
|
24
|
+
This provides a Flask g-like object for FastAPI applications.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, trace_id: str | None = None):
|
|
28
|
+
self.trace_id = trace_id or str(uuid.uuid4())
|
|
29
|
+
self._data: dict[str, Any] = {}
|
|
30
|
+
|
|
31
|
+
def set(self, key: str, value: Any) -> None:
|
|
32
|
+
"""Set a value in the context."""
|
|
33
|
+
self._data[key] = value
|
|
34
|
+
|
|
35
|
+
def get(self, key: str, default: Any | None = None) -> Any:
|
|
36
|
+
"""Get a value from the context."""
|
|
37
|
+
return self._data.get(key, default)
|
|
38
|
+
|
|
39
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
|
40
|
+
if name.startswith("_") or name == "trace_id":
|
|
41
|
+
super().__setattr__(name, value)
|
|
42
|
+
else:
|
|
43
|
+
if not hasattr(self, "_data"):
|
|
44
|
+
super().__setattr__(name, value)
|
|
45
|
+
else:
|
|
46
|
+
self._data[name] = value
|
|
47
|
+
|
|
48
|
+
def __getattr__(self, name: str) -> Any:
|
|
49
|
+
if hasattr(self, "_data") and name in self._data:
|
|
50
|
+
return self._data[name]
|
|
51
|
+
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
|
|
52
|
+
|
|
53
|
+
def to_dict(self) -> dict[str, Any]:
|
|
54
|
+
"""Convert context to dictionary."""
|
|
55
|
+
return {"trace_id": self.trace_id, "data": self._data.copy()}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def set_request_context(context: RequestContext) -> None:
|
|
59
|
+
"""
|
|
60
|
+
Set the current request context.
|
|
61
|
+
|
|
62
|
+
This is typically called by the API dependency injection system.
|
|
63
|
+
"""
|
|
64
|
+
_request_context.set(context.to_dict())
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def get_current_trace_id() -> str | None:
|
|
68
|
+
"""
|
|
69
|
+
Get the current request's trace_id.
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
The trace_id if available, None otherwise.
|
|
73
|
+
"""
|
|
74
|
+
context = _request_context.get()
|
|
75
|
+
if context:
|
|
76
|
+
return context.get("trace_id")
|
|
77
|
+
return None
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def get_current_context() -> RequestContext | None:
|
|
81
|
+
"""
|
|
82
|
+
Get the current request context.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
The current RequestContext if available, None otherwise.
|
|
86
|
+
"""
|
|
87
|
+
context_dict = _request_context.get()
|
|
88
|
+
if context_dict:
|
|
89
|
+
ctx = RequestContext(trace_id=context_dict.get("trace_id"))
|
|
90
|
+
ctx._data = context_dict.get("data", {}).copy()
|
|
91
|
+
return ctx
|
|
92
|
+
return None
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def require_context() -> RequestContext:
|
|
96
|
+
"""
|
|
97
|
+
Get the current request context, raising an error if not available.
|
|
98
|
+
|
|
99
|
+
Returns:
|
|
100
|
+
The current RequestContext.
|
|
101
|
+
|
|
102
|
+
Raises:
|
|
103
|
+
RuntimeError: If called outside of a request context.
|
|
104
|
+
"""
|
|
105
|
+
context = get_current_context()
|
|
106
|
+
if context is None:
|
|
107
|
+
raise RuntimeError(
|
|
108
|
+
"No request context available. This function must be called within a request handler."
|
|
109
|
+
)
|
|
110
|
+
return context
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
# Type for trace_id getter function
|
|
114
|
+
TraceIdGetter = Callable[[], str | None]
|
|
115
|
+
|
|
116
|
+
# Global variable to hold the trace_id getter function
|
|
117
|
+
_trace_id_getter: TraceIdGetter | None = None
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def set_trace_id_getter(getter: TraceIdGetter) -> None:
|
|
121
|
+
"""
|
|
122
|
+
Set a custom trace_id getter function.
|
|
123
|
+
|
|
124
|
+
This allows the logging system to retrieve trace_id without importing
|
|
125
|
+
API-specific modules.
|
|
126
|
+
"""
|
|
127
|
+
global _trace_id_getter
|
|
128
|
+
_trace_id_getter = getter
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def get_trace_id_for_logging() -> str | None:
|
|
132
|
+
"""
|
|
133
|
+
Get trace_id for logging purposes.
|
|
134
|
+
|
|
135
|
+
This function is used by the logging system and will use either
|
|
136
|
+
the custom getter function or fall back to the default context.
|
|
137
|
+
"""
|
|
138
|
+
if _trace_id_getter:
|
|
139
|
+
try:
|
|
140
|
+
return _trace_id_getter()
|
|
141
|
+
except Exception:
|
|
142
|
+
pass
|
|
143
|
+
return get_current_trace_id()
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
# Initialize the default trace_id getter
|
|
147
|
+
set_trace_id_getter(get_current_trace_id)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from fastapi import Depends, Header, Request
|
|
4
|
+
|
|
5
|
+
from memos.api.context.context import RequestContext, set_request_context
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
logger = logging.getLogger(__name__)
|
|
9
|
+
|
|
10
|
+
# Type alias for the RequestContext from context module
|
|
11
|
+
G = RequestContext
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_trace_id_from_header(
|
|
15
|
+
trace_id: str | None = Header(None, alias="trace-id"),
|
|
16
|
+
x_trace_id: str | None = Header(None, alias="x-trace-id"),
|
|
17
|
+
g_trace_id: str | None = Header(None, alias="g-trace-id"),
|
|
18
|
+
) -> str | None:
|
|
19
|
+
"""
|
|
20
|
+
Extract trace_id from various possible headers.
|
|
21
|
+
|
|
22
|
+
Priority: g-trace-id > x-trace-id > trace-id
|
|
23
|
+
"""
|
|
24
|
+
return g_trace_id or x_trace_id or trace_id
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_request_context(
|
|
28
|
+
request: Request, trace_id: str | None = Depends(get_trace_id_from_header)
|
|
29
|
+
) -> RequestContext:
|
|
30
|
+
"""
|
|
31
|
+
Get request context object with trace_id and request metadata.
|
|
32
|
+
|
|
33
|
+
This function creates a RequestContext and automatically sets it
|
|
34
|
+
in the global context for use throughout the request lifecycle.
|
|
35
|
+
"""
|
|
36
|
+
# Create context object
|
|
37
|
+
ctx = RequestContext(trace_id=trace_id)
|
|
38
|
+
|
|
39
|
+
# Set the context globally for this request
|
|
40
|
+
set_request_context(ctx)
|
|
41
|
+
|
|
42
|
+
# Log request start
|
|
43
|
+
logger.info(f"Request started with trace_id: {ctx.trace_id}")
|
|
44
|
+
|
|
45
|
+
# Add request metadata to context
|
|
46
|
+
ctx.set("method", request.method)
|
|
47
|
+
ctx.set("path", request.url.path)
|
|
48
|
+
ctx.set("client_ip", request.client.host if request.client else None)
|
|
49
|
+
|
|
50
|
+
return ctx
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_g_object(trace_id: str | None = Depends(get_trace_id_from_header)) -> G:
|
|
54
|
+
"""
|
|
55
|
+
Get Flask g-like object for the current request.
|
|
56
|
+
|
|
57
|
+
This creates a RequestContext and sets it globally for access
|
|
58
|
+
throughout the request lifecycle.
|
|
59
|
+
"""
|
|
60
|
+
g = RequestContext(trace_id=trace_id)
|
|
61
|
+
set_request_context(g)
|
|
62
|
+
logger.info(f"Request g object created with trace_id: {g.trace_id}")
|
|
63
|
+
return g
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def get_current_g() -> G | None:
|
|
67
|
+
"""
|
|
68
|
+
Get the current request's g object from anywhere in the application.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
The current request's g object if available, None otherwise.
|
|
72
|
+
"""
|
|
73
|
+
from memos.context import get_current_context
|
|
74
|
+
|
|
75
|
+
return get_current_context()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def require_g() -> G:
|
|
79
|
+
"""
|
|
80
|
+
Get the current request's g object, raising an error if not available.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
The current request's g object.
|
|
84
|
+
|
|
85
|
+
Raises:
|
|
86
|
+
RuntimeError: If called outside of a request context.
|
|
87
|
+
"""
|
|
88
|
+
from memos.context import require_context
|
|
89
|
+
|
|
90
|
+
return require_context()
|
memos/api/exceptions.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from fastapi.requests import Request
|
|
4
|
+
from fastapi.responses import JSONResponse
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class APIExceptionHandler:
|
|
11
|
+
"""Centralized exception handling for MemOS APIs."""
|
|
12
|
+
|
|
13
|
+
@staticmethod
|
|
14
|
+
async def value_error_handler(request: Request, exc: ValueError):
|
|
15
|
+
"""Handle ValueError exceptions globally."""
|
|
16
|
+
return JSONResponse(
|
|
17
|
+
status_code=400,
|
|
18
|
+
content={"code": 400, "message": str(exc), "data": None},
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
@staticmethod
|
|
22
|
+
async def global_exception_handler(request: Request, exc: Exception):
|
|
23
|
+
"""Handle all unhandled exceptions globally."""
|
|
24
|
+
logger.exception("Unhandled error:")
|
|
25
|
+
return JSONResponse(
|
|
26
|
+
status_code=500,
|
|
27
|
+
content={"code": 500, "message": str(exc), "data": None},
|
|
28
|
+
)
|