From 954fdab5fe5e95bedf4709f66c850f5d6a6f102f Mon Sep 17 00:00:00 2001 From: HarveyXiang Date: Wed, 19 Nov 2025 12:41:01 +0800 Subject: [PATCH 1/7] Update API Reference link in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4269abf0..c5fcd93c 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ Get Free API: [Try API](https://memos-dashboard.openmem.net/quickstart/?source=g - **Website**: https://memos.openmem.net/ - **Documentation**: https://memos-docs.openmem.net/home/overview/ -- **API Reference**: https://memos-docs.openmem.net/docs/api/info/ +- **API Reference**: https://memos-docs.openmem.net/api-reference/configure-memos/ - **Source Code**: https://github.com/MemTensor/MemOS ## 📰 News From 8a93addf96feaefcf0bea346d357974c5354ed29 Mon Sep 17 00:00:00 2001 From: "yuan.wang" Date: Wed, 19 Nov 2025 15:57:30 +0800 Subject: [PATCH 2/7] hotfix bug in pref init --- README.md | 4 +-- evaluation/.env-example | 1 - src/memos/api/routers/server_router.py | 50 +++++++++++++++++--------- src/memos/mem_cube/navie.py | 20 ++++++----- 4 files changed, 47 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index c5fcd93c..cb464b9c 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,8 @@ Designed for **AI companions, role-playing NPCs, and multi-agent systems**, MemO -Get Free API: [Try API](https://memos-dashboard.openmem.net/quickstart/?source=github) - +Get Free API: [Try API](https://memos-dashboard.openmem.net/quickstart/?source=github) + --- diff --git a/evaluation/.env-example b/evaluation/.env-example index 5381532c..bab6f679 100644 --- a/evaluation/.env-example +++ b/evaluation/.env-example @@ -21,4 +21,3 @@ MEMU_API_KEY="mu_xxx" SUPERMEMORY_API_KEY="sm_xxx" MEMOBASE_API_KEY="xxx" MEMOBASE_PROJECT_URL="http://***.***.***.***:8019" - diff --git a/src/memos/api/routers/server_router.py b/src/memos/api/routers/server_router.py index 8df383bf..23aec0cb 100644 --- a/src/memos/api/routers/server_router.py +++ b/src/memos/api/routers/server_router.py @@ -187,7 +187,11 @@ def init_server(): # Create component instances graph_db = GraphStoreFactory.from_config(graph_db_config) - vector_db = VecDBFactory.from_config(vector_db_config) + vector_db = ( + VecDBFactory.from_config(vector_db_config) + if os.getenv("ENABLE_PREFERENCE_MEMORY", "false").lower() == "true" + else None + ) llm = LLMFactory.from_config(llm_config) embedder = EmbedderFactory.from_config(embedder_config) mem_reader = MemReaderFactory.from_config(mem_reader_config) @@ -195,24 +199,36 @@ def init_server(): internet_retriever = InternetRetrieverFactory.from_config( internet_retriever_config, embedder=embedder ) - pref_extractor = ExtractorFactory.from_config( - config_factory=pref_extractor_config, - llm_provider=llm, - embedder=embedder, - vector_db=vector_db, + pref_extractor = ( + ExtractorFactory.from_config( + config_factory=pref_extractor_config, + llm_provider=llm, + embedder=embedder, + vector_db=vector_db, + ) + if os.getenv("ENABLE_PREFERENCE_MEMORY", "false").lower() == "true" + else None ) - pref_adder = AdderFactory.from_config( - config_factory=pref_adder_config, - llm_provider=llm, - embedder=embedder, - vector_db=vector_db, + pref_adder = ( + AdderFactory.from_config( + config_factory=pref_adder_config, + llm_provider=llm, + embedder=embedder, + vector_db=vector_db, + ) + if os.getenv("ENABLE_PREFERENCE_MEMORY", "false").lower() == "true" + else None ) - pref_retriever = RetrieverFactory.from_config( - config_factory=pref_retriever_config, - llm_provider=llm, - embedder=embedder, - reranker=reranker, - vector_db=vector_db, + pref_retriever = ( + RetrieverFactory.from_config( + config_factory=pref_retriever_config, + llm_provider=llm, + embedder=embedder, + reranker=reranker, + vector_db=vector_db, + ) + if os.getenv("ENABLE_PREFERENCE_MEMORY", "false").lower() == "true" + else None ) # Initialize memory manager diff --git a/src/memos/mem_cube/navie.py b/src/memos/mem_cube/navie.py index ba9f136b..3acc441a 100644 --- a/src/memos/mem_cube/navie.py +++ b/src/memos/mem_cube/navie.py @@ -58,14 +58,18 @@ def __init__( ) self._act_mem: BaseActMemory | None = None self._para_mem: BaseParaMemory | None = None - self._pref_mem: BaseTextMemory | None = SimplePreferenceTextMemory( - extractor_llm=llm, - vector_db=vector_db, - embedder=embedder, - reranker=reranker, - extractor=pref_extractor, - adder=pref_adder, - retriever=pref_retriever, + self._pref_mem: BaseTextMemory | None = ( + SimplePreferenceTextMemory( + extractor_llm=llm, + vector_db=vector_db, + embedder=embedder, + reranker=reranker, + extractor=pref_extractor, + adder=pref_adder, + retriever=pref_retriever, + ) + if os.getenv("ENABLE_PREFERENCE_MEMORY", "false").lower() == "true" + else None ) def load( From b0482974c8b4426150f4ab2bbd5dd10c669c33ed Mon Sep 17 00:00:00 2001 From: harvey_xiang Date: Wed, 19 Nov 2025 21:28:41 +0800 Subject: [PATCH 3/7] feat: log support time rotating --- src/memos/log.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/memos/log.py b/src/memos/log.py index faa80841..1f107df2 100644 --- a/src/memos/log.py +++ b/src/memos/log.py @@ -34,10 +34,12 @@ def _setup_logfile() -> Path: Returns: the logfile Path """ - logfile = Path(settings.MEMOS_DIR / "logs" / "memos.log") - logfile.parent.mkdir(parents=True, exist_ok=True) - logfile.touch(exist_ok=True) - return logfile + today_str = time.strftime("%Y-%m-%d", time.localtime()) + today_file_name = f"{today_str}.memos.log" + today_file = Path(settings.MEMOS_DIR / "logs" / today_file_name) + today_file.parent.mkdir(parents=True, exist_ok=True) + + return today_file class ContextFilter(logging.Filter): @@ -187,7 +189,7 @@ def close(self): }, "handlers": { "console": { - "level": selected_log_level, + "level": "DEBUG", "class": "logging.StreamHandler", "stream": stdout, "formatter": "no_datetime", @@ -195,10 +197,11 @@ def close(self): }, "file": { "level": "DEBUG", - "class": "logging.handlers.RotatingFileHandler", + "class": "logging.handlers.TimedRotatingFileHandler", + "when": "midnight", + "interval": 1, + "backupCount": 5, "filename": _setup_logfile(), - "maxBytes": 1024**2 * 10, - "backupCount": 10, "formatter": "standard", "filters": ["context_filter"], }, From 307e06af4ef3d88f63cb59d6c2215ebb0fde1a0a Mon Sep 17 00:00:00 2001 From: harvey_xiang Date: Wed, 19 Nov 2025 21:40:05 +0800 Subject: [PATCH 4/7] feat: log support time rotating --- src/memos/log.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/memos/log.py b/src/memos/log.py index 1f107df2..89c75cc3 100644 --- a/src/memos/log.py +++ b/src/memos/log.py @@ -189,7 +189,7 @@ def close(self): }, "handlers": { "console": { - "level": "DEBUG", + "level": selected_log_level, "class": "logging.StreamHandler", "stream": stdout, "formatter": "no_datetime", @@ -200,7 +200,7 @@ def close(self): "class": "logging.handlers.TimedRotatingFileHandler", "when": "midnight", "interval": 1, - "backupCount": 5, + "backupCount": 3, "filename": _setup_logfile(), "formatter": "standard", "filters": ["context_filter"], From 76f8f312d812a9d94e8851553024ad6c19712112 Mon Sep 17 00:00:00 2001 From: harvey_xiang Date: Thu, 20 Nov 2025 10:18:06 +0800 Subject: [PATCH 5/7] feat: log support time rotating --- src/memos/log.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/memos/log.py b/src/memos/log.py index 89c75cc3..874f2c6a 100644 --- a/src/memos/log.py +++ b/src/memos/log.py @@ -34,12 +34,11 @@ def _setup_logfile() -> Path: Returns: the logfile Path """ - today_str = time.strftime("%Y-%m-%d", time.localtime()) - today_file_name = f"{today_str}.memos.log" - today_file = Path(settings.MEMOS_DIR / "logs" / today_file_name) - today_file.parent.mkdir(parents=True, exist_ok=True) + logfile = Path(settings.MEMOS_DIR / "logs" / "memos.log") + logfile.parent.mkdir(parents=True, exist_ok=True) + logfile.touch(exist_ok=True) - return today_file + return logfile class ContextFilter(logging.Filter): From 0d5016774448a053feb1b4d2a402b9ebc2ca810f Mon Sep 17 00:00:00 2001 From: harvey_xiang Date: Thu, 20 Nov 2025 11:47:25 +0800 Subject: [PATCH 6/7] feat: delete useless log --- src/memos/mem_scheduler/utils/metrics.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/memos/mem_scheduler/utils/metrics.py b/src/memos/mem_scheduler/utils/metrics.py index 5155c98b..ff5ad4e4 100644 --- a/src/memos/mem_scheduler/utils/metrics.py +++ b/src/memos/mem_scheduler/utils/metrics.py @@ -184,12 +184,7 @@ def on_enqueue( inst_rate = (1.0 / max(1e-3, dt)) if dt is not None else 0.0 # first sample: no spike ls.last_enqueue_ts = now ls.backlog += 1 - old_lam = ls.lambda_ewma.value_at(now) ls.lambda_ewma.update(inst_rate, now) - new_lam = ls.lambda_ewma.value_at(now) - print( - f"[DEBUG enqueue] {label} backlog={ls.backlog} dt={dt if dt is not None else '—'}s inst={inst_rate:.3f} λ {old_lam:.3f}→{new_lam:.3f}" - ) self._label_topk[label].add(mem_cube_id) ds = self._get_detail(label, mem_cube_id) if ds: From d6557f1767e1b146f2dd105356f3f17d4c99c329 Mon Sep 17 00:00:00 2001 From: harvey_xiang Date: Thu, 20 Nov 2025 12:00:04 +0800 Subject: [PATCH 7/7] feat: delete useless log --- .../monitors/dispatcher_monitor.py | 17 +++-------------- src/memos/mem_scheduler/utils/metrics.py | 5 ----- .../tree_text_memory/retrieve/recall.py | 18 ------------------ 3 files changed, 3 insertions(+), 37 deletions(-) diff --git a/src/memos/mem_scheduler/monitors/dispatcher_monitor.py b/src/memos/mem_scheduler/monitors/dispatcher_monitor.py index 46c4e2d4..58ec51be 100644 --- a/src/memos/mem_scheduler/monitors/dispatcher_monitor.py +++ b/src/memos/mem_scheduler/monitors/dispatcher_monitor.py @@ -129,7 +129,9 @@ def _check_pools_health(self) -> None: pool_info=pool_info, stuck_max_interval=4, ) - logger.info(f"Pool '{name}'. is_healthy: {is_healthy}. pool_info: {pool_info}") + if not is_healthy: + logger.info(f"Pool '{name}'. is_healthy: {is_healthy}. pool_info: {pool_info}") + with self._pool_lock: if is_healthy: pool_info["failure_count"] = 0 @@ -231,20 +233,7 @@ def _check_pool_health( # Log health status with comprehensive information if self.dispatcher: - # Check thread activity - active_threads = sum( - 1 - for t in threading.enumerate() - if t.name.startswith(executor._thread_name_prefix) # pylint: disable=protected-access - ) - - task_count = self.dispatcher.get_running_task_count() max_workers = pool_info.get("max_workers", 0) - stuck_count = len(stuck_tasks) - logger.info( - f"Pool health check passed - {active_threads} active threads, " - f"{task_count} running tasks, pool size: {max_workers}, stuck tasks: {stuck_count}" - ) return True, "" diff --git a/src/memos/mem_scheduler/utils/metrics.py b/src/memos/mem_scheduler/utils/metrics.py index ff5ad4e4..0434bb4d 100644 --- a/src/memos/mem_scheduler/utils/metrics.py +++ b/src/memos/mem_scheduler/utils/metrics.py @@ -217,12 +217,7 @@ def on_done( ls.last_done_ts = now if ls.backlog > 0: ls.backlog -= 1 - old_mu = ls.mu_ewma.value_at(now) ls.mu_ewma.update(inst_rate, now) - new_mu = ls.mu_ewma.value_at(now) - print( - f"[DEBUG done] {label} backlog={ls.backlog} dt={dt if dt is not None else '—'}s inst={inst_rate:.3f} μ {old_mu:.3f}→{new_mu:.3f}" - ) ds = self._detail_stats.get((label, mem_cube_id)) if ds: prev_ts_d = ds.last_done_ts diff --git a/src/memos/memories/textual/tree_text_memory/retrieve/recall.py b/src/memos/memories/textual/tree_text_memory/retrieve/recall.py index 8cf2f47f..40e22065 100644 --- a/src/memos/memories/textual/tree_text_memory/retrieve/recall.py +++ b/src/memos/memories/textual/tree_text_memory/retrieve/recall.py @@ -104,15 +104,6 @@ def retrieve( # Merge and deduplicate by ID combined = {item.id: item for item in graph_results + vector_results + bm25_results} - graph_ids = {item.id for item in graph_results} - combined_ids = set(combined.keys()) - lost_ids = graph_ids - combined_ids - - if lost_ids: - print( - f"[DEBUG] The following nodes were in graph_results but missing in combined: {lost_ids}" - ) - return list(combined.values()) def retrieve_from_cube( @@ -150,15 +141,6 @@ def retrieve_from_cube( # Merge and deduplicate by ID combined = {item.id: item for item in graph_results} - graph_ids = {item.id for item in graph_results} - combined_ids = set(combined.keys()) - lost_ids = graph_ids - combined_ids - - if lost_ids: - print( - f"[DEBUG] The following nodes were in graph_results but missing in combined: {lost_ids}" - ) - return list(combined.values()) def _graph_recall(