Skip to content

Commit c299e59

Browse files
author
yuan.wang
committed
merge dev solve confict
2 parents 245f151 + ed38546 commit c299e59

File tree

13 files changed

+242
-141
lines changed

13 files changed

+242
-141
lines changed

src/memos/api/handlers/add_handler.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
from memos.api.handlers.base_handler import BaseHandler, HandlerDependencies
99
from memos.api.product_models import APIADDRequest, MemoryResponse
10+
from memos.memories.textual.item import (
11+
list_all_fields,
12+
)
1013
from memos.multi_mem_cube.composite_cube import CompositeCubeView
1114
from memos.multi_mem_cube.single_cube import SingleCubeView
1215
from memos.multi_mem_cube.views import MemCubeView
@@ -44,6 +47,13 @@ def handle_add_memories(self, add_req: APIADDRequest) -> MemoryResponse:
4447
"""
4548
self.logger.info(f"[AddHandler] Add Req is: {add_req}")
4649

50+
if add_req.info:
51+
exclude_fields = list_all_fields()
52+
info_len = len(add_req.info)
53+
add_req.info = {k: v for k, v in add_req.info.items() if k not in exclude_fields}
54+
if len(add_req.info) < info_len:
55+
self.logger.warning(f"[AddHandler] info fields can not contain {exclude_fields}.")
56+
4757
cube_view = self._build_cube_view(add_req)
4858

4959
results = cube_view.add_memories(add_req)

src/memos/api/handlers/memory_handler.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
This module handles retrieving all memories or specific subgraphs based on queries.
55
"""
66

7-
from typing import Any, Literal
7+
from typing import TYPE_CHECKING, Any, Literal
88

99
from memos.api.handlers.formatters_handler import format_memory_item
1010
from memos.api.product_models import (
@@ -24,6 +24,10 @@
2424
)
2525

2626

27+
if TYPE_CHECKING:
28+
from memos.memories.textual.preference import TextualMemoryItem
29+
30+
2731
logger = get_logger(__name__)
2832

2933

@@ -161,17 +165,20 @@ def handle_get_subgraph(
161165
def handle_get_memories(get_mem_req: GetMemoryRequest, naive_mem_cube: Any) -> GetMemoryResponse:
162166
# TODO: Implement get memory with filter
163167
memories = naive_mem_cube.text_mem.get_all(user_name=get_mem_req.mem_cube_id)["nodes"]
164-
filter_params: dict[str, Any] = {}
165-
if get_mem_req.user_id is not None:
166-
filter_params["user_id"] = get_mem_req.user_id
167-
if get_mem_req.mem_cube_id is not None:
168-
filter_params["mem_cube_id"] = get_mem_req.mem_cube_id
169-
preferences = naive_mem_cube.pref_mem.get_memory_by_filter(filter_params)
168+
preferences: list[TextualMemoryItem] = []
169+
if get_mem_req.include_preference:
170+
filter_params: dict[str, Any] = {}
171+
if get_mem_req.user_id is not None:
172+
filter_params["user_id"] = get_mem_req.user_id
173+
if get_mem_req.mem_cube_id is not None:
174+
filter_params["mem_cube_id"] = get_mem_req.mem_cube_id
175+
preferences = naive_mem_cube.pref_mem.get_memory_by_filter(filter_params)
176+
preferences = [format_memory_item(mem) for mem in preferences]
170177
return GetMemoryResponse(
171178
message="Memories retrieved successfully",
172179
data={
173180
"text_mem": memories,
174-
"pref_mem": [format_memory_item(mem) for mem in preferences],
181+
"pref_mem": preferences,
175182
},
176183
)
177184

src/memos/api/product_models.py

Lines changed: 93 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
# Import message types from core types module
88
from memos.log import get_logger
9-
from memos.types import MessageDict, MessagesType, PermissionDict, SearchMode
9+
from memos.types import MessageList, MessagesType, PermissionDict, SearchMode
1010

1111

1212
logger = get_logger(__name__)
@@ -76,121 +76,43 @@ class ChatRequest(BaseRequest):
7676

7777
# ==== Basic identifiers ====
7878
user_id: str = Field(..., description="User ID")
79-
session_id: str | None = Field(
80-
None,
81-
description=(
82-
"Session ID. Used as a soft signal to give higher weight to "
83-
"recently related memories. Optional for developer API."
84-
),
85-
)
86-
87-
# ==== Query ====
88-
query: str = Field(..., description="Chat query message from user")
89-
90-
# ==== Cube scoping ====
79+
query: str = Field(..., description="Chat query message")
9180
readable_cube_ids: list[str] | None = Field(
92-
None,
93-
description=(
94-
"List of cube IDs user can read for multi-cube chat.\n"
95-
"- Algorithm interface: required\n"
96-
"- Developer API: optional (can fall back to mem_cube_id or defaults)"
97-
),
81+
None, description="List of cube IDs user can read for multi-cube chat"
9882
)
99-
10083
writable_cube_ids: list[str] | None = Field(
101-
None,
102-
description=(
103-
"List of cube IDs user can write for multi-cube chat.\n"
104-
"- Algorithm interface: required\n"
105-
"- Developer API: optional (can fall back to mem_cube_id or defaults)"
106-
),
107-
)
108-
109-
# ==== History & filters ====
110-
history: MessagesType | None = Field(
111-
None,
112-
description=(
113-
"Chat history (algorithm does NOT persist it). Algorithm interface default: []."
114-
),
84+
None, description="List of cube IDs user can write for multi-cube chat"
11585
)
86+
history: MessageList | None = Field(None, description="Chat history")
87+
mode: SearchMode = Field(SearchMode.FAST, description="search mode: fast, fine, or mixture")
88+
system_prompt: str | None = Field(None, description="Base system prompt to use for chat")
89+
top_k: int = Field(10, description="Number of results to return")
90+
session_id: str | None = Field(None, description="Session ID for soft-filtering memories")
91+
include_preference: bool = Field(True, description="Whether to handle preference memory")
92+
pref_top_k: int = Field(6, description="Number of preference results to return")
93+
model_name_or_path: str | None = Field(None, description="Model name to use for chat")
94+
max_tokens: int | None = Field(None, description="Max tokens to generate")
95+
temperature: float | None = Field(None, description="Temperature for sampling")
96+
top_p: float | None = Field(None, description="Top-p (nucleus) sampling parameter")
97+
add_message_on_answer: bool = Field(True, description="Add dialogs to memory after chat")
11698

99+
# ==== Filter conditions ====
117100
filter: dict[str, Any] | None = Field(
118101
None,
119-
description=(
120-
"Memory filter. Developers can provide custom structured predicates "
121-
"to precisely filter memories. Algorithm interface default: {}."
122-
),
123-
)
124-
125-
# ==== Retrieval configuration ====
126-
mode: SearchMode = Field(
127-
SearchMode.FAST,
128-
description="Search mode: fast, fine, or mixture.",
129-
)
130-
131-
top_k: int = Field(
132-
10,
133-
ge=1,
134-
description="Number of memories to retrieve (top-K).",
135-
)
136-
137-
pref_top_k: int = Field(
138-
6,
139-
ge=0,
140-
description="Number of preference memories to retrieve (top-K). Default: 6.",
141-
)
142-
143-
include_preference: bool = Field(
144-
True,
145-
description=(
146-
"Whether to retrieve preference memories. If enabled, the system will "
147-
"automatically recall user preferences related to the query. Default: True."
148-
),
149-
)
150-
151-
threshold: float = Field(
152-
0.5,
153-
description="Internal similarity threshold for filtering references (algorithm internal).",
154-
)
155-
156-
# ==== LLM / generation configuration ====
157-
system_prompt: str | None = Field(
158-
None,
159-
description="Custom system prompt / instruction for this chat.",
160-
)
161-
162-
model_name_or_path: str | None = Field(
163-
None,
164-
description=("Name or path of the chat model to use.\nAlgorithm default: 'gpt-4o-mini'."),
165-
)
166-
167-
max_tokens: int | None = Field(
168-
None,
169-
description="Max tokens to generate. Algorithm default: 8192.",
170-
)
171-
172-
temperature: float | None = Field(
173-
None,
174-
description="Sampling temperature. Algorithm default: 0.7.",
175-
)
176-
177-
top_p: float | None = Field(
178-
None,
179-
description="Top-p (nucleus) sampling parameter. Algorithm default: 0.95.",
180-
)
181-
182-
add_message_on_answer: bool = Field(
183-
True,
184-
description="Whether to append dialog messages to memory after chat. Default: True.",
102+
description="""
103+
Filter for the memory, example:
104+
{
105+
"`and` or `or`": [
106+
{"id": "uuid-xxx"},
107+
{"created_at": {"gt": "2024-01-01"}},
108+
]
109+
}
110+
""",
185111
)
186112

187-
# ==== Search / pipeline toggles ====
188-
internet_search: bool = Field(
189-
True,
190-
description=(
191-
"Whether to use internet search (internal usage; external API may ignore this flag)."
192-
),
193-
)
113+
# ==== Extended capabilities ====
114+
internet_search: bool = Field(True, description="Whether to use internet search")
115+
threshold: float = Field(0.5, description="Threshold for filtering references")
194116

195117
# ==== Backward compatibility ====
196118
moscube: bool = Field(
@@ -237,17 +159,13 @@ def _convert_deprecated_fields(self):
237159
return self
238160

239161

240-
class APIChatCompleteRequest(ChatRequest):
241-
"""Request model for complete chat."""
242-
243-
244162
class ChatCompleteRequest(BaseRequest):
245-
"""Request model for chat operations."""
163+
"""Request model for chat operations. will (Deprecated), instead use APIChatCompleteRequest."""
246164

247165
user_id: str = Field(..., description="User ID")
248166
query: str = Field(..., description="Chat query message")
249167
mem_cube_id: str | None = Field(None, description="Cube ID to use for chat")
250-
history: list[MessageDict] | None = Field(None, description="Chat history")
168+
history: MessageList | None = Field(None, description="Chat history")
251169
internet_search: bool = Field(False, description="Whether to use internet search")
252170
system_prompt: str | None = Field(None, description="Base prompt to use for chat")
253171
top_k: int = Field(10, description="Number of results to return")
@@ -333,7 +251,7 @@ class MemoryCreateRequest(BaseRequest):
333251
"""Request model for creating memories."""
334252

335253
user_id: str = Field(..., description="User ID")
336-
messages: list[MessageDict] | None = Field(None, description="List of messages to store.")
254+
messages: MessagesType | None = Field(None, description="List of messages to store.")
337255
memory_content: str | None = Field(None, description="Memory content to store")
338256
doc_path: str | None = Field(None, description="Path to document to store")
339257
mem_cube_id: str | None = Field(None, description="Cube ID")
@@ -411,7 +329,15 @@ class APISearchRequest(BaseRequest):
411329
# TODO: maybe add detailed description later
412330
filter: dict[str, Any] | None = Field(
413331
None,
414-
description=("Filter for the memory"),
332+
description="""
333+
Filter for the memory, example:
334+
{
335+
"`and` or `or`": [
336+
{"id": "uuid-xxx"},
337+
{"created_at": {"gt": "2024-01-01"}},
338+
]
339+
}
340+
""",
415341
)
416342

417343
# ==== Extended capabilities ====
@@ -433,7 +359,7 @@ class APISearchRequest(BaseRequest):
433359
)
434360

435361
# ==== Context ====
436-
chat_history: MessagesType | None = Field(
362+
chat_history: MessageList | None = Field(
437363
None,
438364
description=(
439365
"Historical chat messages used internally by algorithms. "
@@ -573,7 +499,7 @@ class APIADDRequest(BaseRequest):
573499
)
574500

575501
# ==== Chat history ====
576-
chat_history: MessagesType | None = Field(
502+
chat_history: MessageList | None = Field(
577503
None,
578504
description=(
579505
"Historical chat messages used internally by algorithms. "
@@ -695,6 +621,55 @@ def _convert_deprecated_fields(self) -> "APIADDRequest":
695621
return self
696622

697623

624+
class APIChatCompleteRequest(BaseRequest):
625+
"""Request model for chat operations."""
626+
627+
user_id: str = Field(..., description="User ID")
628+
query: str = Field(..., description="Chat query message")
629+
readable_cube_ids: list[str] | None = Field(
630+
None, description="List of cube IDs user can read for multi-cube chat"
631+
)
632+
writable_cube_ids: list[str] | None = Field(
633+
None, description="List of cube IDs user can write for multi-cube chat"
634+
)
635+
history: MessageList | None = Field(None, description="Chat history")
636+
mode: SearchMode = Field(SearchMode.FAST, description="search mode: fast, fine, or mixture")
637+
system_prompt: str | None = Field(None, description="Base system prompt to use for chat")
638+
top_k: int = Field(10, description="Number of results to return")
639+
session_id: str | None = Field(None, description="Session ID for soft-filtering memories")
640+
include_preference: bool = Field(True, description="Whether to handle preference memory")
641+
pref_top_k: int = Field(6, description="Number of preference results to return")
642+
model_name_or_path: str | None = Field(None, description="Model name to use for chat")
643+
max_tokens: int | None = Field(None, description="Max tokens to generate")
644+
temperature: float | None = Field(None, description="Temperature for sampling")
645+
top_p: float | None = Field(None, description="Top-p (nucleus) sampling parameter")
646+
add_message_on_answer: bool = Field(True, description="Add dialogs to memory after chat")
647+
648+
# ==== Filter conditions ====
649+
filter: dict[str, Any] | None = Field(
650+
None,
651+
description="""
652+
Filter for the memory, example:
653+
{
654+
"`and` or `or`": [
655+
{"id": "uuid-xxx"},
656+
{"created_at": {"gt": "2024-01-01"}},
657+
]
658+
}
659+
""",
660+
)
661+
662+
# ==== Extended capabilities ====
663+
internet_search: bool = Field(True, description="Whether to use internet search")
664+
threshold: float = Field(0.5, description="Threshold for filtering references")
665+
666+
# ==== Backward compatibility ====
667+
mem_cube_id: str | None = Field(None, description="Cube ID to use for chat")
668+
moscube: bool = Field(
669+
False, description="(Deprecated) Whether to use legacy MemOSCube pipeline"
670+
)
671+
672+
698673
class AddStatusRequest(BaseRequest):
699674
"""Request model for checking add status."""
700675

@@ -723,7 +698,7 @@ class SuggestionRequest(BaseRequest):
723698
user_id: str = Field(..., description="User ID")
724699
mem_cube_id: str = Field(..., description="Cube ID")
725700
language: Literal["zh", "en"] = Field("zh", description="Language for suggestions")
726-
message: list[MessageDict] | None = Field(None, description="List of messages to store.")
701+
message: MessagesType | None = Field(None, description="List of messages to store.")
727702

728703

729704
# ─── MemOS Client Response Models ──────────────────────────────────────────────

0 commit comments

Comments
 (0)