Skip to content

Commit 1fba901

Browse files
authored
Dev 20260319 v2.0.10 (#1255)
## Description Please include a summary of the change, the problem it solves, the implementation approach, and relevant context. List any dependencies required for this change. Related Issue (Required): Fixes @issue_number ## Type of change Please delete options that are not relevant. - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Refactor (does not change functionality, e.g. code style improvements, linting) - [ ] Documentation update ## How Has This Been Tested? Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration - [ ] Unit Test - [ ] Test Script Or Test Steps (please provide) - [ ] Pipeline Automated API Test (please provide) ## Checklist - [ ] I have performed a self-review of my own code | 我已自行检查了自己的代码 - [ ] I have commented my code in hard-to-understand areas | 我已在难以理解的地方对代码进行了注释 - [ ] I have added tests that prove my fix is effective or that my feature works | 我已添加测试以证明我的修复有效或功能正常 - [ ] I have created related documentation issue/PR in [MemOS-Docs](https://github.com/MemTensor/MemOS-Docs) (if applicable) | 我已在 [MemOS-Docs](https://github.com/MemTensor/MemOS-Docs) 中创建了相关的文档 issue/PR(如果适用) - [ ] I have linked the issue to this PR (if applicable) | 我已将 issue 链接到此 PR(如果适用) - [ ] I have mentioned the person who will review this PR | 我已提及将审查此 PR 的人 ## Reviewer Checklist - [ ] closes #xxxx (Replace xxxx with the GitHub issue number) - [ ] Made sure Checks passed - [ ] Tests have been provided
2 parents 6cea495 + e529dac commit 1fba901

24 files changed

Lines changed: 602 additions & 165 deletions

File tree

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Please include a summary of the change, the problem it solves, the implementation approach, and relevant context. List any dependencies required for this change.
44

5-
Related Issue (Required): Fixes @issue_number
5+
Related Issue (Required): Fixes #issue_number
66

77
## Type of change
88

.github/workflows/python-tests.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,11 @@ jobs:
102102
if: ${{ !startsWith(matrix.os, 'macos-13') }}
103103
run: |
104104
poetry install --no-interaction --extras all
105-
- name: PyTest unit tests
105+
- name: PyTest unit tests with coverage
106106
if: ${{ !startsWith(matrix.os, 'macos-13') }}
107+
shell: bash
107108
run: |
108-
poetry run pytest tests -vv --durations=10
109+
poetry run pytest tests -vv --durations=10 \
110+
--cov=src/memos \
111+
--cov-report=term-missing \
112+
--cov-fail-under=28

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,8 @@ pip-delete-this-directory.txt
6363

6464
# Unit test / coverage reports
6565
htmlcov/
66+
report/
67+
cov-report/
6668
.tox/
6769
.nox/
6870
.coverage

Makefile

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
.PHONY: test
1+
.PHONY: test test-report test-cov
22

33
install:
44
poetry install --extras all --with dev --with test
@@ -9,10 +9,25 @@ clean:
99
rm -rf .pytest_cache
1010
rm -rf .ruff_cache
1111
rm -rf tmp
12+
rm -rf report cov-report
13+
rm -f .coverage .coverage.*
1214

1315
test:
1416
poetry run pytest tests
1517

18+
test-report:
19+
poetry run pytest tests -vv --durations=10 \
20+
--html=report/index.html \
21+
--cov=src/memos \
22+
--cov-report=term-missing \
23+
--cov-report=html:cov-report/src
24+
25+
test-cov:
26+
poetry run pytest tests \
27+
--cov=src/memos \
28+
--cov-report=term-missing \
29+
--cov-report=html:cov-report/src
30+
1631
format:
1732
poetry run ruff check --fix
1833
poetry run ruff format

poetry.lock

Lines changed: 187 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

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

66
name = "MemoryOS"
7-
version = "2.0.9"
7+
version = "2.0.10"
88
description = "Intelligence Begins with Memory"
99
license = {text = "Apache-2.0"}
1010
readme = "README.md"
@@ -170,6 +170,8 @@ optional = true
170170
[tool.poetry.group.test.dependencies]
171171
pytest = "^8.3.5"
172172
pytest-asyncio = "^0.23.5"
173+
pytest-cov = "^6.1"
174+
pytest-html = "^4.2"
173175
ruff = "^0.11.8"
174176

175177
[tool.poetry.group.eval]
@@ -208,6 +210,23 @@ filterwarnings = [
208210
]
209211

210212

213+
[tool.coverage.run]
214+
source = ["src/memos"]
215+
branch = true
216+
217+
[tool.coverage.report]
218+
show_missing = true
219+
skip_empty = true
220+
exclude_lines = [
221+
"pragma: no cover",
222+
"if TYPE_CHECKING:",
223+
"if __name__ == .__main__.",
224+
]
225+
226+
[tool.coverage.html]
227+
directory = "cov-report"
228+
229+
211230
[tool.ruff]
212231
##############################################################################
213232
# Ruff is a fast Python linter and formatter.

src/memos/__init__.py

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

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

src/memos/api/config.py

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -321,23 +321,40 @@ def get_activation_config() -> dict[str, Any]:
321321

322322
@staticmethod
323323
def get_memreader_config() -> dict[str, Any]:
324-
"""Get MemReader configuration for chat/doc extraction (fine-tuned 0.6B model)."""
325-
return {
326-
"backend": "openai",
327-
"config": {
328-
"model_name_or_path": os.getenv("MEMRADER_MODEL", "gpt-4o-mini"),
329-
"temperature": 0.6,
330-
"max_tokens": int(os.getenv("MEMRADER_MAX_TOKENS", "8000")),
331-
"top_p": 0.95,
332-
"top_k": 20,
333-
"api_key": os.getenv("MEMRADER_API_KEY", "EMPTY"),
334-
# Default to OpenAI base URL when env var is not provided to satisfy pydantic
335-
# validation requirements during tests/import.
336-
"api_base": os.getenv("MEMRADER_API_BASE", "https://api.openai.com/v1"),
337-
"remove_think_prefix": True,
338-
},
324+
"""Get MemReader configuration for chat/doc extraction (fine-tuned 0.6B model).
325+
326+
When MEMREADER_GENERAL_MODEL is configured (i.e. a separate stable LLM exists),
327+
the backup client is automatically enabled so that primary failures (self-deployed
328+
model) fall back to the general LLM.
329+
"""
330+
config = {
331+
"model_name_or_path": os.getenv("MEMRADER_MODEL", "gpt-4o-mini"),
332+
"temperature": 0.6,
333+
"max_tokens": int(os.getenv("MEMRADER_MAX_TOKENS", "8000")),
334+
"top_p": 0.95,
335+
"top_k": 20,
336+
"api_key": os.getenv("MEMRADER_API_KEY", "EMPTY"),
337+
# Default to OpenAI base URL when env var is not provided to satisfy pydantic
338+
# validation requirements during tests/import.
339+
"api_base": os.getenv("MEMRADER_API_BASE", "https://api.openai.com/v1"),
340+
"remove_think_prefix": True,
339341
}
340342

343+
general_model = os.getenv("MEMREADER_GENERAL_MODEL")
344+
enable_backup = os.getenv("MEMREADER_ENABLE_BACKUP", "false").lower() == "true"
345+
if general_model and enable_backup:
346+
config["backup_client"] = True
347+
config["backup_model_name_or_path"] = general_model
348+
config["backup_api_key"] = os.getenv(
349+
"MEMREADER_GENERAL_API_KEY", os.getenv("OPENAI_API_KEY", "EMPTY")
350+
)
351+
config["backup_api_base"] = os.getenv(
352+
"MEMREADER_GENERAL_API_BASE",
353+
os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1"),
354+
)
355+
356+
return {"backend": "openai", "config": config}
357+
341358
@staticmethod
342359
def get_memreader_general_llm_config() -> dict[str, Any]:
343360
"""Get general LLM configuration for non-chat/doc tasks.
@@ -837,7 +854,7 @@ def get_scheduler_config() -> dict[str, Any]:
837854
),
838855
"context_window_size": int(os.getenv("MOS_SCHEDULER_CONTEXT_WINDOW_SIZE", "5")),
839856
"thread_pool_max_workers": int(
840-
os.getenv("MOS_SCHEDULER_THREAD_POOL_MAX_WORKERS", "10000")
857+
os.getenv("MOS_SCHEDULER_THREAD_POOL_MAX_WORKERS", "200")
841858
),
842859
"consume_interval_seconds": float(
843860
os.getenv("MOS_SCHEDULER_CONSUME_INTERVAL_SECONDS", "0.01")
@@ -850,6 +867,8 @@ def get_scheduler_config() -> dict[str, Any]:
850867
"MOS_SCHEDULER_ENABLE_ACTIVATION_MEMORY", "false"
851868
).lower()
852869
== "true",
870+
"use_redis_queue": os.getenv("MEMSCHEDULER_USE_REDIS_QUEUE", "False").lower()
871+
== "true",
853872
},
854873
}
855874

src/memos/api/handlers/component_init.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ def init_server() -> dict[str, Any]:
233233
searcher: Searcher = tree_mem.get_searcher(
234234
manual_close_internet=os.getenv("ENABLE_INTERNET", "true").lower() == "false",
235235
moscube=False,
236-
process_llm=mem_reader.llm,
236+
process_llm=mem_reader.general_llm,
237237
)
238238
logger.debug("Searcher created")
239239

@@ -255,12 +255,13 @@ def init_server() -> dict[str, Any]:
255255
# Initialize Scheduler
256256
scheduler_config_dict = APIConfig.get_scheduler_config()
257257
scheduler_config = SchedulerConfigFactory(
258-
backend="optimized_scheduler", config=scheduler_config_dict
258+
backend=scheduler_config_dict["backend"],
259+
config=scheduler_config_dict["config"],
259260
)
260261
mem_scheduler: OptimizedScheduler = SchedulerFactory.from_config(scheduler_config)
261262
mem_scheduler.initialize_modules(
262263
chat_llm=llm,
263-
process_llm=mem_reader.llm,
264+
process_llm=mem_reader.general_llm,
264265
db_engine=BaseDBManager.create_default_sqlite_engine(),
265266
mem_reader=mem_reader,
266267
redis_client=redis_client,

src/memos/configs/llm.py

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,22 @@ class OpenAILLMConfig(BaseLLMConfig):
2828
default="https://api.openai.com/v1", description="Base URL for OpenAI API"
2929
)
3030
extra_body: Any = Field(default=None, description="extra body")
31+
backup_client: bool = Field(
32+
default=False,
33+
description="Whether to enable backup client for fallback on primary failure",
34+
)
35+
backup_api_key: str | None = Field(
36+
default=None, description="API key for backup OpenAI-compatible endpoint"
37+
)
38+
backup_api_base: str | None = Field(
39+
default=None, description="Base URL for backup OpenAI-compatible endpoint"
40+
)
41+
backup_model_name_or_path: str | None = Field(
42+
default=None, description="Model name for backup endpoint"
43+
)
44+
backup_headers: dict[str, Any] | None = Field(
45+
default=None, description="Default headers for backup client requests"
46+
)
3147

3248

3349
class OpenAIResponsesLLMConfig(BaseLLMConfig):
@@ -42,22 +58,18 @@ class OpenAIResponsesLLMConfig(BaseLLMConfig):
4258
)
4359

4460

45-
class QwenLLMConfig(BaseLLMConfig):
46-
api_key: str = Field(..., description="API key for DashScope (Qwen)")
61+
class QwenLLMConfig(OpenAILLMConfig):
4762
api_base: str = Field(
4863
default="https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
4964
description="Base URL for Qwen OpenAI-compatible API",
5065
)
51-
extra_body: Any = Field(default=None, description="extra body")
5266

5367

54-
class DeepSeekLLMConfig(BaseLLMConfig):
55-
api_key: str = Field(..., description="API key for DeepSeek")
68+
class DeepSeekLLMConfig(OpenAILLMConfig):
5669
api_base: str = Field(
5770
default="https://api.deepseek.com",
5871
description="Base URL for DeepSeek OpenAI-compatible API",
5972
)
60-
extra_body: Any = Field(default=None, description="Extra options for API")
6173

6274

6375
class AzureLLMConfig(BaseLLMConfig):

0 commit comments

Comments
 (0)