diff --git a/Makefile b/Makefile index 6d111cf15..c250316ca 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: test docs +.PHONY: test install: poetry install --with dev --with test @@ -11,7 +11,7 @@ clean: rm -rf tmp test: - PYTHONPATH=src poetry run pytest tests + poetry run pytest tests format: poetry run ruff check --fix @@ -23,24 +23,5 @@ pre_commit: serve: poetry run uvicorn memos.api.start_api:app -docs: - pytest tests/test_docs.py -xq - pip install mkdocs mkdocs-material -q - mkdir -p tmp - rm -f tmp/mkdocs.yml - echo "site_name: MemOS Documentation" > tmp/mkdocs.yml - echo "docs_dir: `pwd`/docs" >> tmp/mkdocs.yml - echo "theme: material" >> tmp/mkdocs.yml - echo "markdown_extensions:" >> tmp/mkdocs.yml - echo " - pymdownx.highlight:" >> tmp/mkdocs.yml - echo " anchor_linenums: true" >> tmp/mkdocs.yml - echo " line_spans: __span" >> tmp/mkdocs.yml - echo " pygments_lang_class: true" >> tmp/mkdocs.yml - echo " - pymdownx.inlinehilite" >> tmp/mkdocs.yml - echo " - pymdownx.snippets" >> tmp/mkdocs.yml - echo " - pymdownx.superfences" >> tmp/mkdocs.yml - cat docs/settings.yml >> tmp/mkdocs.yml - mkdocs serve -f tmp/mkdocs.yml --no-livereload - openapi: poetry run python scripts/export_openapi.py --output docs/openapi.json diff --git a/README.md b/README.md index a54edd21a..654495545 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Discord - + WeChat Group @@ -43,7 +43,7 @@ --- - SOTA SCORE + SOTA SCORE diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..bf5fea70d --- /dev/null +++ b/docs/README.md @@ -0,0 +1,3 @@ +All documentation has been moved to a separate repository: https://github.com/MemTensor/MemOS-Docs. Please edit documentation there. + +所有文档已迁移至独立仓库:https://github.com/MemTensor/MemOS-Docs。请在该仓库中编辑文档。 diff --git a/docs/assets/memos-architecture.png b/docs/assets/memos-architecture.png deleted file mode 100644 index e73444013..000000000 Binary files a/docs/assets/memos-architecture.png and /dev/null differ diff --git a/docs/assets/memos-banner.png b/docs/assets/memos-banner.png deleted file mode 100644 index 4f2422002..000000000 Binary files a/docs/assets/memos-banner.png and /dev/null differ diff --git a/docs/assets/qr-code.png b/docs/assets/qr_code.png similarity index 100% rename from docs/assets/qr-code.png rename to docs/assets/qr_code.png diff --git a/docs/assets/SOTA_Score.jpg b/docs/assets/sota_score.jpg similarity index 100% rename from docs/assets/SOTA_Score.jpg rename to docs/assets/sota_score.jpg diff --git a/docs/best_practice/common_errors_solutions.md b/docs/best_practice/common_errors_solutions.md deleted file mode 100644 index ff2f06631..000000000 --- a/docs/best_practice/common_errors_solutions.md +++ /dev/null @@ -1,74 +0,0 @@ -# Common Errors and Solutions - -## Configuration Errors - -### Missing Required Fields - -```python -# ✅ Always include required fields -llm_config = { - "backend": "openai", - "config": { - "api_key": "your-api-key", - "model_name_or_path": "gpt-4" - } -} -``` - -### Backend Mismatch - -```python -# ✅ KVCache requires HuggingFace backend -kv_config = { - "backend": "kv_cache", - "config": { - "extractor_llm": { - "backend": "huggingface", - "config": { - "model_name_or_path": "Qwen/Qwen3-1.7B" - } - } - } -} -``` - -## Service Connection Issues - -```bash -# Start required services as needed -docker run -p 6333:6333 qdrant/qdrant -ollama serve -``` - -## Memory Issues - -### Loading Failures - -```python -try: - mem_cube.load("memory_dir") -except Exception: - mem_cube = GeneralMemCube(config) - mem_cube.dump("memory_dir") -``` - -### GPU Memory - -```python -import os -os.environ["CUDA_VISIBLE_DEVICES"] = "0" -# Use smaller models if GPU memory is limited: Qwen/Qwen3-0.6B -``` - -## User Management - -```python -# Register user first -mos.register_mem_cube(cube_path="path", user_id="user_id", cube_id="cube_id") - -# Check if user exists -try: - user_id = mos.create_user(user_name="john", role=UserRole.USER) -except ValueError: - user = mos.user_manager.get_user_by_name("john") -``` diff --git a/docs/best_practice/memory_structure_design.md b/docs/best_practice/memory_structure_design.md deleted file mode 100644 index d018abdf3..000000000 --- a/docs/best_practice/memory_structure_design.md +++ /dev/null @@ -1,87 +0,0 @@ -# Memory Structure Design Best Practices - -## Memory Type Selection - -### TreeTextMemory - -**Best for**: Knowledge management, research assistants, hierarchical data -```python -tree_config = { - "backend": "tree_text", - "config": { - "extractor_llm": { - "backend": "ollama", - "config": { - "model_name_or_path": "qwen3:0.6b" - } - }, - "graph_db": { - "backend": "neo4j", - "config": { - "host": "localhost", - "port": 7687 - } - } - } -} -``` - -### GeneralTextMemory - -**Best for**: Conversational AI, personal assistants, FAQ systems -```python -general_config = { - "backend": "general_text", - "config": { - "extractor_llm": { - "backend": "ollama", - "config": { - "model_name_or_path": "qwen3:0.6b" - } - }, - "vector_db": { - "backend": "qdrant", - "config": { - "collection_name": "general" - } - }, - "embedder": { - "backend": "ollama", - "config": { - "model_name_or_path": "nomic-embed-text" - } - } - } -} -``` - -### NaiveTextMemory - -**Best for**: Simple applications, prototyping -```python -naive_config = { - "backend": "naive_text", - "config": { - "extractor_llm": { - "backend": "ollama", - "config": { - "model_name_or_path": "qwen3:0.6b" - } - } - } -} -``` - -## Capacity Planning - -If you enable the scheduler, you can set memory capacities to control resource usage: - -```python -scheduler_config = { - "memory_capacities": { - "working_memory_capacity": 20, # Active conversation - "user_memory_capacity": 500, # User knowledge - "long_term_memory_capacity": 2000 # Domain knowledge - } -} -``` diff --git a/docs/best_practice/network_workarounds.md b/docs/best_practice/network_workarounds.md deleted file mode 100644 index cc342d2bc..000000000 --- a/docs/best_practice/network_workarounds.md +++ /dev/null @@ -1,108 +0,0 @@ -# Network Workarounds - -Here are some solutions to address the network issues you may encounter during developing. - -## **Downloading Huggingface Models** - -### Mirror Site (HF-Mirror) - -To download Huggingface models using the mirror site, you can follow these steps: - -::steps{level="4"} - -#### Install Dependencies - -Install the necessary dependencies by running: - -```bash -pip install -U huggingface_hub -``` - -#### Set Environment Variable - -Set the environment variable `HF_ENDPOINT` to `https://hf-mirror.com`. - -#### Download Models or Datasets - -Use huggingface-cli to download models or datasets. For example: - -- To download a model: - - ```bash - huggingface-cli download --resume-download gpt2 --local-dir gpt2 - ``` -- To download a dataset: - ``` - huggingface-cli download --repo-type dataset --resume-download wikitext --local-dir wikitext - ``` - -:: - -For more detailed instructions and additional methods, please refer to [this link](https://hf-mirror.com/). - -### Alternative Sources -You may still encounter limitations accessing some models in your regions. In such cases, you can use modelscope: - -::steps{level="4"} - -#### Install ModelScope - -Install the necessary dependencies by running: - -```bash -pip install modelscope[framework] -``` - -#### Download Models or Datasets - -Use modelscope to download models or datasets. For example: - -- To download a model: - ```bash - modelscope download --model 'Qwen/Qwen2-7b' --local_dir 'path/to/dir' - ``` -- To download a dataset: - - ```bash - modelscope download --dataset 'Tongyi-DataEngine/SA1B-Dense-Caption' --local_dir './local_dir' - ``` - -:: - -For more detailed instructions and additional methods, please refer to the [official docs](https://modelscope.cn/docs/home). - -## **Using Poetry** - -### Network Errors during Installing -To address network errors when using "poetry install" in your regions, you can follow these steps: - -::steps{level="4"} - -#### Update Configuration - -Update the `pyproject.toml` file to use a mirror source by adding the following configuration: - -```toml -[[tool.poetry.source]] -name = "mirrors" -url = "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" -priority = "primary" -``` - -#### Reconfigure Poetry - -Run the command `poetry lock` in the terminal to reconfigure Poetry with the new mirror source. - -:: - -**Tips:** -Be aware that `poetry lock` will modify both Pyproject.toml and poetry.lock files. To avoid committing redundant changes: - - Option 1: After successful `poetry install`, revert to the git HEAD node using `git reset --hard HEAD`. - - Option 2: When executing `git add`, exclude the Pyproject.toml and poetry.lock files by specifying other files. - -For future dependency management tasks like adding or removing packages, you can use the `poetry add` command: -```bash -poetry add -``` - -Refer to the [Poetry CLI documentation](https://python-poetry.org/docs/cli/) for more commands and details. diff --git a/docs/best_practice/performance_tuning.md b/docs/best_practice/performance_tuning.md deleted file mode 100644 index a82d8ce4a..000000000 --- a/docs/best_practice/performance_tuning.md +++ /dev/null @@ -1,53 +0,0 @@ -# Performance Tuning Best Practices - -## Embedding Optimization - -```python -fast_embedder = { - "backend": "ollama", - "config": { - "model_name_or_path": "nomic-embed-text:latest" - } -} - -slow_embedder = { - "backend": "sentence_transformer", - "config": { - "model_name_or_path": "nomic-ai/nomic-embed-text-v1.5" - } -} -``` - -## Inference Speed - -```python -generation_config = { - "max_new_tokens": 256, # Limit response length - "temperature": 0.7, - "do_sample": True -} -``` - -## System Resource Optimization - -### Memory Capacity Limits - -```python -scheduler_config = { - "memory_capacities": { - "working_memory_capacity": 20, # Active context - "user_memory_capacity": 500, # User storage - "long_term_memory_capacity": 2000, # Domain knowledge - "transformed_act_memory_capacity": 50 # KV cache items - } -} -``` - -### Batch Processing - -```python -def batch_memory_operations(operations, batch_size=10): - for i in range(0, len(operations), batch_size): - batch = operations[i:i + batch_size] - yield batch # Process in batches -``` diff --git a/docs/contribution/commit_guidelines.md b/docs/contribution/commit_guidelines.md deleted file mode 100644 index ff95c738b..000000000 --- a/docs/contribution/commit_guidelines.md +++ /dev/null @@ -1,15 +0,0 @@ -# Commit Guidelines - -Please follow the [Conventional Commits](https://www.conventionalcommits.org/) format: - -- `feat:` for new features -- `fix:` for bug fixes -- `docs:` for documentation updates -- `style:` for formatting changes -- `refactor:` for code refactoring -- `test:` for adding or updating tests -- `chore:` for maintenance tasks -- `ci:` for CI/CD or workflow changes - -**Example:** -`feat: add user authentication` diff --git a/docs/contribution/development_workflow.md b/docs/contribution/development_workflow.md deleted file mode 100644 index a8e2e9bda..000000000 --- a/docs/contribution/development_workflow.md +++ /dev/null @@ -1,65 +0,0 @@ -# Development Workflow - -Follow these steps to contribute to the project. - -::steps{level="4"} - -#### Sync with Upstream - -If you've previously forked the repository, sync with the upstream changes: - -```bash -git checkout dev # switch to dev branch -git fetch upstream # fetch latest changes from upstream -git pull upstream dev # merge changes into your local dev branch -git push origin dev # push changes to your fork -``` - -#### Create a Feature Branch - -Create a new branch for your feature or fix: - -```bash -git checkout -b feat/descriptive-name -``` - -#### Make Your Changes - -Implement your feature, fix, or improvement in the appropriate files. - -- For example, you might add a function in `src/memos/hello_world.py` and create corresponding tests in `tests/test_hello_world.py`. - -#### Test Your Changes - -Run the test suite to ensure your changes work correctly: - -```bash -make test -``` - -#### Commit Your Changes - -Follow the project's commit guidelines (see [Commit Guidelines](./commit_guidelines.md)) when committing your changes. - -#### Push to Your Fork - -Push your feature branch to your forked repository: - -```bash -git push origin feat/descriptive-name -``` - -#### Create a Pull Request - -Submit your changes for review: - -- **Important:** Please create your pull request against - - ✅ the `dev` branch of the upstream repository, - - ❎ not the `main` branch of the upstream repository. -- Go to the original repository on GitHub -- Click on "Pull Requests" -- Click on "New Pull Request" -- Select `dev` as the base branch, and your branch as compare -- Fulfill the PR description carefully. - -:: diff --git a/docs/contribution/overview.md b/docs/contribution/overview.md deleted file mode 100644 index bcff726f0..000000000 --- a/docs/contribution/overview.md +++ /dev/null @@ -1,13 +0,0 @@ -# Overview - -Thank you for your interest in contributing! We've structured our contribution guide into several documents to help you find the information you need quickly. - -- **First-time contributors:** Please start by reading the [Setting Up](./setting_up.md) guide to prepare your development environment. -- **Ready to code?** The [Development Workflow](./development_workflow.md) guide will walk you through our process for submitting changes. -- **Writing good commit messages:** See our [Commit Guidelines](./commit_guidelines.md). -- **Contributing to documentation:** If you're helping us improve our docs, check out the [Writing Documentation](./writing_docs.md) guide. -- **Adding or improving tests:** The [Writing Tests](./writing_tests.md) guide is for you. - -Your contributions make this project better! ✨ If you have any questions, feel free to open an issue or join the discussion or scan the QR codes below to connect with us on Discord or WeChat. - -QR Code diff --git a/docs/contribution/setting_up.md b/docs/contribution/setting_up.md deleted file mode 100644 index 4d5578815..000000000 --- a/docs/contribution/setting_up.md +++ /dev/null @@ -1,47 +0,0 @@ -# Setting Up Your Development Environment - -To contribute to MemOS, you'll need to set up your local development environment. - -::steps{level="4"} - -#### Fork & Clone the Repository - -Set up the repository on your local machine: - -- Fork the repository on GitHub -- Clone your fork to your local machine: - ```bash - git clone https://github.com/YOUR-USERNAME/MemOS.git - cd MemOS - ``` -- Add the upstream repository as a remote: - ```bash - git remote add upstream https://github.com/MemTensor/MemOS.git - ``` - -#### Install Poetry - -Install Poetry for dependency management: - -```bash -curl -sSL https://install.python-poetry.org | python3 - -``` - -Or follow the [official instructions](https://python-poetry.org/docs/#installing-with-the-official-installer). - -Verify installation: -```bash -poetry --version -``` - -#### Install Dependencies and Set Up Pre-commit Hooks - -Install all project dependencies and development tools: - -```bash -make install -``` - -As the environment changes across commit history, you may need to **re-run `make install`** time to time to ensure all dependencies are up-to-date. - -:: diff --git a/docs/contribution/writing_docs.md b/docs/contribution/writing_docs.md deleted file mode 100644 index f1f238434..000000000 --- a/docs/contribution/writing_docs.md +++ /dev/null @@ -1,32 +0,0 @@ -# How to Write and Preview Documentation - -This project uses a custom Nuxt frontend to render documentation from Markdown files. The documentation is deployed at [https://memos.openmem.net/docs/home](https://memos.openmem.net/docs/home). - -## Adding a New Document - -1. Create a new `.md` file in the `docs/` directory or one of its subdirectories. -2. Add content to the file using Markdown syntax. -3. Add the new document to the `nav` section in `docs/settings.yml`. -4. Once the your changes are merged into the `main` branch, the documentation will be automatically updated. - -## Navigation Icons - -When adding entries to the navigation in `docs/settings.yml`, you can include icons using the syntax `(ri:icon-name)`. For example: - -```yaml -- "(ri:home-line) Home": overview.md -- "(ri:team-line) Users": modules/mos/users.md -- "(ri:flask-line) Writing Tests": contribution/writing_tests.md -``` - -The frontend will render these as actual icons. You can find available icons at [https://icones.js.org/](https://icones.js.org/). - -## Previewing the Documentation - -To preview a simple version of the documentation locally, run the following command from the root of the project: - -```bash -make docs -``` - -This command will start a local web server, and you can view the documentation by opening the URL provided in the terminal (usually `http://127.0.0.1:8000`). diff --git a/docs/contribution/writing_tests.md b/docs/contribution/writing_tests.md deleted file mode 100644 index 4791a7c13..000000000 --- a/docs/contribution/writing_tests.md +++ /dev/null @@ -1,42 +0,0 @@ -# How to Write Unit Tests - -This project uses [pytest](https://docs.pytest.org/) for unit testing. - -## Writing a Test - -1. Create a new Python file in the `tests/` directory. The filename should start with `test_`. -2. Inside the file, create functions whose names start with `test_`. -3. Use the `assert` statement to check for expected outcomes. - -Here is a basic example: - -```python -# tests/test_example.py - -def test_addition(): - assert 1 + 1 == 2 -``` - -## Running Tests - -To run all the tests, execute the following command from the root of the project: - -```bash -make test -``` - -This will discover and run all the tests in the `tests/` directory. - -## Advanced Techniques - -Pytest has many advanced features, such as fixtures and mocking. - -### Fixtures - -Fixtures are functions that can provide data or set up state for your tests. They are defined using the `@pytest.fixture` decorator. - -### Mocking - -Mocking is used to replace parts of your system with mock objects. This is useful for isolating the code you are testing. The `unittest.mock` library is commonly used for this, often with the `patch` function. - -For an example of mocking, see `tests/test_hello_world.py`. diff --git a/docs/getting_started/examples.md b/docs/getting_started/examples.md deleted file mode 100644 index dffd933d9..000000000 --- a/docs/getting_started/examples.md +++ /dev/null @@ -1,412 +0,0 @@ -# MemOS Examples - -Congratulations — you’ve mastered the Quick Start and built your first -working memory! Now it’s time to see how far you can take MemOS by combining -different memory types and features. Use these curated examples to inspire -your own agents, chatbots, or knowledge systems. - -::card-group - - :::card - --- - icon: ri:play-line - title: Minimal Pipeline - to: /docs/getting_started/examples#example-1-minimal-pipeline - --- - The smallest working pipeline — add, search, update and dump plaintext memories. - ::: - - :::card - --- - icon: ri:tree-line - title: TreeTextMemory Only - to: /docs/getting_started/examples#example-2-treetextmemory-only - --- - Use Neo4j-backed hierarchical memory to build structured, multi-hop knowledge graphs. - ::: - - :::card - --- - icon: ri:database-2-line - title: KVCacheMemory Only - to: /docs/getting_started/examples#example-3-kvcachememory-only - --- - Speed up sessions with short-term KV cache for fast context injection. - ::: - - :::card - --- - icon: hugeicons:share-07 - title: Hybrid TreeText + KVCache - to: /docs/getting_started/examples#example-4-hybrid - --- - Combine explainable graph memory with fast KV caching in a single MemCube. - ::: - - :::card - --- - icon: ri:calendar-check-line - title: Multi-Memory Scheduling - to: /docs/getting_started/examples#example-5-multi-memory-scheduling - --- - Run dynamic memory orchestration for multi-user, multi-session agents. - ::: - -:: - - -## Example 1: Minimal Pipeline - -### When to Use: -- You want the smallest possible working example. -- You only need simple plaintext memories stored in a vector DB. -- Best for getting started or testing your embedding + vector pipeline. - -### Key Points: -- Uses GeneralTextMemory only (no graph, no KV cache). -- Add, search, update and dump memories. -- Integrates a basic MOS pipeline. - -### Full Example Code -```python -import uuid -from memos.configs.mem_os import MOSConfig -from memos.mem_os.main import MOS - - -# init MOSConfig -mos_config = MOSConfig.from_json_file("examples/data/config/simple_memos_config.json") -mos = MOS(mos_config) - -# Create a user and register a memory cube -user_id = str(uuid.uuid4()) -mos.create_user(user_id=user_id) -mos.register_mem_cube("examples/data/mem_cube_2", user_id=user_id) - -# Add a simple conversation -mos.add( - messages=[ - {"role": "user", "content": "I love playing football."}, - {"role": "assistant", "content": "That's awesome!"} - ], - user_id=user_id -) - -# Search the memory -result = mos.search(query="What do you love?", user_id=user_id) -print("Memories found:", result["text_mem"]) - -# Dump and reload -mos.dump("tmp/my_mem_cube") -mos.load("tmp/my_mem_cube") -``` - -## Example 2: TreeTextMemory Only - -### When to Use: -- You need hierarchical graph-based memories with explainable relations. -- You want to store structured knowledge and trace connections. -- Suitable for knowledge graphs, concept trees, and multi-hop reasoning. - -### Key Points: -- Uses TreeTextMemory backed by Neo4j. -- Requires extractor_llm + dispatcher_llm. -- Stores nodes, edges, and supports traversal queries. - -### Full Example Code -```python -from memos.configs.embedder import EmbedderConfigFactory -from memos.configs.memory import TreeTextMemoryConfig -from memos.configs.mem_reader import SimpleStructMemReaderConfig -from memos.embedders.factory import EmbedderFactory -from memos.mem_reader.simple_struct import SimpleStructMemReader -from memos.memories.textual.tree import TreeTextMemory - -# Setup Embedder -embedder_config = EmbedderConfigFactory.model_validate({ - "backend": "ollama", - "config": {"model_name_or_path": "nomic-embed-text:latest"} -}) -embedder = EmbedderFactory.from_config(embedder_config) - -# Create TreeTextMemory -tree_config = TreeTextMemoryConfig.from_json_file("examples/data/config/tree_config.json") -my_tree_textual_memory = TreeTextMemory(tree_config) -my_tree_textual_memory.delete_all() - -# Setup Reader -reader_config = SimpleStructMemReaderConfig.from_json_file( - "examples/data/config/simple_struct_reader_config.json" -) -reader = SimpleStructMemReader(reader_config) - -# Extract from conversation -scene_data = [[ - {"role": "user", "content": "Tell me about your childhood."}, - {"role": "assistant", "content": "I loved playing in the garden with my dog."} -]] -memory = reader.get_memory(scene_data, type="chat", info={"user_id": "1234", "session_id": "2222"}) -for m_list in memory: - my_tree_textual_memory.add(m_list) - -# Search -results = my_tree_textual_memory.search( - "Talk about the user's childhood story?", - top_k=10 -) - -# [Optional] Dump & Drop -my_tree_textual_memory.dump("tmp/my_tree_textual_memory") -my_tree_textual_memory.drop() -``` - -## Example 3: KVCacheMemory Only - -### When to Use: -- You want short-term working memory for faster multi-turn conversation. -- Useful for chatbot session acceleration or prompt reuse. -- Best for caching hidden states / KV pairs. - -### Key Points: -- Uses KVCacheMemory with no explicit text memory. -- Demonstrates extract → add → merge → get → delete. -- Shows how to dump/load KV caches. - -### Full Example Code - -```python -from memos.configs.memory import MemoryConfigFactory -from memos.memories.factory import MemoryFactory - -# Create config for KVCacheMemory (HuggingFace backend) -config = MemoryConfigFactory( - backend="kv_cache", - config={ - "extractor_llm": { - "backend": "huggingface", - "config": { - "model_name_or_path": "Qwen/Qwen3-0.6B", - "max_tokens": 32, - "add_generation_prompt": True, - "remove_think_prefix": True, - }, - }, - }, -) - -# Instantiate KVCacheMemory -kv_mem = MemoryFactory.from_config(config) - -# Extract a KVCacheItem (DynamicCache) -prompt = [ - {"role": "user", "content": "What is MemOS?"}, - {"role": "assistant", "content": "MemOS is a memory operating system for LLMs."}, -] -print("===== Extract KVCacheItem =====") -cache_item = kv_mem.extract(prompt) -print(cache_item) - -# Add the cache to memory -kv_mem.add([cache_item]) -print("All caches:", kv_mem.get_all()) - -# Get by ID -retrieved = kv_mem.get(cache_item.id) -print("Retrieved:", retrieved) - -# Merge caches (simulate multi-turn) -item2 = kv_mem.extract([{"role": "user", "content": "Tell me a joke."}]) -kv_mem.add([item2]) -merged = kv_mem.get_cache([cache_item.id, item2.id]) -print("Merged cache:", merged) - -# Delete one -kv_mem.delete([cache_item.id]) -print("After delete:", kv_mem.get_all()) - -# Dump & load caches -kv_mem.dump("tmp/kv_mem") -print("Dumped to tmp/kv_mem") -kv_mem.delete_all() -kv_mem.load("tmp/kv_mem") -print("Loaded caches:", kv_mem.get_all()) -``` - -## Example 4: Hybrid - -### When to Use: -- You want long-term explainable memory and short-term fast context together. -- Ideal for complex agents that plan, remember facts, and keep chat context. -- Demonstrates multi-memory orchestration. - -### How It Works: - -- **TreeTextMemory** stores your long-term knowledge in a graph DB (Neo4j). -- **KVCacheMemory** stores recent or stable context as activation caches. -- Both work together in a single **MemCube**, managed by your `MOS` pipeline. - - -### Full Example Code - -```python -import os - -from memos.configs.mem_cube import GeneralMemCubeConfig -from memos.configs.mem_os import MOSConfig -from memos.mem_cube.general import GeneralMemCube -from memos.mem_os.main import MOS - -# 1. Setup CUDA (if needed) — for local GPU inference -os.environ["CUDA_VISIBLE_DEVICES"] = "1" - -# 2. Define user & paths -user_id = "root" -cube_id = "root/mem_cube_kv_cache" -tmp_cube_path = "/tmp/default/mem_cube_5" - -# 3. Initialize MOSConfig -mos_config = MOSConfig.from_json_file("examples/data/config/simple_treekvcache_memos_config.json") -mos = MOS(mos_config) - -# 4. Initialize the MemCube (TreeTextMemory + KVCacheMemory) -cube_config = GeneralMemCubeConfig.from_json_file( - "examples/data/config/simple_treekvcache_cube_config.json" -) -mem_cube = GeneralMemCube(cube_config) - -# 5. Dump the MemCube to disk -try: - mem_cube.dump(tmp_cube_path) -except Exception as e: - print(e) - -# 6. Register the MemCube explicitly -mos.register_mem_cube(tmp_cube_path, mem_cube_id=cube_id, user_id=user_id) - -# 7. Extract and add a KVCache memory (simulate stable context) -extract_kvmem = mos.mem_cubes[cube_id].act_mem.extract("I like football") -mos.mem_cubes[cube_id].act_mem.add([extract_kvmem]) - -# 8. Start chatting — now your chat uses: -# - TreeTextMemory: for structured multi-hop retrieval -# - KVCacheMemory: for fast context injection -while True: - user_input = input("👤 [You] ").strip() - print() - response = mos.chat(user_input) - print(f"🤖 [Assistant] {response}\n") - -print("📢 [System] MemChat has stopped.") -``` - -## Example 5: Multi-Memory Scheduling - -### When to Use: -- You want to manage multiple users, multiple MemCubes, or dynamic memory flows. -- Good for SaaS agents or multi-session LLMs. -- Demonstrates MemScheduler + config YAMLs. - -### Key Points: -- Uses parse_yaml to load MOSConfig and MemCubeConfig. -- Dynamic user and cube creation. -- Shows runtime scheduling of memories. - -### Full Example Code - -```python -import shutil -import uuid -from pathlib import Path - -from memos.configs.mem_cube import GeneralMemCubeConfig -from memos.configs.mem_os import MOSConfig -from memos.mem_cube.general import GeneralMemCube -from memos.mem_os.main import MOS -from memos.mem_scheduler.utils import parse_yaml - -# Load main MOS config with MemScheduler -config = parse_yaml("./examples/data/config/mem_scheduler/memos_config_w_scheduler.yaml") -mos_config = MOSConfig(**config) -mos = MOS(mos_config) - -# Create user with dynamic ID -user_id = str(uuid.uuid4()) -mos.create_user(user_id=user_id) - -# Create MemCube config and dump it -config = GeneralMemCubeConfig.from_yaml_file( - "./examples/data/config/mem_scheduler/mem_cube_config.yaml" -) -mem_cube_id = "mem_cube_5" -mem_cube_name_or_path = f"./outputs/mem_scheduler/{user_id}/{mem_cube_id}" - -# Remove old folder if exists -if Path(mem_cube_name_or_path).exists(): - shutil.rmtree(mem_cube_name_or_path) - print(f"{mem_cube_name_or_path} is not empty, and has been removed.") - -# Dump new cube -mem_cube = GeneralMemCube(config) -mem_cube.dump(mem_cube_name_or_path) - -# Register MemCube for this user -mos.register_mem_cube( - mem_cube_name_or_path=mem_cube_name_or_path, - mem_cube_id=mem_cube_id, - user_id=user_id -) - -# Add messages -messages = [ - { - "role": "user", - "content": "I like playing football." - }, - { - "role": "assistant", - "content": "I like playing football too." - }, -] -mos.add(messages, user_id=user_id, mem_cube_id=mem_cube_id) - -# Chat loop: show TreeTextMemory nodes + KVCache -while True: - user_input = input("👤 [You] ").strip() - print() - response = mos.chat(user_input, user_id=user_id) - retrieved_memories = mos.get_all(mem_cube_id=mem_cube_id, user_id=user_id) - - print(f"🤖 [Assistant] {response}") - - # Show WorkingMemory nodes in TreeTextMemory - for node in retrieved_memories["text_mem"][0]["memories"]["nodes"]: - if node["metadata"]["memory_type"] == "WorkingMemory": - print(f"[WorkingMemory] {node['memory']}") - - # Show Activation Memory - if retrieved_memories["act_mem"][0]["memories"]: - for act_mem in retrieved_memories["act_mem"][0]["memories"]: - print(f"⚡ [KVCache] {act_mem['memory']}") - else: - print("⚡ [KVCache] None\n") -``` - - - -::note -**Keep in Mind**
-Use dump() and load() to persist your memory cubes. - -Always check your vector DB dimension matches your embedder. - -For graph memory, you’ll need Neo4j Desktop (community version support coming soon). -:: - -## Next Steps -You’re just getting started!Next, try: - -- Pick the example that matches your use case. -- Combine modules to build smarter, more persistent agents! - -Need more? -See the API Reference or contribute your own example! diff --git a/docs/getting_started/quick_start.md b/docs/getting_started/quick_start.md deleted file mode 100644 index e03823e9d..000000000 --- a/docs/getting_started/quick_start.md +++ /dev/null @@ -1,109 +0,0 @@ -# Quick Start: Get Up and Running with MemOS - -## What You’ll Learn -Welcome! This guide will help you **install**, **initialize**, and **run your first memory-augmented LLM app** in just a few minutes. - -In just a few minutes, you’ll learn how to set up a **minimal, working MemOS pipeline** that connects your LLM with persistent, searchable memory. -By the end, you’ll be able to **store, retrieve, and update simple memories** for a user or session — the foundation for building memory-augmented chatbots and agents. - - -::steps{} - -### Install MemOS - -```bash -pip install MemoryOS -``` - -::note -**Optional**
If you want to use local transformer models, make sure you have PyTorch installed. -:: - -::note -**Requirement for Neo4j Desktop**
If you plan to use Neo4j for graph memory, install Neo4j Desktop (community edition support coming soon!) -:: - -### Create a Minimal Config - -For this Quick Start, we’ll use the built-in GeneralTextMemory — no external vector DB or graph DB needed. -```python -from memos.configs.mem_os import MOSConfig - -# init MOSConfig -mos_config = MOSConfig.from_json_file("examples/data/config/simple_memos_config.json") -``` - -### Create a User & Register a MemCube - -```python -import uuid -from memos.mem_os.main import MOS - -mos = MOS(mos_config) - -# Generate a unique user ID -user_id = str(uuid.uuid4()) - -# Create the user -mos.create_user(user_id=user_id) - -# Register a simple memory cube for this user -mos.register_mem_cube("examples/data/mem_cube_2", user_id=user_id) -``` - -### Add Your First Memory - -```python -# Add some conversational history -mos.add( - messages=[ - {"role": "user", "content": "I love playing football."}, - {"role": "assistant", "content": "That's awesome! "} - ], - user_id=user_id -) -``` - - -### Retrieve & Search Memory - -```python -# Search for memories related to your query -result = mos.search( - query="What does the user love?", - user_id=user_id -) - -print("Memories found:", result["text_mem"]) -``` - -### Save & Load Memory - -```python -# Save your memory cube -mos.dump("tmp/my_mem_cube") - -# Later, you can load it back -mos.load("tmp/my_mem_cube") -``` - -:: - -## Next Steps - -Congratulations! You’ve just run a minimal memory-augmented pipeline with MemOS. - -Ready to level up? -- Structured Memory: Try TreeTextMemory for graph-based, hierarchical -knowledge. -- Activation Memory: Speed up multi-turn chat with KVCacheMemory. -- Parametric Memory: Use adapters/LoRA for on-the-fly skill injection. -- Graph & Vector Backends: Connect Neo4j or Qdrant for production-scale - vector/graph search. - - -## Need Help? -Check out: -- [Core Concepts](/docs/home/core_concepts) -- [API Reference](/docs/api/info) -- [Contribution Guide](/docs/contribution/overview) diff --git a/docs/getting_started/your_first_memory.md b/docs/getting_started/your_first_memory.md deleted file mode 100644 index e154f0713..000000000 --- a/docs/getting_started/your_first_memory.md +++ /dev/null @@ -1,271 +0,0 @@ -# Your First Memory - -Let’s build your first plaintext memory in MemOS! - -**GeneralTextMemory** is the easiest way to get hands-on with extracting, -embedding, and searching simple text memories. - - -## What You’ll Learn - -By the end of this guide, you will: -- Extract memories from plain text or chat messages. -- Store them as semantic vectors. -- Search and manage them using vector similarity. - -## How It Works - -### Memory Structure - -Every memory is stored as a `TextualMemoryItem`: -- `memory`: the main text content (e.g., “The user loves tomatoes.”) -- `metadata`: extra details to make the memory searchable and manageable — type, - time, source, confidence, entities, tags, visibility, and updated_at. - -These fields make each piece of memory queryable, filterable, and easy to govern. - -For each `TextualMemoryItem`: - -| Field | Example | What it means | -| ------------- | ------------------------- | ------------------------------------------ | -| `type` | `"opinion"` | Classify if it’s a fact, event, or opinion | -| `memory_time` | `"2025-07-02"` | When it happened | -| `source` | `"conversation"` | Where it came from | -| `confidence` | `100.0` | Certainty score (0–100) | -| `entities` | `["tomatoes"]` | Key concepts | -| `tags` | `["food", "preferences"]` | Extra labels for grouping | -| `visibility` | `"private"` | Who can access it | -| `updated_at` | `"2025-07-02T00:00:00Z"` | Last modified | - -::note -**Best Practice**
You can define any metadata fields that make sense for your use case! -:: - - - -### The Core Steps -When you run this example: - -1. **Extract:** -Your messages go through an `extractor_llm`, which returns a JSON list of `TextualMemoryItem`s. - -2. **Embed:** -Each memory’s `memory` field is turned into an embedding vector via `embedder`. - -3. **Store:** -The embeddings are saved into a local **Qdrant** collection. - -4. **Search & Manage:** -You can now `search` by semantic similarity, `update` by ID, or `delete` memories. - -::note -**Hint**
Make sure your embedder's output dimension matches your vector DB's `vector_dimension`. - Mismatch may cause search errors! -:: - - - -::note -**Hint**
If your search results are too noisy or irrelevant, check whether your embedder config and vector DB are properly initialized. -:: - -### Example Flow - -**Input Messages:** - -```json -[ - {"role": "user", "content": "I love tomatoes."}, - {"role": "assistant", "content": "Great! Tomatoes are healthy."} -] -``` - -**Extracted Memory:** - -```json -{ - "memory": "The user loves tomatoes.", - "metadata": { - "type": "opinion", - "memory_time": "2025-07-02", - "source": "conversation", - "confidence": 100.0, - "entities": ["tomatoes"], - "tags": ["food", "preferences"], - "visibility": "private", - "updated_at": "2025-07-02T00:00:00" - } -} -``` - -Here’s a minimal script to create, extract, store, and search a memory: - -::steps{level="4"} - -#### Create a Memory Config - -First, create your minimal GeneralTextMemory config. -It contains three key parts: -- extractor_llm: uses an LLM to extract plaintext memories from conversations. -- embedder: turns each memory into a vector. -- vector_db: stores vectors and supports similarity search. - -```python -from memos.configs.memory import MemoryConfigFactory -from memos.memories.factory import MemoryFactory - -config = MemoryConfigFactory( - backend="general_text", - config={ - "extractor_llm": { - "backend": "ollama", - "config": { - "model_name_or_path": "qwen3:0.6b", - "temperature": 0.0, - "remove_think_prefix": True, - "max_tokens": 8192, - }, - }, - "vector_db": { - "backend": "qdrant", - "config": { - "collection_name": "test_textual_memory", - "distance_metric": "cosine", - "vector_dimension": 768, - }, - }, - "embedder": { - "backend": "ollama", - "config": { - "model_name_or_path": "nomic-embed-text:latest", - }, - }, - }, -) - -m = MemoryFactory.from_config(config) -``` - - -#### Extract Memories from Messages -Give your LLM a simple dialogue and see how it extracts structured plaintext memories. - -```python -memories = m.extract( - [ - {"role": "user", "content": "I love tomatoes."}, - {"role": "assistant", "content": "Great! Tomatoes are delicious."}, - ] -) -print("Extracted:", memories) -``` -You’ll get a list of TextualMemoryItem, with each of them like: -```text -TextualMemoryItem( - id='...', - memory='The user loves tomatoes.', - metadata=... -) -``` - -#### Add Memories to Your Vector DB - -Save the extracted memories to your vector DB and demonstrate adding a custom plaintext memory manually (with a custom ID). - -```python -m.add(memories) -m.add([ - { - "id": "a19b6caa-5d59-42ad-8c8a-e4f7118435b4", - "memory": "User is Chinese.", - "metadata": {"type": "opinion"}, - } -]) -``` - - -#### Search Memories - -Now test similarity search! -Type any natural language query and find related memories. -```python -results = m.search("Tell me more about the user", top_k=2) -print("Search results:", results) -``` - -#### Get Memories by ID - -Fetch any memory directly by its ID: -```python -print("Get one by ID:", m.get("a19b6caa-5d59-42ad-8c8a-e4f7118435b4")) -``` - -#### Update a Memory - -Need to fix or refine a memory? -Update it by ID and re-embed the new version. -```python -m.update( - "a19b6caa-5d59-42ad-8c8a-e4f7118435b4", - { - "memory": "User is Canadian.", - "metadata": { - "type": "opinion", - "confidence": 85, - "memory_time": "2025-05-24", - "source": "conversation", - "entities": ["Canadian"], - "tags": ["happy"], - "visibility": "private", - "updated_at": "2025-05-19T00:00:00", - }, - } -) -print("Updated:", m.get("a19b6caa-5d59-42ad-8c8a-e4f7118435b4")) -``` - -#### Delete Memories - -Remove one or more memories cleanly -```python -m.delete(["a19b6caa-5d59-42ad-8c8a-e4f7118435b4"]) -print("Remaining:", m.get_all()) -``` - -#### Dump Memories to Disk - -Finally, dump all your memories to local storage: -```python -m.dump("tmp/mem") -print("Memory dumped to tmp/mem") -``` -By default, your memories are saved to: -``` -/ -``` -They can be reloaded anytime with `load()`. - -::note -By default, your dumped memories are saved to the file path you set in your config. - Always check config.memory_filename if you want to customize it. -:: - -:: - -Now your agent remembers — no more stateless chatbots! - -## What’s Next? - -Ready to level up? - -- **Try your own LLM backend:** Swap to OpenAI, HuggingFace, or Ollama. -- **Explore [TreeTextMemory](/docs/modules/memories/tree_textual_memory):** Build a graph-based, - hierarchical memory. -- **Add [Activation Memory](/docs/modules/memories/kv_cache_memory):** Cache key-value - states for faster inference. -- **Dive deeper:** Check the [API Reference](/docs/api/info) and [Examples](/docs/getting_started/examples) for advanced workflows. - -::note -**Try Graph Textual Memory**
Try switching to -TreeTextMemory to add a graph-based, hierarchical structure to your memories.
Perfect for scenarios that need explainability and long-term structured knowledge. -:: diff --git a/docs/home/architecture.md b/docs/home/architecture.md deleted file mode 100644 index 9852df3e9..000000000 --- a/docs/home/architecture.md +++ /dev/null @@ -1,89 +0,0 @@ -# Architecture - -MemOS is made up of **core modules** that work together to turn your LLM into a truly **memory-augmented system** — from orchestration to storage to retrieval. - -## Core Modules - -### MOS (Memory Operating System) - -The orchestration layer of MemOS — it - manages predictive, asynchronous scheduling across multiple memory types (plaintext, activation, parametric) and orchestrates **multi-user, multi-session** memory workflows. - -MOS connects memory containers (**MemCubes**) with LLMs via a unified API for adding, searching, updating, transferring, or rolling back memories. It also supports cross-model, cross-device interoperability through a unified Memory Interchange Protocol (MIP). - -### MemCube -A modular, portable **memory container** — think of it like a flexible cartridge that can hold one or more memory types for a **user, agent, or session**. - -MemCubes can be dynamically registered, updated, or removed. They support containerized storage that is transferable across sessions, models, and devices. - -### Memories - - MemOS supports several specialized memory types for different needs: - -#### 1. **Parametric Memory**(**Coming Soon**) - -Embedded in model weights; - long-term, - high-efficiency, but hard to edit. - -#### 2. **Activation Memory** - -Runtime hidden states & KV-cache; short-term, -transient, steering dynamic behavior. - -#### 3. Plaintext Memory - -Structured or unstructured knowledge -blocks; editable, traceable, suitable for fast updates, personalization & multi-agent sharing. - -- **GeneralTextMemory:** Flexible, vector-based storage for unstructured -textual knowledge with semantic search and metadata filtering. -- **TreeTextMemory:** Hierarchical, graph-style memory for structured -knowledge — combining **tree-based hierarchy** and **cross-branch linking** for dynamic, evolving knowledge graphs. It supports long-term organization and multi-hop reasoning (often Neo4j-backed). - -::note -**Best Practice**
-Start simple with GeneralTextMemory — then scale to graph or KV-cache as your needs grow. -:: - -#### Basic Modules - -Includes chunkers, embedders, LLM connectors, parsers, and interfaces for vector/graph databases. These provide the building blocks for memory extraction, semantic embedding, storage, and retrieval. - -## Code Structure - -Your MemOS project is organized for clarity and plug-and-play: - -``` -src/memos/ - api/ # API definitions - chunkers/ # Text chunking utilities - configs/ # Configuration schemas - embedders/ # Embedding models - graph_dbs/ # Graph database backends (e.g., Neo4j) - vec_dbs/ # Vector database backends (e.g., Qdrant) - llms/ # LLM connectors - mem_chat/ # Memory-augmented chat logic - mem_cube/ # MemCube management - mem_os/ # MOS orchestration - mem_reader/ # Memory readers - memories/ # Memory type implementations - parsers/ # Parsing utilities -``` - -::note -**Pro Tip**
-Use examples/ for quick experimentation and docs/ for module deep dives. -:: - -## Extensibility - -MemOS is **modular by design**. -Add your own memory types, storage backends, or LLM connectors with minimal changes — thanks to its **unified config and factory patterns**. - - -::note -**Pro Tip**
-[Contribute](/docs/contribution/overview) a new backend or share your custom memory -type — it’s easy to plug in. -:: diff --git a/docs/home/core_concepts.md b/docs/home/core_concepts.md deleted file mode 100644 index 872384561..000000000 --- a/docs/home/core_concepts.md +++ /dev/null @@ -1,106 +0,0 @@ -# Core Concepts - -MemOS treats memory as a first-class citizen. Its core design revolves around how to orchestrate, store, retrieve, and govern memory for your LLM applications. - -## Overview - -* [MOS (Memory Operating System)](#mos-memory-operating-system) -* [MemCube](#️memcube) -* [Memory Types](#memory-types) -* [Cross-Cutting Concepts](#cross-cutting-concepts) - - -## MOS (Memory Operating System) - -**What it is:** -The orchestration layer that coordinates multiple MemCubes and memory operations. It connects your LLMs with structured, explainable memory for reasoning and planning. - -**When to use:** -Use MOS whenever you need to bridge users, sessions, or agents with consistent, auditable memory workflows. - -## MemCube - -**What it is:** -A MemCube is like a flexible, swappable memory cartridge. Each user, session, or task can have its own MemCube, which can hold one or more memory types. - -**When to use:** -Use different MemCubes to isolate, reuse, or scale your memory as your system grows. - -## Memory Types - -MemOS treats memory like a living system — not just static data but evolving knowledge. Here’s how the three core memory types work together: - -| Memory Type | Description | When to Use | -|----------------|----------------------------------------------|---------------------------------------------| -| **Parametric** | Knowledge distilled into model weights | Evergreen skills, stable domain expertise | -| **Activation** | Short-term KV cache and hidden states | Fast reuse in dialogue, multi-turn sessions | -| **Plaintext** | Text, docs, graph nodes, or vector chunks | Searchable, inspectable, evolving knowledge | - -### Parametric Memory - -**What:** -Knowledge embedded directly into the model’s weights — think of this as the model’s “cortex”. It’s always on, providing zero-latency reasoning. - -**When to use:** -Perfect for stable domain knowledge, distilled FAQs, or skills that rarely change. - -### Activation Memory - -**What:** -Activation Memory is your model’s reusable “working memory” — it includes precomputed key-value caches and hidden states that can be directly injected into the model’s attention mechanism. -Think of it as pre-cooked context that saves your LLM from repeatedly -re-encoding static or frequently used information. - -**Why it matters:** -By storing stable background content (like FAQs or known facts) in a KV-cache, your model can skip redundant computation during the prefill phase. -This dramatically reduces Time To First Token (TTFT) and improves throughput for multi-turn conversations or retrieval-augmented generation. - -**When to use:** -- Reuse background knowledge across many user queries. -- Speed up chatbots that rely on the same domain context each turn. -- Combine with MemScheduler to auto-promote stable plaintext memory to KV format. - -### Explicit Memory - -**What:** -Structured or unstructured knowledge units — user-visible, explainable. These can be documents, chat logs, graph nodes, or vector embeddings. - -**When to use:** -Best for semantic search, user preferences, or traceable facts that evolve over time. Supports tags, provenance, and lifecycle states. - - -## How They Work Together - -MemOS lets you orchestrate all three memory types in a living loop: - -- Hot plaintext memories can be distilled into parametric weights. -- High-frequency activation paths become reusable KV templates. -- Stale parametric or activation units can be downgraded to plaintext nodes for traceability. - -With MemOS, your AI doesn’t just store facts — it **remembers**, **understands**, and **grows**. - -::note -**Insight**
- Over time, frequently used plaintext memories can be distilled into parametric form. - Rarely used weights or caches can be demoted to plaintext storage for auditing and retraining. -:: - -## Cross-Cutting Concepts - -### Hybrid Retrieval - -Combines vector similarity and graph traversal for robust, context-aware search. - -### Governance & Lifecycle - -Every memory unit supports states (active, merged, archived), provenance tracking, and fine-grained access control — essential for auditing and compliance. - -::note -**Compliance Reminder**
-Always track provenance and state changes for each memory unit. - This helps meet audit and data governance requirements. -:: - -## Key Takeaway - -With MemOS, your LLM applications gain structured, evolving memory — empowering agents to plan, reason, and adapt like never before. diff --git a/docs/home/memos_intro.md b/docs/home/memos_intro.md deleted file mode 100644 index 46a37fa4d..000000000 --- a/docs/home/memos_intro.md +++ /dev/null @@ -1,118 +0,0 @@ -# What is MemOS? - -**MemOS** is a **Memory Operating System** for large language models (LLMs) and autonomous agents. -It treats memory as a **first-class, orchestrated, and explainable resource**, rather than an opaque layer hidden inside model weights. - - -![MemOS Architecture](https://statics.memtensor.com.cn/memos/memos-architecture.png) - - -As LLMs advance to handle complex tasks — like multi-turn dialogue, long-term planning, decision-making, and personalized user experiences — their ability to **structure, manage, and evolve memory** becomes critical for achieving true long-term intelligence and adaptability. - -However, most mainstream LLMs still rely heavily on static parametric memory (model weights). This makes it difficult to update knowledge, track memory usage, or accumulate evolving user preferences. The result? High costs to refresh knowledge, brittle behaviors, and limited personalization. - -**MemOS** solves these challenges by redefining memory as a **core, modular system resource** with a unified structure, lifecycle management, and scheduling logic. It provides a Python-based layer that sits between your LLM and external knowledge sources, enabling **persistent, structured, and efficient memory operations**. - -With MemOS, your LLM can retain knowledge over time, manage context more robustly, and reason with memory that’s explainable and auditable — unlocking more intelligent, reliable, and adaptive AI behaviors. - - -::note -**Tip**
MemOS helps bridge the gap between static parametric weights and dynamic, user-specific memory. - Think of it as your agent’s “brain”, with plug-and-play modules for text, graph, and activation memory. -:: - -## Why do we need a Memory OS? - -Modern LLMs are powerful—but static. -They rely heavily on **parametric memory** (the weights) that is hard to inspect, update, or share. -Typical vector search (RAG) helps retrieve external facts, but lacks unified governance, lifecycle control, or cross-agent sharing. - -**MemOS** changes this. -Think of it like an OS for memory: -just as an operating system schedules CPU, RAM, and files, MemOS **schedules, -transforms, and governs** multiple memory types — from parametric weights to ephemeral caches to plaintext, traceable knowledge. - -::note -**Insight**
MemOS helps your LLM evolve, by blending parametric, activation, and plaintext memory into a living loop. -:: - - -## Core Building Blocks -### MemCubes - -**Flexible containers** that hold one or more memory types. -Each user, session, or agent can have its own MemCube — swappable, reusable, and traceable. - -### Memory Lifecycle - -Each memory unit can flow through states like: - -- **Generated** → **Activated** → **Merged** → **Archived** → **Frozen** - -Every step is versioned with **provenance tracking** and audit logs. -Old memories can be “time-machined” back to prior versions for recovery or counterfactual simulations. - - -### Operation & Governance - -Modules like: - -- **MemScheduler** — dynamically transforms memory types for optimal reuse. -- **MemLifecycle** — manages state transitions, merging, and archiving. -- **MemGovernance** — handles access control, redaction, compliance, and audit trails. - - -::note -**Compliance Reminder**
Every memory unit carries full provenance metadata, so you can audit who created, modified, or queried it. -:: - - -## Multi-Perspective Memory - -MemOS blends **three memory forms** in a living loop: - -| Type | Description | Use Case | -|----------------| ---------------------------------------------------- | ---------------------------------------------- | -| **Parametric** | Knowledge distilled into model weights | Evergreen skills, stable domain facts | -| **Activation** | KV-caches and hidden states for inference reuse | Fast multi-turn chat, low-latency generation | -| **Plaintext** | Text, docs, graphs, vector chunks, user-visible facts| Semantic search, evolving, explainable memory | - -Over time: - -- Hot plaintext memories can be distilled into parametric weights. -- Stable context is promoted to KV-cache for rapid injection. -- Cold or outdated knowledge can be demoted for auditing. - - -## What makes MemOS different? - -- Hybrid retrieval — symbolic & semantic, vector + graph. -- Multi-agent & multi-user graphs — private and shared. -- Provenance & audit trail — every memory unit is governed and explainable. -- Automatic KV-cache promotion for stable context reuse. -- Lifecycle-aware scheduling — no more stale facts or bloated weights. - - -## Who is it for? - -- Conversational agents needing **multi-turn, evolving memory** -- Enterprise copilots handling **compliance, domain updates, and personalization** -- Multi-agent systems collaborating on a **shared knowledge graph** -- AI builders wanting modular, inspectable memory instead of black-box prompts - -## Key Takeaway - -**MemOS** upgrades your LLM from “just predicting tokens” -to an intelligent, evolving system that can **remember**, **reason**, and **adapt** — -like an operating system for your agent’s mind. - -**With MemOS, your AI doesn’t just store facts — it grows.** - -## Key Features - -- **Modular Memory Architecture**: Support for textual, activation (KV cache), and parametric (adapters/LoRA) memory. -- **MemCube**: Unified container for all memory types, with easy load/save and API access. -- **MOS**: Memory-augmented chat orchestration for LLMs, with plug-and-play memory modules. -- **Graph-based Backends**: Native support for Neo4j and other graph DBs for structured, explainable memory. -- **Easy Integration**: Works with HuggingFace, Ollama, and custom LLMs. -- **Extensible**: Add your own memory modules or backends. diff --git a/docs/home/overview.md b/docs/home/overview.md deleted file mode 100644 index df095f2b0..000000000 --- a/docs/home/overview.md +++ /dev/null @@ -1,48 +0,0 @@ -# MemOS Documentation - -![MemOS Banner](https://statics.memtensor.com.cn/memos/memos-banner.gif) - -Welcome to the official documentation for **MemOS** – a Python package designed to empower large language models (LLMs) with advanced, modular memory capabilities. - -- **Open Source**: [GitHub Repository](https://github.com/MemTensor/MemOS) -- **PyPI Package**: [MemoryOS on PyPI](https://pypi.org/project/MemoryOS) - -## What is MemOS? - -As large language models (LLMs) evolve to tackle advanced tasks—such as multi-turn dialogue, planning, decision-making, and personalized agents—their ability to manage and utilize memory becomes crucial for achieving long-term intelligence and adaptability. However, mainstream LLM architectures often struggle with weak memory structuring, management, and integration, leading to high knowledge update costs, unsustainable behavioral states, and difficulty in accumulating user preferences. - -**MemOS** addresses these challenges by redefining memory as a core, first-class resource with unified structure, lifecycle management, and scheduling strategies. It provides a Python package that delivers a unified memory layer for LLM-based applications, enabling persistent, structured, and efficient memory operations. This empowers LLMs with long-term knowledge retention, robust context management, and memory-augmented reasoning, supporting more intelligent and adaptive behaviors. - -![MemOS Architecture](https://statics.memtensor.com.cn/memos/memos-architecture.png) - -## Key Features - -- **Modular Memory Architecture**: Support for textual, activation (KV cache), and parametric (adapters/LoRA) memory. -- **MemCube**: Unified container for all memory types, with easy load/save and API access. -- **MOS**: Memory-augmented chat orchestration for LLMs, with plug-and-play memory modules. -- **Graph-based Backends**: Native support for Neo4j and other graph DBs for structured, explainable memory. -- **Easy Integration**: Works with HuggingFace, Ollama, and custom LLMs. -- **Extensible**: Add your own memory modules or backends. - -## Installation - -```bash -pip install MemoryOS -``` - -To use with Ollama: - -```bash -curl -fsSL https://ollama.com/install.sh | sh -``` - -For transformer models, ensure [PyTorch](https://pytorch.org/get-started/locally/) is installed. - -## Contributing - -We welcome contributions! Please see the [contribution guidelines](/docs/contribution/overview) for details on setting up your environment and -submitting pull requests. - -## License - -MemOS is released under the Apache 2.0 License. diff --git a/docs/modules/mem_cube.md b/docs/modules/mem_cube.md deleted file mode 100644 index f2c90dca9..000000000 --- a/docs/modules/mem_cube.md +++ /dev/null @@ -1,78 +0,0 @@ -# MemCube Overview - -`MemCube` is the core organizational unit in MemOS, designed to encapsulate and manage all types of memory for a user or agent. It provides a unified interface for loading, saving, and operating on multiple memory modules, making it easy to build, share, and deploy memory-augmented applications. - -## What is a MemCube? - -A **MemCube** is a container that bundles three major types of memory: - -- **Textual Memory** (e.g., `GeneralTextMemory`, `TreeTextMemory`): For storing and retrieving unstructured or structured text knowledge. -- **Activation Memory** (e.g., `KVCacheMemory`): For storing key-value caches to accelerate LLM inference and context reuse. -- **Parametric Memory** (e.g., `LoRAMemory`): For storing model adaptation parameters (like LoRA weights). - -Each memory type is independently configurable and can be swapped or extended as needed. - -## Structure - -A MemCube is defined by a configuration (see `GeneralMemCubeConfig`), which specifies the backend and settings for each memory type. The typical structure is: - -``` -MemCube - ├── text_mem: TextualMemory - ├── act_mem: ActivationMemory - └── para_mem: ParametricMemory -``` - -All memory modules are accessible via the MemCube interface: -- `mem_cube.text_mem` -- `mem_cube.act_mem` -- `mem_cube.para_mem` - -## API Summary (`GeneralMemCube`) - -### Initialization -```python -from memos.mem_cube.general import GeneralMemCube -mem_cube = GeneralMemCube(config) -``` - -### Core Methods -| Method | Description | -| --------------| ------------------------------------------------ | -| `load(dir)` | Load all memories from a directory | -| `dump(dir)` | Save all memories to a directory | -| `text_mem` | Access the textual memory module | -| `act_mem` | Access the activation memory module | -| `para_mem` | Access the parametric memory module | -| `init_from_dir(dir)` | Load a MemCube from a directory | -| `init_from_remote_repo(repo, base_url)` | Load from remote repo | - -## File Storage - -A MemCube directory contains: -- `config.json` (MemCube configuration) -- `textual_memory.json` (textual memory) -- `activation_memory.pickle` (activation memory) -- `parametric_memory.adapter` (parametric memory) - -## Example Usage - -```python -from memos.mem_cube.general import GeneralMemCube -# Load from local directory -mem_cube = GeneralMemCube.init_from_dir("examples/data/mem_cube_2") -# Load from remote repo -mem_cube = GeneralMemCube.init_from_remote_repo("Ki-Seki/mem_cube_2") -# Access and print all memories -for item in mem_cube.text_mem.get_all(): - print(item) -for item in mem_cube.act_mem.get_all(): - print(item) -mem_cube.dump("tmp/mem_cube") -``` - -## Developer Notes - -* MemCube enforces schema consistency for safe loading/dumping -* Each memory type is pluggable and independently tested -* See `/tests/mem_cube/` for integration tests and usage patterns diff --git a/docs/modules/mem_reader.md b/docs/modules/mem_reader.md deleted file mode 100644 index 89ac8cbcc..000000000 --- a/docs/modules/mem_reader.md +++ /dev/null @@ -1,188 +0,0 @@ -# Getting Started with MemReader - -This guide walks you through how to use the `SimpleStructMemReader` to extract structured memories from conversations and documents using LLMs and embedding models. It is ideal for building memory-aware conversational AI, knowledge bases, and semantic search systems. - ---- - -## Initialize a `SimpleStructMemReader` - -First, configure and initialize the reader with your preferred LLM and embedder models. - -### Example: - -```python -from memos.configs.mem_reader import SimpleStructMemReaderConfig -from memos.mem_reader.simple_struct import SimpleStructMemReader -reader_config = SimpleStructMemReaderConfig.from_json_file( - "examples/data/config/simple_struct_reader_config.json" -) -reader = SimpleStructMemReader(reader_config) -``` -::tip -You can customize the model names or backends depending on your environment. -:: ---- - -## Get Your First Chat Memory - -Extract structured memories from a conversation between a user and assistant. - -### Example Input: - -```python -conversation_data = [ - [ - {"role": "user", "content": "I have a meeting tomorrow at 3 PM"}, - {"role": "assistant", "content": "What's the meeting about?"}, - {"role": "user", "content": "It's about the Q4 project deadline"} - ] -] -``` - -### Extract Memories: - -```python -memories = reader.get_memory( - conversation_data, - type="chat", - info={"user_id": "user_001", "session_id": "session_001"} -) -``` - -### Sample Output: - -```json -[ - TextualMemoryItem( - id='2d5965f9-4c9b-4c24-9068-325b53db098b', - memory='Tomorrow at 3:00 PM, the user will meet with the Q4 project team to discuss the deadline.', - metadata=TreeNodeTextualMemoryMetadata( - user_id='user_001', - session_id='session_001', - status='activated', - type='fact', - confidence=0.99, - tags=['deadline', 'project'], - visibility=None, - updated_at='2025-07-03T14:34:33.535844', - memory_type='UserMemory', - key='Meeting schedule', - sources=[ - "user: I have a meeting tomorrow at 3 PM", - "assistant: What's the meeting about?", - "user: It's about the Q4 project deadline" - ], - embedding=[0.0058597163, ..., 0.009375607], - created_at='2025-07-03T14:34:33.535860', - usage=[], - background="The user plans to meet with the Q4 project team tomorrow at 3:00 PM to address the project's deadline. This action reflects their proactive approach to managing project timelines and their focus on ensuring timely completion." - ) - ) -] -``` -::note -The reader extract related memories and tags from the conversation session. -:: ---- - -## Get Your First Document Memory - -Process text files to extract structured summaries and tags. - -### Example Code: - -```python -doc_paths = [ - "examples/mem_reader/text1.txt", - "examples/mem_reader/text2.txt", -] - -doc_memories = reader.get_memory( - doc_paths, - type="doc", - info={ - "user_id": "user_001", - "session_id": "session_001", - "chunk_size": 512, - "chunk_overlap": 128 - } -) -``` - -### Sample Output: - -```json -[ - TextualMemoryItem( - id='24dabd9f-200b-40c4-84cc-2c0fccaaf8fd', - memory='This is another sample document content for testing purposes.', - metadata=TreeNodeTextualMemoryMetadata( - user_id='user_001', - session_id='session_001', - status='activated', - type='fact', - memory_time=None, - source=None, - confidence=0.99, - entities=None, - tags=['Testing', 'Sample'], - visibility=None, - updated_at='2025-07-03T14:38:29.776147', - memory_type='LongTermMemory', - key='', - sources=['examples/mem_reader/text2.txt_0'], - embedding=[0.028731367, ..., -0.018501928], - created_at='2025-07-03T14:38:29.776213', - usage=[], - background='' - ) - ) -] -``` -::note -Documents are chunked and summarized to create searchable knowledge items. -:: - -### Supported Files - -We use [`markitdown`](https://github.com/microsoft/markitdown) to convert files to Markdown format texts. - -**MarkItDown currently supports the conversion from:** - -``` -PDF -PowerPoint -Word -Excel -Images (EXIF metadata and OCR) -Audio (EXIF metadata and speech transcription) -HTML -Text-based formats (CSV, JSON, XML) -ZIP files (iterates over contents) -YouTube URLs -EPUBs -... and more! -``` -*(Content sourced from [MarkItDown GitHub repository](https://github.com/microsoft/markitdown))* - ---- - - -## Try It Out: Print Extracted Memories - -```python -for memory_list in memories: - for memory_item in memory_list: - print("🧠 Memory:", memory_item.memory) - print("🏷 Tags:", memory_item.metadata.tags) - print("👤 User ID:", memory_item.metadata.user_id) - print("📅 Created At:", memory_item.metadata.created_at) - print("---") -``` - ---- - -You’ve now successfully: -- Initialized a `SimpleStructMemReader` -- Extracted structured memories from chat conversations -- Extracted knowledge from documents diff --git a/docs/modules/mem_scheduler.md b/docs/modules/mem_scheduler.md deleted file mode 100644 index 232531cf0..000000000 --- a/docs/modules/mem_scheduler.md +++ /dev/null @@ -1,119 +0,0 @@ -# MemScheduler: The Scheduler for Memory Organization - -`MemScheduler` is a concurrent memory management system parallel running with the MemOS system, which coordinates memory operations between working memory, long-term memory, and activation memory in AI systems. It handles memory retrieval, updates, and compaction through event-driven scheduling. - -This system is particularly suited for conversational agents and reasoning systems requiring dynamic memory management. - - -## Memory Scheduler Architecture - -The `MemScheduler` system is structured around several key components: - -1. **Message Handling**: Processes incoming messages through a dispatcher with labeled handlers -2. **Memory Management**: Manages different memory types (Working, Long-Term, User) -3. **Retrieval System**: Efficiently retrieves relevant memory items based on context -4. **Monitoring**: Tracks memory usage, frequencies, and triggers updates -5. **Logging**: Maintains logs of memory operations for debugging and analysis - -## Message Processing - -The scheduler processes messages through a dispatcher with dedicated handlers: - -### Message Types - -| Message Type | Handler Method | Description | -|--------------|---------------------------------|--------------------------------------------| -| `QUERY_LABEL` | `_query_message_consume` | Handles user queries and triggers retrieval | -| `ANSWER_LABEL`| `_answer_message_consume` | Processes answers and updates memory usage | - -### Message Structure (`ScheduleMessageItem`) - -| Field | Type | Description | -|---------------|----------------------|-----------------------------------------------| -| `item_id` | `str` | UUID (auto-generated) for unique identification | -| `user_id` | `str` | Identifier for the associated user | -| `mem_cube_id` | `str` | Identifier for the memory cube | -| `label` | `str` | Message label (e.g., `QUERY_LABEL`, `ANSWER_LABEL`) | -| `mem_cube` | `GeneralMemCube | str` | Memory cube object or reference | -| `content` | `str` | Message content | -| `timestamp` | `datetime` | Time when the message was submitted | - -## Memory Management - -### Memory Types and Sizes - -The scheduler manages multiple memory partitions with configurable capacities: - -| Memory Type | Description | Default Capacity | -|---------------------------|------------------------------------------|------------------| -| `long_term_memory` | Persistent knowledge storage | 10,000 items | -| `user_memory` | User-specific knowledge and interactions | 10,000 items | -| `working_memory` | Active context for current interactions | 20 items | -| `transformed_act_memory` | Transformed activation memory (dynamic) | Not initialized | - -### Configuration Parameters - -| Parameter | Description | Default Value | -|----------------------------|-----------------------------------------------------------------------------|---------------| -| `top_k` | Number of candidates to retrieve during initial search | 10 | -| `top_n` | Number of final results to return after processing | 5 | -| `enable_parallel_dispatch` | Enable parallel message processing using thread pool | `True` | -| `thread_pool_max_workers` | Maximum number of worker threads in the pool | 5 | -| `consume_interval_seconds` | Interval (in seconds) for consuming messages from the queue | 3 | -| `act_mem_update_interval` | Interval (in seconds) for updating activation memory | 300 | -| `context_window_size` | Size of the context window for conversation history | 5 | -| `activation_mem_size` | Maximum size of the activation memory - - -## Execution Example - -`examples/mem_scheduler/schedule_w_memos.py` is a demonstration script showcasing how to utilize the `MemScheduler` module. It illustrates memory management and retrieval within conversational contexts. - -### Code Functionality Overview - -This script demonstrates two methods for initializing and using the memory scheduler: - -1. **Automatic Initialization**: Configures the scheduler via configuration files -2. **Manual Initialization**: Explicitly creates and configures scheduler components - -The script simulates a pet-related conversation between a user and an assistant, demonstrating how memory scheduler manages conversation history and retrieves relevant information. - -### Core Code Structure - -```python -def init_task(): - # Initialize sample conversations and questions - conversations = [ - {"role": "user", "content": "I just adopted a golden retriever puppy yesterday."}, - {"role": "assistant", "content": "Congratulations! What did you name your new puppy?"}, - # More conversations... - ] - - questions = [ - {"question": "What's my dog's name again?", "category": "Pet"}, - # More questions... - ] - return conversations, questions - -def show_web_logs(mem_scheduler: GeneralScheduler): - # Display web logs generated by the scheduler - # Includes memory operations, retrieval events, etc. - -def run_with_automatic_scheduler_init(): - # Automatic initialization: Load configuration from YAML files - # Create user and memory cube - # Add conversations to memory - # Process user queries and display answers - # Show web logs - -def run_with_manual_scheduler_init(): - # Manual initialization: Explicitly create and configure scheduler components - # Initialize MemOS, user, and memory cube - # Manually submit messages to the scheduler - # Process user queries and display answers - # Show web logs - -if __name__ == '__main__': - # Run both initialization methods sequentially - run_with_automatic_scheduler_init() - run_with_manual_scheduler_init( diff --git a/docs/modules/memories/general_textual_memory.md b/docs/modules/memories/general_textual_memory.md deleted file mode 100644 index ebe206bab..000000000 --- a/docs/modules/memories/general_textual_memory.md +++ /dev/null @@ -1,103 +0,0 @@ -# GeneralTextMemory: General-Purpose Textual Memory - -`GeneralTextMemory` is a flexible, vector-based textual memory module in MemOS, designed for storing, searching, and managing unstructured knowledge. It is suitable for conversational agents, personal assistants, and any system requiring semantic memory retrieval. - -## Memory Structure - -Each memory is represented as a `TextualMemoryItem`: - -| Field | Type | Description | -| ---------- | --------------------------- | ---------------------------------- | -| `id` | `str` | UUID (auto-generated if omitted) | -| `memory` | `str` | The main memory content (required) | -| `metadata` | `TextualMemoryMetadata` | Metadata for search/filtering | - -### Metadata Fields (`TextualMemoryMetadata`) - -| Field | Type | Description | -| ------------- | -------------------------------------------------- | ----------------------------------- | -| `type` | `"procedure"`, `"fact"`, `"event"`, `"opinion"` | Memory type | -| `memory_time` | `str (YYYY-MM-DD)` | Date/time the memory refers to | -| `source` | `"conversation"`, `"retrieved"`, `"web"`, `"file"` | Source of the memory | -| `confidence` | `float (0-100)` | Certainty/confidence score | -| `entities` | `list[str]` | Key entities/concepts | -| `tags` | `list[str]` | Thematic tags | -| `visibility` | `"private"`, `"public"`, `"session"` | Access scope | -| `updated_at` | `str` | Last update timestamp (ISO 8601) | - -All values are validated. Invalid values will raise errors. - -## API Summary (`GeneralTextMemory`) - -### Initialization -```python -GeneralTextMemory(config: GeneralTextMemoryConfig) -``` - -### Core Methods -| Method | Description | -| ------------------------ | --------------------------------------------------- | -| `extract(messages)` | Extracts memories from message list (LLM-based) | -| `add(memories)` | Adds one or more memories (items or dicts) | -| `search(query, top_k)` | Retrieves top-k memories using vector similarity | -| `get(memory_id)` | Fetch single memory by ID | -| `get_by_ids(ids)` | Fetch multiple memories by IDs | -| `get_all()` | Returns all memories | -| `update(memory_id, new)` | Update a memory by ID | -| `delete(ids)` | Delete memories by IDs | -| `delete_all()` | Delete all memories | -| `dump(dir)` | Serialize all memories to JSON file in directory | -| `load(dir)` | Load memories from saved file | - -## File Storage - -When calling `dump(dir)`, the system writes to: - -``` -/ -``` - -This file contains a JSON list of all memory items, which can be reloaded using `load(dir)`. - -## Example Usage - -```python -from memos.configs.memory import MemoryConfigFactory -from memos.memories.factory import MemoryFactory - -config = MemoryConfigFactory( - backend="general_text", - config={ - "extractor_llm": { ... }, - "vector_db": { ... }, - "embedder": { ... }, - }, -) -m = MemoryFactory.from_config(config) - -# Extract and add memories -memories = m.extract([ - {"role": "user", "content": "I love tomatoes."}, - {"role": "assistant", "content": "Great! Tomatoes are delicious."}, -]) -m.add(memories) - -# Search -results = m.search("Tell me more about the user", top_k=2) - -# Update -m.update(memory_id, {"memory": "User is Canadian.", ...}) - -# Delete -m.delete([memory_id]) - -# Dump/load -m.dump("tmp/mem") -m.load("tmp/mem") -``` - -## Developer Notes - -* Uses Qdrant (or compatible) vector DB for fast similarity search -* Embedding and extraction models are configurable (Ollama/OpenAI supported) -* All methods are covered by integration tests in `/tests` diff --git a/docs/modules/memories/kv_cache_memory.md b/docs/modules/memories/kv_cache_memory.md deleted file mode 100644 index 9ad6ab731..000000000 --- a/docs/modules/memories/kv_cache_memory.md +++ /dev/null @@ -1,181 +0,0 @@ -# KVCacheMemory: Key-Value Cache for Activation Memory - -`KVCacheMemory` is a specialized memory module in MemOS for storing and managing key-value (KV) caches, primarily used to accelerate large language model (LLM) inference and support efficient context reuse. It is especially useful for activation memory in conversational and generative AI systems. - -## KV-cache Memory Use Cases - -In MemOS, KV-cache memory is best suited for storing **semantically stable and frequently reused background content** such as: - -- Frequently asked questions (FAQs) or domain-specific knowledge -- Prior conversation history - -These stable **plaintext memory items** are automatically identified and managed by the `MemScheduler` module. Once selected, they are converted into KV-format representations (`KVCacheItem`) ahead of time. This precomputation step stores the activation states (Key/Value tensors) of the memory in a reusable format, allowing them to be injected into the model’s attention cache during inference. - -Once converted, these KV memories can be **reused across queries without requiring re-encoding** of the original content. This reduces the computational overhead of processing and storing large amounts of text, making it ideal for applications that require **rapid response times** and **high throughput**. - - -## Why KV-cache Memory -Integrating `MemScheduler` with KV-cache memory enables significant performance optimization, particularly in the **prefill phase** of LLM inference. - -### Without KVCacheMemory - -- Each new query is appended to the full prompt, including the background memory. -- The model must **recompute token embeddings and attention** over the full sequence — even for unchanged memory. - -### With KVCacheMemory - -- The background content is **cached once** as Key/Value tensors. -- For each query, only the new user input (query tokens) is encoded. -- The previously cached KV is injected directly into the attention mechanism. - -### Benefits - -This separation reduces redundant computation in the prefill phase and leads to: - -- Skipping repeated encoding of background content -- Faster attention computation between query tokens and cached memory -- **Lower Time To First Token (TTFT)** latency during generation - -This optimization is especially valuable in: - -- Multi-turn chatbot interactions -- Retrieval-augmented or context-augmented generation (RAG, CAG) -- Assistants operating over fixed documentation or FAQ-style memory - - -### KVCacheMemory Acceleration Evaluation - -To validate the performance impact of KV-based memory injection, we conducted a set of controlled experiments simulating real memory reuse in MemOS. - -#### Experiment Setup - -During typical usage, the `MemScheduler` module continuously tracks interaction patterns and promotes high-frequency, stable plaintext memory into KV format. These KV memories are loaded into GPU memory as activation caches and reused during inference. - -The evaluation compares two memory injection strategies: - -1. **Prompt-based injection**: background memory is prepended as raw text. -2. **KV-cache injection**: memory is injected directly into the model’s attention cache. - -We test these strategies across: - -- **Three context sizes**: short, medium, and long -- **Three query types**: short-form, medium-form, and long-form - -The primary metric is **Time To First Token (TTFT)**, a key latency indicator for responsive generation. - -#### Results - -The following table shows results across three models (Qwen3-8B, Qwen3-32B, Qwen2.5-72B). TTFT under KV-cache injection is consistently lower than prompt-based injection, while the output tokens remain identical across both strategies. - -::note{icon="ri:bnb-fill"} -`Build (s)` refers to the one-time preprocessing cost of converting the memory to KV format, amortized across multiple queries. -:: - -| Model | Ctx | CtxTok | Qry | QryTok | Build (s) | KV TTFT (s) | Dir TTFT (s) | Speedup (%) | -| ----------- | ------ | ------ | ------ | ------ | --------- | ----------- | ------------ | ----------- | -| Qwen3-8B | long | 6064 | long | 952.7 | 0.92 | 0.50 | 2.37 | 79.1 | -| | | | medium | 302.7 | 0.93 | 0.19 | 2.16 | 91.1 | -| | | | short | 167 | 0.93 | 0.12 | 2.04 | 94.2 | -| | medium | 2773 | long | 952.7 | 0.41 | 0.43 | 1.22 | 64.6 | -| | | | medium | 302.7 | 0.41 | 0.16 | 1.08 | 85.1 | -| | | | short | 167 | 0.43 | 0.10 | 0.95 | 89.7 | -| | short | 583 | long | 952.7 | 0.12 | 0.39 | 0.51 | 23.0 | -| | | | medium | 302.7 | 0.12 | 0.14 | 0.32 | 55.6 | -| | | | short | 167 | 0.12 | 0.08 | 0.29 | 71.3 | -| Qwen3-32B | long | 6064 | long | 952.7 | 0.71 | 0.31 | 1.09 | 71.4 | -| | | | medium | 302.7 | 0.71 | 0.15 | 0.98 | 84.3 | -| | | | short | 167 | 0.71 | 0.11 | 0.96 | 88.8 | -| | medium | 2773 | long | 952.7 | 0.31 | 0.24 | 0.56 | 56.9 | -| | | | medium | 302.7 | 0.31 | 0.12 | 0.47 | 75.1 | -| | | | short | 167 | 0.31 | 0.08 | 0.44 | 81.2 | -| | short | 583 | long | 952.7 | 0.09 | 0.20 | 0.24 | 18.6 | -| | | | medium | 302.7 | 0.09 | 0.09 | 0.15 | 39.6 | -| | | | short | 167 | 0.09 | 0.07 | 0.14 | 53.5 | -| Qwen2.5-72B | long | 6064 | long | 952.7 | 1.26 | 0.48 | 2.04 | 76.4 | -| | | | medium | 302.7 | 1.26 | 0.23 | 1.82 | 87.2 | -| | | | short | 167 | 1.27 | 0.15 | 1.79 | 91.4 | -| | medium | 2773 | long | 952.7 | 0.58 | 0.39 | 1.05 | 62.7 | -| | | | medium | 302.7 | 0.58 | 0.18 | 0.89 | 79.2 | -| | | | short | 167 | 0.71 | 0.23 | 0.82 | 71.6 | -| | short | 583 | long | 952.7 | 0.16 | 0.33 | 0.43 | 23.8 | -| | | | medium | 302.7 | 0.16 | 0.15 | 0.27 | 43.2 | -| | | | short | 167 | 0.16 | 0.10 | 0.25 | 60.5 | - - -## KV-cache Memory Structure - -KV-based memory reuse via `KVCacheMemory` offers substantial latency reduction across model sizes and query types, while maintaining identical output. By shifting reusable memory from plaintext prompts into precomputed KV caches, MemOS eliminates redundant context encoding and achieves faster response times—especially beneficial in real-time, memory-augmented LLM applications. - -Each cache is stored as a `KVCacheItem`: - -| Field | Type | Description | -| ------------- | -------------- | ------------------------------------------- | -| `kv_cache_id` | `str` | Unique ID for the cache (UUID) | -| `kv_cache` | `DynamicCache` | The actual key-value cache (transformers) | -| `metadata` | `dict` | Metadata (source, extraction time, etc.) | - - -## API Summary (`KVCacheMemory`) - -### Initialization -```python -KVCacheMemory(config: KVCacheMemoryConfig) -``` - -### Core Methods -| Method | Description | -| ------------------------ | -------------------------------------------------------- | -| `extract(text)` | Extracts a KV cache from input text using the LLM | -| `add(memories)` | Adds one or more `KVCacheItem` to memory | -| `get(memory_id)` | Fetch a single cache by ID | -| `get_by_ids(ids)` | Fetch multiple caches by IDs | -| `get_all()` | Returns all stored caches | -| `get_cache(cache_ids)` | Merge and return a combined cache from multiple IDs | -| `delete(ids)` | Delete caches by IDs | -| `delete_all()` | Delete all caches | -| `dump(dir)` | Serialize all caches to a pickle file in directory | -| `load(dir)` | Load caches from a pickle file in directory | -| `from_textual_memory(mem)` | Convert a `TextualMemoryItem` to a `KVCacheItem` | - - -When calling `dump(dir)`, the system writes to: - -``` -/ -``` - -This file contains a pickled dictionary of all KV caches, which can be reloaded using `load(dir)`. - - -## How to Use - -```python -from memos.configs.memory import KVCacheMemoryConfig -from memos.memories.activation.kv import KVCacheMemory - -config = KVCacheMemoryConfig( - extractor_llm={ - "backend": "huggingface", - "config": {"model_name_or_path": "Qwen/Qwen3-1.7B"} - } -) -mem = KVCacheMemory(config) - -# Extract and add a cache -cache_item = mem.extract("The capital of France is Paris.") -mem.add([cache_item]) - -# Retrieve and merge caches -merged_cache = mem.get_cache([cache_item.kv_cache_id]) - -# Save/load -mem.dump("tmp/act_mem") -mem.load("tmp/act_mem") -``` - - -## Developer Notes - -* Uses HuggingFace `DynamicCache` for efficient key-value storage -* Pickle-based serialization for fast load/save -* All methods are covered by integration tests in `/tests` diff --git a/docs/modules/memories/neo4j_graph_db.md b/docs/modules/memories/neo4j_graph_db.md deleted file mode 100644 index 0b1c629b4..000000000 --- a/docs/modules/memories/neo4j_graph_db.md +++ /dev/null @@ -1,97 +0,0 @@ -# Graph Memory Backend - -This module provides graph-based memory storage and querying for memory-augmented systems such as RAG, cognitive agents, or personal memory assistants. - -It defines a clean abstraction (`BaseGraphDB`) and includes a production-ready implementation using **Neo4j**. - -## Why Graph for Memory? - -Unlike flat vector stores, a graph database allows: - -- Structuring memory into **chains, hierarchies, and causal links** -- Performing **multi-hop reasoning** and **subgraph traversal** -- Supporting memory **deduplication, conflict detection, and scheduling** -- Dynamically evolving a memory graph over time - -This forms the backbone of long-term, explainable, and compositional memory reasoning. - -## Features - -- Unified interface across different graph databases -- Built-in support for Neo4j -- Support for vector-enhanced retrieval (`search_by_embedding`) -- Modular, pluggable, and testable -## Directory Structure - -``` - -src/memos/graph_dbs/ -├── base.py # Abstract interface: BaseGraphDB -├── factory.py # Factory to instantiate GraphDB from config -├── neo4j.py # Neo4jGraphDB: production implementation - -```` - -## How to Use - -```python -from memos.graph_dbs.factory import GraphStoreFactory -from memos.configs.graph_db import GraphDBConfigFactory - -# Step 1: Build factory config -config = GraphDBConfigFactory( - backend="neo4j", - config={ - "uri": "bolt://localhost:7687", - "user": "your_neo4j_user_name", - "password": "your_password", - "db_name": "memory_user1", - "auto_create": True, - "embedding_dimension": 768 - } -) - -# Step 2: Instantiate the graph store -graph = GraphStoreFactory.from_config(config) - -# Step 3: Add memory -graph.add_node( - id="node-001", - content="Today I learned about retrieval-augmented generation.", - metadata={"type": "WorkingMemory", "tags": ["RAG", "AI"], "timestamp": "2025-06-05"} -) -```` - -## Pluggable Design - -### Interface: `BaseGraphDB` - -All implementations must implement: - -* `add_node`, `update_node`, `delete_node` -* `add_edge`, `delete_edge`, `edge_exists` -* `get_node`, `get_path`, `get_subgraph`, `get_context_chain` -* `search_by_embedding`, `get_by_metadata` -* `deduplicate_nodes`, `detect_conflicts`, `merge_nodes` -* `clear`, `export_graph`, `import_graph` - -See src/memos/graph_dbs/base.py for full method docs. - -### Current Backend: - -| Backend | Status | File | -| ------- | ------ | ---------- | -| Neo4j | Stable | `neo4j.py` | - -## Extending - -You can add support for any other graph engine (e.g., **TigerGraph**, **DGraph**, **Weaviate hybrid**) by: - -1. Subclassing `BaseGraphDB` -2. Creating a config dataclass (e.g., `DgraphConfig`) -3. Registering it in: - - * `GraphDBConfigFactory.backend_to_class` - * `GraphStoreFactory.backend_to_class` - -See `src/memos/graph_dbs/neo4j.py` as a reference implementation. diff --git a/docs/modules/memories/parametric_memory.md b/docs/modules/memories/parametric_memory.md deleted file mode 100644 index 0b3df3bba..000000000 --- a/docs/modules/memories/parametric_memory.md +++ /dev/null @@ -1,47 +0,0 @@ -# Parametric Memory *(Coming Soon)* - -::note -**Coming Soon** -This feature is still under active development. Stay tuned for updates! -:: - -`Parametric Memory` is the core **long-term knowledge and capability store** inside MemOS. -Unlike plaintext or activation memories, parametric memory is embedded directly within a model’s weights — encoding deep representations of language structure, world knowledge, and general reasoning abilities. - -In the MemOS architecture, parametric memory does not just refer to static pre-trained weights. It also includes modular weight components such as **LoRA adapters** and plug-in expert modules. These allow you to incrementally expand or specialize your LLM’s capabilities without retraining the entire model. - -For example, you could distill structured or stable knowledge into parametric form, save it as a **capability block**, and dynamically load or unload it during inference. This makes it easy to create “expert sub-models” for tasks like legal reasoning, financial analysis, or domain-specific summarization — all managed by MemOS. - - -## Design Goals - -::list -- **Controllability** — Generate, load, swap, or compose parametric modules - on demand. -- **Plasticity** — Evolve alongside plaintext and activation memories; support knowledge distillation and rollback. -- **Traceability** *(Coming Soon)* — Versioning and governance for parametric blocks. -:: - -## Current Status - -`Parametric Memory` is currently under design and prototyping. -APIs for generating, compressing, and hot-swapping parametric modules will be released in future versions — supporting multi-task, multi-role, and multi-agent architectures. - -Stay tuned! - - -## Related Modules - -While parametric memory is under development, try out these today: -- **[GeneralTextMemory](/docs/modules/memories/general_textual_memory)**: Flexible vector-based semantic storage. -- **[TreeTextMemory](/docs/modules/memories/tree_textual_memory)**: Structured, hierarchical knowledge graphs. -- **[Activation Memory](/docs/modules/memories/kv_cache_memory)**: Efficient runtime state caching. - -## Developer Note - -Parametric Memory will complete MemOS’s vision of a unified **Memory³** architecture: -- **Parametric**: Embedded knowledge -- **Activation**: Ephemeral runtime states -- **Plaintext**: Structured, traceable external memories - -Bringing all three together enables adaptable, evolvable, and explainable intelligent systems. diff --git a/docs/modules/memories/tree_textual_memory.md b/docs/modules/memories/tree_textual_memory.md deleted file mode 100644 index 542603d73..000000000 --- a/docs/modules/memories/tree_textual_memory.md +++ /dev/null @@ -1,281 +0,0 @@ -# TreeTextMemory: Structured Hierarchical Textual Memory - - -Let’s build your first **graph-based, tree-structured memory** in MemOS! - -**TreeTextMemory** helps you organize, link, and retrieve memories with rich context and explainability. - -[Neo4j](/docs/modules/memories/neo4j_graph_db) is the current backend, with support for additional graph stores planned in the future. - - -## What You’ll Learn - -By the end of this guide, you will: -- Extract structured memories from raw text or conversations. -- Store them as **nodes** in a graph database. -- Link memories into **hierarchies** and semantic graphs. -- Search them using **vector similarity + graph traversal**. - -## How It Works - -### Memory Structure - -Every node in your `TreeTextMemory` is a `TextualMemoryItem`: -- `id`: Unique memory ID (auto-generated if omitted). -- `memory`: the main text. -- `metadata`: includes hierarchy info, embeddings, tags, entities, source, and status. - -### Metadata Fields (`TreeNodeTextualMemoryMetadata`) - -| Field | Type | Description | -| --------------- |-------------------------------------------------------| ------------------------------------------ | -| `memory_type` | `"WorkingMemory"`, `"LongTermMemory"`, `"UserMemory"` | Lifecycle category | -| `status` | `"activated"`, `"archived"`, `"deleted"` | Node status | -| `visibility` | `"private"`, `"public"`, `"session"` | Access scope | -| `sources` | `list[str]` | List of sources (e.g. files, URLs) | -| `source` | `"conversation"`, `"retrieved"`, `"web"`, `"file"` | Original source type | -| `confidence` | `float (0-100)` | Certainty score | -| `entities` | `list[str]` | Mentioned entities or concepts | -| `tags` | `list[str]` | Thematic tags | -| `embedding` | `list[float]` | Vector embedding for similarity search | -| `created_at` | `str` | Creation timestamp (ISO 8601) | -| `updated_at` | `str` | Last update timestamp (ISO 8601) | -| `usage` | `list[str]` | Usage history | -| `background` | `str` | Additional context | - - -::note -**Best Practice**
- Use meaningful tags and background — they help organize your graph for -multi-hop reasoning. -:: - -### Core Steps - -When you run this example, your workflow will: - -1. **Extract:** Use an LLM to pull structured memories from raw text. - - -2. **Embed:** Generate vector embeddings for similarity search. - - -3. **Store & Link:** Add nodes to your graph database (Neo4j) with relationships. - - -4. **Search:** Query by vector similarity, then expand results by graph hops. - - -::note -**Hint**
Graph links help retrieve context that pure vector search might miss! -:: - -## API Summary (`TreeTextMemory`) - -### Initialization - -```python -TreeTextMemory(config: TreeTextMemoryConfig) -``` - -### Core Methods - -| Method | Description | -| --------------------------- | ----------------------------------------------------- | -| `add(memories)` | Add one or more memories (items or dicts) | -| `replace_working_memory()` | Replace all WorkingMemory nodes | -| `get_working_memory()` | Get all WorkingMemory nodes | -| `search(query, top_k)` | Retrieve top-k memories using vector + graph search | -| `get(memory_id)` | Fetch single memory by ID | -| `get_by_ids(ids)` | Fetch multiple memories by IDs | -| `get_all()` | Export the full memory graph as dictionary | -| `update(memory_id, new)` | Update a memory by ID | -| `delete(ids)` | Delete memories by IDs | -| `delete_all()` | Delete all memories and relationships | -| `dump(dir)` | Serialize the graph to JSON in directory | -| `load(dir)` | Load graph from saved JSON file | -| `drop(keep_last_n)` | Backup graph & drop database, keeping N backups | - -## File Storage - -When calling `dump(dir)`, the system writes to: - -``` -/ -``` - -This file contains a JSON structure with `nodes` and `edges`. It can be reloaded using `load(dir)`. - ---- - -## Your First TreeTextMemory — Step by Step - -::steps{} - -### Create TreeTextMemory Config -Define: -- your embedder (to create vectors), -- your graph DB backend (Neo4j), -- and your extractor LLM (optional). - -```python -from memos.configs.memory import TreeTextMemoryConfig - -config = TreeTextMemoryConfig.from_json_file("examples/data/config/tree_config.json") -``` - - -### Initialize TreeTextMemory - -```python -from memos.memories.textual.tree import TreeTextMemory - -tree_memory = TreeTextMemory(config) -``` - -### Extract Structured Memories - -Use your extractor to parse conversations, files, or docs into `TextualMemoryItem`s. - -```python -from memos.mem_reader.simple_struct import SimpleStructMemReader - -reader = SimpleStructMemReader.from_json_file("examples/data/config/simple_struct_reader_config.json") - -scene_data = [[ - {"role": "user", "content": "Tell me about your childhood."}, - {"role": "assistant", "content": "I loved playing in the garden with my dog."} -]] - -memories = reader.get_memory(scene_data, type="chat", info={"user_id": "1234"}) -for m_list in memories: - tree_memory.add(m_list) -``` - -### Search Memories - -Try a vector + graph search: -```python -results = tree_memory.search("Talk about the garden", top_k=5) -for i, node in enumerate(results): - print(f"{i}: {node.memory}") -``` - -### Replace Working Memory - -Replace your current `WorkingMemory` nodes with new ones: -```python -tree_memory.replace_working_memory( - [{ - "memory": "User is discussing gardening tips.", - "metadata": {"memory_type": "WorkingMemory"} - }] -) -``` - -### Backup & Restore -Dump your entire tree structure to disk and reload anytime: -```python -tree_memory.dump("tmp/tree_memories") -tree_memory.load("tmp/tree_memories") -``` - -:: - - -### Whole Code - -This combines all the steps above into one end-to-end example — copy & run! - -```python -from memos.configs.embedder import EmbedderConfigFactory -from memos.configs.memory import TreeTextMemoryConfig -from memos.configs.mem_reader import SimpleStructMemReaderConfig -from memos.embedders.factory import EmbedderFactory -from memos.mem_reader.simple_struct import SimpleStructMemReader -from memos.memories.textual.tree import TreeTextMemory - -# Setup Embedder -embedder_config = EmbedderConfigFactory.model_validate({ - "backend": "ollama", - "config": {"model_name_or_path": "nomic-embed-text:latest"} -}) -embedder = EmbedderFactory.from_config(embedder_config) - -# Create TreeTextMemory -tree_config = TreeTextMemoryConfig.from_json_file("examples/data/config/tree_config.json") -my_tree_textual_memory = TreeTextMemory(tree_config) -my_tree_textual_memory.delete_all() - -# Setup Reader -reader_config = SimpleStructMemReaderConfig.from_json_file( - "examples/data/config/simple_struct_reader_config.json" -) -reader = SimpleStructMemReader(reader_config) - -# Extract from conversation -scene_data = [[ - { - "role": "user", - "content": "Tell me about your childhood." - }, - { - "role": "assistant", - "content": "I loved playing in the garden with my dog." - }, -]] -memory = reader.get_memory(scene_data, type="chat", info={"user_id": "1234", "session_id": "2222"}) -for m_list in memory: - my_tree_textual_memory.add(m_list) - -# Search -results = my_tree_textual_memory.search( - "Talk about the user's childhood story?", - top_k=10 -) -for i, r in enumerate(results): - print(f"{i}'th result: {r.memory}") - -# [Optional] Add from documents -doc_paths = ["./text1.txt", "./text2.txt"] -doc_memory = reader.get_memory( - doc_paths, "doc", info={ - "user_id": "your_user_id", - "session_id": "your_session_id", - } -) -for m_list in doc_memory: - my_tree_textual_memory.add(m_list) - -# [Optional] Dump & Drop -my_tree_textual_memory.dump("tmp/my_tree_textual_memory") -my_tree_textual_memory.drop() -``` - -## What Makes TreeTextMemory Different? - -- **Structured Hierarchy:** Organize memories like a mind map — nodes can -have parents, children, and cross-links. -- **Graph-Style Linking:** Beyond pure hierarchy — build multi-hop reasoning - chains. -- **Semantic Search + Graph Expansion:** Combine the best of vectors and - graphs. -- **Explainability:** Trace how memories connect, merge, or evolve over time. - -::note -**Try This**
Add memory nodes from documents or web content. Link them -manually or auto-merge similar nodes! -:: - -## What’s Next? - -- **Know more about [Neo4j](/docs/modules/memories/neo4j_graph_db):** TreeTextMemory is powered by a graph database backend. - Understanding how Neo4j handles nodes, edges, and traversal will help you design more efficient memory hierarchies, multi-hop reasoning, and context linking strategies. -- **Add [Activation Memory](/docs/modules/memories/kv_cache_memory):** - Experiment with - runtime KV-cache for session - state. -- **Explore Graph Reasoning:** Build workflows for multi-hop retrieval and answer synthesis. -- **Go Deep:** Check the [API Reference](/docs/api/info) for advanced usage, or run more examples in `examples/`. - -Now your agent remembers not just facts — but the connections between them! diff --git a/docs/modules/mos/overview.md b/docs/modules/mos/overview.md deleted file mode 100644 index 978dd377a..000000000 --- a/docs/modules/mos/overview.md +++ /dev/null @@ -1,426 +0,0 @@ -# MOS API for MemOS - -The **MOS** is a core component of the MemOS Python package for API, designed to empower large language models (LLMs) with advanced, persistent memory capabilities. MOS acts as an orchestration api layer, managing multiple memory modules (MemCubes) and providing a unified interface for memory-augmented applications. - -## API Summary (`MOS`) - -### Initialization -```python -from memos import MOS -mos = MOS(config: MOSConfig) -``` - -### Core Methods - -| Method | Description | -|--------|-------------| -| `register_mem_cube(mem_cube_name_or_path, mem_cube_id=None, user_id=None)` | Register a new memory cube from a directory or remote repo for a user. | -| `unregister_mem_cube(mem_cube_id, user_id=None)` | Unregister (remove) a memory cube by its ID. | -| `add(messages=None, memory_content=None, doc_path=None, mem_cube_id=None, user_id=None)` | Add new memory (from messages, string, or document) to a cube. | -| `search(query, user_id=None, install_cube_ids=None)` | Search memories across cubes for a query, optionally filtered by cube IDs. | -| `chat(query, user_id=None)` | Chat with the LLM, enhanced by memory retrieval for specified user. | -| `get(mem_cube_id, memory_id, user_id=None)` | Get a specific memory by cube and memory ID for a user. | -| `get_all(mem_cube_id=None, user_id=None)` | Get all memories from a cube (or all cubes for user). | -| `update(mem_cube_id, memory_id, text_memory_item, user_id=None)` | Update a memory in a cube by ID for a user. | -| `delete(mem_cube_id, memory_id, user_id=None)` | Delete a memory from a cube by ID for a user. | -| `delete_all(mem_cube_id=None, user_id=None)` | Delete all memories from a cube for a user. | -| `clear_messages(user_id=None)` | Clear the chat history for the specified user session. | - -### User Management Methods - -| Method | Description | -|--------|-------------| -| `create_user(user_id, role=UserRole.USER, user_name=None)` | Create a new user with specified role and optional name. | -| `list_users()` | List all active users with their information. | -| `create_cube_for_user(cube_name, owner_id, cube_path=None, cube_id=None)` | Create a new cube for a specific user as owner. | -| `get_user_info()` | Get current user information including accessible cubes. | -| `share_cube_with_user(cube_id, target_user_id)` | Share a cube with another user. | - -## Class Overview - -`MOS` manages multiple `MemCube` objects, each representing a user's or session's memory. It provides a unified API for memory operations (add, search, update, delete) and integrates with LLMs to enhance chat with contextual memory retrieval. MOS supports multi-user, multi-session scenarios and is extensible to new memory types and backends. - -## Example Usage - -```python -import uuid - -from memos.configs.mem_os import MOSConfig -from memos.mem_os.main import MOS - - -# init MOS -mos_config = MOSConfig.from_json_file("examples/data/config/simple_memos_config.json") -memory = MOS(mos_config) - -# create user -user_id = str(uuid.uuid4()) -memory.create_user(user_id=user_id) - -# register cube for user -memory.register_mem_cube("examples/data/mem_cube_2", user_id=user_id) - -# add memory for user -memory.add( - messages=[ - {"role": "user", "content": "I like playing football."}, - {"role": "assistant", "content": "I like playing football too."}, - ], - user_id=user_id, -) -# Later, when you want to retrieve memory for user -retrieved_memories = memory.search(query="What do you like?", user_id=user_id) -# output text_memories: I like playing football, act_memories, para_memories -print(f"text_memories: {retrieved_memories['text_mem']}") -``` - -## Core Operations Overview - -MOS exposes several main operations for interacting with memories: - -* **Adding Memories** - Store new information from conversations, documents, or direct content -* **Searching Memories** - Retrieve relevant memories based on semantic queries -* **Chat with Memory** - Enhanced conversations with contextual memory retrieval -* **Memory Management** - Update, delete, and organize existing memories -* **Dumping Memories** - Export memory cubes to persistent storage - -## 1. Adding Memories - -### Overview - -The add operation processes and stores new information through several steps - - -#### Adding from Conversation Messages - -```python -import uuid -from memos.configs.mem_os import MOSConfig -from memos.mem_os.main import MOS - -# Initialize MOS -mos_config = MOSConfig.from_json_file("config/simple_memos_config.json") -memory = MOS(mos_config) - -# Create user -user_id = str(uuid.uuid4()) -memory.create_user(user_id=user_id, user_name="Alice") - -# Register memory cube -memory.register_mem_cube("examples/data/mem_cube_2", user_id=user_id) - -# Add memory from conversation -memory.add( - messages=[ - {"role": "user", "content": "I like playing football and watching movies."}, - {"role": "assistant", "content": "That's great! Football is a wonderful sport and movies can be very entertaining."}, - {"role": "user", "content": "My favorite team is Barcelona."}, - {"role": "assistant", "content": "Barcelona is a fantastic team with a rich history!"} - ], - mem_cube_id="personal_memories", - user_id=user_id -) - -print("Memory added successfully from conversation") -``` - -#### Adding Direct Memory Content - -```python -# Add specific memory content directly -memory.add( - memory_content="User prefers vegetarian food and enjoys cooking Italian cuisine", - mem_cube_id="personal_memories", - user_id=user_id -) - -# Add multiple memory items -memory_items = [ - "User works as a software engineer", - "User lives in San Francisco", - "User enjoys hiking on weekends" -] - -for item in memory_items: - memory.add( - memory_content=item, - mem_cube_id="personal_memories", - user_id=user_id - ) -``` - -#### Adding from Documents - -```python - -# Add from multiple documents -doc_path="./examples/data" -memory.add( - doc_path=doc_path, - mem_cube_id="personal_memories", - user_id=user_id -) -``` - -## 2. Searching Memories - -### Overview - -The search operation retrieves memories through search api: - - -#### Basic Memory Search - -```python -# Search for relevant memories -results = memory.search( - query="What sports do I like?", - user_id=user_id -) - -# Access different types of memories -text_memories = results['text_mem'] -activation_memories = results['act_mem'] -parametric_memories = results['para_mem'] - -print(f"Found {len(text_memories)} text memories") -for memory in text_memories: - print(memory) -``` - -#### Search Across Specific Cubes - -```python -# Search only in specific cubes -results = memory.search( - query="What are my preferences?", - user_id=user_id, - install_cube_ids=["personal_memories", "shared_knowledge"] -) - -# Process results by cube -for cube_memories in results['text_mem']: - print(f"\nCube: {cube_memories['cube_id']}") - for memory in cube_memories['memories']: - print(f"- {memory}") -``` - -## 3. Chat with Memory Enhancement - -### Overview - -The chat operation provides memory-enhanced conversations by: - -1. **Memory Retrieval** - Searches for relevant memories based on the query -2. **Context Building** - Incorporates retrieved memories into the conversation context -3. **Response Generation** - LLM generates responses with memory context - - - -#### Basic Chat - -```python -# Simple chat with memory enhancement -response = memory.chat( - query="What do you remember about my interests?", - user_id=user_id -) -print(f"Assistant: {response}") -``` - -## 4. Memory Retrieval and Management - -### Getting Specific Memory - -#### Code Example - -```python -# Get a specific memory by ID -memory_item = memory.get( - mem_cube_id="personal_memories", - memory_id="memory_123", - user_id=user_id -) - -print(f"Memory ID: {memory_item.memory_id}") -print(f"Content: {memory_item.memory}") -print(f"Created: {memory_item.created_at}") -print(f"Metadata: {memory_item.metadata}") -``` - -### Getting All Memories - - - -#### Code Example - -```python -# Get all memories from a specific cube -all_memories = memory.get_all( - mem_cube_id="personal_memories", - user_id=user_id -) - -# Get all memories from all accessible cubes -all_memories = memory.get_all(user_id=user_id) - -# Access different memory types -for cube_memories in all_memories['text_mem']: - print(f"\nCube: {cube_memories['cube_id']}") - print(f"Total memories: {len(cube_memories['memories'])}") - - for memory in cube_memories['memories']: - print(f"- {memory.memory}") - print(f" ID: {memory.memory_id}") - print(f" Created: {memory.created_at}") -``` - -## 5. Memory Updates and Deletion - -### Updating Memories - - - -#### Code Example - -```python -from memos.memories.textual.item import TextualMemoryItem - -# Create updated memory item -updated_memory = TextualMemoryItem( - memory="User now prefers vegan food and enjoys cooking Mediterranean cuisine", - metadata={ - "updated_at": "2024-01-15", - "update_reason": "Dietary preference change" - } -) - -# Update existing memory -memory.update( - mem_cube_id="personal_memories", - memory_id="memory_123", - text_memory_item=updated_memory, - user_id=user_id -) - -print("Memory updated successfully") -``` - -### Deleting Memories - - -```python -# Delete a specific memory -memory.delete( - mem_cube_id="personal_memories", - memory_id="memory_123", - user_id=user_id -) - -# Delete all memories from a specific cube -memory.delete_all( - mem_cube_id="personal_memories", - user_id=user_id -) - -# Delete all memories for a user (use with caution!) -memory.delete_all(user_id=user_id) -``` - -## 6. Dumping Memories - -### Overview - -The dump operation exports memory cubes to persistent storage, allowing you to: - -* **Backup Memories** - Create persistent copies of memory cubes -* **Transfer Memories** - Move memory cubes between systems -* **Archive Memories** - Store memory cubes for long-term preservation -* **Share Memories** - Export memory cubes for sharing with other users - -#### Basic Memory Dump - -```python -# Dump a specific memory cube to a directory -memory.dump( - dump_dir="./backup/memories", - mem_cube_id="personal_memories", - user_id=user_id -) - -print("Memory cube dumped successfully") -``` - -#### Dump Default Cube - -```python -# Dump the default cube for the user (first accessible cube) -memory.dump( - dump_dir="./backup/default_memories", - user_id=user_id -) - -print("Default memory cube dumped successfully") -``` - -#### Dump All User Cubes - -```python -# Get user info to see all accessible cubes -user_info = memory.get_user_info() - -# Dump each accessible cube -for cube_info in user_info['accessible_cubes']: - if cube_info['is_loaded']: - memory.dump( - dump_dir=f"./backup/{cube_info['cube_name']}", - mem_cube_id=cube_info['cube_id'], - user_id=user_id - ) - print(f"Dumped cube: {cube_info['cube_name']}") -``` - -#### Dump with Custom Directory Structure - -```python -import os -from datetime import datetime - -# Create timestamped backup directory -timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") -backup_dir = f"./backups/{timestamp}" - -# Ensure directory exists -os.makedirs(backup_dir, exist_ok=True) - -# Dump memory cube with organized structure -memory.dump( - dump_dir=backup_dir, - mem_cube_id="personal_memories", - user_id=user_id -) - -print(f"Memory cube dumped to: {backup_dir}") -``` - -## 7. Session Management - -### Clearing Chat History - - -```python -# Clear chat history for a user session -memory.clear_messages(user_id=user_id) - -# Verify chat history is cleared -user_info = memory.get_user_info() -print(f"Chat history cleared for user: {user_info['user_name']}") -``` - -## When to Use MOS - -Use MOS when you need to: - -- Build LLM applications with persistent, user-specific memory. -- Support multi-user, multi-session memory management. -- Integrate memory-augmented retrieval and reasoning into chatbots or agents. diff --git a/docs/modules/mos/users.md b/docs/modules/mos/users.md deleted file mode 100644 index 15d3681ef..000000000 --- a/docs/modules/mos/users.md +++ /dev/null @@ -1,305 +0,0 @@ -# User Management in MemOS - -The **MOS** provides comprehensive user management capabilities to support multi-user, multi-session memory operations. This document details the user management methods available in the MOS. - -## User Roles - -MOS supports four user roles with different permission levels: - -| Role | Description | Permissions | -|------|-------------|-------------| -| `ROOT` | System administrator | Full access to all cubes and users, cannot be deleted | -| `ADMIN` | Administrative user | Can manage users and cubes, access to all cubes | -| `USER` | Standard user | Can create and manage own cubes, access shared cubes | -| `GUEST` | Limited user | Read-only access to shared cubes, cannot create cubes | - -## User Management Methods - -### 1. `create_user` - -Creates a new user in the MOS system. - -**Parameters:** -- `user_id` (str): Unique identifier for the user -- `role` (UserRole, optional): User role. Defaults to `UserRole.USER` -- `user_name` (str, optional): Display name for the user. If not provided, uses `user_id` - -**Returns:** -- `str`: The created user ID - -**Example:** -```python -import uuid -from memos.mem_user.user_manager import UserRole - -# Create a standard user -user_id = str(uuid.uuid4()) -memory.create_user(user_id=user_id, role=UserRole.USER, user_name="John Doe") - -# Create an admin user -admin_id = str(uuid.uuid4()) -memory.create_user(user_id=admin_id, role=UserRole.ADMIN, user_name="Admin User") - -# Create a guest user -guest_id = str(uuid.uuid4()) -memory.create_user(user_id=guest_id, role=UserRole.GUEST, user_name="Guest User") -``` - -**Notes:** -- If a user with the same `user_name` already exists, the method returns the existing user's ID -- The system automatically creates a root user during initialization -- User IDs must be unique across the system - -### 2. `list_users` - -Retrieves information about all active users in the system. - -**Parameters:** -- None - -**Returns:** -- `list`: List of dictionaries containing user information: - - `user_id` (str): Unique user identifier - - `user_name` (str): Display name of the user - - `role` (str): User role (root, admin, user, guest) - - `created_at` (str): ISO format timestamp of user creation - - `is_active` (bool): Whether the user account is active - -**Example:** -```python -# List all users -users = memory.list_users() -for user in users: - print(f"User: {user['user_name']} (ID: {user['user_id']})") - print(f"Role: {user['role']}") - print(f"Active: {user['is_active']}") - print(f"Created: {user['created_at']}") - print("---") -``` - -**Output Example:** -``` -User: root (ID: root) -Role: root -Active: True -Created: 2024-01-15T10:30:00 ---- -User: John Doe (ID: 550e8400-e29b-41d4-a716-446655440000) -Role: user -Active: True -Created: 2024-01-15T11:00:00 ---- -``` - -### 3. `create_cube_for_user` - -Creates a new memory cube for a specific user as the owner. - -**Parameters:** -- `cube_name` (str): Name of the cube -- `owner_id` (str): User ID of the cube owner -- `cube_path` (str, optional): Local file path or remote repository URL for the cube -- `cube_id` (str, optional): Custom cube identifier. If not provided, a UUID is generated - -**Returns:** -- `str`: The created cube ID - -**Example:** -```python -import uuid - -# Create a user first -user_id = str(uuid.uuid4()) -memory.create_user(user_id=user_id, user_name="Alice") - -# Create a cube for the user -cube_id = memory.create_cube_for_user( - cube_name="Alice's Personal Memory", - owner_id=user_id, - cube_path="/path/to/alice/memory", - cube_id="alice_personal_cube" -) - -print(f"Created cube: {cube_id}") -``` - -**Notes:** -- The owner automatically gets full access to the created cube -- The cube owner can share the cube with other users -- If `cube_path` is provided, it can be a local directory path or a remote repository URL -- Custom `cube_id` must be unique across the system - -### 4. `get_user_info` - -Retrieves detailed information about the current user and their accessible cubes. - -**Parameters:** -- None - -**Returns:** -- `dict`: Dictionary containing user information and accessible cubes: - - `user_id` (str): Current user's ID - - `user_name` (str): Current user's display name - - `role` (str): Current user's role - - `created_at` (str): ISO format timestamp of user creation - - `accessible_cubes` (list): List of dictionaries for each accessible cube: - - `cube_id` (str): Cube identifier - - `cube_name` (str): Cube display name - - `cube_path` (str): Cube file path or repository URL - - `owner_id` (str): ID of the cube owner - - `is_loaded` (bool): Whether the cube is currently loaded in memory - -**Example:** -```python -# Get current user information -user_info = memory.get_user_info() - -print(f"Current User: {user_info['user_name']} ({user_info['user_id']})") -print(f"Role: {user_info['role']}") -print(f"Created: {user_info['created_at']}") -print("\nAccessible Cubes:") -for cube in user_info['accessible_cubes']: - print(f"- {cube['cube_name']} (ID: {cube['cube_id']})") - print(f" Owner: {cube['owner_id']}") - print(f" Loaded: {cube['is_loaded']}") - print(f" Path: {cube['cube_path']}") -``` - -**Output Example:** -``` -Current User: Alice (550e8400-e29b-41d4-a716-446655440000) -Role: user -Created: 2024-01-15T11:00:00 - -Accessible Cubes: -- Alice's Personal Memory (ID: alice_personal_cube) - Owner: 550e8400-e29b-41d4-a716-446655440000 - Loaded: True - Path: /path/to/alice/memory -- Shared Project Memory (ID: project_cube) - Owner: bob_user_id - Loaded: False - Path: /path/to/project/memory -``` - -### 5. `share_cube_with_user` - -Shares a memory cube with another user, granting them access to the cube's contents. - -**Parameters:** -- `cube_id` (str): ID of the cube to share -- `target_user_id` (str): ID of the user to share the cube with - -**Returns:** -- `bool`: `True` if sharing was successful, `False` otherwise - -**Example:** -```python -# Share a cube with another user -success = memory.share_cube_with_user( - cube_id="alice_personal_cube", - target_user_id="bob_user_id" -) - -if success: - print("Cube shared successfully") -else: - print("Failed to share cube") -``` - -**Notes:** -- The current user must have access to the cube being shared -- The target user must exist and be active -- Sharing a cube grants the target user read and write access to the cube -- Cube owners can always share their cubes -- Users with access to a cube can share it with other users (if they have appropriate permissions) - -## Complete User Management Workflow - -Here's a complete example demonstrating user management operations: - -```python -import uuid -from memos.configs.mem_os import MOSConfig -from memos.mem_os.main import MOS -from memos.mem_user.user_manager import UserRole - -# Initialize MOS -mos_config = MOSConfig.from_json_file("examples/data/config/simple_memos_config.json") -memory = MOS(mos_config) - -# 1. Create users -alice_id = str(uuid.uuid4()) -bob_id = str(uuid.uuid4()) - -memory.create_user(user_id=alice_id, user_name="Alice", role=UserRole.USER) -memory.create_user(user_id=bob_id, user_name="Bob", role=UserRole.USER) - -# 2. List all users -print("All users:") -users = memory.list_users() -for user in users: - print(f"- {user['user_name']} ({user['role']})") - -# 3. Create cubes for users -alice_cube_id = memory.create_cube_for_user( - cube_name="Alice's Personal Memory", - owner_id=alice_id, - cube_path="/path/to/alice/memory" -) - -bob_cube_id = memory.create_cube_for_user( - cube_name="Bob's Work Memory", - owner_id=bob_id, - cube_path="/path/to/bob/work" -) - -# 4. Share cubes between users -memory.share_cube_with_user(alice_cube_id, bob_id) -memory.share_cube_with_user(bob_cube_id, alice_id) - -# 5. Get user information -alice_info = memory.get_user_info() -print(f"\nAlice's accessible cubes: {len(alice_info['accessible_cubes'])}") - -# 6. Add memory to cubes -memory.add( - messages=[ - {"role": "user", "content": "I like playing football."}, - {"role": "assistant", "content": "That's great! Football is a wonderful sport."} - ], - user_id=alice_id, - mem_cube_id=alice_cube_id -) - -# 7. Search memories -retrieved = memory.search( - query="What does Alice like?", - user_id=alice_id -) -print(f"Retrieved memories: {retrieved['text_mem']}") -``` - -## Error Handling - -The user management methods include comprehensive error handling: - -- **User Validation**: Methods validate that users exist and are active before operations -- **Cube Access Validation**: Ensures users have appropriate access to cubes before operations -- **Duplicate Prevention**: Handles duplicate user names and cube IDs gracefully -- **Permission Checks**: Validates user roles and permissions for sensitive operations - -## Database Persistence - -User management data is persisted in a SQLite database: -- **Location**: Defaults to `~/.memos/memos_users.db` -- **Tables**: `users`, `cubes`, `user_cube_association` -- **Relationships**: Many-to-many relationship between users and cubes -- **Soft Deletes**: Users and cubes are soft-deleted (marked as inactive) rather than permanently removed - -## Security Considerations - -- **Role-based Access Control**: Different user roles have different permissions -- **Cube Ownership**: Cube owners have full control over their cubes -- **Access Validation**: All operations validate user access before execution -- **Root User Protection**: Root user cannot be deleted and has full system access diff --git a/docs/modules/mos/users_configurations.md b/docs/modules/mos/users_configurations.md deleted file mode 100644 index 2b084f503..000000000 --- a/docs/modules/mos/users_configurations.md +++ /dev/null @@ -1,718 +0,0 @@ -# MemOS Configuration Guide - -This document provides a comprehensive overview of all configuration fields and initialization methods across the different components in the MemOS system. - -1. [Configuration Overview](#configuration-overview) -2. [MOS Configuration](#mos-configuration) -3. [LLM Configuration](#llm-configuration) -4. [MemReader Configuration](#memreader-configuration) -5. [MemCube Configuration](#memcube-configuration) -6. [Memory Configuration](#memory-configuration) -7. [Embedder Configuration](#embedder-configuration) -8. [Vector Database Configuration](#vector-database-configuration) -9. [Graph Database Configuration](#graph-database-configuration) -10. [Scheduler Configuration](#scheduler-configuration) -11. [Initialization Methods](#initialization-methods) -12. [Configuration Examples](#configuration-examples) - -## Configuration Overview - -MemOS uses a hierarchical configuration system with factory patterns for different backends. Each component has: -- A base configuration class -- Backend-specific configuration classes -- A factory class that creates the appropriate configuration based on the backend - -## MOS Configuration - -The main MOS configuration that orchestrates all components. - -### MOSConfig Fields - -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `user_id` | str | "root" | User ID for the MOS this Config User ID will as default | -| `session_id` | str | auto-generated UUID | Session ID for the MOS | -| `chat_model` | LLMConfigFactory | required | LLM configuration for chat | -| `mem_reader` | MemReaderConfigFactory | required | MemReader configuration | -| `mem_scheduler` | SchedulerFactory | not required | Scheduler configuration | -| `max_turns_window` | int | 15 | Maximum conversation turns to keep | -| `top_k` | int | 5 | Maximum memories to retrieve per query | -| `enable_textual_memory` | bool | True | Enable textual memory | -| `enable_activation_memory` | bool | False | Enable activation memory | -| `enable_parametric_memory` | bool | False | Enable parametric memory | -| `enable_mem_scheduler` | bool | False | Enable scheduler memory | - - -### Example MOS Configuration - -```json -{ - "user_id": "root", - "chat_model": { - "backend": "huggingface", - "config": { - "model_name_or_path": "Qwen/Qwen3-1.7B", - "temperature": 0.1, - "remove_think_prefix": true, - "max_tokens": 4096 - } - }, - "mem_reader": { - "backend": "simple_struct", - "config": { - "llm": { - "backend": "ollama", - "config": { - "model_name_or_path": "qwen3:0.6b", - "temperature": 0.8, - "max_tokens": 1024, - "top_p": 0.9, - "top_k": 50 - } - }, - "embedder": { - "backend": "ollama", - "config": { - "model_name_or_path": "nomic-embed-text:latest" - } - }, - "chunker": { - "backend": "sentence", - "config": { - "tokenizer_or_token_counter": "gpt2", - "chunk_size": 512, - "chunk_overlap": 128, - "min_sentences_per_chunk": 1 - } - } - } - }, - "max_turns_window": 20, - "top_k": 5, - "enable_textual_memory": true, - "enable_activation_memory": false, - "enable_parametric_memory": false -} -``` - -## LLM Configuration - -Configuration for different Large Language Model backends. - -### Base LLM Fields - -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `model_name_or_path` | str | required | Model name or path | -| `temperature` | float | 0.8 | Temperature for sampling | -| `max_tokens` | int | 1024 | Maximum tokens to generate | -| `top_p` | float | 0.9 | Top-p sampling parameter | -| `top_k` | int | 50 | Top-k sampling parameter | -| `remove_think_prefix` | bool | False | Remove think tags from output | - -### Backend-Specific Fields - -#### OpenAI LLM -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `api_key` | str | required | OpenAI API key | -| `api_base` | str | "https://api.openai.com/v1" | OpenAI API base URL | - -#### Ollama LLM -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `api_base` | str | "http://localhost:11434" | Ollama API base URL | - -#### HuggingFace LLM -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `do_sample` | bool | False | Use sampling vs greedy decoding | -| `add_generation_prompt` | bool | True | Apply generation template | - -### Example LLM Configurations - -```json -// OpenAI -{ - "backend": "openai", - "config": { - "model_name_or_path": "gpt-4o", - "temperature": 0.8, - "max_tokens": 1024, - "top_p": 0.9, - "top_k": 50, - "api_key": "sk-...", - "api_base": "https://api.openai.com/v1" - } -} - -// Ollama -{ - "backend": "ollama", - "config": { - "model_name_or_path": "qwen3:0.6b", - "temperature": 0.8, - "max_tokens": 1024, - "top_p": 0.9, - "top_k": 50, - "api_base": "http://localhost:11434" - } -} - -// HuggingFace -{ - "backend": "huggingface", - "config": { - "model_name_or_path": "Qwen/Qwen3-1.7B", - "temperature": 0.1, - "remove_think_prefix": true, - "max_tokens": 4096, - "do_sample": false, - "add_generation_prompt": true - } -} -``` - -## MemReader Configuration - -Configuration for memory reading components. - -### Base MemReader Fields - -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `created_at` | datetime | auto-generated | Creation timestamp | -| `llm` | LLMConfigFactory | required | LLM configuration | -| `embedder` | EmbedderConfigFactory | required | Embedder configuration | -| `chunker` | chunkerConfigFactory | required | chunker configuration | - -### Backend Types - -- `simple_struct`: Structured memory reader - -### Example MemReader Configuration - -```json -{ - "backend": "simple_struct", - "config": { - "llm": { - "backend": "ollama", - "config": { - "model_name_or_path": "qwen3:0.6b", - "temperature": 0.0, - "remove_think_prefix": true, - "max_tokens": 8192 - } - }, - "embedder": { - "backend": "ollama", - "config": { - "model_name_or_path": "nomic-embed-text:latest" - } - }, - "chunker": { - "backend": "sentence", - "config": { - "tokenizer_or_token_counter": "gpt2", - "chunk_size": 512, - "chunk_overlap": 128, - "min_sentences_per_chunk": 1 - } - } - } -} -``` - -## MemCube Configuration - -Configuration for memory cube components. - -### GeneralMemCubeConfig Fields - -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `user_id` | str | "default_user" | User ID for the MemCube | -| `cube_id` | str | auto-generated UUID | Cube ID for the MemCube | -| `text_mem` | MemoryConfigFactory | required | Textual memory configuration | -| `act_mem` | MemoryConfigFactory | required | Activation memory configuration | -| `para_mem` | MemoryConfigFactory | required | Parametric memory configuration | - -### Allowed Backends - -- **Text Memory**: `naive_text`, `general_text`, `tree_text`, `uninitialized` -- **Activation Memory**: `kv_cache`, `uninitialized` -- **Parametric Memory**: `lora`, `uninitialized` - -### Example MemCube Configuration - -```json -{ - "user_id": "root", - "cube_id": "root/mem_cube_kv_cache", - "text_mem": {}, - "act_mem": { - "backend": "kv_cache", - "config": { - "memory_filename": "activation_memory.pickle", - "extractor_llm": { - "backend": "huggingface", - "config": { - "model_name_or_path": "Qwen/Qwen3-1.7B", - "temperature": 0.8, - "max_tokens": 1024, - "top_p": 0.9, - "top_k": 50, - "add_generation_prompt": true, - "remove_think_prefix": false - } - } - } - }, - "para_mem": { - "backend": "lora", - "config": { - "memory_filename": "parametric_memory.adapter", - "extractor_llm": { - "backend": "huggingface", - "config": { - "model_name_or_path": "Qwen/Qwen3-1.7B", - "temperature": 0.8, - "max_tokens": 1024, - "top_p": 0.9, - "top_k": 50, - "add_generation_prompt": true, - "remove_think_prefix": false - } - } - } - } -} -``` - -## Memory Configuration - -Configuration for different types of memory systems. - -### Base Memory Fields - -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `cube_id` | str | None | Unique MemCube identifier is can be cube_name or path as default| - -### Textual Memory Configurations - -#### Base Text Memory -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `memory_filename` | str | "textual_memory.json" | Filename for storing memories | - -#### Naive Text Memory -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `extractor_llm` | LLMConfigFactory | required | LLM for memory extraction | - -#### General Text Memory -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `extractor_llm` | LLMConfigFactory | required | LLM for memory extraction | -| `vector_db` | VectorDBConfigFactory | required | Vector database configuration | -| `embedder` | EmbedderConfigFactory | required | Embedder configuration | - -#### Tree Text Memory -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `extractor_llm` | LLMConfigFactory | required | LLM for memory extraction | -| `dispatcher_llm` | LLMConfigFactory | required | LLM for memory dispatching | -| `embedder` | EmbedderConfigFactory | required | Embedder configuration | -| `graph_db` | GraphDBConfigFactory | required | Graph database configuration | - -### Activation Memory Configurations - -#### Base Activation Memory -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `memory_filename` | str | "activation_memory.pickle" | Filename for storing memories | - -#### KV Cache Memory -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `extractor_llm` | LLMConfigFactory | required | LLM for memory extraction (must be huggingface) | - -### Parametric Memory Configurations - -#### Base Parametric Memory -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `memory_filename` | str | "parametric_memory.adapter" | Filename for storing memories | - -#### LoRA Memory -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `extractor_llm` | LLMConfigFactory | required | LLM for memory extraction (must be huggingface) | - -### Example Memory Configurations - -```json -// Tree Text Memory -{ - "backend": "tree_text", - "config": { - "memory_filename": "tree_memory.json", - "extractor_llm": { - "backend": "ollama", - "config": { - "model_name_or_path": "qwen3:0.6b", - "temperature": 0.0, - "remove_think_prefix": true, - "max_tokens": 8192 - } - }, - "dispatcher_llm": { - "backend": "ollama", - "config": { - "model_name_or_path": "qwen3:0.6b", - "temperature": 0.0, - "remove_think_prefix": true, - "max_tokens": 8192 - } - }, - "embedder": { - "backend": "ollama", - "config": { - "model_name_or_path": "nomic-embed-text:latest" - } - }, - "graph_db": { - "backend": "neo4j", - "config": { - "uri": "bolt://localhost:7687", - "user": "neo4j", - "password": "12345678", - "db_name": "user08alice", - "auto_create": true, - "embedding_dimension": 768 - } - } - } -} -``` - -## Embedder Configuration - -Configuration for embedding models. - -### Base Embedder Fields - -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `model_name_or_path` | str | required | Model name or path | -| `embedding_dims` | int | None | Number of embedding dimensions | - -### Backend-Specific Fields - -#### Ollama Embedder -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `api_base` | str | "http://localhost:11434" | Ollama API base URL | - -#### Sentence Transformer Embedder -No additional fields beyond base configuration. - -### Example Embedder Configurations - -```json -// Ollama Embedder -{ - "backend": "ollama", - "config": { - "model_name_or_path": "nomic-embed-text:latest", - "api_base": "http://localhost:11434" - } -} - -// Sentence Transformer Embedder -{ - "backend": "sentence_transformer", - "config": { - "model_name_or_path": "all-MiniLM-L6-v2", - "embedding_dims": 384 - } -} -``` - -## Vector Database Configuration - -Configuration for vector databases. - -### Base Vector DB Fields - -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `collection_name` | str | required | Name of the collection | -| `vector_dimension` | int | None | Dimension of the vectors | -| `distance_metric` | str | None | Distance metric (cosine, euclidean, dot) | - -### Qdrant Vector DB Fields - -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `host` | str | None | Qdrant host | -| `port` | int | None | Qdrant port | -| `path` | str | None | Qdrant local path | - -### Example Vector DB Configuration - -```json -{ - "backend": "qdrant", - "config": { - "collection_name": "memories", - "vector_dimension": 768, - "distance_metric": "cosine", - "path": "/path/to/qdrant" - } -} -``` - -## Graph Database Configuration - -Configuration for graph databases. - -### Base Graph DB Fields - -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `uri` | str | required | Database URI | -| `user` | str | required | Database username | -| `password` | str | required | Database password | - -### Neo4j Graph DB Fields - -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `db_name` | str | required | Target database name | -| `auto_create` | bool | False | Create DB if it doesn't exist | -| `embedding_dimension` | int | 768 | Vector embedding dimension | - -### Example Graph DB Configuration - -```json -{ - "backend": "neo4j", - "config": { - "uri": "bolt://localhost:7687", - "user": "neo4j", - "password": "12345678", - "db_name": "user08alice", - "auto_create": true, - "embedding_dimension": 768 - } -} -``` - -## Scheduler Configuration - -Configuration for memory scheduling systems that manage memory retrieval and activation. - -### Base Scheduler Fields - -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `top_k` | int | 10 | Number of top candidates to consider in initial retrieval | -| `top_n` | int | 5 | Number of final results to return after processing | -| `enable_parallel_dispatch` | bool | True | Whether to enable parallel message processing using thread pool | -| `thread_pool_max_workers` | int | 5 | Maximum worker threads in pool (1-20) | -| `consume_interval_seconds` | int | 3 | Interval for consuming messages from queue in seconds (0-60) | - -### General Scheduler Fields - -| Field | Type | Default | Description | -|-------|------|---------|-------------| -| `act_mem_update_interval` | int | 300 | Interval in seconds for updating activation memory | -| `context_window_size` | int | 5 | Size of the context window for conversation history | -| `activation_mem_size` | int | 5 | Maximum size of the activation memory | -| `act_mem_dump_path` | str | auto-generated | File path for dumping activation memory | - -### Backend Types - -- `general_scheduler`: Advanced scheduler with activation memory management - -### Example Scheduler Configuration - -```json -{ - "backend": "general_scheduler", - "config": { - "top_k": 10, - "top_n": 5, - "act_mem_update_interval": 300, - "context_window_size": 5, - "activation_mem_size": 1000, - "thread_pool_max_workers": 10, - "consume_interval_seconds": 3, - "enable_parallel_dispatch": true - } -} -``` - -## Initialization Methods - -### From JSON File - -```python -from memos.configs.mem_os import MOSConfig - -# Load configuration from JSON file -mos_config = MOSConfig.from_json_file("path/to/config.json") -``` - -### From Dictionary - -```python -from memos.configs.mem_os import MOSConfig - -# Create configuration from dictionary -config_dict = { - "user_id": "root", - "chat_model": { - "backend": "huggingface", - "config": { - "model_name_or_path": "Qwen/Qwen3-1.7B", - "temperature": 0.1 - } - } - # ... other fields -} - -mos_config = MOSConfig(**config_dict) -``` - -### Factory Pattern Usage - -```python -from memos.configs.llm import LLMConfigFactory - -# Create LLM configuration using factory -llm_config = LLMConfigFactory( - backend="huggingface", - config={ - "model_name_or_path": "Qwen/Qwen3-1.7B", - "temperature": 0.1 - } -) -``` - -## Configuration Examples - -### Complete MOS Setup - -```python -from memos.configs.mem_os import MOSConfig -from memos.mem_os.main import MOS - -# Load configuration -mos_config = MOSConfig.from_json_file("examples/data/config/simple_memos_config.json") - -# Initialize MOS -mos = MOS(mos_config) - -# Create user and register cube -user_id = "user_123" -mos.create_user(user_id=user_id) -mos.register_mem_cube("path/to/mem_cube", user_id=user_id) - -# Use MOS -response = mos.chat("Hello, how are you?", user_id=user_id) -``` - -### Tree Memory Configuration - -```python -from memos.configs.memory import MemoryConfigFactory - -# Create tree memory configuration -tree_memory_config = MemoryConfigFactory( - backend="tree_text", - config={ - "memory_filename": "tree_memory.json", - "extractor_llm": { - "backend": "ollama", - "config": { - "model_name_or_path": "qwen3:0.6b", - "temperature": 0.0, - "max_tokens": 8192 - } - }, - "dispatcher_llm": { - "backend": "ollama", - "config": { - "model_name_or_path": "qwen3:0.6b", - "temperature": 0.0, - "max_tokens": 8192 - } - }, - "embedder": { - "backend": "ollama", - "config": { - "model_name_or_path": "nomic-embed-text:latest" - } - }, - "graph_db": { - "backend": "neo4j", - "config": { - "uri": "bolt://localhost:7687", - "user": "neo4j", - "password": "password", - "db_name": "memories", - "auto_create": True, - "embedding_dimension": 768 - } - } - } -) -``` - -### Multi-Backend LLM Configuration - -```python -from memos.configs.llm import LLMConfigFactory - -# OpenAI configuration -openai_config = LLMConfigFactory( - backend="openai", - config={ - "model_name_or_path": "gpt-4o", - "temperature": 0.8, - "max_tokens": 1024, - "api_key": "sk-...", - "api_base": "https://api.openai.com/v1" - } -) - -# Ollama configuration -ollama_config = LLMConfigFactory( - backend="ollama", - config={ - "model_name_or_path": "qwen3:0.6b", - "temperature": 0.8, - "max_tokens": 1024, - "api_base": "http://localhost:11434" - } -) - -# HuggingFace configuration -hf_config = LLMConfigFactory( - backend="huggingface", - config={ - "model_name_or_path": "Qwen/Qwen3-1.7B", - "temperature": 0.1, - "remove_think_prefix": True, - "max_tokens": 4096, - "do_sample": False, - "add_generation_prompt": True - } -) -``` - -This comprehensive configuration system allows for flexible and extensible setup of the MemOS system with different backends and components. diff --git a/docs/settings.yml b/docs/settings.yml deleted file mode 100644 index 4f99fbc73..000000000 --- a/docs/settings.yml +++ /dev/null @@ -1,45 +0,0 @@ -nav: - # You can include icons using the syntax `(ri:icon-name)`. - # The frontend will render these as actual icons. - # You can find available icons at https://icones.js.org/ - - - "(ri:home-line) Home": - - "(ri:eye-line) Overview": home/overview.md - - "(ri:information-line) What Is MemOS?": home/memos_intro.md - - "(ri:lightbulb-line) Core Concepts": home/core_concepts.md - - "(ri:building-2-line) Architecture": home/architecture.md - - - "(ri:rocket-line) Getting Started": - - "(ri:play-line) Quick Start": getting_started/quick_start.md - - "(ri:bookmark-line) Your First Memory": getting_started/your_first_memory.md - - "(ri:code-line) Examples": getting_started/examples.md - - - "(ri:cpu-line) MOS": - - "(ri:eye-line) Overview": modules/mos/overview.md - - "(ri:team-line) Users": modules/mos/users.md - - "(ri:settings-3-line) Users Configurations": modules/mos/users_configurations.md - - "(ri:checkbox-multiple-blank-line) MemCube": modules/mem_cube.md - - "(ri:book-open-line) MemReader": modules/mem_reader.md - - "(ri:calendar-line) MemScheduler": modules/mem_scheduler.md - - - "(ri:brain-line) Memories": - - "(ri:database-2-line) KV Cache Memory": modules/memories/kv_cache_memory.md - - "(ri:book-2-line) Plaintext Memory": - - "(ri:file-text-line) General Textual Memory": modules/memories/general_textual_memory.md - - "(ri:tree-line) Tree Textual Memory": modules/memories/tree_textual_memory.md - - "(ri:database-line) Neo4j Graph Database": modules/memories/neo4j_graph_db.md - - "(ri:cpu-line) Parametric Memory": modules/memories/parametric_memory.md - - - "(ri:star-line) Best Practice": - - "(ri:speed-line) Performance Tuning": best_practice/performance_tuning.md - - "(ri:building-3-line) Memory Structure Design": best_practice/memory_structure_design.md - - "(ri:wifi-line) Network Workarounds": best_practice/network_workarounds.md - - "(ri:error-warning-line) Common Errors & Solutions": best_practice/common_errors_solutions.md - - - "(ri:heart-line) Contribution": - - "(ri:eye-line) Overview": contribution/overview.md - - "(ri:tools-line) Setting Up": contribution/setting_up.md - - "(ri:git-branch-line) Development Workflow": contribution/development_workflow.md - - "(ri:git-commit-line) Commit Guidelines": contribution/commit_guidelines.md - - "(ri:article-line) Writing Docs": contribution/writing_docs.md - - "(ri:flask-line) Writing Tests": contribution/writing_tests.md diff --git a/tests/test_docs.py b/tests/test_docs.py deleted file mode 100644 index d16ce5e7b..000000000 --- a/tests/test_docs.py +++ /dev/null @@ -1,333 +0,0 @@ -""" -Tests for docs/settings.yml configuration file. - -This module tests the validity and completeness of the documentation -configuration in settings.yml. -""" - -import os -import re -import warnings - -from pathlib import Path -from typing import Literal - -import pytest -import requests -import yaml - - -@pytest.fixture -def settings_file_path() -> Path: - """Return the path to settings.yml file.""" - return Path(__file__).parent.parent / "docs" / "settings.yml" - - -@pytest.fixture -def docs_root_path() -> Path: - """Return the path to docs directory.""" - return Path(__file__).parent.parent / "docs" - - -@pytest.fixture -def settings_data(settings_file_path: Path) -> dict: - """Load and return the settings.yml data.""" - with open(settings_file_path, encoding="utf-8") as f: - return yaml.safe_load(f) - - -def test_yml_file_format_is_valid(settings_file_path: Path): - """Test that settings.yml is a valid YAML file.""" - try: - with open(settings_file_path, encoding="utf-8") as f: - yaml.safe_load(f) - except yaml.YAMLError as e: - pytest.fail(f"settings.yml is not a valid YAML file: {e}") - - -def test_settings_yml_has_required_structure(settings_data: dict): - """Test that settings.yml has the required structure.""" - assert "nav" in settings_data, "Missing 'nav' key" - assert isinstance(settings_data["nav"], list), "'nav' should be a list" - - -def test_all_nav_files_exist_in_docs_folder(settings_data: dict, docs_root_path: Path): - """Test that all files referenced in nav exist in the docs folder.""" - nav_items = settings_data.get("nav", []) - file_paths = _extract_file_paths_from_nav(nav_items) - - missing_files = [] - for file_path in file_paths: - full_path = docs_root_path / file_path - if not full_path.exists(): - missing_files.append(file_path) - - assert not missing_files, ( - f"Files referenced in nav but not found in docs folder: {missing_files}" - ) - - -def test_all_markdown_files_are_in_nav(settings_data: dict, docs_root_path: Path): - """Test that all markdown files in docs folder are referenced in nav.""" - # Get all markdown files in docs folder and subdirectories - markdown_files = set() - for md_file in docs_root_path.rglob("*.md"): - # Get relative path from docs root - relative_path = md_file.relative_to(docs_root_path) - # Convert to forward slashes for consistency - relative_path_str = str(relative_path).replace(os.sep, "/") - markdown_files.add(relative_path_str) - - # Get all files referenced in nav - nav_items = settings_data.get("nav", []) - nav_files = _extract_file_paths_from_nav(nav_items) - - # Find markdown files not in nav - missing_in_nav = markdown_files - nav_files - - assert not missing_in_nav, ( - f"Markdown files in docs folder but not referenced in settings.yml: {missing_in_nav}" - ) - - -def test_nav_files_are_markdown_files_and_properly_named(settings_data: dict): - """Test that all files in nav are markdown files and properly named.""" - - nav_items = settings_data.get("nav", []) - file_paths = _extract_file_paths_from_nav(nav_items) - - non_markdown_files = [] - improperly_named_files = [] - pattern = re.compile(r"^[a-z0-9_\/]+\.md$") - - for file_path in file_paths: - if not file_path.endswith(".md"): - non_markdown_files.append(file_path) - elif not pattern.match(file_path): - improperly_named_files.append(file_path) - - assert not non_markdown_files, f"Non-markdown files found in nav: {non_markdown_files}" - assert not improperly_named_files, ( - "Files in nav must be lowercase, use only a-z, 0-9, underscores, and slashes, and end with .md: " - f"{improperly_named_files}" - ) - - -def test_nav_structure_has_proper_nesting(settings_data: dict): - """Test that nav structure follows proper nesting conventions.""" - nav_items = settings_data.get("nav", []) - - def validate_nav_item(item, depth=0): - """Validate individual nav item structure.""" - if isinstance(item, dict): - assert len(item) == 1, f"Nav item should have exactly one key-value pair: {item}" - key, value = next(iter(item.items())) - assert isinstance(key, str), f"Nav item key should be a string: {key}" - - if isinstance(value, str): - # File reference - assert value.endswith(".md"), f"File reference should be a markdown file: {value}" - elif isinstance(value, list): - # Nested structure - assert depth < 3, f"Nav nesting too deep (max 2 levels): {item}" - for nested_item in value: - validate_nav_item(nested_item, depth + 1) - else: - pytest.fail(f"Invalid nav item value type: {type(value)} for {value}") - else: - pytest.fail(f"Nav item should be a dictionary: {item}") - - for item in nav_items: - validate_nav_item(item) - - -def test_no_duplicate_files_in_nav(settings_data: dict): - """Test that no file is referenced multiple times in nav.""" - nav_items = settings_data.get("nav", []) - file_paths = _extract_file_paths_from_nav(nav_items) - file_paths_list = list(file_paths) - - # Check for duplicates - unique_files = set(file_paths_list) - assert len(file_paths_list) == len(unique_files), "Duplicate file references found in nav" - - -def test_nav_keys_are_descriptive(settings_data: dict): - """Test that navigation keys are descriptive and properly formatted.""" - nav_items = settings_data.get("nav", []) - - def check_nav_keys(items): - """Recursively check navigation keys.""" - problematic_keys = [] - - for item in items: - if isinstance(item, dict): - for key, value in item.items(): - # Check key formatting - if not key.strip(): - problematic_keys.append(f"Empty key: '{key}'") - elif len(key) < 2: - problematic_keys.append(f"Too short key: '{key}'") - elif key != key.strip(): - problematic_keys.append(f"Key has leading/trailing whitespace: '{key}'") - - # Recursively check nested items - if isinstance(value, list): - nested_problems = check_nav_keys(value) - problematic_keys.extend(nested_problems) - - return problematic_keys - - problematic_keys = check_nav_keys(nav_items) - assert not problematic_keys, f"Problematic navigation keys found: {problematic_keys}" - - -def test_yaml_encoding_is_utf8(settings_file_path: Path): - """Test that settings.yml uses UTF-8 encoding.""" - try: - with open(settings_file_path, encoding="utf-8") as f: - f.read() - except UnicodeDecodeError: - pytest.fail("settings.yml is not encoded in UTF-8") - - -def test_yaml_indentation_is_consistent(settings_file_path: Path): - """Test that YAML indentation is consistent (2 spaces).""" - with open(settings_file_path, encoding="utf-8") as f: - lines = f.readlines() - - indentation_errors = [] - for i, line in enumerate(lines, 1): - if line.strip() and line.startswith(" "): - # Count leading spaces - leading_spaces = len(line) - len(line.lstrip(" ")) - if leading_spaces % 2 != 0: - indentation_errors.append( - f"Line {i}: inconsistent indentation ({leading_spaces} spaces)" - ) - - assert not indentation_errors, f"YAML indentation errors: {indentation_errors}" - - -def _all_md_file_paths() -> list[str]: - project_dir = Path(__file__).parent.parent - docs_dir = project_dir / "docs" - return sorted([str(p.relative_to(project_dir)) for p in docs_dir.rglob("*.md")]) - - -def _get_links(file_path: str, mode: Literal["remote", "local"]) -> list[str]: - """Extract remote or local links from a markdown file. - - Args: - file_path (str): Path to the markdown file. - mode (Literal['remote', 'local']): Mode to extract 'remote' or 'local' links. - - Returns: - set[str]: Set of extracted links. - """ - with open(file_path, encoding="utf-8", errors="ignore") as f: - content = f.read() - - matches = re.findall( - r"(?:\!)?\[.*?\]\((?!#)(.*?)\)|" # Markdown links/images (not anchors) - r'href=["\'](?!#)(.*?)["\']|' # HTML href attributes - r"<(https?://[^>]+)>", # Direct URLs in angle brackets - content, - ) - found_links = {url for match in matches for url in match if url} - - remote_links, local_links = [], [] - for link in found_links: - if link.startswith(("http://", "https://")): - remote_links.append(link) - elif not link.startswith("mailto:"): - local_links.append(link) - return remote_links if mode == "remote" else local_links - - -@pytest.mark.parametrize("file_path", _all_md_file_paths(), ids=_all_md_file_paths()) -def test_remote_links_accessibility(file_path: str): - """Test that all remote links in markdown file are accessible""" - remote_links = _get_links(file_path, mode="remote") - print(remote_links) - for link in remote_links: - with requests.Session() as session: - session.headers.update({"User-Agent": "Mozilla/5.0 (compatible; LinkChecker/1.0)"}) - try: - # Try HEAD first (faster) - response = session.head(link, timeout=2, allow_redirects=True) - - if response.status_code >= 400: - warnings.warn( - f"❌ Link {link} in {file_path} may be broken (HEAD request failed). " - "Consider checking the link manually.", - stacklevel=2, - ) - return - except requests.RequestException: - try: - # Fallback to GET with shorter timeout - response = session.get(link, timeout=2, allow_redirects=True, stream=True) - if response.status_code >= 400: - warnings.warn( - f"❌ Link {link} in {file_path} may be broken (GET request failed). " - "Consider checking the link manually.", - stacklevel=2, - ) - return - except requests.RequestException as e: - error_msg = str(e) - if "timeout" in error_msg.lower(): - warnings.warn( - f"❌ Link {link} in {file_path} timed out. " - "Consider checking the link manually.", - stacklevel=2, - ) - return - elif "connection" in error_msg.lower(): - warnings.warn( - f"❌ Link {link} in {file_path} failed to connect. " - "Consider checking the link manually.", - stacklevel=2, - ) - return - else: - warnings.warn( - f"❌ Link {link} in {file_path} failed to connect. " - "Consider checking the link manually.", - stacklevel=2, - ) - return - return - - -def _extract_file_paths_from_nav(nav_items: list, base_path: str = "") -> set[str]: - """ - Recursively extract all file paths from navigation structure. - - Args: - nav_items: List of navigation items - base_path: Base path for relative file paths - - Returns: - Set of file paths found in navigation - """ - file_paths = set() - - for item in nav_items: - if isinstance(item, dict): - for _, value in item.items(): - if isinstance(value, str): - # Direct file reference - file_path = os.path.join(base_path, value) if base_path else value - file_paths.add(file_path) - elif isinstance(value, list): - # Nested navigation structure - nested_paths = _extract_file_paths_from_nav(value, base_path) - file_paths.update(nested_paths) - elif isinstance(item, str): - # Direct string file reference (less common) - file_path = os.path.join(base_path, item) if base_path else item - file_paths.add(file_path) - - return file_paths