Skip to content

Commit bf1d4fc

Browse files
committed
Merge branch 'dev' into feat/mem-search-rank
2 parents cf52276 + 362c32a commit bf1d4fc

File tree

11 files changed

+93
-26
lines changed

11 files changed

+93
-26
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ MemOS is licensed under the [Apache 2.0 License](./LICENSE).
252252
Stay up to date with the latest MemOS announcements, releases, and community highlights.
253253

254254

255+
- **2025-09-10** - 🎉 *MemOS v1.0.1 (Group Q&A Bot)*: Group Q&A bot based on MemOS Cube, updated KV-Cache performance comparison data across different GPU deployment schemes, optimized test benchmarks and statistics, added plaintext memory Reranker sorting, optimized plaintext memory hallucination issues, and Playground version updates. [Try PlayGround](https://memos-playground.openmem.net/login/)
255256
- **2025-08-07** - 🎉 *MemOS v1.0.0 (MemCube Release)*: First MemCube with word game demo, LongMemEval evaluation, BochaAISearchRetriever integration, NebulaGraph support, enhanced search capabilities, and official Playground launch.
256257
- **2025-07-29** – 🎉 *MemOS v0.2.2 (Nebula Update)*: Internet search+Nebula DB integration, refactored memory scheduler, KV Cache stress tests, MemCube Cookbook release (CN/EN), and 4b/1.7b/0.6b memory ops models.
257258
- **2025-07-21** – 🎉 *MemOS v0.2.1 (Neo Release)*: Lightweight Neo version with plaintext+KV Cache functionality, Docker/multi-tenant support, MCP expansion, and new Cookbook/Mud game examples.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
##############################################################################
55

66
name = "MemoryOS"
7-
version = "1.0.0"
7+
version = "1.0.1"
88
description = "Intelligence Begins with Memory"
99
license = {text = "Apache-2.0"}
1010
readme = "README.md"

src/memos/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
__version__ = "1.0.0"
1+
__version__ = "1.0.1"
22

33
from memos.configs.mem_cube import GeneralMemCubeConfig
44
from memos.configs.mem_os import MOSConfig

src/memos/api/product_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
app = FastAPI(
1515
title="MemOS Product REST APIs",
1616
description="A REST API for managing multiple users with MemOS Product.",
17-
version="1.0.0",
17+
version="1.0.1",
1818
)
1919

2020
# Add request context middleware (must be added first)

src/memos/mem_os/product.py

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,10 @@ def _format_mem_block(memories_all, max_items: int = 20, max_chars_each: int = 3
6767
sequence is [i:memId] i; [P]=PersonalMemory / [O]=OuterMemory
6868
"""
6969
if not memories_all:
70-
return "(none)"
70+
return "(none)", "(none)"
7171

72-
lines = []
72+
lines_o = []
73+
lines_p = []
7374
for idx, m in enumerate(memories_all[:max_items], 1):
7475
mid = _short_id(getattr(m, "id", "") or "")
7576
mtype = getattr(getattr(m, "metadata", {}), "memory_type", None) or getattr(
@@ -80,8 +81,11 @@ def _format_mem_block(memories_all, max_items: int = 20, max_chars_each: int = 3
8081
if len(txt) > max_chars_each:
8182
txt = txt[: max_chars_each - 1] + "…"
8283
mid = mid or f"mem_{idx}"
83-
lines.append(f"[{idx}:{mid}] :: [{tag}] {txt}")
84-
return "\n".join(lines)
84+
if tag == "O":
85+
lines_o.append(f"[{idx}:{mid}] :: [{tag}] {txt}\n")
86+
elif tag == "P":
87+
lines_p.append(f"[{idx}:{mid}] :: [{tag}] {txt}")
88+
return "\n".join(lines_o), "\n".join(lines_p)
8589

8690

8791
class MOSProduct(MOSCore):
@@ -410,7 +414,8 @@ def _build_system_prompt(
410414
sys_body = get_memos_prompt(
411415
date=formatted_date, tone=tone, verbosity=verbosity, mode="base"
412416
)
413-
mem_block = _format_mem_block(memories_all)
417+
mem_block_o, mem_block_p = _format_mem_block(memories_all)
418+
mem_block = mem_block_o + "\n" + mem_block_p
414419
prefix = (base_prompt.strip() + "\n\n") if base_prompt else ""
415420
return (
416421
prefix
@@ -434,8 +439,14 @@ def _build_enhance_system_prompt(
434439
sys_body = get_memos_prompt(
435440
date=formatted_date, tone=tone, verbosity=verbosity, mode="enhance"
436441
)
437-
mem_block = _format_mem_block(memories_all)
438-
return sys_body + "\n\n# Memories\n## PersonalMemory & OuterMemory (ordered)\n" + mem_block
442+
mem_block_o, mem_block_p = _format_mem_block(memories_all)
443+
return (
444+
sys_body
445+
+ "\n\n# Memories\n## PersonalMemory (ordered)\n"
446+
+ mem_block_p
447+
+ "\n## OuterMemory (ordered)\n"
448+
+ mem_block_o
449+
)
439450

440451
def _extract_references_from_response(self, response: str) -> tuple[str, list[dict]]:
441452
"""
@@ -693,16 +704,39 @@ def run_async_in_thread():
693704
thread.start()
694705

695706
def _filter_memories_by_threshold(
696-
self, memories: list[TextualMemoryItem], threshold: float = 0.52, min_num: int = 0
707+
self,
708+
memories: list[TextualMemoryItem],
709+
threshold: float = 0.30,
710+
min_num: int = 3,
711+
memory_type: Literal["OuterMemory"] = "OuterMemory",
697712
) -> list[TextualMemoryItem]:
698713
"""
699-
Filter memories by threshold.
714+
Filter memories by threshold and type, at least min_num memories for Non-OuterMemory.
715+
Args:
716+
memories: list[TextualMemoryItem],
717+
threshold: float,
718+
min_num: int,
719+
memory_type: Literal["OuterMemory"],
720+
Returns:
721+
list[TextualMemoryItem]
700722
"""
701723
sorted_memories = sorted(memories, key=lambda m: m.metadata.relativity, reverse=True)
702-
filtered = [m for m in sorted_memories if m.metadata.relativity >= threshold]
724+
filtered_person = [m for m in memories if m.metadata.memory_type != memory_type]
725+
filtered_outer = [m for m in memories if m.metadata.memory_type == memory_type]
726+
filtered = []
727+
per_memory_count = 0
728+
for m in sorted_memories:
729+
if m.metadata.relativity >= threshold:
730+
if m.metadata.memory_type != memory_type:
731+
per_memory_count += 1
732+
filtered.append(m)
703733
if len(filtered) < min_num:
704-
filtered = sorted_memories[:min_num]
705-
return filtered
734+
filtered = filtered_person[:min_num] + filtered_outer[:min_num]
735+
else:
736+
if per_memory_count < min_num:
737+
filtered += filtered_person[per_memory_count:min_num]
738+
filtered_memory = sorted(filtered, key=lambda m: m.metadata.relativity, reverse=True)
739+
return filtered_memory
706740

707741
def register_mem_cube(
708742
self,
@@ -905,9 +939,16 @@ def chat(
905939
internet_search=internet_search,
906940
moscube=moscube,
907941
)["text_mem"]
942+
943+
memories_list = []
908944
if memories_result:
909945
memories_list = memories_result[0]["memories"]
910946
memories_list = self._filter_memories_by_threshold(memories_list, threshold)
947+
new_memories_list = []
948+
for m in memories_list:
949+
m.metadata.embedding = []
950+
new_memories_list.append(m)
951+
memories_list = new_memories_list
911952
system_prompt = super()._build_system_prompt(memories_list, base_prompt)
912953
history_info = []
913954
if history:
@@ -938,7 +979,7 @@ def chat_with_references(
938979
user_id: str,
939980
cube_id: str | None = None,
940981
history: MessageList | None = None,
941-
top_k: int = 10,
982+
top_k: int = 20,
942983
internet_search: bool = False,
943984
moscube: bool = False,
944985
) -> Generator[str, None, None]:
@@ -1284,6 +1325,7 @@ def search(
12841325
memories["metadata"]["memory"] = memories["memory"]
12851326
memories_list.append(memories)
12861327
reformat_memory_list.append({"cube_id": memory["cube_id"], "memories": memories_list})
1328+
logger.info(f"search memory list is : {reformat_memory_list}")
12871329
search_result["text_mem"] = reformat_memory_list
12881330
time_end = time.time()
12891331
logger.info(

src/memos/memories/textual/tree_text_memory/retrieve/bochasearch.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,9 @@ def _process_result(
218218
memory_items = []
219219
for read_item_i in read_items[0]:
220220
read_item_i.memory = (
221-
f"Title: {title}\nNewsTime: {publish_time}\nSummary: {summary}\n"
221+
f"[Outer internet view] Title: {title}\nNewsTime:"
222+
f" {publish_time}\nSummary:"
223+
f" {summary}\n"
222224
f"Content: {read_item_i.memory}"
223225
)
224226
read_item_i.metadata.source = "web"

src/memos/memories/textual/tree_text_memory/retrieve/recall.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ def _vector_recall(
179179
query_embedding: list[list[float]],
180180
memory_scope: str,
181181
top_k: int = 20,
182-
max_num: int = 5,
182+
max_num: int = 3,
183183
cube_name: str | None = None,
184184
) -> list[TextualMemoryItem]:
185185
"""

src/memos/memories/textual/tree_text_memory/retrieve/searcher.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ def search(
8787
self._update_usage_history(final_results, info)
8888

8989
logger.info(f"[SEARCH] Done. Total {len(final_results)} results.")
90+
res_results = ""
91+
for _num_i, result in enumerate(final_results):
92+
res_results += "\n" + (
93+
result.id + "|" + result.metadata.memory_type + "|" + result.memory
94+
)
95+
logger.info(f"[SEARCH] Results. {res_results}")
9096
return final_results
9197

9298
@timed
@@ -108,9 +114,10 @@ def _parse_task(self, query, info, mode, top_k=5):
108114
context = list({node["memory"] for node in related_nodes})
109115

110116
# optional: supplement context with internet knowledge
111-
if self.internet_retriever:
117+
"""if self.internet_retriever:
112118
extra = self.internet_retriever.retrieve_from_internet(query=query, top_k=3)
113119
context.extend(item.memory.partition("\nContent: ")[-1] for item in extra)
120+
"""
114121

115122
# parse goal using LLM
116123
parsed_goal = self.task_goal_parser.parse(

src/memos/memories/textual/tree_text_memory/retrieve/utils.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,20 @@
88
5. Need for internet search: If the user's task instruction only involves objective facts or can be completed without introducing external knowledge, set "internet_search" to False. Otherwise, set it to True.
99
6. Memories: Provide 2–5 short semantic expansions or rephrasings of the rephrased/original user task instruction. These are used for improved embedding search coverage. Each should be clear, concise, and meaningful for retrieval.
1010
11-
Task description:
12-
\"\"\"$task\"\"\"
13-
1411
Former conversation (if any):
1512
\"\"\"
1613
$conversation
1714
\"\"\"
1815
16+
Task description(User Question):
17+
\"\"\"$task\"\"\"
18+
1919
Context (if any):
2020
\"\"\"$context\"\"\"
2121
22-
Return strictly in this JSON format:
22+
Return strictly in this JSON format, note that the
23+
keys/tags/rephrased_instruction/memories should use the same language as the
24+
input query:
2325
{
2426
"keys": [...],
2527
"tags": [...],

src/memos/reranker/http_bge.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
# memos/reranker/http_bge.py
22
from __future__ import annotations
33

4+
import re
5+
46
from typing import TYPE_CHECKING
57

68
import requests
@@ -15,6 +17,8 @@
1517
if TYPE_CHECKING:
1618
from memos.memories.textual.item import TextualMemoryItem
1719

20+
_TAG1 = re.compile(r"^\s*\[[^\]]*\]\s*")
21+
1822

1923
class HTTPBGEReranker(BaseReranker):
2024
"""
@@ -53,10 +57,14 @@ def rerank(
5357
if self.concat_source:
5458
documents = concat_original_source(graph_results)
5559
else:
56-
documents = [getattr(item, "memory", None) for item in graph_results]
60+
documents = [
61+
(_TAG1.sub("", m) if isinstance((m := getattr(item, "memory", None)), str) else m)
62+
for item in graph_results
63+
]
5764
documents = [d for d in documents if isinstance(d, str) and d]
5865

5966
logger.info(f"[HTTPBGERerankerSample] query: {query} , documents: {documents[:5]}...")
67+
6068
if not documents:
6169
return []
6270

0 commit comments

Comments
 (0)