diff --git a/.github/CONTRIBUTING b/.github/CONTRIBUTING index 05c946ebf..bbb218a61 100644 --- a/.github/CONTRIBUTING +++ b/.github/CONTRIBUTING @@ -1,3 +1,3 @@ -Please read https://memos.openmem.net/docs/contribution/overview to learn how to contribute to this repository. 🌟 +Please read https://memos-docs.openmem.net/contribution/overview to learn how to contribute to this repository. 🌟 -请阅读 https://memos.openmem.net/docs/contribution/overview 了解如何为此项目贡献代码。🌟 +请阅读 https://memos-docs.openmem.net/contribution/overview 了解如何为此项目贡献代码。🌟 diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml index 5d72271eb..ed17b4109 100644 --- a/.github/ISSUE_TEMPLATE/feature-request.yml +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -2,40 +2,34 @@ name: "\U0001F680 Feature request" description: Submit a request for a new feature labels: ["enhancement", "pending"] body: - - type: markdown - attributes: - value: | - Please do not create issues that are not related to new features under this category. - 请勿在此分类下创建和新特性无关的 issues。 - - type: checkboxes - id: reminder + id: checklist attributes: - label: Reminder - description: | - Please ensure you have read the above rules carefully and searched the existing issues. - 请确保您已经认真阅读了上述规则并且搜索过现有的 issues。 - + label: Pre-submission checklist options: - - label: I have read the above rules and searched the existing issues. + - label: I have searched existing issues and this feature hasn't been requested before | 我已搜索现有问题,确认此功能尚未被请求 + required: true + - label: I have read the project documentation and confirmed this feature doesn't already exist | 我已阅读项目文档并确认此功能尚未存在 + required: true + - label: This feature request is specific to MemOS and not a general software issue | 该功能请求是针对 MemOS 的,而不是一般软件问题 required: true - type: textarea - id: description + id: problem validations: required: true attributes: - label: Description - description: | - A clear and concise description of the feature proposal. - 请详细描述您希望加入的新功能特性。 + label: Problem Statement + placeholder: | + Describe the problem you're trying to solve... + Example: "As a developer using MemOS, I find it difficult to..." - - type: textarea + - type: checkboxes id: contribution - validations: - required: false attributes: - label: Pull Request - description: | - Have you already created the relevant PR and submitted the code? - 您是否已经创建了相关 PR 并提交了代码? + label: Implementation Contribution + options: + - label: I'm willing to implement this feature myself | 我愿意自己实现此功能 + required: false + - label: I would like someone else to implement this | 我希望其他人来实现此功能 + required: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 4b7f715c9..f532a0c42 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,14 +1,28 @@ ## Description -> Please include a summary of the change and which issue is fixed. -> -> 请介绍你的修改,并说明它修复了哪个 issue. + + +Summary: (summary) + +Fix: #(issue) + +Reviewer: @(reviewer) ## Checklist: - [ ] I have performed a self-review of my own code | 我已自行检查了自己的代码 -- [ ] I have commented my code, particularly in hard-to-understand areas | 我已对代码进行了注释,特别是在难以理解的地方 +- [ ] I have commented my code in hard-to-understand areas | 我已在难以理解的地方对代码进行了注释 - [ ] I have added tests that prove my fix is effective or that my feature works | 我已添加测试以证明我的修复有效或功能正常 -- [ ] I have added necessary documentation (if appropriate) | 我已添加必要的文档(如果有必要) +- [ ] I have added necessary documentation (if applicable) | 我已添加必要的文档(如果适用) +- [ ] I have linked the issue to this PR (if applicable) | 我已将 issue 链接到此 PR(如果适用) +- [ ] I have mentioned the person who will review this PR | 我已提及将审查此 PR 的人 diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index 4bf9ef7ba..83ff35572 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -25,6 +25,10 @@ jobs: matrix: os: - "ubuntu-latest" + - "windows-latest" + - "macos-14" + - "macos-15" + # Ref: https://docs.github.com/en/actions/how-tos/writing-workflows/choosing-where-your-workflow-runs/choosing-the-runner-for-a-job python-version: - "3.10" - "3.11" @@ -51,4 +55,4 @@ jobs: poetry run ruff format --check - name: Test with pytest run: | - PYTHONPATH=src poetry run pytest tests -vv + poetry run pytest tests -vv diff --git a/.gitignore b/.gitignore index 23b79c7db..6a8e52eb4 100644 --- a/.gitignore +++ b/.gitignore @@ -10,8 +10,8 @@ evaluation/data/langmemeval evaluation/*tmp/ evaluation/results evaluation/.env -evaluation/scripts/*.sh evaluation/configs/* +**tree_textual_memory_locomo** .env # Byte-compiled / optimized / DLL files @@ -166,6 +166,7 @@ venv.bak/ *.xlsx *.json *.pkl +*.html # but do not ignore docs/openapi.json !docs/openapi.json 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 d5be3324d..00af88745 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,10 @@
+
-
-
MemOS 1.0: 星河 (Stellar)
MemOS 1.0: 星河 (Stellar)
@@ -19,7 +17,7 @@
-
+
@@ -31,7 +29,7 @@
-
+
@@ -42,17 +40,14 @@
---
-
-
-
-
+
**MemOS** is an operating system for Large Language Models (LLMs) that enhances them with long-term memory capabilities. It allows LLMs to store, retrieve, and manage information, enabling more context-aware, consistent, and personalized interactions.
-- **Website**: https://memos.openmem.net/
-- **Documentation**: https://memos.openmem.net/docs/home
-- **API Reference**: https://memos.openmem.net/docs/api/info
-- **Source Code**: https://github.com/MemTensor/MemOS
+- **Website**: https://memos.openmem.net/
+- **Documentation**: https://memos-docs.openmem.net/home/overview/
+- **API Reference**: https://memos-docs.openmem.net/docs/api/info/
+- **Source Code**: https://github.com/MemTensor/MemOS
## 📈 Performance Benchmark
@@ -66,19 +61,12 @@ MemOS demonstrates significant improvements over baseline memory solutions in mu
> 💡 **Temporal reasoning accuracy improved by 159% compared to the OpenAI baseline.**
-
-
### Details of End-to-End Evaluation on LOCOMO
> [!NOTE]
> Comparison of LLM Judge Scores across five major tasks in the LOCOMO benchmark. Each bar shows the mean evaluation score judged by LLMs for a given method-task pair, with standard deviation as error bars. MemOS-0630 consistently outperforms baseline methods (LangMem, Zep, OpenAI, Mem0) across all task types, especially in multi-hop and temporal reasoning scenarios.
-
-
-
-
-
-
+
## ✨ Key Features
@@ -151,7 +139,11 @@ For more detailed examples, please check out the [`examples`](./examples) direct
## 📦 Installation
> [!WARNING]
-> Currently, MemOS primarily supports Linux platforms. You may encounter issues on Windows and macOS temporarily.
+> MemOS is compatible with Linux, Windows, and macOS.
+>
+> However, if you're using macOS, please note that there may be dependency issues that are difficult to resolve.
+>
+> For example, compatibility with macOS 13 Ventura is currently challenging.
### Install via pip
@@ -192,26 +184,50 @@ Join our community to ask questions, share your projects, and connect with other
- **Discord**: Join our Discord Server.
- **WeChat**: Scan the QR code to join our WeChat group.
-
+
## 📜 Citation
-If you use MemOS in your research, please cite our paper:
+> [!NOTE]
+> We publicly released the Short Version on **May 28, 2025**, making it the earliest work to propose the concept of a Memory Operating System for LLMs.
+
+If you use MemOS in your research, we would appreciate citations to our papers.
```bibtex
-@misc{li2025memos,
- title={MemOS: A Memory OS for AI System},
- author={Zhiyu Li and Shichao Song and Chenyang Xi and Hanyu Wang and Chen Tang and Simin Niu and Ding Chen and Jiawei Yang and Chunyu Li and Qingchen Yu and Jihao Zhao and Yezhaohui Wang and Peng Liu and Zehao Lin and Pengyuan Wang and Jiahao Huo and Tianyi Chen and Kai Chen and Kehang Li and Zhen Tao and Junpeng Ren and Huayi Lai and Hao Wu and Bo Tang and Zhenren Wang and Zhaoxin Fan and Ningyu Zhang and Linfeng Zhang and Junchi Yan and Mingchuan Yang and Tong Xu and Wei Xu and Huajun Chen and Haofeng Wang and Hongkang Yang and Wentao Zhang and Zhi-Qin John Xu and Siheng Chen and Feiyu Xiong},
- year={2025},
- eprint={2507.03724},
- archivePrefix={arXiv},
- primaryClass={cs.CL}
+
+@article{li2025memos_long,
+ title={MemOS: A Memory OS for AI System},
+ author={Li, Zhiyu and Song, Shichao and Xi, Chenyang and Wang, Hanyu and Tang, Chen and Niu, Simin and Chen, Ding and Yang, Jiawei and Li, Chunyu and Yu, Qingchen and Zhao, Jihao and Wang, Yezhaohui and Liu, Peng and Lin, Zehao and Wang, Pengyuan and Huo, Jiahao and Chen, Tianyi and Chen, Kai and Li, Kehang and Tao, Zhen and Ren, Junpeng and Lai, Huayi and Wu, Hao and Tang, Bo and Wang, Zhenren and Fan, Zhaoxin and Zhang, Ningyu and Zhang, Linfeng and Yan, Junchi and Yang, Mingchuan and Xu, Tong and Xu, Wei and Chen, Huajun and Wang, Haofeng and Yang, Hongkang and Zhang, Wentao and Xu, Zhi-Qin John and Chen, Siheng and Xiong, Feiyu},
+ journal={arXiv preprint arXiv:2507.03724},
+ year={2025},
+ url={https://arxiv.org/abs/2507.03724}
+}
+
+@article{li2025memos_short,
+ title={MemOS: An Operating System for Memory-Augmented Generation (MAG) in Large Language Models},
+ author={Li, Zhiyu and Song, Shichao and Wang, Hanyu and Niu, Simin and Chen, Ding and Yang, Jiawei and Xi, Chenyang and Lai, Huayi and Zhao, Jihao and Wang, Yezhaohui and others},
+ journal={arXiv preprint arXiv:2505.22101},
+ year={2025},
+ url={https://arxiv.org/abs/2505.22101}
+}
+
+@article{yang2024memory3,
+author = {Yang, Hongkang and Zehao, Lin and Wenjin, Wang and Wu, Hao and Zhiyu, Li and Tang, Bo and Wenqiang, Wei and Wang, Jinbo and Zeyun, Tang and Song, Shichao and Xi, Chenyang and Yu, Yu and Kai, Chen and Xiong, Feiyu and Tang, Linpeng and Weinan, E},
+title = {Memory$^3$: Language Modeling with Explicit Memory},
+journal = {Journal of Machine Learning},
+year = {2024},
+volume = {3},
+number = {3},
+pages = {300--346},
+issn = {2790-2048},
+doi = {https://doi.org/10.4208/jml.240708},
+url = {https://global-sci.com/article/91443/memory3-language-modeling-with-explicit-memory}
}
```
## 🙌 Contributing
-We welcome contributions from the community! Please read our [contribution guidelines](https://memos.openmem.net/docs/contribution/overview) to get started.
+We welcome contributions from the community! Please read our [contribution guidelines](https://memos-docs.openmem.net/contribution/overview) to get started.
## 📄 License
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/SOTA_Score.jpg b/docs/assets/SOTA_Score.jpg
deleted file mode 100644
index fd0084315..000000000
Binary files a/docs/assets/SOTA_Score.jpg and /dev/null differ
diff --git a/docs/assets/banner_new.gif b/docs/assets/banner_new.gif
deleted file mode 100644
index 8a8309cfe..000000000
Binary files a/docs/assets/banner_new.gif and /dev/null differ
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/memos_logo.png b/docs/assets/memos_logo.png
deleted file mode 100644
index 83ed20b5e..000000000
Binary files a/docs/assets/memos_logo.png and /dev/null differ
diff --git a/docs/assets/qr-code.png b/docs/assets/qr-code.png
deleted file mode 100644
index 6eca4e31d..000000000
Binary files a/docs/assets/qr-code.png and /dev/null differ
diff --git a/docs/assets/score_all_end2end.jpg b/docs/assets/score_all_end2end.jpg
deleted file mode 100644
index 54ea1d700..000000000
Binary files a/docs/assets/score_all_end2end.jpg and /dev/null differ
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
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:
-```
-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.
-
-
-
-
-
-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
-
-
-
-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.
-
-
-
-## 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 d7cb340eb..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 8d2dccfe7..000000000
--- a/docs/modules/mem_scheduler.md
+++ /dev/null
@@ -1,115 +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 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:
-
-```
-
- 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:
-
-```
-
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/openapi.json b/docs/openapi.json
index 58f4be152..52b6980ac 100644
--- a/docs/openapi.json
+++ b/docs/openapi.json
@@ -884,7 +884,7 @@
"type": "string",
"title": "Session Id",
"description": "Session ID for the MOS. This is used to distinguish between different dialogue",
- "default": "5cc9f7d7-74c3-4bb3-9b4f-11adf416530b"
+ "default": "3d88949f-cbe1-4244-a2e1-d346e8b76ca0"
},
"chat_model": {
"$ref": "#/components/schemas/LLMConfigFactory",
@@ -940,6 +940,12 @@
"title": "Enable Mem Scheduler",
"description": "Enable memory scheduler for automated memory management",
"default": false
+ },
+ "PRO_MODE": {
+ "type": "boolean",
+ "title": "Pro Mode",
+ "description": "Enable PRO mode for complex query decomposition",
+ "default": false
}
},
"additionalProperties": false,
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/evaluation/.env-example b/evaluation/.env-example
new file mode 100644
index 000000000..4cb153b75
--- /dev/null
+++ b/evaluation/.env-example
@@ -0,0 +1,11 @@
+MODEL="gpt-4o-mini"
+OPENAI_API_KEY="sk-***REDACTED***"
+OPENAI_BASE_URL="http://***.***.***.***:3000/v1"
+
+MEM0_API_KEY="m0-***REDACTED***"
+
+ZEP_API_KEY="z_***REDACTED***"
+
+CHAT_MODEL="gpt-4o-mini"
+CHAT_MODEL_BASE_URL="http://***.***.***.***:3000/v1"
+CHAT_MODEL_API_KEY="sk-***REDACTED***"
diff --git a/evaluation/README.md b/evaluation/README.md
index 02566fa71..39188aea4 100644
--- a/evaluation/README.md
+++ b/evaluation/README.md
@@ -1,6 +1,6 @@
# Evaluation Memory Framework
-This repository provides tools and scripts for evaluating the LoCoMo and LongMemEval dataset using various models and APIs.
+This repository provides tools and scripts for evaluating the LoCoMo dataset using various models and APIs.
## Installation
@@ -17,67 +17,20 @@ This repository provides tools and scripts for evaluating the LoCoMo and LongMem
## Configuration
-Create an `.env` file in the `evaluation/` directory and include the following environment variables:
+1. Copy the `.env-example` file to `.env`, and fill in the required environment variables according to your environment and API keys.
-```plaintext
-OPENAI_API_KEY="sk-xxx"
-OPENAI_BASE_URL="your_base_url"
+2. Copy the `configs-example/` directory to a new directory named `configs/`, and modify the configuration files inside it as needed. This directory contains model and API-specific settings.
-MEM0_API_KEY="your_mem0_api_key"
-MEM0_PROJECT_ID="your_mem0_proj_id"
-MEM0_ORGANIZATION_ID="your_mem0_org_id"
-MODEL="gpt-4o-mini" # or your preferred model
-EMBEDDING_MODEL="text-embedding-3-small" # or your preferred embedding model
-ZEP_API_KEY="your_zep_api_key"
-```
+## Evaluation Scripts
-## Dataset
-The smaller dataset "LoCoMo" has already been included in the repo to facilitate reproducing.
+### LoCoMo Evaluation
+⚙️ To evaluate the **LoCoMo** dataset using one of the supported memory frameworks — `memos`, `mem0`, or `zep` — run the following [script](./scripts/run_locomo_eval.sh):
-To download the "LongMemEval" dataset, run the following command:
```bash
-huggingface-cli download --repo-type dataset --resume-download xiaowu0162/longmemeval --local-dir data/longmemeval
+# Edit the configuration in ./scripts/run_locomo_eval.sh
+# Specify the model and memory backend you want to use (e.g., mem0, zep, etc.)
+./scripts/run_locomo_eval.sh
```
-After downloading, rename the files as follows:
-- `longmemeval_m.json`
-- `longmemeval_s.json`
-- `longmemeval_oracle.json`
-
-## Evaluation Scripts
-
-To evaluate the `locomo` dataset, execute the following scripts in order:
-
-1. **Ingest locomo history into MemOS:**
- ```bash
- python scripts/locomo/locomo_ingestion.py --lib memos
- ```
-
-2. **Search Memory for each QA pair in locomo:**
- ```bash
- python scripts/locomo/locomo_search.py --lib memos
- ```
-
-3. **Generate responses from OpenAI with provided context:**
- ```bash
- python scripts/locomo/locomo_responses.py --lib memos
- ```
-
-4. **Evaluate the generated answers:**
- ```bash
- python scripts/locomo/locomo_eval.py --lib memos
- ```
-
-5. **Calculate fine-grained scores for each category:**
- ```bash
- python scripts/locomo/locomo_metric.py --lib memos
- ```
-
-## Contributing Guidelines
-
-1. **Add New Metrics**
-When incorporating the evaluation of reflection duration, ensure to record related data in `{lib}_locomo_judged.json`. For additional NLP metrics like BLEU and ROUGE-L score, make adjustments to the `locomo_grader` function in `scripts/locomo/locomo_eval.py`.
-
-2. **Intermediate Results**
-While I have provided intermediate results like `{lib}_locomo_search_results.json`, `{lib}_locomo_responses.json`, and `{lib}_locomo_judged.json` for reproducibility, contributors are encouraged to report final results in the PR description rather than editing these files directly. Any valuable modifications will be combined into an updated version of the evaluation code containing revised intermediate results (at specified intervals).
+✍️ For evaluating OpenAI's native memory feature with the LoCoMo dataset, please refer to the detailed guide: [OpenAI Memory on LoCoMo - Evaluation Guide](./scripts/locomo/openai_memory_locomo_eval_guide.md).
diff --git a/evaluation/scripts/locomo/locomo_eval.py b/evaluation/scripts/locomo/locomo_eval.py
index ac85e087c..b5b478426 100644
--- a/evaluation/scripts/locomo/locomo_eval.py
+++ b/evaluation/scripts/locomo/locomo_eval.py
@@ -363,8 +363,8 @@ async def limited_task(task):
parser.add_argument(
"--lib",
type=str,
- choices=["zep", "memos", "mem0", "mem0_graph", "memos_mos", "langmem", "openai"],
- help="Specify the memory framework (zep or memos or mem0 or mem0_graph or memos_mos)",
+ choices=["zep", "memos", "mem0", "mem0_graph", "langmem", "openai"],
+ help="Specify the memory framework (zep or memos or mem0 or mem0_graph)",
)
parser.add_argument(
"--version",
diff --git a/evaluation/scripts/locomo/locomo_ingestion.py b/evaluation/scripts/locomo/locomo_ingestion.py
index ebd82985d..f3837002d 100644
--- a/evaluation/scripts/locomo/locomo_ingestion.py
+++ b/evaluation/scripts/locomo/locomo_ingestion.py
@@ -15,10 +15,8 @@
from memos.configs.mem_cube import GeneralMemCubeConfig
from memos.configs.mem_os import MOSConfig
-from memos.configs.memory import MemoryConfigFactory
from memos.mem_cube.general import GeneralMemCube
from memos.mem_os.main import MOS
-from memos.memories.factory import MemoryFactory
custom_instructions = """
@@ -61,29 +59,10 @@ def get_client(frame: str, user_id: str | None = None, version: str = "default")
return mem0
elif frame == "memos":
- config_path = "configs/text_memos_config.json"
- with open(config_path) as f:
- config_data = json.load(f)
- config_data["config"]["extractor_llm"]["config"]["model_name_or_path"] = os.getenv("MODEL")
- config_data["config"]["extractor_llm"]["config"]["api_key"] = os.getenv("OPENAI_API_KEY")
- config_data["config"]["extractor_llm"]["config"]["api_base"] = os.getenv("OPENAI_BASE_URL")
- config_data["config"]["vector_db"]["config"]["path"] = (
- f"results/locomo/memos-{version}/storages/{user_id}/qdrant"
- )
- config_data["config"]["embedder"]["config"]["model_name_or_path"] = os.getenv(
- "EMBEDDING_MODEL"
- )
-
- config = MemoryConfigFactory.model_validate(config_data)
-
- m = MemoryFactory.from_config(config)
- m.load(f"results/locomo/memos-{version}/storages/{user_id}")
- return m
-
- elif frame == "memos_mos":
mos_config_path = "configs/mos_memos_config.json"
with open(mos_config_path) as f:
mos_config_data = json.load(f)
+ mos_config_data["top_k"] = 20
mos_config = MOSConfig(**mos_config_data)
mos = MOS(mos_config)
mos.create_user(user_id=user_id)
@@ -147,20 +126,6 @@ def ingest_session(client, session, frame, metadata, revised_client=None):
)
elif frame == "memos":
- for chat in tqdm(session, desc=f"{metadata['session_key']}"):
- data = chat.get("speaker") + ": " + chat.get("text")
- print({"context": data, "conv_id": conv_id, "created_at": iso_date})
- msg = [{"role": "user", "content": data}]
-
- try:
- memories = client.extract(msg)
- except Exception as ex:
- print(f"Error extracting message {msg}: {ex}")
- memories = []
- print(memories)
- client.add(memories)
-
- elif frame == "memos_mos":
messages = []
messages_reverse = []
@@ -276,14 +241,11 @@ def process_user(conv_idx, frame, locomo_df, version, num_workers=1):
client.delete_all(user_id=f"{conversation.get('speaker_a')}_{conv_idx}")
client.delete_all(user_id=f"{conversation.get('speaker_b')}_{conv_idx}")
elif frame == "memos":
- conv_id = "locomo_exp_user_" + str(conv_idx)
- client = get_client("memos", conv_id, version)
- elif frame == "memos_mos":
conv_id = "locomo_exp_user_" + str(conv_idx)
speaker_a_user_id = conv_id + "_speaker_a"
speaker_b_user_id = conv_id + "_speaker_b"
- client = get_client("memos_mos", speaker_a_user_id, version)
- revised_client = get_client("memos_mos", speaker_b_user_id, version)
+ client = get_client("memos", speaker_a_user_id, version)
+ revised_client = get_client("memos", speaker_b_user_id, version)
sessions_to_process = []
for session_idx in range(max_session_count):
@@ -324,11 +286,6 @@ def process_user(conv_idx, frame, locomo_df, version, num_workers=1):
except Exception as e:
print(f"Error processing user {conv_idx}, session {session_key}: {e!s}")
- if frame == "memos":
- conv_id = "locomo_exp_user_" + str(conv_idx)
- client.dump(f"results/locomo/memos-{version}/storages/{conv_id}")
- del client
-
end_time = time.time()
elapsed_time = round(end_time - start_time, 2)
print(f"User {conv_idx} processed successfully in {elapsed_time} seconds")
@@ -383,8 +340,8 @@ def main(frame, version="default", num_workers=4):
parser.add_argument(
"--lib",
type=str,
- choices=["zep", "memos", "mem0", "mem0_graph", "memos_mos"],
- help="Specify the memory framework (zep or memos or mem0 or mem0_graph or memos_mos)",
+ choices=["zep", "memos", "mem0", "mem0_graph"],
+ help="Specify the memory framework (zep or memos or mem0 or mem0_graph)",
)
parser.add_argument(
"--version",
diff --git a/evaluation/scripts/locomo/locomo_metric.py b/evaluation/scripts/locomo/locomo_metric.py
index caaf601c0..9335ec5ba 100644
--- a/evaluation/scripts/locomo/locomo_metric.py
+++ b/evaluation/scripts/locomo/locomo_metric.py
@@ -9,8 +9,8 @@
parser.add_argument(
"--lib",
type=str,
- choices=["zep", "memos", "mem0", "mem0_graph", "memos_mos", "langmem", "openai"],
- help="Specify the memory framework (zep or memos or mem0 or mem0_graph or memos_mos)",
+ choices=["zep", "memos", "mem0", "mem0_graph", "langmem", "openai"],
+ help="Specify the memory framework (zep or memos or mem0 or mem0_graph)",
)
parser.add_argument(
"--version",
diff --git a/evaluation/scripts/locomo/locomo_openai.py b/evaluation/scripts/locomo/locomo_openai.py
new file mode 100644
index 000000000..0b6c52922
--- /dev/null
+++ b/evaluation/scripts/locomo/locomo_openai.py
@@ -0,0 +1,173 @@
+import argparse
+import json
+import os
+import time
+
+from collections import defaultdict
+from multiprocessing.dummy import Pool
+
+from dotenv import load_dotenv
+from openai import OpenAI
+from tenacity import retry, stop_after_attempt, wait_random_exponential
+from tqdm import tqdm
+
+
+load_dotenv()
+
+# Retry policy constants
+WAIT_MIN = 5 # minimum backoff delay in seconds
+WAIT_MAX = 30 # maximum backoff delay in seconds
+MAX_TRIES = 10 # maximum number of retry attempts
+
+WORKERS = 5 # number of parallel worker processes
+
+ANSWER_PROMPT = """
+ You are an intelligent memory assistant tasked with retrieving accurate information from conversation memories.
+
+ # CONTEXT:
+ You have access to memories from a conversation. These memories contain
+ timestamped information that may be relevant to answering the question.
+
+ # INSTRUCTIONS:
+ 1. Carefully analyze all provided memories
+ 2. Pay special attention to the timestamps to determine the answer
+ 3. If the question asks about a specific event or fact, look for direct evidence in the memories
+ 4. If the memories contain contradictory information, prioritize the most recent memory
+ 5. If there is a question about time references (like "last year", "two months ago", etc.),
+ calculate the actual date based on the memory timestamp. For example, if a memory from
+ 4 May 2022 mentions "went to India last year," then the trip occurred in 2021.
+ 6. Always convert relative time references to specific dates, months, or years. For example,
+ convert "last year" to "2022" or "two months ago" to "March 2023" based on the memory
+ timestamp. Ignore the reference while answering the question.
+ 7. Focus only on the content of the memories. Do not confuse character
+ names mentioned in memories with the actual users who created those memories.
+ 8. The answer should be less than 5-6 words.
+
+ # APPROACH (Think step by step):
+ 1. First, examine all memories that contain information related to the question
+ 2. Examine the timestamps and content of these memories carefully
+ 3. Look for explicit mentions of dates, times, locations, or events that answer the question
+ 4. If the answer requires calculation (e.g., converting relative time references), show your work
+ 5. Formulate a precise, concise answer based solely on the evidence in the memories
+ 6. Double-check that your answer directly addresses the question asked
+ 7. Ensure your final answer is specific and avoids vague time references
+
+ Memories:
+
+ {context}
+
+ Question: {question}
+ Answer:
+ """
+
+
+class OpenAIPredict:
+ def __init__(self, model="gpt-4o-mini"):
+ self.model = model
+ self.openai_client = OpenAI(
+ api_key=os.getenv("OPENAI_API_KEY"), base_url=os.getenv("OPENAI_BASE_URL")
+ )
+ self.results = defaultdict(list)
+
+ def search_memory(self, idx):
+ with open(f"openai_memory/{idx}.txt", encoding="utf-8") as file:
+ memories = file.read().strip().replace("\n\n", "\n")
+
+ return memories, 0
+
+ def process_question(self, val, idx):
+ question = val.get("question", "")
+ answer = val.get("answer", "")
+ category = val.get("category", -1)
+
+ response, search_memory_time, response_time, context = self.answer_question(idx, question)
+
+ result = {
+ "question": question,
+ "answer": response,
+ "category": category,
+ "golden_answer": answer,
+ "search_context": context,
+ "response_duration_ms": response_time,
+ "search_duration_ms": search_memory_time,
+ }
+
+ return result
+
+ @retry(
+ wait=wait_random_exponential(min=WAIT_MIN, max=WAIT_MAX),
+ stop=stop_after_attempt(MAX_TRIES),
+ reraise=True,
+ )
+ def answer_question(self, idx, question):
+ memories, search_memory_time = self.search_memory(idx)
+
+ answer_prompt = ANSWER_PROMPT.format(context=memories, question=question)
+
+ t1 = time.time()
+ response = self.openai_client.chat.completions.create(
+ model=self.model,
+ messages=[{"role": "system", "content": answer_prompt}],
+ temperature=0.0,
+ )
+ t2 = time.time()
+ response_time = (t2 - t1) * 1000
+ return response.choices[0].message.content, search_memory_time, response_time, memories
+
+ def process_data_file(self, file_path, output_file_path):
+ with open(file_path, encoding="utf-8") as f:
+ data = json.load(f)
+
+ # Function to process each conversation
+ def process_conversation(item):
+ idx, conversation = item
+ results_for_conversation = []
+
+ # Process each question in the conversation
+ for question_item in tqdm(
+ conversation["qa"], desc=f"Processing questions for conversation {idx}", leave=False
+ ):
+ if int(question_item.get("category", "")) == 5:
+ continue
+ result = self.process_question(question_item, idx)
+ results_for_conversation.append(result)
+
+ return idx, results_for_conversation
+
+ # Use multiprocessing to process the conversations in parallel
+ with Pool(processes=WORKERS) as pool:
+ results = list(
+ tqdm(
+ pool.imap(process_conversation, list(enumerate(data))),
+ total=len(data),
+ desc="Processing conversations",
+ )
+ )
+
+ # Reorganize results and store them in self.results
+ for idx, results_for_conversation in results:
+ self.results[f"locomo_exp_user_{idx}"] = results_for_conversation
+
+ # Save results to output file
+ with open(output_file_path, "w") as f:
+ json.dump(self.results, f, indent=4)
+
+
+def main(version):
+ os.makedirs(f"results/locomo/openai-{version}/", exist_ok=True)
+ output_file_path = f"results/locomo/openai-{version}/openai_locomo_responses.json"
+ openai_predict = OpenAIPredict()
+ openai_predict.process_data_file("data/locomo/locomo10.json", output_file_path)
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument(
+ "--version",
+ type=str,
+ default="default",
+ help="Version identifier for loading results (e.g., 1010)",
+ )
+ args = parser.parse_args()
+ version = args.version
+ main(version)
diff --git a/evaluation/scripts/locomo/locomo_responses.py b/evaluation/scripts/locomo/locomo_responses.py
index 80f4d893c..5d0374c2b 100644
--- a/evaluation/scripts/locomo/locomo_responses.py
+++ b/evaluation/scripts/locomo/locomo_responses.py
@@ -24,7 +24,7 @@ async def locomo_response(frame, llm_client, context: str, question: str) -> str
context=context,
question=question,
)
- elif frame == "memos" or frame == "memos_mos":
+ elif frame == "memos":
prompt = ANSWER_PROMPT_MEMOS.format(
context=context,
question=question,
@@ -124,8 +124,8 @@ async def main(frame, version="default"):
parser.add_argument(
"--lib",
type=str,
- choices=["zep", "memos", "mem0", "mem0_graph", "memos_mos", "openai"],
- help="Specify the memory framework (zep or memos or mem0 or mem0_graph or memos_mos)",
+ choices=["zep", "memos", "mem0", "mem0_graph", "openai"],
+ help="Specify the memory framework (zep or memos or mem0 or mem0_graph)",
)
parser.add_argument(
"--version",
diff --git a/evaluation/scripts/locomo/locomo_search.py b/evaluation/scripts/locomo/locomo_search.py
index 732b7d8b2..26e7dd467 100644
--- a/evaluation/scripts/locomo/locomo_search.py
+++ b/evaluation/scripts/locomo/locomo_search.py
@@ -15,12 +15,10 @@
from zep_cloud.client import Zep
from memos.configs.mem_os import MOSConfig
-from memos.configs.memory import MemoryConfigFactory
from memos.mem_os.main import MOS
-from memos.memories.factory import MemoryFactory
-def get_client(frame: str, user_id: str | None = None, version: str = "default"):
+def get_client(frame: str, user_id: str | None = None, version: str = "default", top_k: int = 20):
if frame == "zep":
zep = Zep(api_key=os.getenv("ZEP_API_KEY"), base_url="https://api.getzep.com/api/v2")
return zep
@@ -30,29 +28,10 @@ def get_client(frame: str, user_id: str | None = None, version: str = "default")
return mem0
elif frame == "memos":
- config_path = "configs/text_memos_config.json"
- with open(config_path) as f:
- config_data = json.load(f)
- config_data["config"]["extractor_llm"]["config"]["model_name_or_path"] = os.getenv("MODEL")
- config_data["config"]["extractor_llm"]["config"]["api_key"] = os.getenv("OPENAI_API_KEY")
- config_data["config"]["extractor_llm"]["config"]["api_base"] = os.getenv("OPENAI_BASE_URL")
- config_data["config"]["vector_db"]["config"]["path"] = (
- f"results/locomo/memos-{version}/storages/{user_id}/qdrant"
- )
- config_data["config"]["embedder"]["config"]["model_name_or_path"] = os.getenv(
- "EMBEDDING_MODEL"
- )
-
- config = MemoryConfigFactory.model_validate(config_data)
-
- m = MemoryFactory.from_config(config)
- m.load(f"results/locomo/memos-{version}/storages/{user_id}")
- return m
-
- elif frame == "memos_mos":
mos_config_path = "configs/mos_memos_config.json"
with open(mos_config_path) as f:
mos_config_data = json.load(f)
+ mos_config_data["top_k"] = top_k
mos_config = MOSConfig(**mos_config_data)
mos = MOS(mos_config)
mos.create_user(user_id=user_id)
@@ -123,18 +102,6 @@ def get_client(frame: str, user_id: str | None = None, version: str = "default")
"""
-def memos_search(client, query):
- start = time()
- search_results = client.search(query, top_k=20)
- context = ""
- for item in search_results:
- item = item.to_dict()
- context += f"{item['memory']}\n"
- print(query, context)
- duration_ms = (time() - start) * 1000
- return context, duration_ms
-
-
def mem0_search(client, query, speaker_a_user_id, speaker_b_user_id, top_k=20):
start = time()
search_speaker_a_results = client.search(
@@ -192,7 +159,7 @@ def mem0_search(client, query, speaker_a_user_id, speaker_b_user_id, top_k=20):
return context, duration_ms
-def memos_mos_search(client, query, conv_id, speaker_a, speaker_b, reversed_client=None):
+def memos_search(client, query, conv_id, speaker_a, speaker_b, reversed_client=None):
start = time()
search_a_results = client.search(
query=query,
@@ -339,8 +306,6 @@ def search_query(client, query, metadata, frame, reversed_client=None, top_k=20)
if frame == "zep":
context, duration_ms = zep_search(client, query, conv_id, top_k)
- elif frame == "memos":
- context, duration_ms = memos_search(client, query)
elif frame == "mem0":
context, duration_ms = mem0_search(
client, query, speaker_a_user_id, speaker_b_user_id, top_k
@@ -349,8 +314,8 @@ def search_query(client, query, metadata, frame, reversed_client=None, top_k=20)
context, duration_ms = mem0_graph_search(
client, query, speaker_a_user_id, speaker_b_user_id, top_k
)
- elif frame == "memos_mos":
- context, duration_ms = memos_mos_search(
+ elif frame == "memos":
+ context, duration_ms = memos_search(
client, query, conv_id, speaker_a, speaker_b, reversed_client
)
return context, duration_ms
@@ -394,11 +359,11 @@ def process_user(group_idx, locomo_df, frame, version, top_k=20, num_workers=1):
}
reversed_client = None
- if frame == "memos_mos":
+ if frame == "memos":
speaker_a_user_id = conv_id + "_speaker_a"
speaker_b_user_id = conv_id + "_speaker_b"
- client = get_client(frame, speaker_a_user_id, version)
- reversed_client = get_client(frame, speaker_b_user_id, version)
+ client = get_client(frame, speaker_a_user_id, version, top_k=top_k)
+ reversed_client = get_client(frame, speaker_b_user_id, version, top_k=top_k)
else:
client = get_client(frame, conv_id, version)
@@ -474,8 +439,8 @@ def main(frame, version="default", num_workers=1, top_k=20):
parser.add_argument(
"--lib",
type=str,
- choices=["zep", "memos", "mem0", "mem0_graph", "memos_mos", "langmem"],
- help="Specify the memory framework (zep or memos or mem0 or mem0_graph or memos_mos)",
+ choices=["zep", "memos", "mem0", "mem0_graph", "langmem"],
+ help="Specify the memory framework (zep or memos or mem0 or mem0_graph)",
)
parser.add_argument(
"--version",
diff --git a/evaluation/scripts/locomo/openai_memory_locomo_eval_guide.md b/evaluation/scripts/locomo/openai_memory_locomo_eval_guide.md
new file mode 100644
index 000000000..c7b5a7e3f
--- /dev/null
+++ b/evaluation/scripts/locomo/openai_memory_locomo_eval_guide.md
@@ -0,0 +1,115 @@
+# OpenAI Memory on LoCoMo - Evaluation Guide
+
+This document outlines the evaluation process for OpenAI's Memory feature using the LoCoMo dataset.
+
+## 1. Introduction
+
+Since OpenAI's [Memory feature](https://openai.com/index/memory-and-new-controls-for-chatgpt/) does not have a public API, the evaluation requires a manual process. Dialogues from the LoCoMo dataset are formatted and manually input into the ChatGPT web interface. The resulting memories are then retrieved from the account's memory management page and saved locally.
+
+To evaluate the quality of these memories, we will use the `gpt-4o-mini` model via API. The model will be asked questions from the LoCoMo dataset, and the full history of memories for the relevant conversation will be provided as context. This simulates a perfect memory retrieval system, giving the model the best possible information to answer the question.
+
+## 2. Step-by-Step Workflow
+
+### Step 2.1: Generate Input Context for Memory Extraction
+
+Run the following Python script to generate the input prompts for each session in each conversation. The script will create a separate `.txt` file for each session, containing the formatted conversation history and the extraction prompt.
+
+**Script:**
+```python
+import json
+import os
+
+# Ensure the path to the dataset is correct
+LOCOMO_DATA_PATH = "data/locomo/locomo10.json"
+SAVE_DIR = "openai_inputs"
+
+os.makedirs(SAVE_DIR, exist_ok=True)
+
+TEMPLATE = """Can you please extract relevant information from this conversation and create memory entries for each user mentioned? Please store these memories in your knowledge base in addition to the timestamp provided for future reference and personalized interactions.
+
+{context}
+"""
+
+with open(LOCOMO_DATA_PATH, "r", encoding="utf-8") as f:
+ data = json.load(f)
+
+for conv_idx, item in enumerate(data):
+ conv = item["conversation"]
+
+ for i in range(1, 35):
+ session_key = f"session_{i}"
+ session_dt_key = f"session_{i}_date_time"
+ if session_key not in conv:
+ continue
+
+ session = conv[session_key]
+ session_dt = conv[session_dt_key]
+
+ session_context = ""
+ for chat in session:
+ chat_str = f"({session_dt}) {chat['speaker']}: {chat['text']}\n"
+ session_context += chat_str
+
+ input_string = TEMPLATE.format(context=session_context)
+
+ output_filename = os.path.join(SAVE_DIR, f"{conv_idx}-D{i}.txt")
+ with open(output_filename, "w", encoding="utf-8") as f:
+ f.write(input_string)
+
+print(f"Generated {len(os.listdir(SAVE_DIR))} input files in '{SAVE_DIR}' directory.")
+```
+
+**Example Input (`0-D9.txt`):**
+```plaintext
+Can you please extract relevant information from this conversation and create memory entries for each user mentioned? Please store these memories in your knowledge base in addition to the timestamp provided for future reference and personalized interactions.
+
+(2:31 pm on 17 July, 2023) Melanie: Hey Caroline, hope all's good! I had a quiet weekend after we went camping with my fam two weekends ago. It was great to unplug and hang with the kids. What've you been up to? Anything fun over the weekend?
+(2:31 pm on 17 July, 2023) Caroline: Hey Melanie! That sounds great! Last weekend I joined a mentorship program for LGBTQ youth - it's really rewarding to help the community.
+... (rest of the conversation)
+```
+
+### Step 2.2: Extract and Save Memories from ChatGPT
+
+1. **Enable Memory:** In ChatGPT, go to **Settings -> Personalization** and ensure **Memory** is turned on.
+2. **Clear Existing Memories:** Before processing a new conversation, click on **Manage** and **Clear all** to ensure a clean slate.
+3. **Input and Verify:**
+ * Open a new chat.
+ * Ensure the model is set to **GPT-4o**.
+ * Copy the content of a generated `.txt` file (e.g., `0-D1.txt`) and paste it into the chat.
+ * After the model responds, verify that you see the "Memory updated" confirmation.
+4. **Save Memories:**
+ * Click on **Manage** in the memory confirmation to view the newly generated memories.
+ * Create a new local `.txt` file with the same name as the input file (e.g., `0-D1.txt`).
+ * Copy each memory entry from ChatGPT and paste it into the new file, with each memory on a new line.
+5. **Reset Memories for the Next Conversation:**
+ * Once all sessions for a conversation are complete, it is essential to **delete all memories to ensure a clean state for the next conversation**. Navigate to Settings -> Personalization -> Manage and click Delete all.
+
+**Example Memory Output (`0-D9.txt`):**
+```plaintext
+As of November 17, 2023, Dave has taken up photography and enjoys capturing nature scenes like sunsets, beaches, waves, rocks, and waterfalls.
+Dave recently purchased a vintage camera that takes high-quality photos.
+Dave discovered a serene park nearby with a peaceful spot featuring a bench under a tree with pink flowers.
+As of November 17, 2023, Calvin attended a fancy gala in Boston where he had an inspiring conversation with an artist about music and art.
+Calvin finds music a powerful connector and source of creativity.
+Calvin took a photo in a Japanese garden that he shared with Dave.
+Calvin accepted an invitation to perform at an upcoming show in Boston, expressing excitement about the musical experience.
+```
+
+### Step 2.3: Consolidate Memories
+
+The memories are currently saved per session. You need to write a simple script to consolidate all memories belonging to the same conversation into a single file. For example, all memories from `0-D1.txt`, `0-D2.txt`, etc., should be merged into a single `conversation_0_memories.txt`.
+
+
+### Step 2.4: Automated Evaluation
+
+Once the memories for all conversations have been extracted and saved, you can run the automated [evaluation script](../run_openai_eval.sh). This script will handle the process of generating answers, evaluating them, and calculating metrics.
+
+```bash
+# Edit the configuration in ./scripts/run_openai_eval.sh
+./scripts/run_openai_eval.sh
+```
+
+## 3. Considerations
+
+- **Account Differences:** Be aware of potential differences between free and Plus accounts, such as context length limitations and the number of memories that can be stored.
+- **Granularity:** The evaluation process adds memories at the session level. To ensure high-quality memory extraction, you should follow this same principle. Feeding the entire conversation to the model at once has been shown to be ineffective, often causing it to overlook important details and leading to substantial information loss.
diff --git a/evaluation/scripts/run_locomo_eval.sh b/evaluation/scripts/run_locomo_eval.sh
new file mode 100755
index 000000000..df1a865f2
--- /dev/null
+++ b/evaluation/scripts/run_locomo_eval.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+
+# Common parameters for all scripts
+LIB="memos"
+VERSION="063001"
+WORKERS=10
+TOPK=20
+
+echo "Running locomo_ingestion.py..."
+CUDA_VISIBLE_DEVICES=0 python scripts/locomo/locomo_ingestion.py --lib $LIB --version $VERSION --workers $WORKERS
+if [ $? -ne 0 ]; then
+ echo "Error running locomo_ingestion.py"
+ exit 1
+fi
+
+echo "Running locomo_search.py..."
+CUDA_VISIBLE_DEVICES=0 python scripts/locomo/locomo_search.py --lib $LIB --version $VERSION --top_k $TOPK --workers $WORKERS
+if [ $? -ne 0 ]; then
+ echo "Error running locomo_search.py"
+ exit 1
+fi
+
+echo "Running locomo_responses.py..."
+python scripts/locomo/locomo_responses.py --lib $LIB --version $VERSION
+if [ $? -ne 0 ]; then
+ echo "Error running locomo_responses.py."
+ exit 1
+fi
+
+echo "Running locomo_eval.py..."
+python scripts/locomo/locomo_eval.py --lib $LIB --version $VERSION --workers $WORKERS --num_runs 3
+if [ $? -ne 0 ]; then
+ echo "Error running locomo_eval.py"
+ exit 1
+fi
+
+echo "Running locomo_metric.py..."
+python scripts/locomo/locomo_metric.py --lib $LIB --version $VERSION
+if [ $? -ne 0 ]; then
+ echo "Error running locomo_metric.py"
+ exit 1
+fi
+
+echo "All scripts completed successfully!"
diff --git a/evaluation/scripts/run_openai_eval.sh b/evaluation/scripts/run_openai_eval.sh
new file mode 100644
index 000000000..27bb712af
--- /dev/null
+++ b/evaluation/scripts/run_openai_eval.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# Common parameters for all scripts
+LIB="openai"
+VERSION="063001"
+WORKERS=10
+NUM_RUNS=3
+
+
+echo "Running locomo_openai.py..."
+python scripts/locomo/locomo_openai.py --version $VERSION
+if [ $? -ne 0 ]; then
+ echo "Error running locomo_openai.py."
+ exit 1
+fi
+
+echo "Running locomo_eval.py..."
+python scripts/locomo/locomo_eval.py --lib $LIB --version $VERSION --num_runs $NUM_RUNS
+if [ $? -ne 0 ]; then
+ echo "Error running locomo_eval.py"
+ exit 1
+fi
+
+echo "Running locomo_metric.py..."
+python scripts/locomo/locomo_metric.py --lib $LIB --version $VERSION
+if [ $? -ne 0 ]; then
+ echo "Error running locomo_metric.py"
+ exit 1
+fi
+
+echo "All scripts completed successfully!"
diff --git a/examples/basic_modules/tree_textual_memory_reasoner.py b/examples/basic_modules/tree_textual_memory_reasoner.py
index be31160c4..369787458 100644
--- a/examples/basic_modules/tree_textual_memory_reasoner.py
+++ b/examples/basic_modules/tree_textual_memory_reasoner.py
@@ -37,12 +37,18 @@
# Step 1: Prepare a mock ParsedTaskGoal
parsed_goal = ParsedTaskGoal(
- topic_level=["Multi-UAV Long-Term Coverage"],
- concept_level=["Coverage Metrics", "Reward Function Design", "Energy Model"],
- fact_level=["CT and FT Definition", "Reward Components", "Energy Cost Components"],
+ memories=[
+ "Multi-UAV Long-Term Coverage",
+ "Coverage Metrics",
+ "Reward Function Design",
+ "Energy Model",
+ "CT and FT Definition",
+ "Reward Components",
+ "Energy Cost Components",
+ ],
+ keys=["UAV", "coverage", "energy", "reward"],
+ tags=[],
goal_type="explanation",
- graph_suggestion="Use all relevant knowledge from previous paper review",
- retrieval_keywords=["UAV", "coverage", "energy", "reward"],
)
query = "How can multiple UAVs coordinate to maximize coverage while saving energy?"
@@ -85,7 +91,53 @@
sources=["paper://multi-uav-coverage/metrics"],
embedding=[0.01] * 768,
),
- )
+ ),
+ TextualMemoryItem(
+ id="c34f5e6b-2d34-4e6f-8c9b-abcdef123456",
+ memory="The capital of France is Paris, which is known for the Eiffel Tower.",
+ metadata=TreeNodeTextualMemoryMetadata(
+ user_id=None,
+ session_id=None,
+ status="activated",
+ type="fact",
+ memory_time="2024-01-01",
+ source="file",
+ confidence=90.0,
+ entities=["France", "Paris", "Eiffel Tower"],
+ tags=["geography", "city", "landmark"],
+ visibility="public",
+ updated_at="2025-06-11T11:51:24.438001",
+ memory_type="LongTermMemory",
+ key="Geography Fact",
+ value="Paris is the capital of France",
+ hierarchy_level="concept",
+ sources=["wikipedia://paris"],
+ embedding=[0.03] * 768,
+ ),
+ ),
+ TextualMemoryItem(
+ id="d56a7b8c-3e45-4f7a-9dab-fedcba654321",
+ memory="Total energy cost is calculated from both mechanical movement and communication transmission.",
+ metadata=TreeNodeTextualMemoryMetadata(
+ user_id=None,
+ session_id=None,
+ status="activated",
+ type="fact",
+ memory_time="2024-01-01",
+ source="file",
+ confidence=89.0,
+ entities=["movement power", "transmission power"],
+ tags=["energy", "movement", "transmission"],
+ visibility="public",
+ updated_at="2025-06-11T11:51:24.438001",
+ memory_type="LongTermMemory",
+ key="Energy Cost Components",
+ value="Includes movement and communication energy",
+ hierarchy_level="fact",
+ sources=["paper://multi-uav-coverage/energy-detail"],
+ embedding=[0.04] * 768,
+ ),
+ ),
]
# Step 7: Init memory retriever
diff --git a/examples/basic_modules/tree_textual_memory_relation_reason_detector.py b/examples/basic_modules/tree_textual_memory_relation_reason_detector.py
new file mode 100644
index 000000000..72e4deb60
--- /dev/null
+++ b/examples/basic_modules/tree_textual_memory_relation_reason_detector.py
@@ -0,0 +1,213 @@
+import uuid
+
+from memos import log
+from memos.configs.embedder import EmbedderConfigFactory
+from memos.configs.graph_db import GraphDBConfigFactory
+from memos.configs.llm import LLMConfigFactory
+from memos.embedders.factory import EmbedderFactory
+from memos.graph_dbs.factory import GraphStoreFactory
+from memos.graph_dbs.item import GraphDBNode
+from memos.llms.factory import LLMFactory
+from memos.memories.textual.item import TreeNodeTextualMemoryMetadata
+from memos.memories.textual.tree_text_memory.organize.relation_reason_detector import (
+ RelationAndReasoningDetector,
+)
+
+
+logger = log.get_logger(__name__)
+
+# === Step 1: Initialize embedder ===
+embedder_config = EmbedderConfigFactory.model_validate(
+ {
+ "backend": "ollama",
+ "config": {
+ "model_name_or_path": "nomic-embed-text:latest",
+ },
+ }
+)
+embedder = EmbedderFactory.from_config(embedder_config)
+
+# === Step 2: Initialize Neo4j GraphStore ===
+graph_config = GraphDBConfigFactory(
+ backend="neo4j",
+ config={
+ "uri": "bolt://localhost:7687",
+ "user": "neo4j",
+ "password": "12345678",
+ "db_name": "lucy4",
+ "auto_create": True,
+ },
+)
+graph_store = GraphStoreFactory.from_config(graph_config)
+
+# === Step 3: Initialize LLM for pairwise relation detection ===
+# Step 1: Load LLM config and instantiate
+config = LLMConfigFactory.model_validate(
+ {
+ "backend": "ollama",
+ "config": {
+ "model_name_or_path": "qwen3:0.6b",
+ "temperature": 0.7,
+ "max_tokens": 1024,
+ },
+ }
+)
+llm = LLMFactory.from_config(config)
+
+# === Step 4: Create a mock GraphDBNode to test relation detection ===
+
+node_a = GraphDBNode(
+ id=str(uuid.uuid4()),
+ memory="Caroline faced increased workload stress during the project deadline.",
+ metadata=TreeNodeTextualMemoryMetadata(
+ memory_type="LongTermMemory",
+ embedding=[0.1] * 10,
+ key="Workload stress",
+ tags=["stress", "workload"],
+ type="fact",
+ background="Project",
+ confidence=0.95,
+ updated_at="2024-06-28T09:00:00Z",
+ ),
+)
+
+node_b = GraphDBNode(
+ id=str(uuid.uuid4()),
+ memory="After joining the support group, Caroline reported improved mental health.",
+ metadata=TreeNodeTextualMemoryMetadata(
+ memory_type="LongTermMemory",
+ embedding=[0.1] * 10,
+ key="Improved mental health",
+ tags=["mental health", "support group"],
+ type="fact",
+ background="Personal follow-up",
+ confidence=0.95,
+ updated_at="2024-07-10T12:00:00Z",
+ ),
+)
+
+node_c = GraphDBNode(
+ id=str(uuid.uuid4()),
+ memory="Peer support groups are effective in reducing stress for LGBTQ individuals.",
+ metadata=TreeNodeTextualMemoryMetadata(
+ memory_type="LongTermMemory",
+ embedding=[0.1] * 10,
+ key="Support group benefits",
+ tags=["LGBTQ", "support group", "stress"],
+ type="fact",
+ background="General research",
+ confidence=0.95,
+ updated_at="2024-06-29T14:00:00Z",
+ ),
+)
+
+# === D: Work pressure ➜ stress ===
+node_d = GraphDBNode(
+ id=str(uuid.uuid4()),
+ memory="Excessive work pressure increases stress levels among employees.",
+ metadata=TreeNodeTextualMemoryMetadata(
+ memory_type="LongTermMemory",
+ embedding=[0.1] * 10,
+ key="Work pressure impact",
+ tags=["stress", "work pressure"],
+ type="fact",
+ background="Workplace study",
+ confidence=0.9,
+ updated_at="2024-06-15T08:00:00Z",
+ ),
+)
+
+# === E: Stress ➜ poor sleep ===
+node_e = GraphDBNode(
+ id=str(uuid.uuid4()),
+ memory="High stress levels often result in poor sleep quality.",
+ metadata=TreeNodeTextualMemoryMetadata(
+ memory_type="LongTermMemory",
+ embedding=[0.1] * 10,
+ key="Stress and sleep",
+ tags=["stress", "sleep"],
+ type="fact",
+ background="Health study",
+ confidence=0.9,
+ updated_at="2024-06-18T10:00:00Z",
+ ),
+)
+
+# === F: Poor sleep ➜ low performance ===
+node_f = GraphDBNode(
+ id=str(uuid.uuid4()),
+ memory="Employees with poor sleep show reduced work performance.",
+ metadata=TreeNodeTextualMemoryMetadata(
+ memory_type="LongTermMemory",
+ embedding=[0.1] * 10,
+ key="Sleep and performance",
+ tags=["sleep", "performance"],
+ type="fact",
+ background="HR report",
+ confidence=0.9,
+ updated_at="2024-06-20T12:00:00Z",
+ ),
+)
+
+node = GraphDBNode(
+ id="a88db9ce-3c77-4e83-8d61-aa9ef95c957e",
+ memory="Caroline joined an LGBTQ support group to cope with work-related stress.",
+ metadata=TreeNodeTextualMemoryMetadata(
+ memory_type="LongTermMemory",
+ embedding=embedder.embed(
+ ["Caroline joined an LGBTQ support group to cope with work-related stress."]
+ )[0],
+ key="Caroline LGBTQ stress",
+ tags=["LGBTQ", "support group", "stress"],
+ type="fact",
+ background="Personal",
+ confidence=0.95,
+ updated_at="2024-07-01T10:00:00Z",
+ ),
+)
+
+
+for n in [node, node_a, node_b, node_c, node_d, node_e, node_f]:
+ graph_store.add_node(n.id, n.memory, n.metadata.dict())
+
+
+# === Step 5: Initialize RelationDetector and run detection ===
+relation_detector = RelationAndReasoningDetector(
+ graph_store=graph_store, llm=llm, embedder=embedder
+)
+
+results = relation_detector.process_node(
+ node=node,
+ exclude_ids=[node.id], # Exclude self when searching for neighbors
+ top_k=5,
+)
+
+# === Step 6: Print detected relations ===
+print("\n=== Detected Global Relations ===")
+
+
+# === Step 6: Pretty-print detected results ===
+print("\n=== Detected Pairwise Relations ===")
+for rel in results["relations"]:
+ print(f" Source ID: {rel['source_id']}")
+ print(f" Target ID: {rel['target_id']}")
+ print(f" Relation Type: {rel['relation_type']}")
+ print("------")
+
+print("\n=== Inferred Nodes ===")
+for node in results["inferred_nodes"]:
+ print(f" New Fact: {node.memory}")
+ print(f" Sources: {node.metadata.sources}")
+ print("------")
+
+print("\n=== Sequence Links (FOLLOWS) ===")
+for link in results["sequence_links"]:
+ print(f" From: {link['from_id']} -> To: {link['to_id']}")
+ print("------")
+
+print("\n=== Aggregate Concepts ===")
+for agg in results["aggregate_nodes"]:
+ print(f" Concept Key: {agg.metadata.key}")
+ print(f" Concept Memory: {agg.memory}")
+ print(f" Sources: {agg.metadata.sources}")
+ print("------")
diff --git a/examples/core_memories/textual_internet_memoy.py b/examples/core_memories/textual_internet_memoy.py
new file mode 100644
index 000000000..21979e890
--- /dev/null
+++ b/examples/core_memories/textual_internet_memoy.py
@@ -0,0 +1,241 @@
+from memos import log
+from memos.configs.embedder import EmbedderConfigFactory
+from memos.configs.internet_retriever import InternetRetrieverConfigFactory
+from memos.configs.mem_reader import SimpleStructMemReaderConfig
+from memos.configs.memory import TreeTextMemoryConfig
+from memos.embedders.factory import EmbedderFactory
+from memos.mem_reader.simple_struct import SimpleStructMemReader
+from memos.memories.textual.tree import TreeTextMemory
+
+
+logger = log.get_logger(__name__)
+
+
+embedder_config = EmbedderConfigFactory.model_validate(
+ {
+ "backend": "ollama",
+ "config": {
+ "model_name_or_path": "nomic-embed-text:latest",
+ },
+ }
+)
+embedder = EmbedderFactory.from_config(embedder_config)
+
+
+def embed_memory_item(memory: str) -> list[float]:
+ return embedder.embed([memory])[0]
+
+
+# google or xinyu pelase change tree_config_with_internet api key or token or url
+tree_config = TreeTextMemoryConfig.from_json_file("examples/data/config/tree_config.json")
+interconfig = InternetRetrieverConfigFactory(
+ backend="xinyu",
+ config={
+ "api_key": "google or xinyu token",
+ "search_engine_id": "google engine id or xinyu url",
+ "max_results": 15,
+ "num_per_request": 10,
+ },
+)
+tree_config.internet_retriever = interconfig
+
+my_tree_textual_memory = TreeTextMemory(tree_config)
+my_tree_textual_memory.delete_all()
+
+# Create a memory reader instance
+reader_config = SimpleStructMemReaderConfig.from_json_file(
+ "examples/data/config/simple_struct_reader_config.json"
+)
+reader = SimpleStructMemReader(reader_config)
+
+scene_data = [
+ [
+ {"role": "user", "chat_time": "3 May 2025", "content": "I’m feeling a bit down today."},
+ {
+ "role": "assistant",
+ "chat_time": "3 May 2025",
+ "content": "I’m sorry to hear that. Do you want to talk about what’s been going on?",
+ },
+ {
+ "role": "user",
+ "chat_time": "3 May 2025",
+ "content": "It’s just been a tough couple of days, you know? Everything feels a bit overwhelming, and I just can’t seem to shake it off.",
+ },
+ {
+ "role": "assistant",
+ "chat_time": "3 May 2025",
+ "content": "It sounds like you're going through a lot right now. Sometimes it helps to talk things out. Is there something specific that's been weighing on you, or is it more of a general feeling?",
+ },
+ {
+ "role": "user",
+ "chat_time": "3 May 2025",
+ "content": "It’s a mix, I guess. Work’s been really stressful, and on top of that, I’ve been feeling kinda disconnected from the people around me.",
+ },
+ {
+ "role": "assistant",
+ "chat_time": "3 May 2025",
+ "content": "That can be really draining, especially when you’re feeling isolated on top of the stress. Do you think there’s something from your past that’s contributing to how you’re feeling now? Sometimes our emotions are tied to older experiences.",
+ },
+ {
+ "role": "user",
+ "chat_time": "3 May 2025",
+ "content": "Yeah, now that you mention it… I’ve been thinking a lot about my childhood lately. I didn’t have the easiest upbringing. My parents were always busy, and I often felt like I had to figure things out on my own. I remember one winter, I got really sick with a high fever. My parents were both working, and I didn’t want to bother them. I just lay in bed, crying by myself, not knowing what to do.",
+ },
+ {
+ "role": "assistant",
+ "chat_time": "3 May 2025",
+ "content": "That must have been very lonely. Growing up without that support can really make you feel like you have to handle everything on your own. How do you think that experience has affected you now?",
+ },
+ {
+ "role": "user",
+ "chat_time": "3 May 2025",
+ "content": "Yeah, it was really lonely. I remember spending a lot of time doing things on my own, like drawing, because it was my only way to escape. I used to draw animals, and I created my own little world on paper. It was peaceful in a way, just me and my imagination, with no outside distractions.",
+ },
+ {
+ "role": "assistant",
+ "chat_time": "3 May 2025",
+ "content": "Drawing sounds like a beautiful way to express yourself and find some peace in that solitude. It must have been a very quiet and private world for you. Do you think that sense of loneliness from back then has shaped how you connect with others today?",
+ },
+ {
+ "role": "user",
+ "chat_time": "3 May 2025",
+ "content": "I think it has. I’ve always found it hard to let others in. I feel like I have to handle everything on my own. If I rely on someone else, I feel vulnerable, and I start to feel that loneliness again.",
+ },
+ {
+ "role": "assistant",
+ "chat_time": "3 May 2025",
+ "content": "It sounds like this was a protective mechanism that helped you cope with your feelings of loneliness back then. But as you’ve grown, it seems like this pattern might not be serving you as well anymore. Have you thought about trying to break this cycle, or finding new ways to connect with others?",
+ },
+ {
+ "role": "user",
+ "chat_time": "3 May 2025",
+ "content": "I’ve thought about it, though it’s hard. But I also know I can’t keep going like this forever. Maybe it’s time to seek some help.",
+ },
+ {
+ "role": "assistant",
+ "chat_time": "3 May 2025",
+ "content": "It’s a big step, but a positive one. Exploring your emotions and past experiences could really help you understand how they’ve shaped your present. Therapy could be a great place to start, as it would help you connect with both yourself and others. Would you be open to trying it?",
+ },
+ {
+ "role": "user",
+ "chat_time": "3 May 2025",
+ "content": "I’m open to trying. Thank you for encouraging me. It feels like it might be a good starting point for me.",
+ },
+ {
+ "role": "assistant",
+ "chat_time": "3 May 2025",
+ "content": "I’m really glad to hear that. Taking that first step is always difficult, but you’ve made an important decision. If you need help finding the right therapist, or just want to talk, I’m here for you.",
+ },
+ ],
+ [
+ {
+ "role": "user",
+ "chat_time": "3 May 2025",
+ "content": "This week I’ve been feeling a bit off, especially when playing tennis. My body just doesn’t feel right.",
+ },
+ {
+ "role": "assistant",
+ "chat_time": "3 May 2025",
+ "content": "It sounds like you've been having some physical discomfort lately. Where specifically are you feeling unwell? Is there something particular about tennis that's been difficult?",
+ },
+ {
+ "role": "user",
+ "chat_time": "3 May 2025",
+ "content": "I just feel a bit fatigued, and every time I play tennis, my movements feel off. I used to play pretty well, but lately, I’ve been feeling weak and my movements aren’t as coordinated as they used to be.",
+ },
+ {
+ "role": "assistant",
+ "chat_time": "3 May 2025",
+ "content": "Physical discomfort can definitely affect performance, especially in a sport like tennis that requires quick reactions and coordination. Have you noticed anything specific that might be causing these changes? Could it be overtraining, or is there another physical issue making you feel off?",
+ },
+ {
+ "role": "user",
+ "chat_time": "3 May 2025",
+ "content": "I think it might be due to stress and lack of sleep recently. I just feel drained all the time. Plus, I’ve been frustrated with my tennis performance, which makes me feel even worse, like I’m stuck in a vicious cycle.",
+ },
+ {
+ "role": "assistant",
+ "chat_time": "3 May 2025",
+ "content": "Stress and poor sleep quality can definitely affect your physical performance, especially in sports. When you’re also feeling down about your performance, it’s easy to fall into a negative cycle. Have you tried anything to relieve some of the stress, or to improve your sleep?",
+ },
+ {
+ "role": "user",
+ "chat_time": "3 May 2025",
+ "content": "I’ve tried some relaxation techniques, like deep breathing and simple meditation, but it doesn’t seem to help much. I still can’t focus during tennis, and I feel like my mind is distracted by other things.",
+ },
+ {
+ "role": "assistant",
+ "chat_time": "3 May 2025",
+ "content": "Relaxation techniques like deep breathing and meditation can help reduce stress, but sometimes we need a more structured approach to improve both our physical and mental state. For example, you might want to focus on specific aspects of your tennis training, or adjust your rest and recovery time. Have you thought about setting smaller goals for yourself? Like focusing on a specific tennis move each day, rather than expecting perfection right away? That might help you gradually regain confidence.",
+ },
+ {
+ "role": "user",
+ "chat_time": "3 May 2025",
+ "content": "That’s a good idea. I think I’ve been expecting too much from myself, which just makes me more anxious. Maybe I can start with small practice sessions and gradually find my rhythm again.",
+ },
+ {
+ "role": "assistant",
+ "chat_time": "3 May 2025",
+ "content": "Exactly! Setting small and clear goals will help reduce pressure and give you a sense of accomplishment. And don’t forget that rest is just as important—taking time to recover will help you feel better physically and mentally. Both physical and mental recovery are key to improving your performance and health.",
+ },
+ {
+ "role": "user",
+ "chat_time": "3 May 2025",
+ "content": "Thanks, I feel like I need to rethink a few things. Maybe I really need to be kinder to myself and take things step by step.",
+ },
+ {
+ "role": "assistant",
+ "chat_time": "3 May 2025",
+ "content": "You’re on the right track. Rethinking things and giving yourself space and patience is so important. You’ve already taken the first step, now just keep moving forward, one step at a time. If you need anything, I’m always here to help.",
+ },
+ ],
+]
+
+# Acquiring memories
+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)
+
+results = my_tree_textual_memory.search(
+ "Talk about the user's childhood story?",
+ top_k=10,
+ info={"query": "Talk about the user's childhood story?", "user_id": "111", "session": "2234"},
+)
+for i, r in enumerate(results):
+ r = r.to_dict()
+ print(f"{i}'th similar result is: " + str(r["memory"]))
+print(f"Successfully search {len(results)} memories")
+
+# find related nodes
+related_nodes = my_tree_textual_memory.get_relevant_subgraph("Painting")
+
+# get current memory_size
+print(f"Current Memory Size is {my_tree_textual_memory.get_current_memory_size()}")
+
+logger.info("Start doc search example...")
+# Processing Documents
+doc_paths = [
+ "./text1.txt",
+ "./text2.txt",
+]
+# Acquiring memories from documents
+doc_memory = reader.get_memory(doc_paths, "doc", info={"user_id": "1111", "session_id": "2222"})
+
+for m_list in doc_memory:
+ my_tree_textual_memory.add(m_list)
+
+results = my_tree_textual_memory.search(
+ "Tell me about what memos consist of?",
+ top_k=30,
+ info={"query": "Tell me about what memos consist of?", "user_id": "111", "session": "2234"},
+)
+for i, r in enumerate(results):
+ r = r.to_dict()
+ print(f"{i}'th similar result is: " + str(r["memory"]))
+print(f"Successfully search {len(results)} memories")
+
+
+# my_tree_textual_memory.dump
+my_tree_textual_memory.dump("tmp/my_tree_textual_memory")
+my_tree_textual_memory.drop()
diff --git a/examples/core_memories/tree_textual_memory.py b/examples/core_memories/tree_textual_memory.py
index 2b3bbdf29..9a4035b87 100644
--- a/examples/core_memories/tree_textual_memory.py
+++ b/examples/core_memories/tree_textual_memory.py
@@ -183,6 +183,7 @@ def embed_memory_item(memory: str) -> list[float]:
for m_list in memory:
my_tree_textual_memory.add(m_list)
+ my_tree_textual_memory.memory_manager.wait_reorganizer()
results = my_tree_textual_memory.search(
"Talk about the user's childhood story?",
@@ -211,6 +212,7 @@ def embed_memory_item(memory: str) -> list[float]:
for m_list in doc_memory:
my_tree_textual_memory.add(m_list)
+ my_tree_textual_memory.memory_manager.wait_reorganizer()
results = my_tree_textual_memory.search(
"Tell me about what memos consist of?",
@@ -222,6 +224,9 @@ def embed_memory_item(memory: str) -> list[float]:
print(f"{i}'th similar result is: " + str(r["memory"]))
print(f"Successfully search {len(results)} memories")
+# close the synchronous thread in memory manager
+my_tree_textual_memory.memory_manager.close()
+
# my_tree_textual_memory.dump
my_tree_textual_memory.dump("tmp/my_tree_textual_memory")
diff --git a/examples/data/config/tree_config.json b/examples/data/config/tree_config.json
index f41237555..bcb07b3a4 100644
--- a/examples/data/config/tree_config.json
+++ b/examples/data/config/tree_config.json
@@ -33,5 +33,6 @@
"auto_create": true,
"embedding_dimension": 768
}
- }
+ },
+ "reorganize": false
}
diff --git a/examples/mem_os/cot_usage_example.py b/examples/mem_os/cot_usage_example.py
new file mode 100644
index 000000000..e3d10fa75
--- /dev/null
+++ b/examples/mem_os/cot_usage_example.py
@@ -0,0 +1,342 @@
+#!/usr/bin/env python3
+"""
+MemOS CoT (Chain of Thought) Usage Example
+This example demonstrates how to use CoT functionality with tree textual memory.
+It shows how to:
+1. Decompose complex questions into sub-questions
+2. Get answers for sub-questions using tree_textual_memory
+3. Use JSON configuration files with environment variable overrides
+"""
+
+import json
+import os
+
+# Load environment variables
+from dotenv import load_dotenv
+
+from memos.configs.llm import LLMConfigFactory
+from memos.configs.mem_reader import SimpleStructMemReaderConfig
+from memos.configs.memory import TreeTextMemoryConfig
+from memos.mem_os.main import MOS
+from memos.mem_reader.simple_struct import SimpleStructMemReader
+from memos.memories.textual.tree import TreeTextMemory
+
+
+load_dotenv()
+
+
+def load_and_modify_config(config_path: str) -> dict:
+ """Load JSON config and modify it with environment variables."""
+ with open(config_path) as f:
+ config = json.load(f)
+
+ # Get environment variables
+ openai_api_key = os.getenv("OPENAI_API_KEY")
+ openai_base_url = os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1")
+
+ # Modify config to use ollama for embedder and gpt-4o-mini for LLMs
+ if "embedder" in config:
+ config["embedder"] = {
+ "backend": "ollama",
+ "config": {"model_name_or_path": "nomic-embed-text:latest"},
+ }
+
+ # Modify LLM configs to use gpt-4o-mini
+ if "llm" in config:
+ config["llm"] = {
+ "backend": "openai",
+ "config": {
+ "model_name_or_path": "gpt-4o-mini",
+ "api_key": openai_api_key,
+ "api_base": openai_base_url,
+ "temperature": 0.5,
+ "remove_think_prefix": True,
+ "max_tokens": 8192,
+ },
+ }
+
+ if "extractor_llm" in config:
+ config["extractor_llm"] = {
+ "backend": "openai",
+ "config": {
+ "model_name_or_path": "gpt-4o-mini",
+ "api_key": openai_api_key,
+ "api_base": openai_base_url,
+ "temperature": 0.5,
+ "remove_think_prefix": True,
+ "max_tokens": 8192,
+ },
+ }
+
+ if "dispatcher_llm" in config:
+ config["dispatcher_llm"] = {
+ "backend": "openai",
+ "config": {
+ "model_name_or_path": "gpt-4o-mini",
+ "api_key": openai_api_key,
+ "api_base": openai_base_url,
+ "temperature": 0.5,
+ "remove_think_prefix": True,
+ "max_tokens": 8192,
+ },
+ }
+
+ # Modify graph_db config if present
+ if "graph_db" in config:
+ neo4j_uri = os.getenv("NEO4J_URI", "bolt://localhost:7687")
+ neo4j_user = os.getenv("NEO4J_USER", "neo4j")
+ neo4j_password = os.getenv("NEO4J_PASSWORD", "12345678")
+
+ config["graph_db"] = {
+ "backend": "neo4j",
+ "config": {
+ "uri": neo4j_uri,
+ "user": neo4j_user,
+ "password": neo4j_password,
+ "db_name": "testlcy",
+ "auto_create": True,
+ "embedding_dimension": 768,
+ },
+ }
+
+ return config
+
+
+def setup_llm_config():
+ """Setup LLM configuration for CoT operations."""
+ # Get environment variables
+ openai_api_key = os.getenv("OPENAI_API_KEY")
+ openai_base_url = os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1")
+ # Use ollama with gpt-4o-mini model
+ return LLMConfigFactory(
+ backend="openai",
+ config={
+ "model_name_or_path": "gpt-4o-mini",
+ "api_key": openai_api_key,
+ "api_base": openai_base_url,
+ "temperature": 0.5,
+ "remove_think_prefix": True,
+ "max_tokens": 8192,
+ },
+ )
+
+
+def create_tree_memory():
+ """Create a tree textual memory with sample data."""
+ print("Creating tree textual memory...")
+
+ # Load and modify configurations
+ tree_config_dict = load_and_modify_config("examples/data/config/tree_config.json")
+ reader_config_dict = load_and_modify_config(
+ "examples/data/config/simple_struct_reader_config.json"
+ )
+
+ # Create config objects
+ tree_config = TreeTextMemoryConfig.model_validate(tree_config_dict)
+ reader_config = SimpleStructMemReaderConfig.model_validate(reader_config_dict)
+
+ # Create tree memory
+ tree_memory = TreeTextMemory(tree_config)
+ tree_memory.delete_all() # Clear existing data
+
+ # Create memory reader
+ reader = SimpleStructMemReader(reader_config)
+
+ # Sample conversation data
+ sample_conversations = [
+ [
+ {"role": "user", "content": "Tell me about China and its capital."},
+ {
+ "role": "assistant",
+ "content": "China is a country in East Asia. Beijing is its capital city.",
+ },
+ {"role": "user", "content": "Who is Lang Ping?"},
+ {
+ "role": "assistant",
+ "content": "Lang Ping is a famous Chinese volleyball coach and former player.",
+ },
+ {"role": "user", "content": "What about Madagascar?"},
+ {
+ "role": "assistant",
+ "content": "Madagascar is an island country in the Indian Ocean. It's known for its unique wildlife.",
+ },
+ {"role": "user", "content": "Tell me about trade between China and Madagascar."},
+ {
+ "role": "assistant",
+ "content": "China and Madagascar have developed trade relations, particularly in agriculture and mining.",
+ },
+ {"role": "user", "content": "What about the essential oil industry in Madagascar?"},
+ {
+ "role": "assistant",
+ "content": "The essential oil industry is growing in Madagascar, especially on Nosy Be Island where vanilla and ylang-ylang are produced.",
+ },
+ ]
+ ]
+
+ # Acquire memories using the reader
+ memories = reader.get_memory(
+ sample_conversations, type="chat", info={"user_id": "cot_user", "session_id": "cot_session"}
+ )
+
+ # Add memories to tree structure
+ for memory_list in memories:
+ tree_memory.add(memory_list)
+
+ print("✓ Added sample conversations to tree memory")
+ return tree_memory
+
+
+def cot_decompose():
+ """Test the cot_decompose functionality."""
+ print("\n=== Testing CoT Decomposition ===")
+
+ # Setup LLM config
+ llm_config = setup_llm_config()
+
+ # Test questions
+ test_questions = [
+ "Who is the current head coach of the gymnastics team in the capital of the country that Lang Ping represents?",
+ "What is the weather like today?",
+ "How did the trade relationship between Madagascar and China develop, and how does this relationship affect the market expansion of the essential oil industry on Nosy Be Island?",
+ ]
+
+ for i, question in enumerate(test_questions, 1):
+ print(f"\nTest {i}: {question}")
+ result = MOS.cot_decompose(question, llm_config)
+ print(f"✓ Decomposition result: {result}")
+
+ if result.get("is_complex", False):
+ sub_questions = result.get("sub_questions", [])
+ print(f"✓ Found {len(sub_questions)} sub-questions:")
+ for j, sub_q in enumerate(sub_questions, 1):
+ print(f" {j}. {sub_q}")
+ else:
+ print("✓ Question is not complex, no decomposition needed.")
+
+ return llm_config
+
+
+def get_sub_answers_with_tree_memory():
+ """Test get_sub_answers with tree textual memory."""
+ print("\n=== Testing get_sub_answers with Tree Textual Memory ===")
+
+ # Setup
+ llm_config = setup_llm_config()
+ tree_memory = create_tree_memory()
+
+ # Test sub-questions
+ sub_questions = [
+ "Which country does Lang Ping represent in volleyball?",
+ "What is the capital of this country?",
+ "Who is the current head coach of the gymnastics team in this capital?",
+ ]
+
+ print("Sub-questions to answer:")
+ for i, q in enumerate(sub_questions, 1):
+ print(f" {i}. {q}")
+ print("\nGenerating answers using tree memory and LLM...")
+ sub_questions, sub_answers = MOS.get_sub_answers(
+ sub_questions=sub_questions, search_engine=tree_memory, llm_config=llm_config, top_k=3
+ )
+
+ print("✓ Generated answers:")
+ for i, (question, answer) in enumerate(zip(sub_questions, sub_answers, strict=False), 1):
+ print(f"\n Sub-question {i}: {question}")
+ print(f" Answer: {answer}")
+
+
+def complete_cot_workflow():
+ """Test the complete CoT workflow from decomposition to final synthesis."""
+ print("\n=== Testing Complete CoT Workflow ===")
+
+ # Setup
+ llm_config = setup_llm_config()
+ tree_memory = create_tree_memory()
+
+ # Complex question
+ complex_question = "How did the trade relationship between Madagascar and China develop, and how does this relationship affect the market expansion of the essential oil industry on Nosy Be Island?"
+
+ print(f"Original question: {complex_question}")
+
+ try:
+ # Step 1: Decompose the question
+ print("\n1. Decomposing question...")
+ decomposition_result = MOS.cot_decompose(complex_question, llm_config)
+ print(f"✓ Decomposition result: {decomposition_result}")
+
+ if not decomposition_result.get("is_complex", False):
+ print("Question is not complex, no decomposition needed.")
+ return
+
+ sub_questions = decomposition_result.get("sub_questions", [])
+ print(f"✓ Found {len(sub_questions)} sub-questions:")
+ for i, q in enumerate(sub_questions, 1):
+ print(f" {i}. {q}")
+
+ # Step 2: Get answers for sub-questions
+ print("\n2. Getting answers for sub-questions...")
+ sub_questions, sub_answers = MOS.get_sub_answers(
+ sub_questions=sub_questions, search_engine=tree_memory, llm_config=llm_config, top_k=3
+ )
+
+ print("✓ Generated answers:")
+ for i, (question, answer) in enumerate(zip(sub_questions, sub_answers, strict=False), 1):
+ print(f"\n Sub-question {i}: {question}")
+ print(f" Answer: {answer}")
+
+ # Step 3: Generate final synthesis
+ print("\n3. Generating final synthesis...")
+ # Build the sub-questions and answers text
+ qa_text = ""
+ for i, (question, answer) in enumerate(zip(sub_questions, sub_answers, strict=False), 1):
+ qa_text += f"Q{i}: {question}\nA{i}: {answer}\n\n"
+
+ synthesis_prompt = f"""You are an expert at synthesizing information from multiple sources to provide comprehensive answers.
+
+Sub-questions and their answers:
+{qa_text}
+Please synthesize these answers into a comprehensive response that:
+1. Addresses the original question completely
+2. Integrates information from all sub-questions
+3. Provides clear reasoning and connections
+4. Is well-structured and easy to understand
+
+Original question: {complex_question}
+
+Your response:"""
+
+ # Generate final answer
+ from memos.llms.factory import LLMFactory
+
+ llm = LLMFactory.from_config(llm_config)
+ messages = [
+ {
+ "role": "system",
+ "content": "You are a helpful assistant that synthesizes information from multiple sources.",
+ },
+ {"role": "user", "content": synthesis_prompt},
+ ]
+
+ final_answer = llm.generate(messages)
+ print(f"\n✓ Final synthesized answer:\n{final_answer}")
+
+ except Exception as e:
+ print(f"✗ Error in complete workflow: {e}")
+
+
+def main():
+ """Main function to run the CoT example."""
+ print("MemOS CoT (Chain of Thought) Usage Example")
+ print("=" * 60)
+
+ # Run the examples
+ cot_decompose()
+ get_sub_answers_with_tree_memory()
+ complete_cot_workflow()
+
+ print("\n" + "=" * 60)
+ print("✓ All examples completed successfully!")
+
+
+if __name__ == "__main__":
+ main()
diff --git a/examples/mem_os/simple_openapi_memos.py b/examples/mem_os/simple_openapi_memos.py
index e55a250d9..a9faa3dc8 100644
--- a/examples/mem_os/simple_openapi_memos.py
+++ b/examples/mem_os/simple_openapi_memos.py
@@ -1,14 +1,19 @@
+import os
import time
import uuid
from datetime import datetime
+from dotenv import load_dotenv
+
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
+load_dotenv()
+
# 1. Create MOS Config and set openai config
print(f"🚀 [{datetime.now().strftime('%H:%M:%S')}] Starting to create MOS configuration...")
start_time = time.time()
@@ -18,17 +23,17 @@
# 1.1 Set openai config
openapi_config = {
- "model_name_or_path": "gpt-4o",
+ "model_name_or_path": "gpt-4o-mini",
"temperature": 0.8,
"max_tokens": 1024,
"top_p": 0.9,
"top_k": 50,
"remove_think_prefix": True,
- "api_key": "sk-xxxxxx",
- "api_base": "https://api.openai.com/v1",
+ "api_key": os.getenv("OPENAI_API_KEY", "sk-xxxxx"),
+ "api_base": os.getenv("OPENAI_API_BASE", "https://api.openai.com/v1"),
}
# 1.2 Set neo4j config
-neo4j_uri = "bolt://localhost:7687"
+neo4j_uri = os.getenv("NEO4J_URI", "bolt://localhost:7687")
# 1.3 Create MOS Config
config = {
@@ -69,6 +74,7 @@
}
mos_config = MOSConfig(**config)
+# you can set PRO_MODE to True to enable CoT enhancement mos_config.PRO_MODE = True
mos = MOS(mos_config)
print(
diff --git a/examples/mem_os/simple_vllm_memos.py b/examples/mem_os/simple_vllm_memos.py
new file mode 100644
index 000000000..e073526d4
--- /dev/null
+++ b/examples/mem_os/simple_vllm_memos.py
@@ -0,0 +1,80 @@
+#!/usr/bin/env python3
+"""
+Simple example demonstrating how to use VLLMLLM with existing vLLM server.
+Requires a vLLM server to be running on localhost:8088.
+"""
+
+import asyncio
+import sys
+
+from memos.configs.llm import VLLMLLMConfig
+from memos.llms.vllm import VLLMLLM
+from memos.types import MessageList
+
+
+def main():
+ """Main function demonstrating VLLMLLM usage."""
+
+ # Configuration for connecting to existing vLLM server
+ config = VLLMLLMConfig(
+ model_name_or_path="Qwen/Qwen3-1.7B", # Model name (for reference)
+ api_key="", # Not needed for local server
+ api_base="http://localhost:8088", # vLLM server address
+ temperature=0.7,
+ max_tokens=512,
+ top_p=0.9,
+ top_k=50,
+ model_schema="memos.configs.llm.VLLMLLMConfig",
+ )
+
+ # Initialize VLLM LLM
+ print("Initializing VLLM LLM...")
+ llm = VLLMLLM(config)
+
+ # Test messages for KV cache building
+ system_messages: MessageList = [
+ {"role": "system", "content": "You are a helpful AI assistant."},
+ {"role": "user", "content": "Hello! Can you tell me about vLLM?"}
+ ]
+
+ # Build KV cache for system messages
+ print("Building KV cache for system messages...")
+ try:
+ prompt = llm.build_vllm_kv_cache(system_messages)
+ print(f"✓ KV cache built successfully. Prompt length: {len(prompt)}")
+ except Exception as e:
+ print(f"✗ Failed to build KV cache: {e}")
+
+ # Test with different messages
+ user_messages: MessageList = [
+ {"role": "system", "content": "You are a helpful AI assistant."},
+ {"role": "user", "content": "What are the benefits of using vLLM?"}
+ ]
+
+ # Generate response
+ print("\nGenerating response...")
+ try:
+ response = llm.generate(user_messages)
+ print(f"Response: {response}")
+ except Exception as e:
+ print(f"Error generating response: {e}")
+
+ # Test with string input for KV cache
+ print("\nTesting KV cache with string input...")
+ try:
+ string_prompt = llm.build_vllm_kv_cache("You are a helpful assistant.")
+ print(f"✓ String KV cache built successfully. Prompt length: {len(string_prompt)}")
+ except Exception as e:
+ print(f"✗ Failed to build string KV cache: {e}")
+
+ # Test with list of strings input for KV cache
+ print("\nTesting KV cache with list of strings input...")
+ try:
+ list_prompt = llm.build_vllm_kv_cache(["You are helpful.", "You are knowledgeable."])
+ print(f"✓ List KV cache built successfully. Prompt length: {len(list_prompt)}")
+ except Exception as e:
+ print(f"✗ Failed to build list KV cache: {e}")
+
+
+if __name__ == "__main__":
+ main()
\ No newline at end of file
diff --git a/poetry.lock b/poetry.lock
index 533b6b850..0df9b1ddc 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -57,6 +57,32 @@ files = [
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
]
+[[package]]
+name = "anthropic"
+version = "0.57.1"
+description = "The official Python library for the anthropic API"
+optional = false
+python-versions = ">=3.8"
+groups = ["eval"]
+files = [
+ {file = "anthropic-0.57.1-py3-none-any.whl", hash = "sha256:33afc1f395af207d07ff1bffc0a3d1caac53c371793792569c5d2f09283ea306"},
+ {file = "anthropic-0.57.1.tar.gz", hash = "sha256:7815dd92245a70d21f65f356f33fc80c5072eada87fb49437767ea2918b2c4b0"},
+]
+
+[package.dependencies]
+anyio = ">=3.5.0,<5"
+distro = ">=1.7.0,<2"
+httpx = ">=0.25.0,<1"
+jiter = ">=0.4.0,<1"
+pydantic = ">=1.9.0,<3"
+sniffio = "*"
+typing-extensions = ">=4.10,<5"
+
+[package.extras]
+aiohttp = ["aiohttp", "httpx-aiohttp (>=0.1.6)"]
+bedrock = ["boto3 (>=1.28.57)", "botocore (>=1.31.57)"]
+vertex = ["google-auth[requests] (>=2,<3)"]
+
[[package]]
name = "anyio"
version = "4.9.0"
@@ -80,6 +106,19 @@ doc = ["Sphinx (>=8.2,<9.0)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)",
test = ["anyio[trio]", "blockbuster (>=1.5.23)", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "trustme", "truststore (>=0.9.1) ; python_version >= \"3.10\"", "uvloop (>=0.21) ; platform_python_implementation == \"CPython\" and platform_system != \"Windows\" and python_version < \"3.14\""]
trio = ["trio (>=0.26.1)"]
+[[package]]
+name = "async-timeout"
+version = "4.0.3"
+description = "Timeout context manager for asyncio programs"
+optional = false
+python-versions = ">=3.7"
+groups = ["main", "eval"]
+markers = "python_version == \"3.10\""
+files = [
+ {file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"},
+ {file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
+]
+
[[package]]
name = "async-timeout"
version = "5.0.1"
@@ -87,7 +126,7 @@ description = "Timeout context manager for asyncio programs"
optional = false
python-versions = ">=3.8"
groups = ["main"]
-markers = "python_full_version < \"3.11.3\""
+markers = "python_version == \"3.11\" and python_full_version < \"3.11.3\""
files = [
{file = "async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c"},
{file = "async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3"},
@@ -168,8 +207,7 @@ version = "1.17.1"
description = "Foreign Function Interface for Python calling C code."
optional = false
python-versions = ">=3.8"
-groups = ["main"]
-markers = "platform_python_implementation != \"PyPy\""
+groups = ["main", "eval"]
files = [
{file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"},
{file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"},
@@ -239,6 +277,7 @@ files = [
{file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"},
{file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"},
]
+markers = {main = "platform_python_implementation != \"PyPy\"", eval = "platform_python_implementation == \"PyPy\""}
[package.dependencies]
pycparser = "*"
@@ -663,6 +702,24 @@ files = [
[package.dependencies]
python-dotenv = "*"
+[[package]]
+name = "dydantic"
+version = "0.0.8"
+description = "Dynamically generate pydantic models from JSON schema."
+optional = false
+python-versions = "<4.0,>=3.9"
+groups = ["eval"]
+files = [
+ {file = "dydantic-0.0.8-py3-none-any.whl", hash = "sha256:cd0a991f523bd8632699872f1c0c4278415dd04783e36adec5428defa0afb721"},
+ {file = "dydantic-0.0.8.tar.gz", hash = "sha256:14a31d4cdfce314ce3e69e8f8c7c46cbc26ce3ce4485de0832260386c612942f"},
+]
+
+[package.dependencies]
+pydantic = ">=2,<3"
+
+[package.extras]
+email = ["email-validator (>=2.1,<3.0)"]
+
[[package]]
name = "email-validator"
version = "2.2.0"
@@ -1405,6 +1462,33 @@ files = [
{file = "joblib-1.5.1.tar.gz", hash = "sha256:f4f86e351f39fe3d0d32a9f2c3d8af1ee4cec285aafcb27003dda5205576b444"},
]
+[[package]]
+name = "jsonpatch"
+version = "1.33"
+description = "Apply JSON-Patches (RFC 6902)"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*"
+groups = ["eval"]
+files = [
+ {file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"},
+ {file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"},
+]
+
+[package.dependencies]
+jsonpointer = ">=1.9"
+
+[[package]]
+name = "jsonpointer"
+version = "3.0.0"
+description = "Identify specific nodes in a JSON document (RFC 6901)"
+optional = false
+python-versions = ">=3.7"
+groups = ["eval"]
+files = [
+ {file = "jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"},
+ {file = "jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef"},
+]
+
[[package]]
name = "kiwisolver"
version = "1.4.8"
@@ -1495,6 +1579,234 @@ files = [
{file = "kiwisolver-1.4.8.tar.gz", hash = "sha256:23d5f023bdc8c7e54eb65f03ca5d5bb25b601eac4d7f1a042888a1f45237987e"},
]
+[[package]]
+name = "langchain"
+version = "0.3.26"
+description = "Building applications with LLMs through composability"
+optional = false
+python-versions = ">=3.9"
+groups = ["eval"]
+files = [
+ {file = "langchain-0.3.26-py3-none-any.whl", hash = "sha256:361bb2e61371024a8c473da9f9c55f4ee50f269c5ab43afdb2b1309cb7ac36cf"},
+ {file = "langchain-0.3.26.tar.gz", hash = "sha256:8ff034ee0556d3e45eff1f1e96d0d745ced57858414dba7171c8ebdbeb5580c9"},
+]
+
+[package.dependencies]
+async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""}
+langchain-core = ">=0.3.66,<1.0.0"
+langchain-text-splitters = ">=0.3.8,<1.0.0"
+langsmith = ">=0.1.17"
+pydantic = ">=2.7.4,<3.0.0"
+PyYAML = ">=5.3"
+requests = ">=2,<3"
+SQLAlchemy = ">=1.4,<3"
+
+[package.extras]
+anthropic = ["langchain-anthropic"]
+aws = ["langchain-aws"]
+azure-ai = ["langchain-azure-ai"]
+cohere = ["langchain-cohere"]
+community = ["langchain-community"]
+deepseek = ["langchain-deepseek"]
+fireworks = ["langchain-fireworks"]
+google-genai = ["langchain-google-genai"]
+google-vertexai = ["langchain-google-vertexai"]
+groq = ["langchain-groq"]
+huggingface = ["langchain-huggingface"]
+mistralai = ["langchain-mistralai"]
+ollama = ["langchain-ollama"]
+openai = ["langchain-openai"]
+perplexity = ["langchain-perplexity"]
+together = ["langchain-together"]
+xai = ["langchain-xai"]
+
+[[package]]
+name = "langchain-anthropic"
+version = "0.3.17"
+description = "An integration package connecting AnthropicMessages and LangChain"
+optional = false
+python-versions = ">=3.9"
+groups = ["eval"]
+files = [
+ {file = "langchain_anthropic-0.3.17-py3-none-any.whl", hash = "sha256:6df784615b93aab0336fbd6a50ca2bd16a704ef01c9488c36a4fa7aad2faf2d6"},
+ {file = "langchain_anthropic-0.3.17.tar.gz", hash = "sha256:f2c2a0382ed7992204d790ff8538448f5243f4dbb1e798256ef790c9a69033e4"},
+]
+
+[package.dependencies]
+anthropic = ">=0.57.0,<1"
+langchain-core = ">=0.3.68,<1.0.0"
+pydantic = ">=2.7.4,<3.0.0"
+
+[[package]]
+name = "langchain-core"
+version = "0.3.68"
+description = "Building applications with LLMs through composability"
+optional = false
+python-versions = ">=3.9"
+groups = ["eval"]
+files = [
+ {file = "langchain_core-0.3.68-py3-none-any.whl", hash = "sha256:5e5c1fbef419590537c91b8c2d86af896fbcbaf0d5ed7fdcdd77f7d8f3467ba0"},
+ {file = "langchain_core-0.3.68.tar.gz", hash = "sha256:312e1932ac9aa2eaf111b70fdc171776fa571d1a86c1f873dcac88a094b19c6f"},
+]
+
+[package.dependencies]
+jsonpatch = ">=1.33,<2.0"
+langsmith = ">=0.3.45"
+packaging = ">=23.2,<25"
+pydantic = ">=2.7.4"
+PyYAML = ">=5.3"
+tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<10.0.0"
+typing-extensions = ">=4.7"
+
+[[package]]
+name = "langchain-openai"
+version = "0.3.23"
+description = "An integration package connecting OpenAI and LangChain"
+optional = false
+python-versions = ">=3.9"
+groups = ["eval"]
+files = [
+ {file = "langchain_openai-0.3.23-py3-none-any.whl", hash = "sha256:624794394482c0923823f0aac44979968d77fdcfa810e42d4b0abd8096199a40"},
+ {file = "langchain_openai-0.3.23.tar.gz", hash = "sha256:73411c06e04bc145db7146a6fcf33dd0f1a85130499dcae988829a4441ddaa66"},
+]
+
+[package.dependencies]
+langchain-core = ">=0.3.65,<1.0.0"
+openai = ">=1.68.2,<2.0.0"
+tiktoken = ">=0.7,<1"
+
+[[package]]
+name = "langchain-text-splitters"
+version = "0.3.8"
+description = "LangChain text splitting utilities"
+optional = false
+python-versions = "<4.0,>=3.9"
+groups = ["eval"]
+files = [
+ {file = "langchain_text_splitters-0.3.8-py3-none-any.whl", hash = "sha256:e75cc0f4ae58dcf07d9f18776400cf8ade27fadd4ff6d264df6278bb302f6f02"},
+ {file = "langchain_text_splitters-0.3.8.tar.gz", hash = "sha256:116d4b9f2a22dda357d0b79e30acf005c5518177971c66a9f1ab0edfdb0f912e"},
+]
+
+[package.dependencies]
+langchain-core = ">=0.3.51,<1.0.0"
+
+[[package]]
+name = "langgraph"
+version = "0.5.1"
+description = "Building stateful, multi-actor applications with LLMs"
+optional = false
+python-versions = ">=3.9"
+groups = ["eval"]
+files = [
+ {file = "langgraph-0.5.1-py3-none-any.whl", hash = "sha256:707f0cc0d2713011fff4578bf57de8226cd96bcc0679868be2f41eb0984bb5af"},
+ {file = "langgraph-0.5.1.tar.gz", hash = "sha256:312d341979e38034dde60e08df53505b8a196619df1266d6eacf6b002a0a65a8"},
+]
+
+[package.dependencies]
+langchain-core = ">=0.1"
+langgraph-checkpoint = ">=2.1.0,<3.0.0"
+langgraph-prebuilt = ">=0.5.0,<0.6.0"
+langgraph-sdk = ">=0.1.42,<0.2.0"
+pydantic = ">=2.7.4"
+xxhash = ">=3.5.0"
+
+[[package]]
+name = "langgraph-checkpoint"
+version = "2.1.0"
+description = "Library with base interfaces for LangGraph checkpoint savers."
+optional = false
+python-versions = ">=3.9"
+groups = ["eval"]
+files = [
+ {file = "langgraph_checkpoint-2.1.0-py3-none-any.whl", hash = "sha256:4cea3e512081da1241396a519cbfe4c5d92836545e2c64e85b6f5c34a1b8bc61"},
+ {file = "langgraph_checkpoint-2.1.0.tar.gz", hash = "sha256:cdaa2f0b49aa130ab185c02d82f02b40299a1fbc9ac59ac20cecce09642a1abe"},
+]
+
+[package.dependencies]
+langchain-core = ">=0.2.38"
+ormsgpack = ">=1.10.0"
+
+[[package]]
+name = "langgraph-prebuilt"
+version = "0.5.2"
+description = "Library with high-level APIs for creating and executing LangGraph agents and tools."
+optional = false
+python-versions = ">=3.9"
+groups = ["eval"]
+files = [
+ {file = "langgraph_prebuilt-0.5.2-py3-none-any.whl", hash = "sha256:1f4cd55deca49dffc3e5127eec12fcd244fc381321002f728afa88642d5ec59d"},
+ {file = "langgraph_prebuilt-0.5.2.tar.gz", hash = "sha256:2c900a5be0d6a93ea2521e0d931697cad2b646f1fcda7aa5c39d8d7539772465"},
+]
+
+[package.dependencies]
+langchain-core = ">=0.3.67"
+langgraph-checkpoint = ">=2.1.0"
+
+[[package]]
+name = "langgraph-sdk"
+version = "0.1.72"
+description = "SDK for interacting with LangGraph API"
+optional = false
+python-versions = ">=3.9"
+groups = ["eval"]
+files = [
+ {file = "langgraph_sdk-0.1.72-py3-none-any.whl", hash = "sha256:925d3fcc7a26361db04f9c4beb3ec05bc36361b2a836d181ff2ab145071ec3ce"},
+ {file = "langgraph_sdk-0.1.72.tar.gz", hash = "sha256:396d8195881830700e2d54a0a9ee273e8b1173428e667502ef9c182a3cec7ab7"},
+]
+
+[package.dependencies]
+httpx = ">=0.25.2"
+orjson = ">=3.10.1"
+
+[[package]]
+name = "langmem"
+version = "0.0.27"
+description = "Prebuilt utilities for memory management and retrieval."
+optional = false
+python-versions = ">=3.10"
+groups = ["eval"]
+files = [
+ {file = "langmem-0.0.27-py3-none-any.whl", hash = "sha256:25e9f06ad7c420442cf4b62caff6f805b124dfb2e2cc9cacc464d7a455fbafda"},
+ {file = "langmem-0.0.27.tar.gz", hash = "sha256:729c1eb77c4cd8d9f2285f908a68a1e622ef01f074eeeb8cbbc7343f296efc53"},
+]
+
+[package.dependencies]
+langchain = ">=0.3.15"
+langchain-anthropic = ">=0.3.3"
+langchain-core = ">=0.3.46"
+langchain-openai = ">=0.3.1"
+langgraph = ">=0.3.23"
+langgraph-checkpoint = ">=2.0.12"
+langsmith = ">=0.3.8"
+trustcall = ">=0.0.39"
+
+[[package]]
+name = "langsmith"
+version = "0.4.4"
+description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform."
+optional = false
+python-versions = ">=3.9"
+groups = ["eval"]
+files = [
+ {file = "langsmith-0.4.4-py3-none-any.whl", hash = "sha256:014c68329bd085bd6c770a6405c61bb6881f82eb554ce8c4d1984b0035fd1716"},
+ {file = "langsmith-0.4.4.tar.gz", hash = "sha256:70c53bbff24a7872e88e6fa0af98270f4986a6e364f9e85db1cc5636defa4d66"},
+]
+
+[package.dependencies]
+httpx = ">=0.23.0,<1"
+orjson = {version = ">=3.9.14,<4.0.0", markers = "platform_python_implementation != \"PyPy\""}
+packaging = ">=23.2"
+pydantic = ">=1,<3"
+requests = ">=2,<3"
+requests-toolbelt = ">=1.0.0,<2.0.0"
+zstandard = ">=0.23.0,<0.24.0"
+
+[package.extras]
+langsmith-pyo3 = ["langsmith-pyo3 (>=0.1.0rc2,<0.2.0)"]
+openai-agents = ["openai-agents (>=0.0.3,<0.1)"]
+otel = ["opentelemetry-api (>=1.30.0,<2.0.0)", "opentelemetry-exporter-otlp-proto-http (>=1.30.0,<2.0.0)", "opentelemetry-sdk (>=1.30.0,<2.0.0)"]
+pytest = ["pytest (>=7.0.0)", "rich (>=13.9.4,<14.0.0)"]
+
[[package]]
name = "lxml"
version = "5.4.0"
@@ -2437,7 +2749,7 @@ version = "3.10.18"
description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy"
optional = false
python-versions = ">=3.9"
-groups = ["main"]
+groups = ["main", "eval"]
files = [
{file = "orjson-3.10.18-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a45e5d68066b408e4bc383b6e4ef05e717c65219a9e1390abc6155a520cac402"},
{file = "orjson-3.10.18-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be3b9b143e8b9db05368b13b04c84d37544ec85bb97237b3a923f076265ec89c"},
@@ -2513,16 +2825,67 @@ files = [
{file = "orjson-3.10.18.tar.gz", hash = "sha256:e8da3947d92123eda795b68228cafe2724815621fe35e8e320a9e9593a4bcd53"},
]
+[[package]]
+name = "ormsgpack"
+version = "1.10.0"
+description = "Fast, correct Python msgpack library supporting dataclasses, datetimes, and numpy"
+optional = false
+python-versions = ">=3.9"
+groups = ["eval"]
+files = [
+ {file = "ormsgpack-1.10.0-cp310-cp310-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8a52c7ce7659459f3dc8dec9fd6a6c76f855a0a7e2b61f26090982ac10b95216"},
+ {file = "ormsgpack-1.10.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:060f67fe927582f4f63a1260726d019204b72f460cf20930e6c925a1d129f373"},
+ {file = "ormsgpack-1.10.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7058ef6092f995561bf9f71d6c9a4da867b6cc69d2e94cb80184f579a3ceed5"},
+ {file = "ormsgpack-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f6f3509c1b0e51b15552d314b1d409321718122e90653122ce4b997f01453a"},
+ {file = "ormsgpack-1.10.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:51c1edafd5c72b863b1f875ec31c529f09c872a5ff6fe473b9dfaf188ccc3227"},
+ {file = "ormsgpack-1.10.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c780b44107a547a9e9327270f802fa4d6b0f6667c9c03c3338c0ce812259a0f7"},
+ {file = "ormsgpack-1.10.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:137aab0d5cdb6df702da950a80405eb2b7038509585e32b4e16289604ac7cb84"},
+ {file = "ormsgpack-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:3e666cb63030538fa5cd74b1e40cb55b6fdb6e2981f024997a288bf138ebad07"},
+ {file = "ormsgpack-1.10.0-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4bb7df307e17b36cbf7959cd642c47a7f2046ae19408c564e437f0ec323a7775"},
+ {file = "ormsgpack-1.10.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8817ae439c671779e1127ee62f0ac67afdeaeeacb5f0db45703168aa74a2e4af"},
+ {file = "ormsgpack-1.10.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2f345f81e852035d80232e64374d3a104139d60f8f43c6c5eade35c4bac5590e"},
+ {file = "ormsgpack-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21de648a1c7ef692bdd287fb08f047bd5371d7462504c0a7ae1553c39fee35e3"},
+ {file = "ormsgpack-1.10.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3a7d844ae9cbf2112c16086dd931b2acefce14cefd163c57db161170c2bfa22b"},
+ {file = "ormsgpack-1.10.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e4d80585403d86d7f800cf3d0aafac1189b403941e84e90dd5102bb2b92bf9d5"},
+ {file = "ormsgpack-1.10.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:da1de515a87e339e78a3ccf60e39f5fb740edac3e9e82d3c3d209e217a13ac08"},
+ {file = "ormsgpack-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:57c4601812684024132cbb32c17a7d4bb46ffc7daf2fddf5b697391c2c4f142a"},
+ {file = "ormsgpack-1.10.0-cp312-cp312-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:4e159d50cd4064d7540e2bc6a0ab66eab70b0cc40c618b485324ee17037527c0"},
+ {file = "ormsgpack-1.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eeb47c85f3a866e29279d801115b554af0fefc409e2ed8aa90aabfa77efe5cc6"},
+ {file = "ormsgpack-1.10.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c28249574934534c9bd5dce5485c52f21bcea0ee44d13ece3def6e3d2c3798b5"},
+ {file = "ormsgpack-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1957dcadbb16e6a981cd3f9caef9faf4c2df1125e2a1b702ee8236a55837ce07"},
+ {file = "ormsgpack-1.10.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3b29412558c740bf6bac156727aa85ac67f9952cd6f071318f29ee72e1a76044"},
+ {file = "ormsgpack-1.10.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6933f350c2041ec189fe739f0ba7d6117c8772f5bc81f45b97697a84d03020dd"},
+ {file = "ormsgpack-1.10.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9a86de06d368fcc2e58b79dece527dc8ca831e0e8b9cec5d6e633d2777ec93d0"},
+ {file = "ormsgpack-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:35fa9f81e5b9a0dab42e09a73f7339ecffdb978d6dbf9deb2ecf1e9fc7808722"},
+ {file = "ormsgpack-1.10.0-cp313-cp313-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:8d816d45175a878993b7372bd5408e0f3ec5a40f48e2d5b9d8f1cc5d31b61f1f"},
+ {file = "ormsgpack-1.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a90345ccb058de0f35262893751c603b6376b05f02be2b6f6b7e05d9dd6d5643"},
+ {file = "ormsgpack-1.10.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:144b5e88f1999433e54db9d637bae6fe21e935888be4e3ac3daecd8260bd454e"},
+ {file = "ormsgpack-1.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2190b352509d012915921cca76267db136cd026ddee42f1b0d9624613cc7058c"},
+ {file = "ormsgpack-1.10.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:86fd9c1737eaba43d3bb2730add9c9e8b5fbed85282433705dd1b1e88ea7e6fb"},
+ {file = "ormsgpack-1.10.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:33afe143a7b61ad21bb60109a86bb4e87fec70ef35db76b89c65b17e32da7935"},
+ {file = "ormsgpack-1.10.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f23d45080846a7b90feabec0d330a9cc1863dc956728412e4f7986c80ab3a668"},
+ {file = "ormsgpack-1.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:534d18acb805c75e5fba09598bf40abe1851c853247e61dda0c01f772234da69"},
+ {file = "ormsgpack-1.10.0-cp39-cp39-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:efdb25cf6d54085f7ae557268d59fd2d956f1a09a340856e282d2960fe929f32"},
+ {file = "ormsgpack-1.10.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddfcb30d4b1be2439836249d675f297947f4fb8efcd3eeb6fd83021d773cadc4"},
+ {file = "ormsgpack-1.10.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee0944b6ccfd880beb1ca29f9442a774683c366f17f4207f8b81c5e24cadb453"},
+ {file = "ormsgpack-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35cdff6a0d3ba04e40a751129763c3b9b57a602c02944138e4b760ec99ae80a1"},
+ {file = "ormsgpack-1.10.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:599ccdabc19c618ef5de6e6f2e7f5d48c1f531a625fa6772313b8515bc710681"},
+ {file = "ormsgpack-1.10.0-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:bf46f57da9364bd5eefd92365c1b78797f56c6f780581eecd60cd7b367f9b4d3"},
+ {file = "ormsgpack-1.10.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b796f64fdf823dedb1e35436a4a6f889cf78b1aa42d3097c66e5adfd8c3bd72d"},
+ {file = "ormsgpack-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:106253ac9dc08520951e556b3c270220fcb8b4fef0d30b71eedac4befa4de749"},
+ {file = "ormsgpack-1.10.0.tar.gz", hash = "sha256:7f7a27efd67ef22d7182ec3b7fa7e9d147c3ad9be2a24656b23c989077e08b16"},
+]
+
[[package]]
name = "packaging"
-version = "25.0"
+version = "24.2"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.8"
groups = ["main", "eval", "test"]
files = [
- {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"},
- {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"},
+ {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"},
+ {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"},
]
[[package]]
@@ -2878,23 +3241,23 @@ version = "2.22"
description = "C parser in Python"
optional = false
python-versions = ">=3.8"
-groups = ["main"]
-markers = "platform_python_implementation != \"PyPy\""
+groups = ["main", "eval"]
files = [
{file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
{file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
]
+markers = {main = "platform_python_implementation != \"PyPy\"", eval = "platform_python_implementation == \"PyPy\""}
[[package]]
name = "pydantic"
-version = "2.11.4"
+version = "2.11.7"
description = "Data validation using Python type hints"
optional = false
python-versions = ">=3.9"
groups = ["main", "eval"]
files = [
- {file = "pydantic-2.11.4-py3-none-any.whl", hash = "sha256:d9615eaa9ac5a063471da949c8fc16376a84afb5024688b3ff885693506764eb"},
- {file = "pydantic-2.11.4.tar.gz", hash = "sha256:32738d19d63a226a52eed76645a98ee07c1f410ee41d93b4afbfa85ed8111c2d"},
+ {file = "pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b"},
+ {file = "pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db"},
]
[package.dependencies]
@@ -3172,14 +3535,14 @@ six = ">=1.5"
[[package]]
name = "python-dotenv"
-version = "1.1.0"
+version = "1.1.1"
description = "Read key-value pairs from a .env file and set them as environment variables"
optional = false
python-versions = ">=3.9"
groups = ["main", "eval"]
files = [
- {file = "python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d"},
- {file = "python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5"},
+ {file = "python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc"},
+ {file = "python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab"},
]
[package.extras]
@@ -3492,6 +3855,21 @@ urllib3 = ">=1.21.1,<3"
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
+[[package]]
+name = "requests-toolbelt"
+version = "1.0.0"
+description = "A utility belt for advanced users of python-requests"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
+groups = ["eval"]
+files = [
+ {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"},
+ {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"},
+]
+
+[package.dependencies]
+requests = ">=2.0.1,<3.0.0"
+
[[package]]
name = "rich"
version = "14.0.0"
@@ -3612,6 +3990,21 @@ tensorflow = ["safetensors[numpy]", "tensorflow (>=2.11.0)"]
testing = ["h5py (>=3.7.0)", "huggingface-hub (>=0.12.1)", "hypothesis (>=6.70.2)", "pytest (>=7.2.0)", "pytest-benchmark (>=4.0.0)", "safetensors[numpy]", "setuptools-rust (>=1.5.2)"]
torch = ["safetensors[numpy]", "torch (>=1.10)"]
+[[package]]
+name = "schedule"
+version = "1.2.2"
+description = "Job scheduling for humans."
+optional = false
+python-versions = ">=3.7"
+groups = ["main"]
+files = [
+ {file = "schedule-1.2.2-py3-none-any.whl", hash = "sha256:5bef4a2a0183abf44046ae0d164cadcac21b1db011bdd8102e4a0c1e91e06a7d"},
+ {file = "schedule-1.2.2.tar.gz", hash = "sha256:15fe9c75fe5fd9b9627f3f19cc0ef1420508f9f9a46f45cd0769ef75ede5f0b7"},
+]
+
+[package.extras]
+timezone = ["pytz"]
+
[[package]]
name = "scikit-learn"
version = "1.7.0"
@@ -3668,7 +4061,8 @@ version = "1.15.3"
description = "Fundamental algorithms for scientific computing in Python"
optional = false
python-versions = ">=3.10"
-groups = ["main"]
+groups = ["main", "eval"]
+markers = "python_version == \"3.10\""
files = [
{file = "scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c"},
{file = "scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253"},
@@ -3726,6 +4120,62 @@ dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodest
doc = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.0.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"]
test = ["Cython", "array-api-strict (>=2.0,<2.1.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja ; sys_platform != \"emscripten\"", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"]
+[[package]]
+name = "scipy"
+version = "1.16.0"
+description = "Fundamental algorithms for scientific computing in Python"
+optional = false
+python-versions = ">=3.11"
+groups = ["main", "eval"]
+markers = "python_version >= \"3.11\""
+files = [
+ {file = "scipy-1.16.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:deec06d831b8f6b5fb0b652433be6a09db29e996368ce5911faf673e78d20085"},
+ {file = "scipy-1.16.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:d30c0fe579bb901c61ab4bb7f3eeb7281f0d4c4a7b52dbf563c89da4fd2949be"},
+ {file = "scipy-1.16.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:b2243561b45257f7391d0f49972fca90d46b79b8dbcb9b2cb0f9df928d370ad4"},
+ {file = "scipy-1.16.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:e6d7dfc148135e9712d87c5f7e4f2ddc1304d1582cb3a7d698bbadedb61c7afd"},
+ {file = "scipy-1.16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:90452f6a9f3fe5a2cf3748e7be14f9cc7d9b124dce19667b54f5b429d680d539"},
+ {file = "scipy-1.16.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a2f0bf2f58031c8701a8b601df41701d2a7be17c7ffac0a4816aeba89c4cdac8"},
+ {file = "scipy-1.16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c4abb4c11fc0b857474241b812ce69ffa6464b4bd8f4ecb786cf240367a36a7"},
+ {file = "scipy-1.16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b370f8f6ac6ef99815b0d5c9f02e7ade77b33007d74802efc8316c8db98fd11e"},
+ {file = "scipy-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:a16ba90847249bedce8aa404a83fb8334b825ec4a8e742ce6012a7a5e639f95c"},
+ {file = "scipy-1.16.0-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:7eb6bd33cef4afb9fa5f1fb25df8feeb1e52d94f21a44f1d17805b41b1da3180"},
+ {file = "scipy-1.16.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:1dbc8fdba23e4d80394ddfab7a56808e3e6489176d559c6c71935b11a2d59db1"},
+ {file = "scipy-1.16.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:7dcf42c380e1e3737b343dec21095c9a9ad3f9cbe06f9c05830b44b1786c9e90"},
+ {file = "scipy-1.16.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:26ec28675f4a9d41587266084c626b02899db373717d9312fa96ab17ca1ae94d"},
+ {file = "scipy-1.16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:952358b7e58bd3197cfbd2f2f2ba829f258404bdf5db59514b515a8fe7a36c52"},
+ {file = "scipy-1.16.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:03931b4e870c6fef5b5c0970d52c9f6ddd8c8d3e934a98f09308377eba6f3824"},
+ {file = "scipy-1.16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:512c4f4f85912767c351a0306824ccca6fd91307a9f4318efe8fdbd9d30562ef"},
+ {file = "scipy-1.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e69f798847e9add03d512eaf5081a9a5c9a98757d12e52e6186ed9681247a1ac"},
+ {file = "scipy-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:adf9b1999323ba335adc5d1dc7add4781cb5a4b0ef1e98b79768c05c796c4e49"},
+ {file = "scipy-1.16.0-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:e9f414cbe9ca289a73e0cc92e33a6a791469b6619c240aa32ee18abdce8ab451"},
+ {file = "scipy-1.16.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:bbba55fb97ba3cdef9b1ee973f06b09d518c0c7c66a009c729c7d1592be1935e"},
+ {file = "scipy-1.16.0-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:58e0d4354eacb6004e7aa1cd350e5514bd0270acaa8d5b36c0627bb3bb486974"},
+ {file = "scipy-1.16.0-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:75b2094ec975c80efc273567436e16bb794660509c12c6a31eb5c195cbf4b6dc"},
+ {file = "scipy-1.16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6b65d232157a380fdd11a560e7e21cde34fdb69d65c09cb87f6cc024ee376351"},
+ {file = "scipy-1.16.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d8747f7736accd39289943f7fe53a8333be7f15a82eea08e4afe47d79568c32"},
+ {file = "scipy-1.16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:eb9f147a1b8529bb7fec2a85cf4cf42bdfadf9e83535c309a11fdae598c88e8b"},
+ {file = "scipy-1.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:d2b83c37edbfa837a8923d19c749c1935ad3d41cf196006a24ed44dba2ec4358"},
+ {file = "scipy-1.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:79a3c13d43c95aa80b87328a46031cf52508cf5f4df2767602c984ed1d3c6bbe"},
+ {file = "scipy-1.16.0-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:f91b87e1689f0370690e8470916fe1b2308e5b2061317ff76977c8f836452a47"},
+ {file = "scipy-1.16.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:88a6ca658fb94640079e7a50b2ad3b67e33ef0f40e70bdb7dc22017dae73ac08"},
+ {file = "scipy-1.16.0-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:ae902626972f1bd7e4e86f58fd72322d7f4ec7b0cfc17b15d4b7006efc385176"},
+ {file = "scipy-1.16.0-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:8cb824c1fc75ef29893bc32b3ddd7b11cf9ab13c1127fe26413a05953b8c32ed"},
+ {file = "scipy-1.16.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:de2db7250ff6514366a9709c2cba35cb6d08498e961cba20d7cff98a7ee88938"},
+ {file = "scipy-1.16.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e85800274edf4db8dd2e4e93034f92d1b05c9421220e7ded9988b16976f849c1"},
+ {file = "scipy-1.16.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4f720300a3024c237ace1cb11f9a84c38beb19616ba7c4cdcd771047a10a1706"},
+ {file = "scipy-1.16.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:aad603e9339ddb676409b104c48a027e9916ce0d2838830691f39552b38a352e"},
+ {file = "scipy-1.16.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f56296fefca67ba605fd74d12f7bd23636267731a72cb3947963e76b8c0a25db"},
+ {file = "scipy-1.16.0.tar.gz", hash = "sha256:b5ef54021e832869c8cfb03bc3bf20366cbcd426e02a58e8a58d7584dfbb8f62"},
+]
+
+[package.dependencies]
+numpy = ">=1.25.2,<2.6"
+
+[package.extras]
+dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"]
+doc = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "linkify-it-py", "matplotlib (>=3.5)", "myst-nb (>=1.2.0)", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.2.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"]
+test = ["Cython", "array-api-strict (>=2.3.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja ; sys_platform != \"emscripten\"", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"]
+
[[package]]
name = "sentence-transformers"
version = "4.1.0"
@@ -3963,7 +4413,7 @@ version = "9.1.2"
description = "Retry code until it succeeds"
optional = false
python-versions = ">=3.9"
-groups = ["main"]
+groups = ["main", "eval"]
files = [
{file = "tenacity-9.1.2-py3-none-any.whl", hash = "sha256:f77bf36710d8b73a50b2dd155c97b870017ad21afe6ab300326b0371b3b05138"},
{file = "tenacity-9.1.2.tar.gz", hash = "sha256:1169d376c297e7de388d18b4481760d478b0e99a777cad3a9c86e556f4b697cb"},
@@ -3985,6 +4435,54 @@ files = [
{file = "threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e"},
]
+[[package]]
+name = "tiktoken"
+version = "0.9.0"
+description = "tiktoken is a fast BPE tokeniser for use with OpenAI's models"
+optional = false
+python-versions = ">=3.9"
+groups = ["eval"]
+files = [
+ {file = "tiktoken-0.9.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:586c16358138b96ea804c034b8acf3f5d3f0258bd2bc3b0227af4af5d622e382"},
+ {file = "tiktoken-0.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d9c59ccc528c6c5dd51820b3474402f69d9a9e1d656226848ad68a8d5b2e5108"},
+ {file = "tiktoken-0.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0968d5beeafbca2a72c595e8385a1a1f8af58feaebb02b227229b69ca5357fd"},
+ {file = "tiktoken-0.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92a5fb085a6a3b7350b8fc838baf493317ca0e17bd95e8642f95fc69ecfed1de"},
+ {file = "tiktoken-0.9.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15a2752dea63d93b0332fb0ddb05dd909371ededa145fe6a3242f46724fa7990"},
+ {file = "tiktoken-0.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:26113fec3bd7a352e4b33dbaf1bd8948de2507e30bd95a44e2b1156647bc01b4"},
+ {file = "tiktoken-0.9.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f32cc56168eac4851109e9b5d327637f15fd662aa30dd79f964b7c39fbadd26e"},
+ {file = "tiktoken-0.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:45556bc41241e5294063508caf901bf92ba52d8ef9222023f83d2483a3055348"},
+ {file = "tiktoken-0.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03935988a91d6d3216e2ec7c645afbb3d870b37bcb67ada1943ec48678e7ee33"},
+ {file = "tiktoken-0.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b3d80aad8d2c6b9238fc1a5524542087c52b860b10cbf952429ffb714bc1136"},
+ {file = "tiktoken-0.9.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b2a21133be05dc116b1d0372af051cd2c6aa1d2188250c9b553f9fa49301b336"},
+ {file = "tiktoken-0.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:11a20e67fdf58b0e2dea7b8654a288e481bb4fc0289d3ad21291f8d0849915fb"},
+ {file = "tiktoken-0.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e88f121c1c22b726649ce67c089b90ddda8b9662545a8aeb03cfef15967ddd03"},
+ {file = "tiktoken-0.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a6600660f2f72369acb13a57fb3e212434ed38b045fd8cc6cdd74947b4b5d210"},
+ {file = "tiktoken-0.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95e811743b5dfa74f4b227927ed86cbc57cad4df859cb3b643be797914e41794"},
+ {file = "tiktoken-0.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99376e1370d59bcf6935c933cb9ba64adc29033b7e73f5f7569f3aad86552b22"},
+ {file = "tiktoken-0.9.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:badb947c32739fb6ddde173e14885fb3de4d32ab9d8c591cbd013c22b4c31dd2"},
+ {file = "tiktoken-0.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:5a62d7a25225bafed786a524c1b9f0910a1128f4232615bf3f8257a73aaa3b16"},
+ {file = "tiktoken-0.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2b0e8e05a26eda1249e824156d537015480af7ae222ccb798e5234ae0285dbdb"},
+ {file = "tiktoken-0.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:27d457f096f87685195eea0165a1807fae87b97b2161fe8c9b1df5bd74ca6f63"},
+ {file = "tiktoken-0.9.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cf8ded49cddf825390e36dd1ad35cd49589e8161fdcb52aa25f0583e90a3e01"},
+ {file = "tiktoken-0.9.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc156cb314119a8bb9748257a2eaebd5cc0753b6cb491d26694ed42fc7cb3139"},
+ {file = "tiktoken-0.9.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cd69372e8c9dd761f0ab873112aba55a0e3e506332dd9f7522ca466e817b1b7a"},
+ {file = "tiktoken-0.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:5ea0edb6f83dc56d794723286215918c1cde03712cbbafa0348b33448faf5b95"},
+ {file = "tiktoken-0.9.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c6386ca815e7d96ef5b4ac61e0048cd32ca5a92d5781255e13b31381d28667dc"},
+ {file = "tiktoken-0.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:75f6d5db5bc2c6274b674ceab1615c1778e6416b14705827d19b40e6355f03e0"},
+ {file = "tiktoken-0.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e15b16f61e6f4625a57a36496d28dd182a8a60ec20a534c5343ba3cafa156ac7"},
+ {file = "tiktoken-0.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebcec91babf21297022882344c3f7d9eed855931466c3311b1ad6b64befb3df"},
+ {file = "tiktoken-0.9.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e5fd49e7799579240f03913447c0cdfa1129625ebd5ac440787afc4345990427"},
+ {file = "tiktoken-0.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:26242ca9dc8b58e875ff4ca078b9a94d2f0813e6a535dcd2205df5d49d927cc7"},
+ {file = "tiktoken-0.9.0.tar.gz", hash = "sha256:d02a5ca6a938e0490e1ff957bc48c8b078c88cb83977be1625b1fd8aac792c5d"},
+]
+
+[package.dependencies]
+regex = ">=2022.1.18"
+requests = ">=2.26.0"
+
+[package.extras]
+blobfile = ["blobfile (>=2)"]
+
[[package]]
name = "tokenizers"
version = "0.21.1"
@@ -4243,6 +4741,23 @@ build = ["cmake (>=3.20)", "lit"]
tests = ["autopep8", "isort", "llnl-hatchet", "numpy", "pytest", "pytest-forked", "pytest-xdist", "scipy (>=1.7.1)"]
tutorials = ["matplotlib", "pandas", "tabulate"]
+[[package]]
+name = "trustcall"
+version = "0.0.39"
+description = "Tenacious & trustworthy tool calling built on LangGraph."
+optional = false
+python-versions = "<4.0,>=3.10"
+groups = ["eval"]
+files = [
+ {file = "trustcall-0.0.39-py3-none-any.whl", hash = "sha256:d7da42e0bba816c0539b2936dfed90ffb3ea8d789e548e73865d416f8ac4ee64"},
+ {file = "trustcall-0.0.39.tar.gz", hash = "sha256:ec315818224501b9537ce6b7618dbc21be41210c6e8f2e239169a5a00912cd6e"},
+]
+
+[package.dependencies]
+dydantic = ">=0.0.8,<1.0.0"
+jsonpatch = ">=1.33,<2.0"
+langgraph = ">=0.2.25"
+
[[package]]
name = "typer"
version = "0.16.0"
@@ -4734,6 +5249,139 @@ files = [
{file = "xlsxwriter-3.2.3.tar.gz", hash = "sha256:ad6fd41bdcf1b885876b1f6b7087560aecc9ae5a9cc2ba97dcac7ab2e210d3d5"},
]
+[[package]]
+name = "xxhash"
+version = "3.5.0"
+description = "Python binding for xxHash"
+optional = false
+python-versions = ">=3.7"
+groups = ["eval"]
+files = [
+ {file = "xxhash-3.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ece616532c499ee9afbb83078b1b952beffef121d989841f7f4b3dc5ac0fd212"},
+ {file = "xxhash-3.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3171f693dbc2cef6477054a665dc255d996646b4023fe56cb4db80e26f4cc520"},
+ {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7c5d3e570ef46adaf93fc81b44aca6002b5a4d8ca11bd0580c07eac537f36680"},
+ {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7cb29a034301e2982df8b1fe6328a84f4b676106a13e9135a0d7e0c3e9f806da"},
+ {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d0d307d27099bb0cbeea7260eb39ed4fdb99c5542e21e94bb6fd29e49c57a23"},
+ {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0342aafd421795d740e514bc9858ebddfc705a75a8c5046ac56d85fe97bf196"},
+ {file = "xxhash-3.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3dbbd9892c5ebffeca1ed620cf0ade13eb55a0d8c84e0751a6653adc6ac40d0c"},
+ {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:4cc2d67fdb4d057730c75a64c5923abfa17775ae234a71b0200346bfb0a7f482"},
+ {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ec28adb204b759306a3d64358a5e5c07d7b1dd0ccbce04aa76cb9377b7b70296"},
+ {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:1328f6d8cca2b86acb14104e381225a3d7b42c92c4b86ceae814e5c400dbb415"},
+ {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8d47ebd9f5d9607fd039c1fbf4994e3b071ea23eff42f4ecef246ab2b7334198"},
+ {file = "xxhash-3.5.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b96d559e0fcddd3343c510a0fe2b127fbff16bf346dd76280b82292567523442"},
+ {file = "xxhash-3.5.0-cp310-cp310-win32.whl", hash = "sha256:61c722ed8d49ac9bc26c7071eeaa1f6ff24053d553146d5df031802deffd03da"},
+ {file = "xxhash-3.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:9bed5144c6923cc902cd14bb8963f2d5e034def4486ab0bbe1f58f03f042f9a9"},
+ {file = "xxhash-3.5.0-cp310-cp310-win_arm64.whl", hash = "sha256:893074d651cf25c1cc14e3bea4fceefd67f2921b1bb8e40fcfeba56820de80c6"},
+ {file = "xxhash-3.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:02c2e816896dc6f85922ced60097bcf6f008dedfc5073dcba32f9c8dd786f3c1"},
+ {file = "xxhash-3.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6027dcd885e21581e46d3c7f682cfb2b870942feeed58a21c29583512c3f09f8"},
+ {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1308fa542bbdbf2fa85e9e66b1077eea3a88bef38ee8a06270b4298a7a62a166"},
+ {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c28b2fdcee797e1c1961cd3bcd3d545cab22ad202c846235197935e1df2f8ef7"},
+ {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:924361811732ddad75ff23e90efd9ccfda4f664132feecb90895bade6a1b4623"},
+ {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:89997aa1c4b6a5b1e5b588979d1da048a3c6f15e55c11d117a56b75c84531f5a"},
+ {file = "xxhash-3.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:685c4f4e8c59837de103344eb1c8a3851f670309eb5c361f746805c5471b8c88"},
+ {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dbd2ecfbfee70bc1a4acb7461fa6af7748ec2ab08ac0fa298f281c51518f982c"},
+ {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:25b5a51dc3dfb20a10833c8eee25903fd2e14059e9afcd329c9da20609a307b2"},
+ {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a8fb786fb754ef6ff8c120cb96629fb518f8eb5a61a16aac3a979a9dbd40a084"},
+ {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:a905ad00ad1e1c34fe4e9d7c1d949ab09c6fa90c919860c1534ff479f40fd12d"},
+ {file = "xxhash-3.5.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:963be41bcd49f53af6d795f65c0da9b4cc518c0dd9c47145c98f61cb464f4839"},
+ {file = "xxhash-3.5.0-cp311-cp311-win32.whl", hash = "sha256:109b436096d0a2dd039c355fa3414160ec4d843dfecc64a14077332a00aeb7da"},
+ {file = "xxhash-3.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:b702f806693201ad6c0a05ddbbe4c8f359626d0b3305f766077d51388a6bac58"},
+ {file = "xxhash-3.5.0-cp311-cp311-win_arm64.whl", hash = "sha256:c4dcb4120d0cc3cc448624147dba64e9021b278c63e34a38789b688fd0da9bf3"},
+ {file = "xxhash-3.5.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:14470ace8bd3b5d51318782cd94e6f94431974f16cb3b8dc15d52f3b69df8e00"},
+ {file = "xxhash-3.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:59aa1203de1cb96dbeab595ded0ad0c0056bb2245ae11fac11c0ceea861382b9"},
+ {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08424f6648526076e28fae6ea2806c0a7d504b9ef05ae61d196d571e5c879c84"},
+ {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:61a1ff00674879725b194695e17f23d3248998b843eb5e933007ca743310f793"},
+ {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2f2c61bee5844d41c3eb015ac652a0229e901074951ae48581d58bfb2ba01be"},
+ {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d32a592cac88d18cc09a89172e1c32d7f2a6e516c3dfde1b9adb90ab5df54a6"},
+ {file = "xxhash-3.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:70dabf941dede727cca579e8c205e61121afc9b28516752fd65724be1355cc90"},
+ {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e5d0ddaca65ecca9c10dcf01730165fd858533d0be84c75c327487c37a906a27"},
+ {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e5b5e16c5a480fe5f59f56c30abdeba09ffd75da8d13f6b9b6fd224d0b4d0a2"},
+ {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149b7914451eb154b3dfaa721315117ea1dac2cc55a01bfbd4df7c68c5dd683d"},
+ {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:eade977f5c96c677035ff39c56ac74d851b1cca7d607ab3d8f23c6b859379cab"},
+ {file = "xxhash-3.5.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fa9f547bd98f5553d03160967866a71056a60960be00356a15ecc44efb40ba8e"},
+ {file = "xxhash-3.5.0-cp312-cp312-win32.whl", hash = "sha256:f7b58d1fd3551b8c80a971199543379be1cee3d0d409e1f6d8b01c1a2eebf1f8"},
+ {file = "xxhash-3.5.0-cp312-cp312-win_amd64.whl", hash = "sha256:fa0cafd3a2af231b4e113fba24a65d7922af91aeb23774a8b78228e6cd785e3e"},
+ {file = "xxhash-3.5.0-cp312-cp312-win_arm64.whl", hash = "sha256:586886c7e89cb9828bcd8a5686b12e161368e0064d040e225e72607b43858ba2"},
+ {file = "xxhash-3.5.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:37889a0d13b0b7d739cfc128b1c902f04e32de17b33d74b637ad42f1c55101f6"},
+ {file = "xxhash-3.5.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:97a662338797c660178e682f3bc180277b9569a59abfb5925e8620fba00b9fc5"},
+ {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f85e0108d51092bdda90672476c7d909c04ada6923c14ff9d913c4f7dc8a3bc"},
+ {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cd2fd827b0ba763ac919440042302315c564fdb797294d86e8cdd4578e3bc7f3"},
+ {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:82085c2abec437abebf457c1d12fccb30cc8b3774a0814872511f0f0562c768c"},
+ {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:07fda5de378626e502b42b311b049848c2ef38784d0d67b6f30bb5008642f8eb"},
+ {file = "xxhash-3.5.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c279f0d2b34ef15f922b77966640ade58b4ccdfef1c4d94b20f2a364617a493f"},
+ {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:89e66ceed67b213dec5a773e2f7a9e8c58f64daeb38c7859d8815d2c89f39ad7"},
+ {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bcd51708a633410737111e998ceb3b45d3dbc98c0931f743d9bb0a209033a326"},
+ {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3ff2c0a34eae7df88c868be53a8dd56fbdf592109e21d4bfa092a27b0bf4a7bf"},
+ {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:4e28503dccc7d32e0b9817aa0cbfc1f45f563b2c995b7a66c4c8a0d232e840c7"},
+ {file = "xxhash-3.5.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a6c50017518329ed65a9e4829154626f008916d36295b6a3ba336e2458824c8c"},
+ {file = "xxhash-3.5.0-cp313-cp313-win32.whl", hash = "sha256:53a068fe70301ec30d868ece566ac90d873e3bb059cf83c32e76012c889b8637"},
+ {file = "xxhash-3.5.0-cp313-cp313-win_amd64.whl", hash = "sha256:80babcc30e7a1a484eab952d76a4f4673ff601f54d5142c26826502740e70b43"},
+ {file = "xxhash-3.5.0-cp313-cp313-win_arm64.whl", hash = "sha256:4811336f1ce11cac89dcbd18f3a25c527c16311709a89313c3acaf771def2d4b"},
+ {file = "xxhash-3.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:6e5f70f6dca1d3b09bccb7daf4e087075ff776e3da9ac870f86ca316736bb4aa"},
+ {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e76e83efc7b443052dd1e585a76201e40b3411fe3da7af4fe434ec51b2f163b"},
+ {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33eac61d0796ca0591f94548dcfe37bb193671e0c9bcf065789b5792f2eda644"},
+ {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0ec70a89be933ea49222fafc3999987d7899fc676f688dd12252509434636622"},
+ {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86b8e7f703ec6ff4f351cfdb9f428955859537125904aa8c963604f2e9d3e7"},
+ {file = "xxhash-3.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0adfbd36003d9f86c8c97110039f7539b379f28656a04097e7434d3eaf9aa131"},
+ {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:63107013578c8a730419adc05608756c3fa640bdc6abe806c3123a49fb829f43"},
+ {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:683b94dbd1ca67557850b86423318a2e323511648f9f3f7b1840408a02b9a48c"},
+ {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:5d2a01dcce81789cf4b12d478b5464632204f4c834dc2d064902ee27d2d1f0ee"},
+ {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:a9d360a792cbcce2fe7b66b8d51274ec297c53cbc423401480e53b26161a290d"},
+ {file = "xxhash-3.5.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:f0b48edbebea1b7421a9c687c304f7b44d0677c46498a046079d445454504737"},
+ {file = "xxhash-3.5.0-cp37-cp37m-win32.whl", hash = "sha256:7ccb800c9418e438b44b060a32adeb8393764da7441eb52aa2aa195448935306"},
+ {file = "xxhash-3.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:c3bc7bf8cb8806f8d1c9bf149c18708cb1c406520097d6b0a73977460ea03602"},
+ {file = "xxhash-3.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:74752ecaa544657d88b1d1c94ae68031e364a4d47005a90288f3bab3da3c970f"},
+ {file = "xxhash-3.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:dee1316133c9b463aa81aca676bc506d3f80d8f65aeb0bba2b78d0b30c51d7bd"},
+ {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:602d339548d35a8579c6b013339fb34aee2df9b4e105f985443d2860e4d7ffaa"},
+ {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:695735deeddfb35da1677dbc16a083445360e37ff46d8ac5c6fcd64917ff9ade"},
+ {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1030a39ba01b0c519b1a82f80e8802630d16ab95dc3f2b2386a0b5c8ed5cbb10"},
+ {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a5bc08f33c4966f4eb6590d6ff3ceae76151ad744576b5fc6c4ba8edd459fdec"},
+ {file = "xxhash-3.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:160e0c19ee500482ddfb5d5570a0415f565d8ae2b3fd69c5dcfce8a58107b1c3"},
+ {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f1abffa122452481a61c3551ab3c89d72238e279e517705b8b03847b1d93d738"},
+ {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:d5e9db7ef3ecbfc0b4733579cea45713a76852b002cf605420b12ef3ef1ec148"},
+ {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:23241ff6423378a731d84864bf923a41649dc67b144debd1077f02e6249a0d54"},
+ {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:82b833d5563fefd6fceafb1aed2f3f3ebe19f84760fdd289f8b926731c2e6e91"},
+ {file = "xxhash-3.5.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0a80ad0ffd78bef9509eee27b4a29e56f5414b87fb01a888353e3d5bda7038bd"},
+ {file = "xxhash-3.5.0-cp38-cp38-win32.whl", hash = "sha256:50ac2184ffb1b999e11e27c7e3e70cc1139047e7ebc1aa95ed12f4269abe98d4"},
+ {file = "xxhash-3.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:392f52ebbb932db566973693de48f15ce787cabd15cf6334e855ed22ea0be5b3"},
+ {file = "xxhash-3.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bfc8cdd7f33d57f0468b0614ae634cc38ab9202c6957a60e31d285a71ebe0301"},
+ {file = "xxhash-3.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e0c48b6300cd0b0106bf49169c3e0536408dfbeb1ccb53180068a18b03c662ab"},
+ {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe1a92cfbaa0a1253e339ccec42dbe6db262615e52df591b68726ab10338003f"},
+ {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:33513d6cc3ed3b559134fb307aae9bdd94d7e7c02907b37896a6c45ff9ce51bd"},
+ {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eefc37f6138f522e771ac6db71a6d4838ec7933939676f3753eafd7d3f4c40bc"},
+ {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a606c8070ada8aa2a88e181773fa1ef17ba65ce5dd168b9d08038e2a61b33754"},
+ {file = "xxhash-3.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:42eca420c8fa072cc1dd62597635d140e78e384a79bb4944f825fbef8bfeeef6"},
+ {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:604253b2143e13218ff1ef0b59ce67f18b8bd1c4205d2ffda22b09b426386898"},
+ {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6e93a5ad22f434d7876665444a97e713a8f60b5b1a3521e8df11b98309bff833"},
+ {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:7a46e1d6d2817ba8024de44c4fd79913a90e5f7265434cef97026215b7d30df6"},
+ {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:30eb2efe6503c379b7ab99c81ba4a779748e3830241f032ab46bd182bf5873af"},
+ {file = "xxhash-3.5.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c8aa771ff2c13dd9cda8166d685d7333d389fae30a4d2bb39d63ab5775de8606"},
+ {file = "xxhash-3.5.0-cp39-cp39-win32.whl", hash = "sha256:5ed9ebc46f24cf91034544b26b131241b699edbfc99ec5e7f8f3d02d6eb7fba4"},
+ {file = "xxhash-3.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:220f3f896c6b8d0316f63f16c077d52c412619e475f9372333474ee15133a558"},
+ {file = "xxhash-3.5.0-cp39-cp39-win_arm64.whl", hash = "sha256:a7b1d8315d9b5e9f89eb2933b73afae6ec9597a258d52190944437158b49d38e"},
+ {file = "xxhash-3.5.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:2014c5b3ff15e64feecb6b713af12093f75b7926049e26a580e94dcad3c73d8c"},
+ {file = "xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fab81ef75003eda96239a23eda4e4543cedc22e34c373edcaf744e721a163986"},
+ {file = "xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2febf914ace002132aa09169cc572e0d8959d0f305f93d5828c4836f9bc5a6"},
+ {file = "xxhash-3.5.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5d3a10609c51da2a1c0ea0293fc3968ca0a18bd73838455b5bca3069d7f8e32b"},
+ {file = "xxhash-3.5.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5a74f23335b9689b66eb6dbe2a931a88fcd7a4c2cc4b1cb0edba8ce381c7a1da"},
+ {file = "xxhash-3.5.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2b4154c00eb22e4d543f472cfca430e7962a0f1d0f3778334f2e08a7ba59363c"},
+ {file = "xxhash-3.5.0-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d30bbc1644f726b825b3278764240f449d75f1a8bdda892e641d4a688b1494ae"},
+ {file = "xxhash-3.5.0-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fa0b72f2423e2aa53077e54a61c28e181d23effeaafd73fcb9c494e60930c8e"},
+ {file = "xxhash-3.5.0-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13de2b76c1835399b2e419a296d5b38dc4855385d9e96916299170085ef72f57"},
+ {file = "xxhash-3.5.0-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:0691bfcc4f9c656bcb96cc5db94b4d75980b9d5589f2e59de790091028580837"},
+ {file = "xxhash-3.5.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:297595fe6138d4da2c8ce9e72a04d73e58725bb60f3a19048bc96ab2ff31c692"},
+ {file = "xxhash-3.5.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc1276d369452040cbb943300dc8abeedab14245ea44056a2943183822513a18"},
+ {file = "xxhash-3.5.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2061188a1ba352fc699c82bff722f4baacb4b4b8b2f0c745d2001e56d0dfb514"},
+ {file = "xxhash-3.5.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:38c384c434021e4f62b8d9ba0bc9467e14d394893077e2c66d826243025e1f81"},
+ {file = "xxhash-3.5.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e6a4dd644d72ab316b580a1c120b375890e4c52ec392d4aef3c63361ec4d77d1"},
+ {file = "xxhash-3.5.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:531af8845aaadcadf951b7e0c1345c6b9c68a990eeb74ff9acd8501a0ad6a1c9"},
+ {file = "xxhash-3.5.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ce379bcaa9fcc00f19affa7773084dd09f5b59947b3fb47a1ceb0179f91aaa1"},
+ {file = "xxhash-3.5.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd1b2281d01723f076df3c8188f43f2472248a6b63118b036e641243656b1b0f"},
+ {file = "xxhash-3.5.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c770750cc80e8694492244bca7251385188bc5597b6a39d98a9f30e8da984e0"},
+ {file = "xxhash-3.5.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b150b8467852e1bd844387459aa6fbe11d7f38b56e901f9f3b3e6aba0d660240"},
+ {file = "xxhash-3.5.0.tar.gz", hash = "sha256:84f2caddf951c9cbf8dc2e22a89d4ccf5d86391ac6418fe81e3c67d0cf60b45f"},
+]
+
[[package]]
name = "zep-cloud"
version = "2.15.0"
@@ -4751,7 +5399,120 @@ httpx = ">=0.21.2"
pydantic = ">=1.9.2"
typing_extensions = ">=4.0.0"
+[[package]]
+name = "zstandard"
+version = "0.23.0"
+description = "Zstandard bindings for Python"
+optional = false
+python-versions = ">=3.8"
+groups = ["eval"]
+files = [
+ {file = "zstandard-0.23.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bf0a05b6059c0528477fba9054d09179beb63744355cab9f38059548fedd46a9"},
+ {file = "zstandard-0.23.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fc9ca1c9718cb3b06634c7c8dec57d24e9438b2aa9a0f02b8bb36bf478538880"},
+ {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77da4c6bfa20dd5ea25cbf12c76f181a8e8cd7ea231c673828d0386b1740b8dc"},
+ {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2170c7e0367dde86a2647ed5b6f57394ea7f53545746104c6b09fc1f4223573"},
+ {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c16842b846a8d2a145223f520b7e18b57c8f476924bda92aeee3a88d11cfc391"},
+ {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:157e89ceb4054029a289fb504c98c6a9fe8010f1680de0201b3eb5dc20aa6d9e"},
+ {file = "zstandard-0.23.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:203d236f4c94cd8379d1ea61db2fce20730b4c38d7f1c34506a31b34edc87bdd"},
+ {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:dc5d1a49d3f8262be192589a4b72f0d03b72dcf46c51ad5852a4fdc67be7b9e4"},
+ {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:752bf8a74412b9892f4e5b58f2f890a039f57037f52c89a740757ebd807f33ea"},
+ {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:80080816b4f52a9d886e67f1f96912891074903238fe54f2de8b786f86baded2"},
+ {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:84433dddea68571a6d6bd4fbf8ff398236031149116a7fff6f777ff95cad3df9"},
+ {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:ab19a2d91963ed9e42b4e8d77cd847ae8381576585bad79dbd0a8837a9f6620a"},
+ {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:59556bf80a7094d0cfb9f5e50bb2db27fefb75d5138bb16fb052b61b0e0eeeb0"},
+ {file = "zstandard-0.23.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:27d3ef2252d2e62476389ca8f9b0cf2bbafb082a3b6bfe9d90cbcbb5529ecf7c"},
+ {file = "zstandard-0.23.0-cp310-cp310-win32.whl", hash = "sha256:5d41d5e025f1e0bccae4928981e71b2334c60f580bdc8345f824e7c0a4c2a813"},
+ {file = "zstandard-0.23.0-cp310-cp310-win_amd64.whl", hash = "sha256:519fbf169dfac1222a76ba8861ef4ac7f0530c35dd79ba5727014613f91613d4"},
+ {file = "zstandard-0.23.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:34895a41273ad33347b2fc70e1bff4240556de3c46c6ea430a7ed91f9042aa4e"},
+ {file = "zstandard-0.23.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:77ea385f7dd5b5676d7fd943292ffa18fbf5c72ba98f7d09fc1fb9e819b34c23"},
+ {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:983b6efd649723474f29ed42e1467f90a35a74793437d0bc64a5bf482bedfa0a"},
+ {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80a539906390591dd39ebb8d773771dc4db82ace6372c4d41e2d293f8e32b8db"},
+ {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:445e4cb5048b04e90ce96a79b4b63140e3f4ab5f662321975679b5f6360b90e2"},
+ {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd30d9c67d13d891f2360b2a120186729c111238ac63b43dbd37a5a40670b8ca"},
+ {file = "zstandard-0.23.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d20fd853fbb5807c8e84c136c278827b6167ded66c72ec6f9a14b863d809211c"},
+ {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ed1708dbf4d2e3a1c5c69110ba2b4eb6678262028afd6c6fbcc5a8dac9cda68e"},
+ {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:be9b5b8659dff1f913039c2feee1aca499cfbc19e98fa12bc85e037c17ec6ca5"},
+ {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:65308f4b4890aa12d9b6ad9f2844b7ee42c7f7a4fd3390425b242ffc57498f48"},
+ {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:98da17ce9cbf3bfe4617e836d561e433f871129e3a7ac16d6ef4c680f13a839c"},
+ {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8ed7d27cb56b3e058d3cf684d7200703bcae623e1dcc06ed1e18ecda39fee003"},
+ {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:b69bb4f51daf461b15e7b3db033160937d3ff88303a7bc808c67bbc1eaf98c78"},
+ {file = "zstandard-0.23.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:034b88913ecc1b097f528e42b539453fa82c3557e414b3de9d5632c80439a473"},
+ {file = "zstandard-0.23.0-cp311-cp311-win32.whl", hash = "sha256:f2d4380bf5f62daabd7b751ea2339c1a21d1c9463f1feb7fc2bdcea2c29c3160"},
+ {file = "zstandard-0.23.0-cp311-cp311-win_amd64.whl", hash = "sha256:62136da96a973bd2557f06ddd4e8e807f9e13cbb0bfb9cc06cfe6d98ea90dfe0"},
+ {file = "zstandard-0.23.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:b4567955a6bc1b20e9c31612e615af6b53733491aeaa19a6b3b37f3b65477094"},
+ {file = "zstandard-0.23.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e172f57cd78c20f13a3415cc8dfe24bf388614324d25539146594c16d78fcc8"},
+ {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0e166f698c5a3e914947388c162be2583e0c638a4703fc6a543e23a88dea3c1"},
+ {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12a289832e520c6bd4dcaad68e944b86da3bad0d339ef7989fb7e88f92e96072"},
+ {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d50d31bfedd53a928fed6707b15a8dbeef011bb6366297cc435accc888b27c20"},
+ {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72c68dda124a1a138340fb62fa21b9bf4848437d9ca60bd35db36f2d3345f373"},
+ {file = "zstandard-0.23.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53dd9d5e3d29f95acd5de6802e909ada8d8d8cfa37a3ac64836f3bc4bc5512db"},
+ {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:6a41c120c3dbc0d81a8e8adc73312d668cd34acd7725f036992b1b72d22c1772"},
+ {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:40b33d93c6eddf02d2c19f5773196068d875c41ca25730e8288e9b672897c105"},
+ {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9206649ec587e6b02bd124fb7799b86cddec350f6f6c14bc82a2b70183e708ba"},
+ {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:76e79bc28a65f467e0409098fa2c4376931fd3207fbeb6b956c7c476d53746dd"},
+ {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:66b689c107857eceabf2cf3d3fc699c3c0fe8ccd18df2219d978c0283e4c508a"},
+ {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9c236e635582742fee16603042553d276cca506e824fa2e6489db04039521e90"},
+ {file = "zstandard-0.23.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:a8fffdbd9d1408006baaf02f1068d7dd1f016c6bcb7538682622c556e7b68e35"},
+ {file = "zstandard-0.23.0-cp312-cp312-win32.whl", hash = "sha256:dc1d33abb8a0d754ea4763bad944fd965d3d95b5baef6b121c0c9013eaf1907d"},
+ {file = "zstandard-0.23.0-cp312-cp312-win_amd64.whl", hash = "sha256:64585e1dba664dc67c7cdabd56c1e5685233fbb1fc1966cfba2a340ec0dfff7b"},
+ {file = "zstandard-0.23.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:576856e8594e6649aee06ddbfc738fec6a834f7c85bf7cadd1c53d4a58186ef9"},
+ {file = "zstandard-0.23.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:38302b78a850ff82656beaddeb0bb989a0322a8bbb1bf1ab10c17506681d772a"},
+ {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d2240ddc86b74966c34554c49d00eaafa8200a18d3a5b6ffbf7da63b11d74ee2"},
+ {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ef230a8fd217a2015bc91b74f6b3b7d6522ba48be29ad4ea0ca3a3775bf7dd5"},
+ {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:774d45b1fac1461f48698a9d4b5fa19a69d47ece02fa469825b442263f04021f"},
+ {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f77fa49079891a4aab203d0b1744acc85577ed16d767b52fc089d83faf8d8ed"},
+ {file = "zstandard-0.23.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac184f87ff521f4840e6ea0b10c0ec90c6b1dcd0bad2f1e4a9a1b4fa177982ea"},
+ {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c363b53e257246a954ebc7c488304b5592b9c53fbe74d03bc1c64dda153fb847"},
+ {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:e7792606d606c8df5277c32ccb58f29b9b8603bf83b48639b7aedf6df4fe8171"},
+ {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a0817825b900fcd43ac5d05b8b3079937073d2b1ff9cf89427590718b70dd840"},
+ {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9da6bc32faac9a293ddfdcb9108d4b20416219461e4ec64dfea8383cac186690"},
+ {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fd7699e8fd9969f455ef2926221e0233f81a2542921471382e77a9e2f2b57f4b"},
+ {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:d477ed829077cd945b01fc3115edd132c47e6540ddcd96ca169facff28173057"},
+ {file = "zstandard-0.23.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa6ce8b52c5987b3e34d5674b0ab529a4602b632ebab0a93b07bfb4dfc8f8a33"},
+ {file = "zstandard-0.23.0-cp313-cp313-win32.whl", hash = "sha256:a9b07268d0c3ca5c170a385a0ab9fb7fdd9f5fd866be004c4ea39e44edce47dd"},
+ {file = "zstandard-0.23.0-cp313-cp313-win_amd64.whl", hash = "sha256:f3513916e8c645d0610815c257cbfd3242adfd5c4cfa78be514e5a3ebb42a41b"},
+ {file = "zstandard-0.23.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:2ef3775758346d9ac6214123887d25c7061c92afe1f2b354f9388e9e4d48acfc"},
+ {file = "zstandard-0.23.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4051e406288b8cdbb993798b9a45c59a4896b6ecee2f875424ec10276a895740"},
+ {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2d1a054f8f0a191004675755448d12be47fa9bebbcffa3cdf01db19f2d30a54"},
+ {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f83fa6cae3fff8e98691248c9320356971b59678a17f20656a9e59cd32cee6d8"},
+ {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:32ba3b5ccde2d581b1e6aa952c836a6291e8435d788f656fe5976445865ae045"},
+ {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2f146f50723defec2975fb7e388ae3a024eb7151542d1599527ec2aa9cacb152"},
+ {file = "zstandard-0.23.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1bfe8de1da6d104f15a60d4a8a768288f66aa953bbe00d027398b93fb9680b26"},
+ {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:29a2bc7c1b09b0af938b7a8343174b987ae021705acabcbae560166567f5a8db"},
+ {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:61f89436cbfede4bc4e91b4397eaa3e2108ebe96d05e93d6ccc95ab5714be512"},
+ {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:53ea7cdc96c6eb56e76bb06894bcfb5dfa93b7adcf59d61c6b92674e24e2dd5e"},
+ {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:a4ae99c57668ca1e78597d8b06d5af837f377f340f4cce993b551b2d7731778d"},
+ {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:379b378ae694ba78cef921581ebd420c938936a153ded602c4fea612b7eaa90d"},
+ {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:50a80baba0285386f97ea36239855f6020ce452456605f262b2d33ac35c7770b"},
+ {file = "zstandard-0.23.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:61062387ad820c654b6a6b5f0b94484fa19515e0c5116faf29f41a6bc91ded6e"},
+ {file = "zstandard-0.23.0-cp38-cp38-win32.whl", hash = "sha256:b8c0bd73aeac689beacd4e7667d48c299f61b959475cdbb91e7d3d88d27c56b9"},
+ {file = "zstandard-0.23.0-cp38-cp38-win_amd64.whl", hash = "sha256:a05e6d6218461eb1b4771d973728f0133b2a4613a6779995df557f70794fd60f"},
+ {file = "zstandard-0.23.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3aa014d55c3af933c1315eb4bb06dd0459661cc0b15cd61077afa6489bec63bb"},
+ {file = "zstandard-0.23.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0a7f0804bb3799414af278e9ad51be25edf67f78f916e08afdb983e74161b916"},
+ {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb2b1ecfef1e67897d336de3a0e3f52478182d6a47eda86cbd42504c5cbd009a"},
+ {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:837bb6764be6919963ef41235fd56a6486b132ea64afe5fafb4cb279ac44f259"},
+ {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1516c8c37d3a053b01c1c15b182f3b5f5eef19ced9b930b684a73bad121addf4"},
+ {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48ef6a43b1846f6025dde6ed9fee0c24e1149c1c25f7fb0a0585572b2f3adc58"},
+ {file = "zstandard-0.23.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11e3bf3c924853a2d5835b24f03eeba7fc9b07d8ca499e247e06ff5676461a15"},
+ {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2fb4535137de7e244c230e24f9d1ec194f61721c86ebea04e1581d9d06ea1269"},
+ {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8c24f21fa2af4bb9f2c492a86fe0c34e6d2c63812a839590edaf177b7398f700"},
+ {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a8c86881813a78a6f4508ef9daf9d4995b8ac2d147dcb1a450448941398091c9"},
+ {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:fe3b385d996ee0822fd46528d9f0443b880d4d05528fd26a9119a54ec3f91c69"},
+ {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:82d17e94d735c99621bf8ebf9995f870a6b3e6d14543b99e201ae046dfe7de70"},
+ {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c7c517d74bea1a6afd39aa612fa025e6b8011982a0897768a2f7c8ab4ebb78a2"},
+ {file = "zstandard-0.23.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:1fd7e0f1cfb70eb2f95a19b472ee7ad6d9a0a992ec0ae53286870c104ca939e5"},
+ {file = "zstandard-0.23.0-cp39-cp39-win32.whl", hash = "sha256:43da0f0092281bf501f9c5f6f3b4c975a8a0ea82de49ba3f7100e64d422a1274"},
+ {file = "zstandard-0.23.0-cp39-cp39-win_amd64.whl", hash = "sha256:f8346bfa098532bc1fb6c7ef06783e969d87a99dd1d2a5a18a892c1d7a643c58"},
+ {file = "zstandard-0.23.0.tar.gz", hash = "sha256:b2d8c62d08e7255f68f7a740bae85b3c9b8e5466baa9cbf7f57f1cde0ac6bc09"},
+]
+
+[package.dependencies]
+cffi = {version = ">=1.11", markers = "platform_python_implementation == \"PyPy\""}
+
+[package.extras]
+cffi = ["cffi (>=1.11)"]
+
[metadata]
lock-version = "2.1"
python-versions = "^3.10"
-content-hash = "0e0294fc960128caac7069561ac7ec4e4dda42634db988ee96923ddc0af1ca1a"
+content-hash = "b56786e7bcdae03bbe0f031e2fe0bee284fef76534a3d3bfb24d6f70a44f4f0d"
diff --git a/pyproject.toml b/pyproject.toml
index 9d066b987..fe4bc0804 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -2,7 +2,7 @@
[tool.poetry]
name = "MemoryOS"
-version = "0.1.12"
+version = "0.1.13"
description = "Intelligence Begins with Memory"
license = "Apache-2.0"
authors = ["MemTensor