Repository navigation
Description
Pre-submission checklist | 提交前检查
- I have searched existing issues and this hasn't been mentioned before
- I have read the project documentation and confirmed this issue doesn't already exist
- This issue is specific to MemOS and not a general software issue
Bug Description | 问题描述
On every chat turn, MemOS rebuilds the system message from that turn's retrieval and sends the conversation history after it. Provider prefix caches keep the longest identical prefix from the start of the request. When the first message changes, the unchanged history behind it cannot be reused.
This is how the product chat API and the library chat entry build the provider request.
What happens:
ChatHandler.handle_chat_complete,handle_chat_stream,handle_chat_stream_playground, andhandle_chat_stream_for_business_usersearch memories for the current query, then build one system string and place history after it._build_system_promptwrites that turn's fact memories and preference text into the system string ({memories}, or an appended## Fact Memoriesblock).get_cloud_chat_promptalso writes the current minute into the same string, so the system message changes on the next minute even when the retrieved memories are the same.- The playground stream uses
_build_enhance_system_prompt, which writes the current time and appends PersonalMemory and OuterMemory to that same system message. MOS.chatinsrc/memos/mem_os/core.py, the chain-of-thought synthesis path insrc/memos/mem_os/main.py, andSimpleMemChatuse the same order: a system message that contains the memories, then the prior turns, then the current user message.src/memos/llms/openai.pysends thatmessageslist to the provider unchanged.
What was expected:
The part that stays the same across turns — the fixed instructions and the prior turns — should remain a common prefix. The text that changes with this turn's retrieval should come after that prefix, so a provider prefix cache can reuse the history.
MemOSClient.chat only posts the query to the hosted /chat endpoint. It does not build the provider messages. The assembly above is in ChatHandler and in MOS.chat.
How to Reproduce | 如何重现
- Call
POST /chat/completeorPOST /chat/streamtwice in one conversation. On the second call, pass the history that includes the first turn's user and assistant messages. Let the two calls retrieve different memories, or call them in different minutes with the same memories. - Look at the
messageslist the handler passes to the LLM. Insrc/memos/api/handlers/chat_handler.pyit is[system, *history[-20:], current user message]. The system content comes from_build_system_promptor, onPOST /chat/stream/playground, from_build_enhance_system_prompt. The business stream uses the same list. - Compare the two requests. The first message differs because it contains that turn's memories and, for the cloud prompt, the current minute. The prior turns are after that message, so they are not part of the shared prefix.
- The same order is in
MOS.chat(src/memos/mem_os/core.py):_build_system_promptwith the memories for this query, thenchat_history.chat_history, then the current user message. src/memos/llms/openai.py_build_request_bodyputs that list in the provider request asmessagesand does not move the system message.
A provider that caches the longest identical prefix therefore misses from the system message through the rest of the prompt. Unchanged history is not a cache hit.
Environment | 环境信息
- Python version: 3.12.15
- Operating System: macOS (Darwin 27.0.0, arm64)
- MemOS version: 2.0.33 (
pip show memoryosreports Name: MemoryOS, Version: 2.0.33)
Additional Context | 其他信息
Open issues were searched for prefix cache, prompt cache, and system-prompt retrieval. None describe this message order. The chat API documentation says retrieved memories are injected into the prompt; it does not keep a stable prefix ahead of the per-turn retrieval. The open activation-memory cache report is a different problem: it is about an in-process DynamicCache growing during generation, not about the provider prompt prefix.
Willingness to Implement | 实现意愿
- I'm willing to implement this myself
- I would like someone else to implement this
Activity
Memtensor-AI commentedon Oct 21, 2026
🤖 AutoDev has picked up this issue and started working on it.
Task ID:
e4f30089c2eb8ee3Working branch:
bugfix/autodev-2524-20261021095707472Target branch:
latest dev* branchWorkflow: opsp (analysis → coding → testing → PR)
I will post the PR link here once done. If I need more information, I will ask in the comments.
fix: keep stable system prompt + history as the shared prefix (MemTen…
Memtensor-AI commentedon Oct 21, 2026
✅ AutoDev task
e4f30089c2eb8ee3completed.Summary: Fix issue #2524: chat prompt rewrite busted provider prefix caches. The handler used to splice the current turn's retrieval and current minute into the system message and send that first, with chat history after it — so the first message changed every turn and the identical history behind it could not be reused.
Split the system blob into a stable prompt (byte-identical across turns in one conversation) plus a per-turn dynamic context message carrying the current time, retrieved memories, and preferences. New message layout is
[stable system, ...history, dynamic context, user], so the shared cross-turn prefix now grows with the chat history. Applied inChatHandler.handle_chat_complete,handle_chat_stream,handle_chat_stream_playground,handle_chat_stream_for_business_user,MOSCore.chat,MOS._generate_synthesis_response, andSimpleMemChat.run. Legacy callers that pass a custombase_promptcontaining{memories}keep the single-system shape for backward compatibility.Tests: added
tests/api/test_chat_message_order.py(9 cases covering stable/dynamic split, cacheable assembly, cross-turn shared prefix, and legacy-base-prompt compat), updatedtests/mem_os/test_memos_core.py::TestMOSChat::test_chat_with_custom_base_promptfor the new ordering, and addedtest_chat_places_history_before_dynamic_context_issue_2524. Full targeted runpytest tests/mem_os/ tests/api/ tests/mem_chat/is green: 167 passed. Ruff lint + format clean on all modified files. No API schema change (nomake openapineeded).Base branch:
mainBranch:
bugfix/autodev-2524-20261021095707472Commit:
8849727PR: #2529
Assigned to: @CarltonXiang
Reviewers: @WeiminLee
fix: address OCR feedback on prefix-cache refactor (MemTensor#2524)
fix: round 2 OCR follow-up — portable role for per-turn context (MemT…